diff --git a/.github/actions/build_linux/Dockerfile b/.github/actions/build_linux/Dockerfile index 229d3699..ed022d99 100644 --- a/.github/actions/build_linux/Dockerfile +++ b/.github/actions/build_linux/Dockerfile @@ -10,7 +10,7 @@ LABEL "homepage"="TBD" LABEL "maintainer"="dewb" RUN apt-get update -RUN apt-get install -y build-essential cmake curl gcc g++ git make tar unzip zip libgl1-mesa-dev libglu1-mesa-dev jq +RUN apt-get install -y build-essential cmake curl gcc g++ git make tar unzip zip libgl1-mesa-dev libglu1-mesa-dev jq zstd ADD entrypoint.sh /entrypoint.sh RUN chmod a+x /entrypoint.sh diff --git a/.github/actions/build_linux/entrypoint.sh b/.github/actions/build_linux/entrypoint.sh index 09bad89c..29ac645c 100644 --- a/.github/actions/build_linux/entrypoint.sh +++ b/.github/actions/build_linux/entrypoint.sh @@ -7,7 +7,7 @@ export RACK_USER_DIR=${GITHUB_WORKSPACE} git submodule update --init --recursive -curl -L https://vcvrack.com/downloads/Rack-SDK-${RACK_SDK_VERSION}.zip -o rack-sdk.zip +curl -L https://vcvrack.com/downloads/Rack-SDK-${RACK_SDK_VERSION}-lin.zip -o rack-sdk.zip unzip -o rack-sdk.zip rm rack-sdk.zip diff --git a/.github/actions/build_osx/Dockerfile b/.github/actions/build_osx/Dockerfile deleted file mode 100644 index dc144b36..00000000 --- a/.github/actions/build_osx/Dockerfile +++ /dev/null @@ -1,64 +0,0 @@ - -FROM debian - -LABEL "com.github.actions.name"="VCVRackPluginBuilder-OSX" -LABEL "com.github.actions.description"="Builds a VCV Rack plugin for OS X" -LABEL "com.github.actions.icon"="headphones" -LABEL "com.github.actions.color"="purple" - -LABEL "repository"="TBD" -LABEL "homepage"="TBD" -LABEL "maintainer"="dewb" - -RUN apt-get update && \ - apt-get upgrade -yy && \ - apt-get install -yy \ - automake \ - bison \ - curl \ - file \ - flex \ - git \ - libtool \ - pkg-config \ - python \ - texinfo \ - vim \ - wget \ - zlib1g-dev \ - build-essential \ - cmake \ - make \ - tar \ - unzip \ - zip \ - libgl1-mesa-dev \ - libglu1-mesa-dev \ - jq \ - rsync - -# Install osxcross -# NOTE: The Docker Hub's build machines run varying types of CPUs, so an image -# built with `-march=native` on one of those may not run on every machine - I -# ran into this problem when the images wouldn't run on my 2013-era Macbook -# Pro. As such, we remove this flag entirely. -ENV OSXCROSS_SDK_VERSION 10.11 -RUN SDK_VERSION=$OSXCROSS_SDK_VERSION \ - mkdir /opt/osxcross && \ - cd /opt && \ - git clone https://github.com/tpoechtrager/osxcross.git && \ - cd osxcross && \ - git checkout e0a171828a72a0d7ad4409489033536590008ebf && \ - sed -i -e 's|-march=native||g' ./build_clang.sh ./wrapper/build.sh && \ - ./tools/get_dependencies.sh && \ - curl -L -o ./tarballs/MacOSX${OSXCROSS_SDK_VERSION}.sdk.tar.xz \ - https://github.com/apriorit/osxcross-sdks/raw/master/MacOSX${OSXCROSS_SDK_VERSION}.sdk.tar.xz && \ - yes | PORTABLE=true ./build.sh && \ - ./build_compiler_rt.sh - -ENV PATH $PATH:/opt/osxcross/target/bin - -ADD entrypoint.sh /entrypoint.sh -RUN chmod a+x /entrypoint.sh - -ENTRYPOINT ["/entrypoint.sh"] diff --git a/.github/actions/build_osx/entrypoint.sh b/.github/actions/build_osx/entrypoint.sh deleted file mode 100644 index 2d867bdd..00000000 --- a/.github/actions/build_osx/entrypoint.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -set -eu - -export RACK_DIR=${GITHUB_WORKSPACE}/Rack-SDK -export RACK_USER_DIR=${GITHUB_WORKSPACE} - -export CC=x86_64-apple-darwin15-clang -export CXX=x86_64-apple-darwin15-clang++ -export STRIP=x86_64-apple-darwin15-strip - -git submodule update --init --recursive - -curl -L https://vcvrack.com/downloads/Rack-SDK-${RACK_SDK_VERSION}.zip -o rack-sdk.zip -unzip -o rack-sdk.zip -rm rack-sdk.zip - -make clean -make dist diff --git a/.github/actions/build_win/Dockerfile b/.github/actions/build_win/Dockerfile index cbd05724..a073a229 100644 --- a/.github/actions/build_win/Dockerfile +++ b/.github/actions/build_win/Dockerfile @@ -10,7 +10,7 @@ LABEL "homepage"="TBD" LABEL "maintainer"="dewb" RUN apt-get update -RUN apt-get install -y build-essential cmake curl gcc g++ git make tar unzip zip libgl1-mesa-dev libglu1-mesa-dev jq g++-mingw-w64-x86-64 +RUN apt-get install -y build-essential cmake curl gcc g++ git make tar unzip zip libgl1-mesa-dev libglu1-mesa-dev jq g++-mingw-w64-x86-64 zstd ADD entrypoint.sh /entrypoint.sh RUN chmod a+x /entrypoint.sh diff --git a/.github/actions/build_win/entrypoint.sh b/.github/actions/build_win/entrypoint.sh index bac5efa3..f434d8ac 100644 --- a/.github/actions/build_win/entrypoint.sh +++ b/.github/actions/build_win/entrypoint.sh @@ -11,9 +11,10 @@ export STRIP=x86_64-w64-mingw32-strip git submodule update --init --recursive -curl -L https://vcvrack.com/downloads/Rack-SDK-${RACK_SDK_VERSION}.zip -o rack-sdk.zip +curl -L https://vcvrack.com/downloads/Rack-SDK-${RACK_SDK_VERSION}-win.zip -o rack-sdk.zip unzip -o rack-sdk.zip rm rack-sdk.zip make clean make dist +chmod 644 dist/*.vcvplugin diff --git a/.github/actions/combine_zip/script.sh b/.github/actions/combine_zip/script.sh deleted file mode 100644 index 8494d1ce..00000000 --- a/.github/actions/combine_zip/script.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh - -set -eu - -GITHUB_API_URL=https://api.github.com - -GITHUB_TOKEN=$1 - -curl -o release.json \ - --header "Authorization: token ${GITHUB_TOKEN}" \ - --request GET \ - ${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases/${GITHUB_REF#"refs/"} - -UPLOAD_URL=$(jq -r .upload_url release.json) - -DOWNLOAD_LIST=$(jq -r ".assets | .[] | .url" release.json) - -rm release.json - -mkdir dist - -echo "$DOWNLOAD_LIST" | while IFS= read -r line -do - curl -L -o $(basename $line).zip --header "Authorization: token ${GITHUB_TOKEN}" --header "Accept: application/octet-stream" --request GET $line - unzip -o $(basename $line).zip -d dist - rm $(basename $line).zip -done - -PLUGIN_BUILD_SLUG=$(jq -r .slug plugin.json) -PLUGIN_BUILD_NAME=${PLUGIN_BUILD_SLUG}-$(jq -r .version plugin.json) -cd dist -zip -q -9 -r ${PLUGIN_BUILD_NAME}.zip ./${PLUGIN_BUILD_SLUG} -cd .. - -ASSET_PATH=$(ls dist/*.zip) - -curl -i \ - --header "Authorization: token ${GITHUB_TOKEN}" \ - --header "Content-Type: application/zip" \ - --request POST \ - --data-binary @"${ASSET_PATH}" \ - ${UPLOAD_URL%"{?name,label\}"}?name=${ASSET_PATH#"dist/"} diff --git a/.github/actions/upload_zip/script.sh b/.github/actions/upload_plugin_lin/script.sh similarity index 85% rename from .github/actions/upload_zip/script.sh rename to .github/actions/upload_plugin_lin/script.sh index af089805..aa184761 100644 --- a/.github/actions/upload_zip/script.sh +++ b/.github/actions/upload_plugin_lin/script.sh @@ -14,11 +14,11 @@ curl -o release.json \ UPLOAD_URL=$(jq -r .upload_url release.json) -ASSET_PATH=$(ls dist/*.zip) +ASSET_PATH=$(ls dist/*.vcvplugin) curl -i \ --header "Authorization: token ${GITHUB_TOKEN}" \ - --header "Content-Type: application/zip" \ + --header "Content-Type: application/zstd" \ --request POST \ --data-binary @"${ASSET_PATH}" \ ${UPLOAD_URL%"{?name,label\}"}?name=${ASSET_PATH#"dist/"} diff --git a/.github/actions/upload_plugin_mac/script.sh b/.github/actions/upload_plugin_mac/script.sh new file mode 100644 index 00000000..8d1b1d17 --- /dev/null +++ b/.github/actions/upload_plugin_mac/script.sh @@ -0,0 +1,25 @@ + +#!/bin/bash + +set -eu + +GITHUB_API_URL=https://api.github.com + +GITHUB_TOKEN=$1 + +# Get release url +curl -o release.json \ + --header "Authorization: token ${GITHUB_TOKEN}" \ + --request GET \ + ${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases/${GITHUB_REF#"refs/"} + +UPLOAD_URL=$(jq -r .upload_url release.json) + +ASSET_PATH=$(ls dist/*.vcvplugin) + +curl -i \ + --header "Authorization: token ${GITHUB_TOKEN}" \ + --header "Content-Type: application/zstd" \ + --request POST \ + --data-binary @"${ASSET_PATH}" \ + ${UPLOAD_URL/\{\?name,label\}/}?name=${ASSET_PATH#"dist/"} diff --git a/.github/actions/upload_plugin_win/script.sh b/.github/actions/upload_plugin_win/script.sh new file mode 100644 index 00000000..2fcf36a3 --- /dev/null +++ b/.github/actions/upload_plugin_win/script.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +set -eu + +GITHUB_API_URL=https://api.github.com + +GITHUB_TOKEN=$1 + +# Get release url +curl -o release.json \ + --header "Authorization: token ${GITHUB_TOKEN}" \ + --request GET \ + ${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases/${GITHUB_REF#"refs/"} + +UPLOAD_URL=$(jq -r .upload_url release.json) +# sleep 5 +# ls -al dist +# ls -al +ASSET_PATH=$(ls dist/*.vcvplugin) +# cp ${ASSET_PATH} . +# ASSET_PATH=${ASSET_PATH#"dist/"} +# echo ${ASSET_PATH} +# ls -al +# ls -al dist + +curl -i \ + --header "Authorization: token ${GITHUB_TOKEN}" \ + --header "Content-Type: application/zstd" \ + --request POST \ + --data-binary @"${ASSET_PATH}" \ + ${UPLOAD_URL%"{?name,label\}"}?name=${ASSET_PATH#"dist/"} diff --git a/.github/workflows/buildDevelop.yml b/.github/workflows/buildDevelop.yml index 744a36f6..adb63d40 100644 --- a/.github/workflows/buildDevelop.yml +++ b/.github/workflows/buildDevelop.yml @@ -4,7 +4,7 @@ on: - develop name: Develop env: - RACK_SDK_VERSION: 1.1.6 + RACK_SDK_VERSION: 2.0.0 jobs: buildLinux: name: Build Linux diff --git a/.github/workflows/buildRelease.yml b/.github/workflows/buildRelease.yml index 26fa3243..3e2998b1 100644 --- a/.github/workflows/buildRelease.yml +++ b/.github/workflows/buildRelease.yml @@ -3,7 +3,9 @@ on: types: [published] name: Release env: - RACK_SDK_VERSION: 1.1.6 + RACK_DIR: ${GITHUB_WORKSPACE}/Rack-SDK + RACK_USER_DIR: ${GITHUB_WORKSPACE} + RACK_SDK_VERSION: 2.0.0 jobs: buildLinux: name: Build Linux @@ -13,7 +15,7 @@ jobs: - name: Build Linux uses: ./.github/actions/build_linux - name: upload zip - run: sh ./.github/actions/upload_zip/script.sh ${{ secrets.GITHUB_TOKEN }} + run: sh ./.github/actions/upload_plugin_lin/script.sh ${{ secrets.GITHUB_TOKEN }} buildWindows: name: Build Windows runs-on: ubuntu-latest @@ -22,21 +24,23 @@ jobs: - name: Build Windows uses: ./.github/actions/build_win - name: upload zip - run: sh ./.github/actions/upload_zip/script.sh ${{ secrets.GITHUB_TOKEN }} + run: sh ./.github/actions/upload_plugin_win/script.sh ${{ secrets.GITHUB_TOKEN }} buildOsx: name: Build OSX - runs-on: ubuntu-latest + runs-on: macos-10.15 steps: - uses: actions/checkout@master - - name: Build OSX - uses: ./.github/actions/build_osx + - name: install tools + run: brew install automake + - name: get Rack-SDK + run: curl -L https://vcvrack.com/downloads/Rack-SDK-${RACK_SDK_VERSION}-mac.zip -o rack-sdk.zip + - name: unzip SDK + run: unzip -o rack-sdk.zip + - name: clean up SDK + run: rm rack-sdk.zip + - name: update submodules + run: git submodule update --init --recursive + - name: make + run: make dist - name: upload zip - run: sh ./.github/actions/upload_zip/script.sh ${{ secrets.GITHUB_TOKEN }} - combineDist: - name: Combine Distributions - runs-on: ubuntu-latest - needs: [buildLinux, buildWindows, buildOsx] - steps: - - uses: actions/checkout@master - - name: combine zip - run: sh ./.github/actions/combine_zip/script.sh ${{ secrets.GITHUB_TOKEN }} + run: sh ./.github/actions/upload_plugin_mac/script.sh ${{ secrets.GITHUB_TOKEN }} diff --git a/Makefile b/Makefile index ea1dafd7..38be9da5 100755 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # FLAGS will be passed to both the C and C++ compiler FLAGS += CFLAGS += -CXXFLAGS += +CXXFLAGS += # Careful about linking to shared libraries, since you can't assume much about the user's environment and library search path. # Static libraries are fine. diff --git a/changelog.md b/changelog.md index 238ea0d0..094cf3c8 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,32 @@ # Changelog +## v2.0.1 +- 30-Nov-2021 Add LA-216 Polyphonic Logic Analyser + +## v2.0.0 +- 11-Oct-2021 Port shared components to v2 +- 11-Oct-2021 Port Blanking plates to v2 +- 14-Oct-2021 Port LA-108 to v2 +- 15-Oct-2021 Port AG-xxx OG-xxx NG-xxx XG-xxx LD-xxx and PG-xxx to v2 +- 15-Oct-2021 Persist DS suite voltage range between devices. When voltage is changed, new devices use the same option +- 15-Oct-2021 Port BB-xxx DN-xxx FF-xxx OA-xxx to v2 +- 25-Oct-2021 Port Text devices and Wiremanager +- 26-Oct-2021 Port HS-101 and EO-102 to v2 +- 26-Oct-2021 Port EN-104 PO-101 PO-102 PO-202 and SN-101 to v2 +- 28-Oct-2021 Port WK-101 and WK-205 to v2 Deprecated Torpedo in WK devices and replace with extension modules +- 28-Oct-2021 Add Module Link lights for expander modules +- 29-Oct-2021 Port LT-116 to v2 +- 29-Oct-2021 Port XF-xxx to v2 +- 29-Oct-2021 Port VU meters to v2, including new backlights +- 03-Nov-2021 Make DO-1xx devices more usable, improve connection labelling, add shuffle and copy/paste +- 05-Nov-2021 Add visuals to TD-xxx, DO-1xx and WM-102 devices in the module browser +- 05-Nov-2021 Add Device copy/paste and undo to AO-1xx devices +- 12-Nov-2021 Add expansion capabilities to VM-1xx and VM-2xx devices +- 14-Nov-2021 Use keywords to make library searching more effective +- 14-Nov-2021 Add VM-104 Quad digital VU-meter +- 19-Nov-2021 Add VM-204 Quad vintage VU-meter +- 22-Nov-2021 Fix rendering bug in VM-1xx devices + ## v1.1.10 - 10-Dec-2020 Update images in manual - 26-Nov-2020 Add exponential response to VM-needle diff --git a/manual/A0-106.png b/manual/A0-106.png new file mode 100644 index 00000000..b0072f28 Binary files /dev/null and b/manual/A0-106.png differ diff --git a/manual/A0-112.png b/manual/A0-112.png new file mode 100644 index 00000000..023cb281 Binary files /dev/null and b/manual/A0-112.png differ diff --git a/manual/A0-118.png b/manual/A0-118.png new file mode 100644 index 00000000..ced6933e Binary files /dev/null and b/manual/A0-118.png differ diff --git a/manual/A0-124.png b/manual/A0-124.png new file mode 100644 index 00000000..5b18a602 Binary files /dev/null and b/manual/A0-124.png differ diff --git a/manual/A0-136.png b/manual/A0-136.png new file mode 100644 index 00000000..a48e0f68 Binary files /dev/null and b/manual/A0-136.png differ diff --git a/manual/AG-104.m.png b/manual/AG-104.m.png deleted file mode 100644 index 3547cc3b..00000000 Binary files a/manual/AG-104.m.png and /dev/null differ diff --git a/manual/AG-104.png b/manual/AG-104.png new file mode 100644 index 00000000..b0d29a81 Binary files /dev/null and b/manual/AG-104.png differ diff --git a/manual/AG-106.m.png b/manual/AG-106.m.png deleted file mode 100644 index 715fd301..00000000 Binary files a/manual/AG-106.m.png and /dev/null differ diff --git a/manual/AG-106.png b/manual/AG-106.png new file mode 100644 index 00000000..ae805223 Binary files /dev/null and b/manual/AG-106.png differ diff --git a/manual/AG-202.m.png b/manual/AG-202.m.png deleted file mode 100644 index 37e513d5..00000000 Binary files a/manual/AG-202.m.png and /dev/null differ diff --git a/manual/AG-202.png b/manual/AG-202.png new file mode 100644 index 00000000..5252b2c5 Binary files /dev/null and b/manual/AG-202.png differ diff --git a/manual/AG.md b/manual/AG.md index 010de337..d4639623 100755 --- a/manual/AG.md +++ b/manual/AG.md @@ -1,11 +1,11 @@ # Logical AND Gates ### [Part of the Digital Suite](DS.md) #### AG-104 AND Gates -![View of the AND Gates](AG-104.m.png "AND Gates") +![View of the AND Gates](AG-104.png "AND Gates") #### AG-106 AND Gates -![View of the AND Gates](AG-106.m.png "AND Gates") +![View of the AND Gates](AG-106.png "AND Gates") #### AG-202 Polyphonic AND Gates -![View of the AND Gates](AG-202.m.png "AND Gates") +![View of the AND Gates](AG-202.png "AND Gates") ## Basic Operation diff --git a/manual/AO-106.m.png b/manual/AO-106.m.png deleted file mode 100644 index c7beaa84..00000000 Binary files a/manual/AO-106.m.png and /dev/null differ diff --git a/manual/AO-112.m.png b/manual/AO-112.m.png deleted file mode 100644 index deb248be..00000000 Binary files a/manual/AO-112.m.png and /dev/null differ diff --git a/manual/AO-118.m.png b/manual/AO-118.m.png deleted file mode 100644 index 8dda2ca4..00000000 Binary files a/manual/AO-118.m.png and /dev/null differ diff --git a/manual/AO-124.m.png b/manual/AO-124.m.png deleted file mode 100644 index 7bbf8fb9..00000000 Binary files a/manual/AO-124.m.png and /dev/null differ diff --git a/manual/AO-136.m.png b/manual/AO-136.m.png deleted file mode 100644 index b95d23e5..00000000 Binary files a/manual/AO-136.m.png and /dev/null differ diff --git a/manual/AO.md b/manual/AO.md index e1da3fe6..07c5a33d 100755 --- a/manual/AO.md +++ b/manual/AO.md @@ -1,14 +1,14 @@ # Arithmetic Operators #### AO-106 6 Algorithm Arithmetic Operators -![View of the AO-106 - Arithmetic Operators](AO-106.m.png "Arithmetic Operators") +![View of the AO-106 - Arithmetic Operators](AO-106.png "Arithmetic Operators") #### AO-112 12 Algorithm Arithmetic Operators -![View of the AO-112 - Arithmetic Operators](AO-112.m.png "Arithmetic Operators") +![View of the AO-112 - Arithmetic Operators](AO-112.png "Arithmetic Operators") #### AO-118 18 Algorithm Arithmetic Operators -![View of the AO-118 - Arithmetic Operators](AO-118.m.png "Arithmetic Operators") +![View of the AO-118 - Arithmetic Operators](AO-118.png "Arithmetic Operators") #### AO-124 24 Algorithm Arithmetic Operators -![View of the AO-124 - Arithmetic Operators](AO-124.m.png "Arithmetic Operators") +![View of the AO-124 - Arithmetic Operators](AO-124.png "Arithmetic Operators") #### AO-136 36 Algorithm Arithmetic Operators -![View of the AO-136 - Arithmetic Operators](AO-136.m.png "Arithmetic Operators") +![View of the AO-136 - Arithmetic Operators](AO-136.png "Arithmetic Operators") ## Basic Operation diff --git a/manual/BB-120.m.png b/manual/BB-120.m.png deleted file mode 100644 index 036b3ab6..00000000 Binary files a/manual/BB-120.m.png and /dev/null differ diff --git a/manual/BB-120.png b/manual/BB-120.png new file mode 100644 index 00000000..db4c1d6e Binary files /dev/null and b/manual/BB-120.png differ diff --git a/manual/BB.md b/manual/BB.md index 2c852220..587d3c00 100755 --- a/manual/BB.md +++ b/manual/BB.md @@ -3,7 +3,7 @@ #### BB-120 20-Stage Bucket Brigade Sample and Hold -![View of the Sample and Hold Latches](BB-120.m.png "Sample and Hold Latches") +![View of the Sample and Hold Latches](BB-120.png "Sample and Hold Latches") ## Basic Operation diff --git a/manual/BP-101.m.png b/manual/BP-101.m.png deleted file mode 100644 index 22eeba0a..00000000 Binary files a/manual/BP-101.m.png and /dev/null differ diff --git a/manual/BP-101.png b/manual/BP-101.png new file mode 100644 index 00000000..469af734 Binary files /dev/null and b/manual/BP-101.png differ diff --git a/manual/BP-102.m.png b/manual/BP-102.m.png deleted file mode 100644 index 43aaaeb1..00000000 Binary files a/manual/BP-102.m.png and /dev/null differ diff --git a/manual/BP-102.png b/manual/BP-102.png new file mode 100644 index 00000000..fcc6ebac Binary files /dev/null and b/manual/BP-102.png differ diff --git a/manual/BP-104.m.png b/manual/BP-104.m.png deleted file mode 100644 index 3f6e93d0..00000000 Binary files a/manual/BP-104.m.png and /dev/null differ diff --git a/manual/BP-104.png b/manual/BP-104.png new file mode 100644 index 00000000..a3c1f874 Binary files /dev/null and b/manual/BP-104.png differ diff --git a/manual/BP-108.m.png b/manual/BP-108.m.png deleted file mode 100644 index f4321780..00000000 Binary files a/manual/BP-108.m.png and /dev/null differ diff --git a/manual/BP-108.png b/manual/BP-108.png new file mode 100644 index 00000000..3ef08f05 Binary files /dev/null and b/manual/BP-108.png differ diff --git a/manual/BP-110.m.png b/manual/BP-110.m.png deleted file mode 100644 index 5e027ae6..00000000 Binary files a/manual/BP-110.m.png and /dev/null differ diff --git a/manual/BP-110.png b/manual/BP-110.png new file mode 100644 index 00000000..6ae430e2 Binary files /dev/null and b/manual/BP-110.png differ diff --git a/manual/BP-112.m.png b/manual/BP-112.m.png deleted file mode 100644 index 535bfe76..00000000 Binary files a/manual/BP-112.m.png and /dev/null differ diff --git a/manual/BP-112.png b/manual/BP-112.png new file mode 100644 index 00000000..b28669ca Binary files /dev/null and b/manual/BP-112.png differ diff --git a/manual/BP-116.m.png b/manual/BP-116.m.png deleted file mode 100644 index 3cb9c732..00000000 Binary files a/manual/BP-116.m.png and /dev/null differ diff --git a/manual/BP-116.png b/manual/BP-116.png new file mode 100644 index 00000000..7716f6d1 Binary files /dev/null and b/manual/BP-116.png differ diff --git a/manual/BP-120.m.png b/manual/BP-120.m.png deleted file mode 100644 index 2340180b..00000000 Binary files a/manual/BP-120.m.png and /dev/null differ diff --git a/manual/BP-120.png b/manual/BP-120.png new file mode 100644 index 00000000..701ad88c Binary files /dev/null and b/manual/BP-120.png differ diff --git a/manual/BP-124.m.png b/manual/BP-124.m.png deleted file mode 100644 index 5fdbec1b..00000000 Binary files a/manual/BP-124.m.png and /dev/null differ diff --git a/manual/BP-124.png b/manual/BP-124.png new file mode 100644 index 00000000..f0c39633 Binary files /dev/null and b/manual/BP-124.png differ diff --git a/manual/BP-132.m.png b/manual/BP-132.m.png deleted file mode 100644 index 7774e6c2..00000000 Binary files a/manual/BP-132.m.png and /dev/null differ diff --git a/manual/BP-132.png b/manual/BP-132.png new file mode 100644 index 00000000..7cd79578 Binary files /dev/null and b/manual/BP-132.png differ diff --git a/manual/BP.md b/manual/BP.md index 679b612a..af7a9bf1 100755 --- a/manual/BP.md +++ b/manual/BP.md @@ -1,24 +1,24 @@ # Blanking Plates #### BP-101 -![View of the Blanking Plates](BP-101.m.png "Blanking Plates") +![View of the Blanking Plates](BP-101.png "Blanking Plates") #### BP-102 -![View of the Blanking Plates](BP-102.m.png "Blanking Plates") +![View of the Blanking Plates](BP-102.png "Blanking Plates") #### BP-104 -![View of the Blanking Plates](BP-104.m.png "Blanking Plates") +![View of the Blanking Plates](BP-104.png "Blanking Plates") #### BP-108 -![View of the Blanking Plates](BP-108.m.png "Blanking Plates") +![View of the Blanking Plates](BP-108.png "Blanking Plates") #### BP-110 -![View of the Blanking Plates](BP-110.m.png "Blanking Plates") +![View of the Blanking Plates](BP-110.png "Blanking Plates") #### BP-112 -![View of the Blanking Plates](BP-112.m.png "Blanking Plates") +![View of the Blanking Plates](BP-112.png "Blanking Plates") #### BP-116 -![View of the Blanking Plates](BP-116.m.png "Blanking Plates") +![View of the Blanking Plates](BP-116.png "Blanking Plates") #### BP-120 -![View of the Blanking Plates](BP-120.m.png "Blanking Plates") +![View of the Blanking Plates](BP-120.png "Blanking Plates") #### BP-124 -![View of the Blanking Plates](BP-124.m.png "Blanking Plates") +![View of the Blanking Plates](BP-124.png "Blanking Plates") #### BP-132 -![View of the Blanking Plates](BP-132.m.png "Blanking Plates") +![View of the Blanking Plates](BP-132.png "Blanking Plates") A range of Blanking Plates in convenient sizes to keep the dust out of your rack. Designed to match the aesthetic of the Submarine range of modules, the Blanking Plates are made of Titanium-Unobtanium alloy, bevelled edges, and fully concealed fixings for durability and peace of mind. diff --git a/manual/DN-112.m.png b/manual/DN-112.m.png deleted file mode 100644 index 108cdaa0..00000000 Binary files a/manual/DN-112.m.png and /dev/null differ diff --git a/manual/DN-112.png b/manual/DN-112.png new file mode 100644 index 00000000..bb1c2a11 Binary files /dev/null and b/manual/DN-112.png differ diff --git a/manual/DN.md b/manual/DN.md index 39c2c31e..59a373aa 100644 --- a/manual/DN.md +++ b/manual/DN.md @@ -3,7 +3,7 @@ #### DN-112 Digital Noise Source -![View of the Digital Noise Source](DN-112.m.png "Digital Noise Source") +![View of the Digital Noise Source](DN-112.png "Digital Noise Source") ## Basic Operation diff --git a/manual/DO-105.m.png b/manual/DO-105.m.png deleted file mode 100644 index ee5e1b87..00000000 Binary files a/manual/DO-105.m.png and /dev/null differ diff --git a/manual/DO-105.png b/manual/DO-105.png new file mode 100644 index 00000000..83e898bd Binary files /dev/null and b/manual/DO-105.png differ diff --git a/manual/DO-110.m.png b/manual/DO-110.m.png deleted file mode 100644 index eb29f8d8..00000000 Binary files a/manual/DO-110.m.png and /dev/null differ diff --git a/manual/DO-110.png b/manual/DO-110.png new file mode 100644 index 00000000..aad4b3bd Binary files /dev/null and b/manual/DO-110.png differ diff --git a/manual/DO-115.m.png b/manual/DO-115.m.png deleted file mode 100644 index 6e027e07..00000000 Binary files a/manual/DO-115.m.png and /dev/null differ diff --git a/manual/DO-115.png b/manual/DO-115.png new file mode 100644 index 00000000..30f42855 Binary files /dev/null and b/manual/DO-115.png differ diff --git a/manual/DO-120.m.png b/manual/DO-120.m.png deleted file mode 100644 index cc86dd42..00000000 Binary files a/manual/DO-120.m.png and /dev/null differ diff --git a/manual/DO-120.png b/manual/DO-120.png new file mode 100644 index 00000000..eae72444 Binary files /dev/null and b/manual/DO-120.png differ diff --git a/manual/DO.md b/manual/DO.md index 39f1d2e8..4ce021ea 100644 --- a/manual/DO.md +++ b/manual/DO.md @@ -1,13 +1,13 @@ # Digital Operators ### [Part of the Digital Suite](DS.md) #### DO-105 5 Gate Digital Operators -![View of the Digital Operators](DO-105.m.png "Digital Operators") +![View of the Digital Operators](DO-105.png "Digital Operators") #### DO-110 10 Gate Digital Operators -![View of the Digital Operators](DO-110.m.png "Digital Operators") +![View of the Digital Operators](DO-110.png "Digital Operators") #### DO-115 15 Gate Digital Operators -![View of the Digital Operators](DO-115.m.png "Digital Operators") +![View of the Digital Operators](DO-115.png "Digital Operators") #### DO-120 20 Gate Digital Operators -![View of the Digital Operators](DO-120.m.png "Digital Operators") +![View of the Digital Operators](DO-120.png "Digital Operators") ## Basic Operation @@ -34,7 +34,7 @@ the routing of the device. But you can connect a cable directly between the dev ## Truth Tables -If you right click on a gate, a truth table will be displayed to help you understand the connections to and from the gate. +If you right click on a gate, the menu will offer a truth table which can help you understand the connections to and from the gate. ## Signal Range @@ -49,3 +49,18 @@ An input not connected will generate 0V on all polyphonic channels. The meaning All 4 outputs will have a number of channels which is the maximum number of channels presented at the inputs. An input with a single channel will present that voltage across all the channels being processed. An input with more than one channel, but fewer than the number of channels being processed will present 0V on the excess channels. + +## Shuffle + +Empty (not connected) gate slots can be deleted using the right-click menu on the gate. This will cause any gates below that to be shuffled up the device, including all the related connections. + +Gates which are not empty can be shuffled down if you need to make additional space to insert a gate. All related connections will be automatically adjusted at the same time. + +## Copying to another device + +The right click menu on the device as a whole (not on an individual gate) offers copy and paste options which will allow you to copy and paste even between DO-1xx devices of different sizes. + +When copying to a smaller device, empty (not connected) gate slots may be deleted to help the circuit fit into the destination device, all connections will be correctly adjusted to suit. Note that deleting empty slots will only happen if it is necessary. +The circuit in the source device will not be affected. + + diff --git a/manual/EN-104.m.png b/manual/EN-104.m.png deleted file mode 100644 index 07add096..00000000 Binary files a/manual/EN-104.m.png and /dev/null differ diff --git a/manual/EN-104.png b/manual/EN-104.png new file mode 100644 index 00000000..451c6a5a Binary files /dev/null and b/manual/EN-104.png differ diff --git a/manual/EN.md b/manual/EN.md index 85a43213..40a14dd1 100755 --- a/manual/EN.md +++ b/manual/EN.md @@ -2,7 +2,7 @@ #### EN-104 Envelope Generator -![View of the Envelope Generator](EN-104.m.png "Envelope Generator") +![View of the Envelope Generator](EN-104.png "Envelope Generator") ## Basic Operation diff --git a/manual/EO-102.m.png b/manual/EO-102.m.png deleted file mode 100644 index 5f483ac2..00000000 Binary files a/manual/EO-102.m.png and /dev/null differ diff --git a/manual/EO-102.png b/manual/EO-102.png new file mode 100644 index 00000000..6c0e44c8 Binary files /dev/null and b/manual/EO-102.png differ diff --git a/manual/EO.md b/manual/EO.md index 368b6adf..af9fcc6a 100755 --- a/manual/EO.md +++ b/manual/EO.md @@ -1,7 +1,7 @@ # Envelope Oscilloscope #### EO-102 2-Channel Envelope Oscilloscope -![View of the Envelope Oscilloscope](EO-102.m.png "Envelope Oscilloscope") +![View of the Envelope Oscilloscope](EO-102.png "Envelope Oscilloscope") ## Basic Operation diff --git a/manual/FF-110.m.png b/manual/FF-110.m.png deleted file mode 100644 index 316c5e25..00000000 Binary files a/manual/FF-110.m.png and /dev/null differ diff --git a/manual/FF-110.png b/manual/FF-110.png new file mode 100644 index 00000000..1b141b2a Binary files /dev/null and b/manual/FF-110.png differ diff --git a/manual/FF-120.m.png b/manual/FF-120.m.png deleted file mode 100644 index 12c99924..00000000 Binary files a/manual/FF-120.m.png and /dev/null differ diff --git a/manual/FF-120.png b/manual/FF-120.png new file mode 100644 index 00000000..8cb37c11 Binary files /dev/null and b/manual/FF-120.png differ diff --git a/manual/FF-206.m.png b/manual/FF-206.m.png deleted file mode 100644 index 1b743b80..00000000 Binary files a/manual/FF-206.m.png and /dev/null differ diff --git a/manual/FF-206.png b/manual/FF-206.png new file mode 100644 index 00000000..b739add5 Binary files /dev/null and b/manual/FF-206.png differ diff --git a/manual/FF-212.m.png b/manual/FF-212.m.png deleted file mode 100644 index b6951806..00000000 Binary files a/manual/FF-212.m.png and /dev/null differ diff --git a/manual/FF-212.png b/manual/FF-212.png new file mode 100644 index 00000000..0376cd7d Binary files /dev/null and b/manual/FF-212.png differ diff --git a/manual/FF.md b/manual/FF.md index c0c0a913..925d5de1 100755 --- a/manual/FF.md +++ b/manual/FF.md @@ -1,13 +1,13 @@ # Flip-Flops ### [Part of the Digital Suite](DS.md) #### FF-110 10-Stage Flip-Flop Cascade -![View of the Flip-Flop modules](FF-110.m.png "Flip-Flop Range") +![View of the Flip-Flop modules](FF-110.png "Flip-Flop Range") #### FF-120 20-Stage Flip-Flop Cascade -![View of the Flip-Flop modules](FF-120.m.png "Flip-Flop Range") +![View of the Flip-Flop modules](FF-120.png "Flip-Flop Range") #### FF-206 6 Edge Triggered Flip-Flops -![View of the Flip-Flop modules](FF-206.m.png "Flip-Flop Range") +![View of the Flip-Flop modules](FF-206.png "Flip-Flop Range") #### FF-212 12 Edge Triggered Flip-Flops -![View of the Flip-Flop modules](FF-212.m.png "Flip-Flop Range") +![View of the Flip-Flop modules](FF-212.png "Flip-Flop Range") ## Basic Operation diff --git a/manual/HS-101.m.png b/manual/HS-101.m.png deleted file mode 100644 index 073e70da..00000000 Binary files a/manual/HS-101.m.png and /dev/null differ diff --git a/manual/HS-101.png b/manual/HS-101.png new file mode 100644 index 00000000..241065f3 Binary files /dev/null and b/manual/HS-101.png differ diff --git a/manual/HS.md b/manual/HS.md index fb2e1cda..3d5b452c 100755 --- a/manual/HS.md +++ b/manual/HS.md @@ -1,7 +1,7 @@ # Hi-Resolution Storage Scope #### HS-101 Hi-Res Storage Scope -![View of the Storage Scope](HS-101.m.png "Hi-Res Storage Scope") +![View of the Storage Scope](HS-101.png "Hi-Res Storage Scope") ## Basic Operation diff --git a/manual/LA-108.m.png b/manual/LA-108.m.png deleted file mode 100644 index 93e87f79..00000000 Binary files a/manual/LA-108.m.png and /dev/null differ diff --git a/manual/LA-108.png b/manual/LA-108.png new file mode 100644 index 00000000..9c6fdad0 Binary files /dev/null and b/manual/LA-108.png differ diff --git a/manual/LA-216.png b/manual/LA-216.png new file mode 100644 index 00000000..0d5b011f Binary files /dev/null and b/manual/LA-216.png differ diff --git a/manual/LA.md b/manual/LA.md index 2e585d2a..cd5d5f5b 100755 --- a/manual/LA.md +++ b/manual/LA.md @@ -2,13 +2,19 @@ ### [Part of the Digital Suite](DS.md) #### LA-108 8-Channel Logic Analyser -![View of the Logic Analyser](LA-108.m.png "Logic Analyser") +![View of the Logic Analyser](LA-108.png "Logic Analyser") + +#### LA-216 Dual-Channel Polyphonic Logic Analyser + +![View of the Logic Analyser](LA-216.png "Logic Analyser") ## Basic Operation The logic analyser takes 8 input signals which it will trace out on the scope screen. It is designed to take digital signals, but it will happily accept analog signals which will be clamped to the configured range. It has one additional input (EXT.TR) which is not traced, but which can be used as a trigger. +The polyphonic analyser has 2 inputs (plus an external trigger) and will output up to 16 traces for each. + ## Trigger Any one of the 9 input signals can be used as a trigger to synchronise the scope display. The TRIGGER knob will select the input to be used, and a small blue led next to the input will illuminate to indicate the selected input. diff --git a/manual/LD-103.m.png b/manual/LD-103.m.png deleted file mode 100644 index dc50b899..00000000 Binary files a/manual/LD-103.m.png and /dev/null differ diff --git a/manual/LD-103.png b/manual/LD-103.png new file mode 100644 index 00000000..d92119f8 Binary files /dev/null and b/manual/LD-103.png differ diff --git a/manual/LD-106.m.png b/manual/LD-106.m.png deleted file mode 100644 index fe1f16dc..00000000 Binary files a/manual/LD-106.m.png and /dev/null differ diff --git a/manual/LD-106.png b/manual/LD-106.png new file mode 100644 index 00000000..6b4e43d7 Binary files /dev/null and b/manual/LD-106.png differ diff --git a/manual/LD.md b/manual/LD.md index 3b4934d5..9093a7b4 100755 --- a/manual/LD.md +++ b/manual/LD.md @@ -1,9 +1,9 @@ # Schmitt Trigger Line Drivers ### [Part of the Digital Suite](DS.md) #### LD-103 Line Drivers -![View of the Line Drivers](LD-103.m.png "Line Drivers") +![View of the Line Drivers](LD-103.png "Line Drivers") #### LD-106 Line Drivers -![View of the Line Drivers](LD-106.m.png "Line Drivers") +![View of the Line Drivers](LD-106.png "Line Drivers") ## Basic Operation diff --git a/manual/LT-116.m.png b/manual/LT-116.m.png deleted file mode 100644 index ea4ae27c..00000000 Binary files a/manual/LT-116.m.png and /dev/null differ diff --git a/manual/LT-116.png b/manual/LT-116.png new file mode 100644 index 00000000..2b8bbcff Binary files /dev/null and b/manual/LT-116.png differ diff --git a/manual/LT.md b/manual/LT.md index d659fa8b..58cf1e9e 100755 --- a/manual/LT.md +++ b/manual/LT.md @@ -1,7 +1,7 @@ # Linear Transformations #### LT-116 Linear Transformations -![View of the Linear Transformations](LT-116.m.png "Linear Transformations") +![View of the Linear Transformations](LT-116.png "Linear Transformations") ## Basic Operation diff --git a/manual/MZ-909.m.png b/manual/MZ-909.m.png deleted file mode 100644 index 8d760aa1..00000000 Binary files a/manual/MZ-909.m.png and /dev/null differ diff --git a/manual/MZ-909.png b/manual/MZ-909.png new file mode 100644 index 00000000..e92fe1f2 Binary files /dev/null and b/manual/MZ-909.png differ diff --git a/manual/MZ.md b/manual/MZ.md index a55139c3..e3595d01 100755 --- a/manual/MZ.md +++ b/manual/MZ.md @@ -1,7 +1,7 @@ # Masterizer #### MZ-909 Masterizer -![View of the Masterizer](MZ-909.m.png "Masterizer") +![View of the Masterizer](MZ-909.png "Masterizer") ## Features diff --git a/manual/NG-106.m.png b/manual/NG-106.m.png deleted file mode 100644 index 50bb1c5f..00000000 Binary files a/manual/NG-106.m.png and /dev/null differ diff --git a/manual/NG-106.png b/manual/NG-106.png new file mode 100644 index 00000000..ba7a6505 Binary files /dev/null and b/manual/NG-106.png differ diff --git a/manual/NG-112.m.png b/manual/NG-112.m.png deleted file mode 100644 index 0a5605f3..00000000 Binary files a/manual/NG-112.m.png and /dev/null differ diff --git a/manual/NG-112.png b/manual/NG-112.png new file mode 100644 index 00000000..f43e0078 Binary files /dev/null and b/manual/NG-112.png differ diff --git a/manual/NG-206.m.png b/manual/NG-206.m.png deleted file mode 100644 index edd03d56..00000000 Binary files a/manual/NG-206.m.png and /dev/null differ diff --git a/manual/NG-206.png b/manual/NG-206.png new file mode 100644 index 00000000..98a182ef Binary files /dev/null and b/manual/NG-206.png differ diff --git a/manual/NG.md b/manual/NG.md index 45bccad3..5a384739 100755 --- a/manual/NG.md +++ b/manual/NG.md @@ -1,11 +1,11 @@ # Logical NOT Gates ### [Part of the Digital Suite](DS.md) #### NG-106 NOT Gates -![View of the NOT Gates](NG-106.m.png "NOT Gates") +![View of the NOT Gates](NG-106.png "NOT Gates") #### NG-112 NOT Gates -![View of the NOT Gates](NG-112.m.png "NOT Gates") +![View of the NOT Gates](NG-112.png "NOT Gates") #### NG-206 NOT Gates -![View of the NOT Gates](NG-206.m.png "NOT Gates") +![View of the NOT Gates](NG-206.png "NOT Gates") ## Basic Operation diff --git a/manual/OA-103.m.png b/manual/OA-103.m.png deleted file mode 100644 index 8f1aaa8d..00000000 Binary files a/manual/OA-103.m.png and /dev/null differ diff --git a/manual/OA-103.png b/manual/OA-103.png new file mode 100644 index 00000000..4311f08f Binary files /dev/null and b/manual/OA-103.png differ diff --git a/manual/OA-105.m.png b/manual/OA-105.m.png deleted file mode 100644 index b1ab6e64..00000000 Binary files a/manual/OA-105.m.png and /dev/null differ diff --git a/manual/OA-105.png b/manual/OA-105.png new file mode 100644 index 00000000..5b0f726d Binary files /dev/null and b/manual/OA-105.png differ diff --git a/manual/OA.md b/manual/OA.md index 589f97a0..1395cea0 100755 --- a/manual/OA.md +++ b/manual/OA.md @@ -1,9 +1,9 @@ # Logical Operational Amplifiers ### [Part of the Digital Suite](DS.md) #### OA-103 OP-Amps -![View of the Op-Amps](OA-103.m.png "Operation Amplifiers") +![View of the Op-Amps](OA-103.png "Operation Amplifiers") #### OA-105 OP-Amps -![View of the Op-Amps](OA-105.m.png "Operation Amplifiers") +![View of the Op-Amps](OA-105.png "Operation Amplifiers") ## Basic Operation diff --git a/manual/OG-104.m.png b/manual/OG-104.m.png deleted file mode 100644 index 5f50362e..00000000 Binary files a/manual/OG-104.m.png and /dev/null differ diff --git a/manual/OG-104.png b/manual/OG-104.png new file mode 100644 index 00000000..d8398fb9 Binary files /dev/null and b/manual/OG-104.png differ diff --git a/manual/OG-106.m.png b/manual/OG-106.m.png deleted file mode 100644 index 06c6dc7e..00000000 Binary files a/manual/OG-106.m.png and /dev/null differ diff --git a/manual/OG-106.png b/manual/OG-106.png new file mode 100644 index 00000000..5e73eabe Binary files /dev/null and b/manual/OG-106.png differ diff --git a/manual/OG-202.m.png b/manual/OG-202.m.png deleted file mode 100644 index d44792eb..00000000 Binary files a/manual/OG-202.m.png and /dev/null differ diff --git a/manual/OG-202.png b/manual/OG-202.png new file mode 100644 index 00000000..75f43e27 Binary files /dev/null and b/manual/OG-202.png differ diff --git a/manual/OG.md b/manual/OG.md index 9be0348e..af593fbc 100755 --- a/manual/OG.md +++ b/manual/OG.md @@ -1,11 +1,11 @@ # Logical OR Gates ### [Part of the Digital Suite](DS.md) #### OG-104 OR Gates -![View of the OR Gates](OG-104.m.png "OR Gates") +![View of the OR Gates](OG-104.png "OR Gates") #### OG-106 OR Gates -![View of the OR Gates](OG-106.m.png "OR Gates") +![View of the OR Gates](OG-106.png "OR Gates") #### OG-202 OR Gates -![View of the OR Gates](OG-202.m.png "OR Gates") +![View of the OR Gates](OG-202.png "OR Gates") ## Basic Operation diff --git a/manual/PG-104.m.png b/manual/PG-104.m.png deleted file mode 100644 index dc59b6ac..00000000 Binary files a/manual/PG-104.m.png and /dev/null differ diff --git a/manual/PG-104.png b/manual/PG-104.png new file mode 100644 index 00000000..7969a401 Binary files /dev/null and b/manual/PG-104.png differ diff --git a/manual/PG-112.m.png b/manual/PG-112.m.png deleted file mode 100644 index a917a6dd..00000000 Binary files a/manual/PG-112.m.png and /dev/null differ diff --git a/manual/PG-112.png b/manual/PG-112.png new file mode 100644 index 00000000..69bd31de Binary files /dev/null and b/manual/PG-112.png differ diff --git a/manual/PG.md b/manual/PG.md index 0d0009f6..55ee5083 100755 --- a/manual/PG.md +++ b/manual/PG.md @@ -1,9 +1,9 @@ # Pulse Generators ### [Part of the Digital Suite](DS.md) #### PG-104 Pulse Generators -![View of the Pulse Generators](PG-104.m.png "Pulse Generators") +![View of the Pulse Generators](PG-104.png "Pulse Generators") #### PG-112 Pulse Generators -![View of the Pulse Generators](PG-112.m.png "Pulse Generators") +![View of the Pulse Generators](PG-112.png "Pulse Generators") ## Basic Operation diff --git a/manual/PO-101.m.png b/manual/PO-101.m.png deleted file mode 100644 index f2d55ba5..00000000 Binary files a/manual/PO-101.m.png and /dev/null differ diff --git a/manual/PO-101.png b/manual/PO-101.png new file mode 100644 index 00000000..0f355886 Binary files /dev/null and b/manual/PO-101.png differ diff --git a/manual/PO-102.m.png b/manual/PO-102.m.png deleted file mode 100644 index 906a8998..00000000 Binary files a/manual/PO-102.m.png and /dev/null differ diff --git a/manual/PO-102.png b/manual/PO-102.png new file mode 100644 index 00000000..c93de16d Binary files /dev/null and b/manual/PO-102.png differ diff --git a/manual/PO-204.m.png b/manual/PO-204.m.png deleted file mode 100644 index 98687f5a..00000000 Binary files a/manual/PO-204.m.png and /dev/null differ diff --git a/manual/PO-204.png b/manual/PO-204.png new file mode 100644 index 00000000..899c474c Binary files /dev/null and b/manual/PO-204.png differ diff --git a/manual/PO.md b/manual/PO.md index 2deaefc1..b2572e35 100755 --- a/manual/PO.md +++ b/manual/PO.md @@ -1,8 +1,8 @@ # Phase Oscillators #### PO-101 Phased VCO -![View of the Phased VCO](PO-101.m.png "Phased VCO") +![View of the Phased VCO](PO-101.png "Phased VCO") #### PO-102 Phased LFO -![View of the Phased LFO](PO-102.m.png "Phased LFO") +![View of the Phased LFO](PO-102.png "Phased LFO") ## Basic Operation @@ -11,7 +11,7 @@ The PO-101 and PO-102 devices are digital oscillators which offer a choice of 5 16 fixed phase outputs are provided, dividing the cycle into 12 and 8 equal parts. In addition 4 further adjustable phase outputs are provided. The phase of these outputs can be controlled using a control knob, and/or an associated CV input. #### PO-204 Phase Modulation Engine -![View of the Phase Modulation Engine](PO-204.m.png "Phase Modulation Engine") +![View of the Phase Modulation Engine](PO-204.png "Phase Modulation Engine") ## Basic Operation diff --git a/manual/SN-101.m.png b/manual/SN-101.m.png deleted file mode 100644 index fef498d6..00000000 Binary files a/manual/SN-101.m.png and /dev/null differ diff --git a/manual/SN-101.png b/manual/SN-101.png new file mode 100644 index 00000000..19762739 Binary files /dev/null and b/manual/SN-101.png differ diff --git a/manual/SN.md b/manual/SN.md index c5ba442d..b8ff9006 100755 --- a/manual/SN.md +++ b/manual/SN.md @@ -1,6 +1,6 @@ # Smooth Noise #### SN-101 Smooth Noise Oscillator -![View of the Smooth Noise Oscillator](SN-101.m.png "Smooth Noise Oscillator") +![View of the Smooth Noise Oscillator](SN-101.png "Smooth Noise Oscillator") ## Basic Operation diff --git a/manual/SS-112.m.png b/manual/SS-112.m.png deleted file mode 100644 index 73d74a03..00000000 Binary files a/manual/SS-112.m.png and /dev/null differ diff --git a/manual/SS-112.png b/manual/SS-112.png new file mode 100644 index 00000000..0fb1c3a9 Binary files /dev/null and b/manual/SS-112.png differ diff --git a/manual/SS-208.m.png b/manual/SS-208.m.png deleted file mode 100644 index 6e89d287..00000000 Binary files a/manual/SS-208.m.png and /dev/null differ diff --git a/manual/SS-208.png b/manual/SS-208.png new file mode 100644 index 00000000..67aa4b55 Binary files /dev/null and b/manual/SS-208.png differ diff --git a/manual/SS-212.m.png b/manual/SS-212.m.png deleted file mode 100644 index c6cac7e2..00000000 Binary files a/manual/SS-212.m.png and /dev/null differ diff --git a/manual/SS-212.png b/manual/SS-212.png new file mode 100644 index 00000000..a29206b7 Binary files /dev/null and b/manual/SS-212.png differ diff --git a/manual/SS-220.m.png b/manual/SS-220.m.png deleted file mode 100644 index 4dab0b13..00000000 Binary files a/manual/SS-220.m.png and /dev/null differ diff --git a/manual/SS-220.png b/manual/SS-220.png new file mode 100644 index 00000000..9d4b52b1 Binary files /dev/null and b/manual/SS-220.png differ diff --git a/manual/SS-221.m.png b/manual/SS-221.m.png deleted file mode 100644 index da10787d..00000000 Binary files a/manual/SS-221.m.png and /dev/null differ diff --git a/manual/SS-221.png b/manual/SS-221.png new file mode 100644 index 00000000..2f84f8fb Binary files /dev/null and b/manual/SS-221.png differ diff --git a/manual/SS.md b/manual/SS.md index e1232a56..95d9df63 100755 --- a/manual/SS.md +++ b/manual/SS.md @@ -1,14 +1,14 @@ # Sources and Sinks - Lightweight voltage sources #### SS-112 - 12 Voltage Sinks -![View of the Sources and Sinks Range](SS-112.m.png "Sources and Sinks") +![View of the Sources and Sinks Range](SS-112.png "Sources and Sinks") #### SS-208 - 8 Irrational Voltage Sources -![View of the Sources and Sinks Range](SS-208.m.png "Sources and Sinks") +![View of the Sources and Sinks Range](SS-208.png "Sources and Sinks") #### SS-212 - 12 Chromatic Voltage Sources -![View of the Sources and Sinks Range](SS-212.m.png "Sources and Sinks") +![View of the Sources and Sinks Range](SS-212.png "Sources and Sinks") #### SS-220 - 120 Chromatic Voltage Sources -![View of the Sources and Sinks Range](SS-220.m.png "Sources and Sinks") +![View of the Sources and Sinks Range](SS-220.png "Sources and Sinks") #### SS-221 - 21 Voltage Sources -![View of the Sources and Sinks Range](SS-221.m.png "Sources and Sinks") +![View of the Sources and Sinks Range](SS-221.png "Sources and Sinks") ## Basic Operation diff --git a/manual/TD-116.m.png b/manual/TD-116.m.png deleted file mode 100644 index 3b26956a..00000000 Binary files a/manual/TD-116.m.png and /dev/null differ diff --git a/manual/TD-116.png b/manual/TD-116.png new file mode 100644 index 00000000..33c2dfdf Binary files /dev/null and b/manual/TD-116.png differ diff --git a/manual/TD-202.m.png b/manual/TD-202.m.png deleted file mode 100644 index faf0775e..00000000 Binary files a/manual/TD-202.m.png and /dev/null differ diff --git a/manual/TD-202.png b/manual/TD-202.png new file mode 100644 index 00000000..6c39da45 Binary files /dev/null and b/manual/TD-202.png differ diff --git a/manual/TD-316.m.png b/manual/TD-316.m.png deleted file mode 100644 index ab9fe763..00000000 Binary files a/manual/TD-316.m.png and /dev/null differ diff --git a/manual/TD-316.png b/manual/TD-316.png new file mode 100644 index 00000000..78ab97e1 Binary files /dev/null and b/manual/TD-316.png differ diff --git a/manual/TD-410.m.png b/manual/TD-410.m.png deleted file mode 100644 index 0f7c7bcf..00000000 Binary files a/manual/TD-410.m.png and /dev/null differ diff --git a/manual/TD-410.png b/manual/TD-410.png new file mode 100644 index 00000000..a41c6546 Binary files /dev/null and b/manual/TD-410.png differ diff --git a/manual/TD-510.m.png b/manual/TD-510.m.png deleted file mode 100644 index 05160abb..00000000 Binary files a/manual/TD-510.m.png and /dev/null differ diff --git a/manual/TD-510.png b/manual/TD-510.png new file mode 100644 index 00000000..d471986a Binary files /dev/null and b/manual/TD-510.png differ diff --git a/manual/TD.md b/manual/TD.md index 5333b14e..3a175c39 100755 --- a/manual/TD.md +++ b/manual/TD.md @@ -1,24 +1,19 @@ # Formattable Text Display -#### TD-116 Formattable Text Display -![View of the Formattable Text Display](TD-116.m.png "Formattable Text Display") -![View of the Formattable Text Display](TD-316.m.png "Formattable Text Display") +#### TD-316 Formattable Text Display +![View of the Formattable Text Display](TD-316.png "Formattable Text Display") ## Basic Operation -The TD-116 is a text display on which you can make notes or put text into the visuals of your rack. Similar to the Fundamental Notes module, the TD-116 also allows you to control the text and background colors, and also the text size. The standard text size is not easy to read in a You-Tube video, so a larger size is sometimes useful for demonstrations. - -The TD-116 features [Torpedo](https://github.com/david-c14/Torpedo) input and ouput ports. Changes to the text are sent through the output port, which allows you to capture the text in any suitable Torpedo device. - -Text or formatting information can be sent into the TD-116 through the Torpedo input port, allowing you to change the text or formatting programmatically. Formatting can also be achieved through the context menu, or by using an extension device. - -The TD-316 is a similar device to the TD-116 but with a 20% larger text display. Although the TD-316 does not feature Torpedo ports, it can still be formatted using the context menu or an extension device. +The TD-316 is a similar device to the now deprecated TD-116 but with a 20% larger text display. It can be formatted using the context menu or an extension device. The TD-316 is resizable using the drag handles in the top corners of the device. The [TF-101](TF.md) or [TF-102](TF.md) are suitable devices to control the formatting. +The TD-116 is deprecated and should not be used in new patches. + #### TD-202 Vertical Text Display -![View of the Vertical Text Display](TD-202.m.png "Vertical Text Display") +![View of the Vertical Text Display](TD-202.png "Vertical Text Display") ## Basic Operation @@ -28,7 +23,7 @@ sections of a patch. The colors of the TD-202 can be adjusted using the context menu. Or by using an extension device such as the [TF-101](TF.md) or [TF-102](TF.md). #### TD-410 Multiple Label Display -![View of the Multiple Label Display](TD-410.m.png "Multiple Label Display") +![View of the Multiple Label Display](TD-410.png "Multiple Label Display") ## Basic Operation @@ -43,7 +38,7 @@ The labels can be dragged up and down the device to the position that you need. The TD-410 is resizable using the drag handles in the top corners of the device. #### TD-510 Vertical Multiple Label Display -![View of the Vertical Multiple Lable Display](TD-510.m.png "Vertical Multiple Label Display") +![View of the Vertical Multiple Lable Display](TD-510.png "Vertical Multiple Label Display") ## Basic Operation diff --git a/manual/TF-101.m.png b/manual/TF-101.m.png deleted file mode 100644 index d77b61ee..00000000 Binary files a/manual/TF-101.m.png and /dev/null differ diff --git a/manual/TF-101.png b/manual/TF-101.png new file mode 100644 index 00000000..eb0bf064 Binary files /dev/null and b/manual/TF-101.png differ diff --git a/manual/TF-102.m.png b/manual/TF-102.m.png deleted file mode 100644 index f8399bcd..00000000 Binary files a/manual/TF-102.m.png and /dev/null differ diff --git a/manual/TF-102.png b/manual/TF-102.png new file mode 100644 index 00000000..0add5129 Binary files /dev/null and b/manual/TF-102.png differ diff --git a/manual/TF.md b/manual/TF.md index 5506f1dc..e8879f76 100755 --- a/manual/TF.md +++ b/manual/TF.md @@ -1,14 +1,14 @@ # Text Display Formatter #### TF-101 Text Display Formatter -![View of the Text Display Formatter](TF-101.m.png "Text Display Formatter") +![View of the Text Display Formatter](TF-101.png "Text Display Formatter") #### TF-102 Text Display Formatter -![View of the Text Dispaly Formatter](TF-102.m.png "Text Display Formatter") +![View of the Text Dispaly Formatter](TF-102.png "Text Display Formatter") ## Basic Operation The TF-101 is a format controller for the [TD-xxx](TD.md) Text Display devices. It has controls for the text color, background color and text size. -Format information is passed from the TF-101 to the TD-116 using a [Torpedo](https://github.com/david-c14/Torpedo) protocol, or to any TD-xxx device by using it as an extension. If the TF-101 (or TF-102) is placed directly to the left or right of a TD-xxx device, it will control the formatting of the TD-xxx device without the need for cables +Format information is passed from the TF-101 to any TD-xxx device by using it as an extension. If the TF-101 (or TF-102) is placed directly to the left or right of a TD-xxx device, it will control the formatting of the TD-xxx device without the need for cables Each color is controlled using three CV/Knob combinations, controlling the Red, Green and Blue components separately. A full-color LED on the TF-101 indicates the color mix selected. diff --git a/manual/TM-105.m.png b/manual/TM-105.m.png deleted file mode 100644 index 3f986c99..00000000 Binary files a/manual/TM-105.m.png and /dev/null differ diff --git a/manual/TM-105.png b/manual/TM-105.png new file mode 100644 index 00000000..3e84f745 Binary files /dev/null and b/manual/TM-105.png differ diff --git a/manual/TM.md b/manual/TM.md deleted file mode 100755 index af7996c9..00000000 --- a/manual/TM.md +++ /dev/null @@ -1,9 +0,0 @@ -# Torpedo Message Merge -#### TM-105 - 5 port Torpedo Message Merge -![View of the Torpedo Message Merge](TM-105.m.png "Torpedo Message Merge") - -## Basic Operation - -Because [Torpedo](https://github.com/david-c14/Torpedo) signals are data streams, they cannot be mixed without corrupting the data in the stream. - -The TM-105 is a message buffer with 5 separate inputs and a single Torpedo output. As messages array at the input ports, they are buffered until the output port is free to send them on. Up to 5 messages may be buffered at once, if the buffer fills, messages will be dropped. A set of leds indicate how full the buffer is at any one time. diff --git a/manual/VM-101.m.png b/manual/VM-101.m.png deleted file mode 100644 index 5c1e41bc..00000000 Binary files a/manual/VM-101.m.png and /dev/null differ diff --git a/manual/VM-101.png b/manual/VM-101.png new file mode 100644 index 00000000..d2fdb1a3 Binary files /dev/null and b/manual/VM-101.png differ diff --git a/manual/VM-102.m.png b/manual/VM-102.m.png deleted file mode 100644 index 7b48c664..00000000 Binary files a/manual/VM-102.m.png and /dev/null differ diff --git a/manual/VM-102.png b/manual/VM-102.png new file mode 100644 index 00000000..da7eb4bd Binary files /dev/null and b/manual/VM-102.png differ diff --git a/manual/VM-104.png b/manual/VM-104.png new file mode 100644 index 00000000..f9193814 Binary files /dev/null and b/manual/VM-104.png differ diff --git a/manual/VM-201.m.png b/manual/VM-201.m.png deleted file mode 100644 index 9f667bed..00000000 Binary files a/manual/VM-201.m.png and /dev/null differ diff --git a/manual/VM-201.png b/manual/VM-201.png new file mode 100644 index 00000000..0be1e006 Binary files /dev/null and b/manual/VM-201.png differ diff --git a/manual/VM-202.m.png b/manual/VM-202.m.png deleted file mode 100644 index b39502fa..00000000 Binary files a/manual/VM-202.m.png and /dev/null differ diff --git a/manual/VM-202.png b/manual/VM-202.png new file mode 100644 index 00000000..2ac073fa Binary files /dev/null and b/manual/VM-202.png differ diff --git a/manual/VM-204.png b/manual/VM-204.png new file mode 100644 index 00000000..864d1f6d Binary files /dev/null and b/manual/VM-204.png differ diff --git a/manual/VM.md b/manual/VM.md index e0e422d8..5bbaf347 100755 --- a/manual/VM.md +++ b/manual/VM.md @@ -1,12 +1,16 @@ # VU Meter #### VM-101 Compact VU Meter -![View of the Dual Vintage VU Meter](VM-101.m.png "VU Meter") +![View of the Digital VU Meter](VM-101.png "VU Meter") #### VM-102 Compact Dual VU Meter -![View of the Dual Vintage VU Meter](VM-102.m.png "VU Meter") +![View of the Dual Digital VU Meter](VM-102.png "VU Meter") +#### VM-104 Compact Quad VU Meter +![View of the Quad Digital VU Meter](VM-104.png "VU Meter") #### VM-201 Vintage VU Meter -![View of the Dual Vintage VU Meter](VM-201.m.png "VU Meter") +![View of the Vintage VU Meter](VM-201.png "VU Meter") #### VM-202 Dual Vintage VU Meter -![View of the Dual Vintage VU Meter](VM-202.m.png "VU Meter") +![View of the Dual Vintage VU Meter](VM-202.png "VU Meter") +#### VM-204 Quad Vintage VU Meter +![View of the Quad Vintage VU Meter](VM-204.png "VU Meter") ## Basic Operation @@ -28,8 +32,13 @@ For a sinusoidal bipolar wave with a peak of 5V, the RMS is approximately 3.5V. ## Inputs -The VM-102 and VM-202 meters will accept a two-channel polyphonic input. The VM-202 has two inputs, and if the second input is connected, the lower meter will display measure the second input. When only the first input is connected, the lower meter is connected to the second channel of the first (polyphonic) input. +The VM-102 and VM-202 meters will accept a two-channel polyphonic input. The VM-104 and VM-204 will accept a four-channel polyphonic input. The VM-202 has two inputs, and if the second input is connected, the lower meter will display measure the second input. When only the first input is connected, the lower meter is connected to the second channel of the first (polyphonic) input. ## Compact option -The VM-101 and VM-102 are small form factor meters with OLED strip displays. +The VM-101, VM-102 and VM-104 are small form factor meters with OLED strip displays. + +## Expansion + +All of the VM-1xx and VM-2xx series meters can be chained together as expander modules to provide polyphonic metering capabilities. Additional channels to input to the meter, will be passed to another meter on the right if that expansion meter has no inputs of its own. +Load and attenuator settings are copied from the device on the left to the device on the right. The meters models themselves and inter-compatible and can be mixed and matched. diff --git a/manual/Vis_B3.png b/manual/Vis_B3.png index f6ee21ba..741c1f97 100644 Binary files a/manual/Vis_B3.png and b/manual/Vis_B3.png differ diff --git a/manual/Vis_BF.png b/manual/Vis_BF.png index 699f5177..eccc6968 100644 Binary files a/manual/Vis_BF.png and b/manual/Vis_BF.png differ diff --git a/manual/Vis_D3.png b/manual/Vis_D3.png index e444bd62..f883dd7f 100644 Binary files a/manual/Vis_D3.png and b/manual/Vis_D3.png differ diff --git a/manual/Vis_DF.png b/manual/Vis_DF.png index 3866db44..2d8b2550 100644 Binary files a/manual/Vis_DF.png and b/manual/Vis_DF.png differ diff --git a/manual/Vis_L3.png b/manual/Vis_L3.png index 296dc608..8959b99b 100644 Binary files a/manual/Vis_L3.png and b/manual/Vis_L3.png differ diff --git a/manual/Vis_LF.png b/manual/Vis_LF.png index 1993718f..d0ff5e74 100644 Binary files a/manual/Vis_LF.png and b/manual/Vis_LF.png differ diff --git a/manual/WK-101.m.png b/manual/WK-101.m.png deleted file mode 100644 index a2503df4..00000000 Binary files a/manual/WK-101.m.png and /dev/null differ diff --git a/manual/WK-101.png b/manual/WK-101.png new file mode 100644 index 00000000..04493aa6 Binary files /dev/null and b/manual/WK-101.png differ diff --git a/manual/WK-205.m.png b/manual/WK-205.m.png deleted file mode 100644 index 6f022bfe..00000000 Binary files a/manual/WK-205.m.png and /dev/null differ diff --git a/manual/WK-205.png b/manual/WK-205.png new file mode 100644 index 00000000..6f4498a4 Binary files /dev/null and b/manual/WK-205.png differ diff --git a/manual/WK.md b/manual/WK.md index 29973106..5d70cbe0 100755 --- a/manual/WK.md +++ b/manual/WK.md @@ -1,25 +1,21 @@ # Das Wohltemperierte Klavier - Unequal Temperament Quantizer #### WK-101 Das Wohltemperierte Klavier -![View of the Das Wohltemperierte Klavier](WK-101.m.png "Das Wohltemperierte Klavier") +![View of the Das Wohltemperierte Klavier](WK-101.png "Das Wohltemperierte Klavier") ## Basic Operation -The WK-101 takes a note CV and quantizes it to a 12-ET chromatic scale. It then adjusts the quantized signal up or down by up to 50 cents according to which pitch it has been quantized to. The each of the 12 pitches can have a different adjustment specified by using the control knobs. The cent adjustment is displayed to the side of each knob. +The WK-101 takes a note CV and quantizes it to a 12-ET chromatic scale. It then adjusts the quantized signal up or down by up to 50 cents according to which pitch it has been quantized to. Each of the 12 pitches can have a different adjustment specified by using the control knobs. The cent adjustment is displayed to the side of each knob. -The currently recognized pitch is indicated by a small blue led in the centre of the 12 adjustment knobs. +The currently recognized pitch is indicated by the index light in the adjustment knob turning red. The context menu offers presets which you can configure. See below for more details #### WK-205 Das Wohltemperierte Klavier Nano -![View of the Das Wohltemperierte Klavier nano](WK-205.m.png "Das Wohltemperierte Klavier nano") +![View of the Das Wohltemperierte Klavier nano](WK-205.png "Das Wohltemperierte Klavier nano") ## Basic Operation -The WK-205 has 5 input and output pairs. It takes each note CV input, quantizes it to a 12-ET chromatic scale, and then adjusts the quantized signal up or down by up to 50 cents. There are no control knobs on the WK-205 so the adjustment settings must be selected either from presets on the context menu, or by synching the device from a WK-101. - -## Synch Ports - -The WK-101 can output its settings to another WK-101 or to a WK-205. Connect a patch lead from the Sync-out port on the master device to the Sync-in port on the slave devige. Settings are automatically transmitted whenever they change on the master device. +The WK-205 has 5 input and output pairs. It takes each note CV input, quantizes it to a 12-ET chromatic scale, and then adjusts the quantized signal up or down by up to 50 cents. There are no control knobs on the WK-205 so the adjustment settings must be selected either from presets on the context menu, or by synching the device from a WK-101 as an extension module. Place the WK-205 to the immediate right of a WK-101 or another WK-205. ## Presets diff --git a/manual/WM-101.m.png b/manual/WM-101.m.png deleted file mode 100644 index c66e62c3..00000000 Binary files a/manual/WM-101.m.png and /dev/null differ diff --git a/manual/WM-101.png b/manual/WM-101.png new file mode 100644 index 00000000..2d2131cf Binary files /dev/null and b/manual/WM-101.png differ diff --git a/manual/WM-102.m.png b/manual/WM-102.m.png deleted file mode 100644 index a9153bf8..00000000 Binary files a/manual/WM-102.m.png and /dev/null differ diff --git a/manual/WM-102.png b/manual/WM-102.png new file mode 100644 index 00000000..fcc23928 Binary files /dev/null and b/manual/WM-102.png differ diff --git a/manual/WM.md b/manual/WM.md index f04404d9..91d459ef 100644 --- a/manual/WM.md +++ b/manual/WM.md @@ -1,8 +1,8 @@ # Wire Manager #### WM-101 Wire Manager -![View of the Wire Manager](WM-101.m.png "Wire Manager") +![View of the Wire Manager](WM-101.png "Wire Manager") #### WM-102 Wire Manager Billboard -![View of the Wire Manager](WM-102.m.png "Wire Manager") +![View of the Wire Manager](WM-102.png "Wire Manager") The wire manager offers the ability to choose more colors for the patch cables that you use in your patches. It also has highlighting options which some users may find useful in tracing wires around the patch. diff --git a/manual/XF-101.m.png b/manual/XF-101.m.png deleted file mode 100644 index f1e71753..00000000 Binary files a/manual/XF-101.m.png and /dev/null differ diff --git a/manual/XF-101.png b/manual/XF-101.png new file mode 100644 index 00000000..4ad1d31e Binary files /dev/null and b/manual/XF-101.png differ diff --git a/manual/XF-102.m.png b/manual/XF-102.m.png deleted file mode 100644 index ffde32a9..00000000 Binary files a/manual/XF-102.m.png and /dev/null differ diff --git a/manual/XF-102.png b/manual/XF-102.png new file mode 100644 index 00000000..b363fc7f Binary files /dev/null and b/manual/XF-102.png differ diff --git a/manual/XF-104.m.png b/manual/XF-104.m.png deleted file mode 100644 index 47ed8ad0..00000000 Binary files a/manual/XF-104.m.png and /dev/null differ diff --git a/manual/XF-104.png b/manual/XF-104.png new file mode 100644 index 00000000..37cfd478 Binary files /dev/null and b/manual/XF-104.png differ diff --git a/manual/XF-201.m.png b/manual/XF-201.m.png deleted file mode 100644 index 790557bf..00000000 Binary files a/manual/XF-201.m.png and /dev/null differ diff --git a/manual/XF-201.png b/manual/XF-201.png new file mode 100644 index 00000000..4a79c77e Binary files /dev/null and b/manual/XF-201.png differ diff --git a/manual/XF-202.m.png b/manual/XF-202.m.png deleted file mode 100644 index 877262ff..00000000 Binary files a/manual/XF-202.m.png and /dev/null differ diff --git a/manual/XF-202.png b/manual/XF-202.png new file mode 100644 index 00000000..741c1f97 Binary files /dev/null and b/manual/XF-202.png differ diff --git a/manual/XF-301.m.png b/manual/XF-301.m.png deleted file mode 100644 index 9be312b0..00000000 Binary files a/manual/XF-301.m.png and /dev/null differ diff --git a/manual/XF-301.png b/manual/XF-301.png new file mode 100644 index 00000000..9b0385c1 Binary files /dev/null and b/manual/XF-301.png differ diff --git a/manual/XF.md b/manual/XF.md index bb258d6a..cefa147c 100755 --- a/manual/XF.md +++ b/manual/XF.md @@ -1,16 +1,16 @@ # Equal Power Cross-Fader #### XF-101 Single Monophonic Cross-Fader -![View of the Cross-Fader modules](XF-101.m.png "Cross-Fader Range") +![View of the Cross-Fader modules](XF-101.png "Cross-Fader Range") #### XF-102 Dual Monophonic Cross-Fader with LINK option -![View of the Cross-Fader modules](XF-102.m.png "Cross-Fader Range") +![View of the Cross-Fader modules](XF-102.png "Cross-Fader Range") #### XF-104 Quad Monophonic Cross-Fader with LINK option -![View of the Cross-Fader modules](XF-104.m.png "Cross-Fader Range") +![View of the Cross-Fader modules](XF-104.png "Cross-Fader Range") #### XF-201 Single Stereophonic Cross-Fader -![View of the Cross-Fader modules](XF-201.m.png "Cross-Fader Range") +![View of the Cross-Fader modules](XF-201.png "Cross-Fader Range") #### XF-202 Dual Stereophonic Cross-Fader -![View of the Cross-Fader modules](XF-202.m.png "Cross-Fader Range") +![View of the Cross-Fader modules](XF-202.png "Cross-Fader Range") #### XF-301 Small Form Factor Stereophonic Cross-Fader -![View of the Cross-Fader modules](XF-301.m.png "Cross-Fader Range") +![View of the Cross-Fader modules](XF-301.png "Cross-Fader Range") ## Basic Operation diff --git a/manual/XG-104.m.png b/manual/XG-104.m.png deleted file mode 100644 index d2d0de94..00000000 Binary files a/manual/XG-104.m.png and /dev/null differ diff --git a/manual/XG-104.png b/manual/XG-104.png new file mode 100644 index 00000000..75ff8b32 Binary files /dev/null and b/manual/XG-104.png differ diff --git a/manual/XG-106.m.png b/manual/XG-106.m.png deleted file mode 100644 index 2abd9d8c..00000000 Binary files a/manual/XG-106.m.png and /dev/null differ diff --git a/manual/XG-106.png b/manual/XG-106.png new file mode 100644 index 00000000..70db1e63 Binary files /dev/null and b/manual/XG-106.png differ diff --git a/manual/XG-202.m.png b/manual/XG-202.m.png deleted file mode 100644 index dffa6835..00000000 Binary files a/manual/XG-202.m.png and /dev/null differ diff --git a/manual/XG-202.png b/manual/XG-202.png new file mode 100644 index 00000000..26a2fb73 Binary files /dev/null and b/manual/XG-202.png differ diff --git a/manual/XG.md b/manual/XG.md index feb1760c..9f0d8293 100755 --- a/manual/XG.md +++ b/manual/XG.md @@ -1,11 +1,11 @@ # Logical XOR Gates ### [Part of the Digital Suite](DS.md) #### XG-104 XOR Gates -![View of the XOR Gates](XG-104.m.png "XOR Gates") +![View of the XOR Gates](XG-104.png "XOR Gates") #### XG-106 XOR Gates -![View of the XOR Gates](XG-106.m.png "XOR Gates") +![View of the XOR Gates](XG-106.png "XOR Gates") #### XG-202 XOR Gates -![View of the XOR Gates](XG-202.m.png "XOR Gates") +![View of the XOR Gates](XG-202.png "XOR Gates") ## Basic Operation diff --git a/manual/XX-219.m.png b/manual/XX-219.m.png deleted file mode 100644 index 4a9bfb1c..00000000 Binary files a/manual/XX-219.m.png and /dev/null differ diff --git a/manual/XX-219.png b/manual/XX-219.png new file mode 100644 index 00000000..3e84f745 Binary files /dev/null and b/manual/XX-219.png differ diff --git a/manual/gates/CLK-DELAY_timing.png b/manual/gates/CLK-DELAY_timing.png index cf7c1c40..97b2bbd6 100644 Binary files a/manual/gates/CLK-DELAY_timing.png and b/manual/gates/CLK-DELAY_timing.png differ diff --git a/manual/index.md b/manual/index.md index 461ec1ae..199c57ac 100755 --- a/manual/index.md +++ b/manual/index.md @@ -74,9 +74,6 @@ Formattable Text Display # [TF](TF.md) Text Format Controller -# [TM](TM.md) -Torpedo Message Merge - # [VM](VM.md) ANSI C16.5-1942 VU Meter diff --git a/plugin.json b/plugin.json index cc542088..3e82cb21 100644 --- a/plugin.json +++ b/plugin.json @@ -9,14 +9,15 @@ "sourceUrl": "https://github.com/david-c14/SubmarineFree", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/index.md", "donateUrl": "https://www.paypal.me/SubmarineFree", - "pluginUrl": "https://github.com/david-c14/SubmarineFree/blob/main/README.md", + "pluginUrl": "https://vcvrack.submarine.org.uk", "changelogUrl": "https://github.com/david-c14/SubmarineFree/blob/main/changelog.md", - "version": "1.1.10", + "version": "2.0.1", "modules": [ { "slug":"AG-104", "name":"AG-104", "description": "AG-104 AND Gates", + "keywords": "Quad Four Digital Logic And Gates", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/AG.md", "tags": ["LOGIC", "MULTIPLE"] }, @@ -24,6 +25,7 @@ "slug":"AG-106", "name":"AG-106", "description": "AG-106 AND Gates", + "keywords": "Hex Six Digital Logic And Gates", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/AG.md", "tags": ["LOGIC", "MULTIPLE"] }, @@ -31,6 +33,7 @@ "slug":"AG-202", "name":"AG-202", "description": "AG-202 4-input Polyphonic AND Gates", + "keywords": "Dual Two Digital Logic And Gates", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/AG.md", "tags": ["LOGIC", "DUAL", "POLYPHONIC"] }, @@ -38,6 +41,7 @@ "slug":"A0-106", "name":"AO-106", "description": "AO-106 Arithmetic Operators", + "keywords": "Hex Six Maths Algoritmm Arthimetic Operators", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/AO.md", "tags": ["UTILITY", "MULTIPLE"] }, @@ -45,6 +49,7 @@ "slug":"A0-112", "name":"AO-112", "description": "AO-112 Arithmetic Operators", + "keywords": "Twelve Maths Algoritmm Arthimetic Operators", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/AO.md", "tags": ["UTILITY", "MULTIPLE"] }, @@ -52,6 +57,7 @@ "slug":"A0-118", "name":"AO-118", "description": "AO-118 Arithmetic Operators", + "keywords": "Eighteen Maths Algoritmm Arthimetic Operators", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/AO.md", "tags": ["UTILITY", "MULTIPLE"] }, @@ -59,6 +65,7 @@ "slug":"A0-124", "name":"AO-124", "description": "AO-124 Arithmetic Operators", + "keywords": "Twenty Four Maths Algoritmm Arthimetic Operators", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/AO.md", "tags": ["UTILITY", "MULTIPLE"] }, @@ -66,6 +73,7 @@ "slug":"A0-136", "name":"AO-136", "description": "AO-136 Arithmetic Operators", + "keywords": "Thirty Six Maths Algoritmm Arthimetic Operators", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/AO.md", "tags": ["UTILITY", "MULTIPLE"] }, @@ -73,6 +81,7 @@ "slug":"BB-120", "name":"BB-120", "description": "BB-120 20-Stage Bucket Brigade Sample and Hold", + "keywords": "Digital Bucket Brigade Twenty Sample Hold", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/BB.md", "tags": ["LOGIC", "DELAY", "SAMPLE AND HOLD", "MULTIPLE"] }, @@ -80,6 +89,7 @@ "slug":"BP-101", "name":"BP-101", "description": "BP-101 Blanking Plate", + "keywords": "Blanking Plate", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/BP.md", "tags": ["BLANK"] }, @@ -87,6 +97,7 @@ "slug":"BP-102", "name":"BP-102", "description": "BP-102 Blanking Plate", + "keywords": "Blanking Plate", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/BP.md", "tags": ["BLANK"] }, @@ -94,6 +105,7 @@ "slug":"BP-104", "name":"BP-104", "description": "BP-104 Blanking Plate", + "keywords": "Blanking Plate", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/BP.md", "tags": ["BLANK"] }, @@ -101,6 +113,7 @@ "slug":"BP-108", "name":"BP-108", "description": "BP-108 Blanking Plate", + "keywords": "Blanking Plate", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/BP.md", "tags": ["BLANK"] }, @@ -108,6 +121,7 @@ "slug":"BP-110", "name":"BP-110", "description": "BP-110 Blanking Plate", + "keywords": "Blanking Plate", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/BP.md", "tags": ["BLANK"] }, @@ -115,6 +129,7 @@ "slug":"BP-112", "name":"BP-112", "description": "BP-112 Blanking Plate", + "keywords": "Blanking Plate", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/BP.md", "tags": ["BLANK"] }, @@ -122,6 +137,7 @@ "slug":"BP-116", "name":"BP-116", "description": "BP-116 Blanking Plate", + "keywords": "Blanking Plate", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/BP.md", "tags": ["BLANK"] }, @@ -129,6 +145,7 @@ "slug":"BP-120", "name":"BP-120", "description": "BP-120 Blanking Plate", + "keywords": "Blanking Plate", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/BP.md", "tags": ["BLANK"] }, @@ -136,6 +153,7 @@ "slug":"BP-124", "name":"BP-124", "description": "BP-124 Blanking Plate", + "keywords": "Blanking Plate", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/BP.md", "tags": ["BLANK"] }, @@ -143,6 +161,7 @@ "slug":"BP-132", "name":"BP-132", "description": "BP-132 Blanking Plate", + "keywords": "Blanking Plate", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/BP.md", "tags": ["BLANK"] }, @@ -150,6 +169,7 @@ "slug":"DN-112", "name":"DN-112", "description": "DN-112 Digital Noise", + "keywords": "Twelve Digital Random Noise", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/DN.md", "tags": ["DIGITAL", "NOISE", "MULTIPLE"] }, @@ -157,6 +177,7 @@ "slug":"DO-105", "name":"DO-105", "description": "DO-105 Digital Operators", + "keywords": "Five Digital Logic Gates", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/DO.md", "tags": ["LOGIC", "MULTIPLE", "POLYPHONIC"] }, @@ -164,6 +185,7 @@ "slug":"DO-110", "name":"DO-110", "description": "DO-110 Digital Operators", + "keywords": "Ten Digital Logic Gates", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/DO.md", "tags": ["LOGIC", "MULTIPLE", "POLYPHONIC"] }, @@ -171,6 +193,7 @@ "slug":"DO-115", "name":"DO-115", "description": "DO-115 Digital Operators", + "keywords": "Fifteen Digital Logic Gates", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/DO.md", "tags": ["LOGIC", "MULTIPLE", "POLYPHONIC"] }, @@ -178,6 +201,7 @@ "slug":"DO-120", "name":"DO-120", "description": "DO-120 Digital Operators", + "keywords": "Twenty Digital Logic Gates", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/DO.md", "tags": ["LOGIC", "MULTIPLE", "POLYPHONIC"] }, @@ -185,6 +209,7 @@ "slug":"EN-104", "name":"EN-104", "description": "EN-104 Quad ADSR Enveloper Generator", + "keywords": "Quad Four ADSR Linear Envelope", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/EN.md", "tags": ["ENVELOPE GENERATOR", "VCA", "MULTIPLE"] }, @@ -192,6 +217,7 @@ "slug":"EO-102", "name":"EO-102", "description": "EO-102 Envelope Oscilloscope", + "keywords": "Dual Two Envelope Oscilloscope Scope", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/EO.md", "tags": ["VISUAL"] }, @@ -199,6 +225,7 @@ "slug":"FF-110", "name":"FF-110", "description": "FF-110 10-Stage Flip-Flop Counter", + "keywords": "Ten Flip Flop Digital Counter Clock Divider", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/FF.md", "tags": ["LOGIC", "MULTIPLE"] }, @@ -206,6 +233,7 @@ "slug":"FF-120", "name":"FF-120", "description": "FF-120 20-Stage Flip-Flop Counter", + "keywords": "Twenty Flip Flop Digital Counter Clock Divider", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/FF.md", "tags": ["LOGIC", "MULTIPLE"] }, @@ -213,6 +241,7 @@ "slug":"FF-206", "name":"FF-206", "description": "FF-206 Edge Triggered Flip-Flops", + "keywords": "Hex Six Flip Flop Digital", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/FF.md", "tags": ["LOGIC", "MULTIPLE"] }, @@ -220,6 +249,7 @@ "slug":"FF-212", "name":"FF-212", "description": "FF-212 Edge Triggered Flip-Flops", + "keywords": "Twelve Flip Flop Digital", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/FF.md", "tags": ["LOGIC", "MULTIPLE"] }, @@ -227,6 +257,7 @@ "slug":"HS-101", "name":"HS-101", "description": "HS-101 Hi-Res Storage Oscilloscope", + "keywords": "High Resolution Storage Oscilloscope Scope", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/HS.md", "tags": ["VISUAL"] }, @@ -234,13 +265,23 @@ "slug":"LA-108", "name":"LA-108", "description": "LA-108 Logic Analyser", + "keywords": "Digital Logic Analyser Oct Eight Oscilloscope Scope", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/LA.md", "tags": ["LOGIC", "VISUAL"] }, + { + "slug":"LA-216", + "name":"LA-216", + "description": "LA-216 Logic Analyser", + "keywords": "Digital Logic Analyser Dual Polyphonic Oscilloscope Scope", + "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/LA.md", + "tags": ["LOGIC", "VISUAL", "DUAL", "POLYPHONIC"] + }, { "slug":"LD-103", "name":"LD-103", "description": "LD-103 Schmitt Trigger Line Drivers", + "keywords": "Tri Three Schmitt Trigger Line Driver Digital", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/LD.md", "tags": ["LOGIC", "MULTIPLE"] }, @@ -248,6 +289,7 @@ "slug":"LD-106", "name":"LD-106", "description": "LD-106 Schmitt Trigger Line Drivers", + "keywords": "Hex Six Schmitt Trigger Line Driver Digital", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/LD.md", "tags": ["LOGIC", "MULTIPLE"] }, @@ -255,6 +297,7 @@ "slug":"LT-116", "name":"LT-116", "description": "LT-116 Linear Transformations", + "keywords": "Linear Transform Matrix Polyphonic Cross Mixer", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/LT.md", "tags": ["UTILITY", "POLYPHONIC"] }, @@ -262,6 +305,7 @@ "slug":"MZ-909", "name":"MZ-909", "description": "MZ-909 Masterizer", + "keywords": "Useless Dummy Masterizer Mastererizer", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/MZ.md", "tags": ["POLYPHONIC"] }, @@ -269,6 +313,7 @@ "slug":"NG-106", "name":"NG-106", "description": "NG-106 NOT Gates", + "keywords": "Hex Six Digital Logic Not Gates", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/NG.md", "tags": ["LOGIC", "MULTIPLE"] }, @@ -276,6 +321,7 @@ "slug":"NG-112", "name":"NG-112", "description": "NG-112 NOT Gates", + "keywords": "Twelve Digital Logic Not Gates", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/NG.md", "tags": ["LOGIC", "MULTIPLE"] }, @@ -283,6 +329,7 @@ "slug":"NG-206", "name":"NG-206", "description": "NG-206 Polyphonic NOT Gates", + "keywords": "Hex Six Digital Logic Not Gates", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/NG.md", "tags": ["LOGIC", "MULTIPLE", "POLYPHONIC"] }, @@ -290,6 +337,7 @@ "slug":"OA-103", "name":"OA-103", "description": "OA-103 Op-Amps", + "keywords": "Tri Three Digital Operation Amplifier Comparator", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/OA.md", "tags": ["LOGIC", "MULTIPLE"] }, @@ -297,6 +345,7 @@ "slug":"OA-105", "name":"OA-105", "description": "OA-105 Op-Amps", + "keywords": "Five Digital Operation Amplifier Comparator", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/OA.md", "tags": ["LOGIC", "MULTIPLE"] }, @@ -304,12 +353,14 @@ "slug":"OG-104", "name":"OG-104", "description": "OG-104 OR Gates", + "keywords": "Quad Four Digital Logic Or Gates", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/OG.md", "tags": ["LOGIC", "MULTIPLE"] }, { "slug":"OG-106", "name":"OG-106", + "keywords": "Hex Six Digital Logic Or Gates", "description": "OG-106 OR Gates", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/OG.md", "tags": ["LOGIC", "MULTIPLE"] @@ -318,6 +369,7 @@ "slug":"OG-202", "name":"OG-202", "description": "OG-202 4-Channel Polyphonic OR Gates", + "keywords": "Dual Two Digital Logic Or Gates", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/OG.md", "tags": ["LOGIC", "DUAL", "POLYPHONIC"] }, @@ -325,6 +377,7 @@ "slug":"PG-104", "name":"PG-104", "description": "PG-104 Pulse Generators", + "keywords": "Quad Four Digital Pulse Generator Timing", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/PG.md", "tags": ["LOGIC", "MULTIPLE"] }, @@ -332,6 +385,7 @@ "slug":"PG-112", "name":"PG-112", "description": "PG-112 Pulse Generators", + "keywords": "Twelve Digital Pulse Generator Timing", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/PG.md", "tags": ["LOGIC", "MULTIPLE"] }, @@ -339,6 +393,7 @@ "slug":"PO-101", "name":"PO-101", "description": "PO-101 Phased VCO", + "Keywords": "Phase Oscillator VCO", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/PO.md", "tags": ["OSCILLATOR", "MULTIPLE", "DIGITAL"] }, @@ -346,6 +401,7 @@ "slug":"PO-102", "name":"PO-102", "description": "PO-102 Phased LFO", + "keywords": "Phase Oscillator LFO", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/PO.md", "tags": ["OSCILLATOR", "MULTIPLE", "DIGITAL"] }, @@ -353,6 +409,7 @@ "slug":"PO-204", "name":"PO-204", "description": "PO-204 Phase Modulation Engine", + "keywords": "Phase Oscillator Quad Four Modulation", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/PO.md", "tags": ["OSCILLATOR", "QUAD", "DIGITAL"] }, @@ -360,6 +417,7 @@ "slug":"SN-101", "name":"SN-101", "description": "SN-101 Smooth Noise Generator", + "keywords": "Smooth Random Noise LFO VCO Perlin Simplex", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/SN.md", "tags": ["OSCILLATOR", "NOISE"] }, @@ -367,6 +425,7 @@ "slug":"SS-112", "name":"SS-112", "description": "SS-112 12 Input Sinks", + "keywords": "Twelve Sink", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/SS.md", "tags": ["UTILITY"] }, @@ -374,6 +433,7 @@ "slug":"SS-208", "name":"SS-208", "description": "SS-208 8 Irrational Output Voltage Sources", + "keywords": "Irrational Number Constant Voltage", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/SS.md", "tags": ["UTILITY"] }, @@ -381,6 +441,7 @@ "slug":"SS-212", "name":"SS-212", "description": "SS-212 12 Chromatic Output Voltage Sources", + "keywords": "Constant Voltage Chromatic Tuned", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/SS.md", "tags": ["UTILITY"] }, @@ -388,6 +449,7 @@ "slug":"SS-220", "name":"SS-220", "description": "SS-220 120 Chromatic Output Voltage Sources", + "keywords": "Constant Voltage Chromatic Tuned", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/SS.md", "tags": ["UTILITY"] }, @@ -395,13 +457,15 @@ "slug":"SS-221", "name":"SS-221", "description": "SS-221 21 Output Voltage Sources", + "keywords": "Constant Voltage Chromatic Tuned", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/SS.md", "tags": ["UTILITY"] }, { "slug":"TD-116", "name":"TD-116", - "description": "TD-116 Text Display", + "hidden":true, + "deprecated":true, "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/TD.md", "tags": ["VISUAL"] }, @@ -409,6 +473,7 @@ "slug":"TD-202", "name":"TD-202", "description": "TD-202 Vertical Text Display", + "keywords": "Text Display Formattable", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/TD.md", "tags": ["VISUAL"] }, @@ -416,6 +481,7 @@ "slug":"TD-316", "name":"TD-316", "description": "TD-316 Text Display", + "keywords": "Text Display Formattable", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/TD.md", "tags": ["VISUAL"] }, @@ -423,6 +489,7 @@ "slug":"TD-410", "name":"TD-410", "description": "TD-410 Text Display", + "keywords": "Text Display Formattable", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/TD.md", "tags": ["VISUAL"] }, @@ -430,6 +497,7 @@ "slug":"TD-510", "name":"TD-510", "description": "TD-510 Vertical Text Display", + "keywords": "Text Display Formattable", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/TD.md", "tags": ["VISUAL"] }, @@ -437,6 +505,7 @@ "slug":"TF-101", "name":"TF-101", "description": "TF-101 Text Display Format Control", + "keywords": "Text Display Formatting", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/TF.md", "tags": ["VISUAL"] }, @@ -444,48 +513,71 @@ "slug":"TF-102", "name":"TF-102", "description": "TF-102 Text Display Format Control", + "keywords": "Text Display Formatting", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/TF.md", "tags": ["VISUAL"] }, { "slug":"TM-105", - "name":"TM-105", - "description": "TM-105 Torpedo Message Merge", - "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/TM.md", - "tags": ["UTILITY"] + "name":"Obsolete", + "hidden":true, + "deprecated":true, + "description": "This was Torpedo Merge TM-105", + "tags": ["BLANK"] }, { "slug":"VM-101", "name":"VM-101", "description": "VM-101 VU-Meter", + "keywords": "Meter VU RMS Peak", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/VM.md", - "tags": ["UTILITY", "VISUAL", "HARDWARE"] + "tags": ["UTILITY", "VISUAL", "HARDWARE", "POLYPHONIC"] }, { "slug":"VM-102", "name":"VM-102", "description": "VM-102 2-Channel VU-Meter", + "keywords": "Dual Two Meter VU RMS Peak", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/VM.md", "tags": ["UTILITY", "VISUAL", "DUAL", "POLYPHONIC", "HARDWARE"] }, + { + "slug":"VM-104", + "name":"VM-104", + "description": "VM-104 4-Channel VU-Meter", + "keywords": "Quad Four Meter VU RMS Peak", + "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/VM.md", + "tags": ["UTILITY", "VISUAL", "QUAD", "POLYPHONIC", "HARDWARE"] + }, { "slug":"VM-201", "name":"VM-201", "description": "VM-201 Vintage VU-Meter", + "keywords": "Meter VU RMS Peak Vintage Needle", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/VM.md", - "tags": ["UTILITY", "VISUAL", "HARDWARE"] + "tags": ["UTILITY", "VISUAL", "HARDWARE", "POLYPHONIC"] }, { "slug":"VM-202", "name":"VM-202", "description": "VM-202 2-Channel Vintage VU-Meter", + "keywords": "Dual Two Meter VU RMS Peak Vintage Needle", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/VM.md", "tags": ["UTILITY", "VISUAL", "DUAL", "POLYPHONIC", "HARDWARE"] }, + { + "slug":"VM-204", + "name":"VM-204", + "description": "VM-204 4-Channel Vintage VU-Meter", + "keywords": "Quad Four Meter VU RMS Peak Vintage Needle", + "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/VM.md", + "tags": ["UTILITY", "VISUAL", "QUAD", "POLYPHONIC", "HARDWARE"] + }, { "slug":"WK-101", "name":"WK-101", "description": "WK-101 Das Wohltemperierte Klavier", + "keywords": "Quantizer Scala Tuning", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/WK.md", "tags": ["QUANTIZER", "TUNER"] }, @@ -493,6 +585,7 @@ "slug":"WK-205", "name":"WK-205", "description": "WK-205 Das Wohltemperierte Klavier Nano", + "keywords": "Quantizer Scala Tuning", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/WK.md", "tags": ["QUANTIZER", "TUNER", "MULTIPLE"] }, @@ -500,6 +593,7 @@ "slug":"WM-101", "name":"WM-101", "description":"WM-101 Wire Manager", + "keywords": "Wire Cable Color Colour", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/WM.md", "tags": ["UTILITY"] }, @@ -507,6 +601,7 @@ "slug":"WM-102", "name":"WM-102", "description":"WM-102 Wire Manager Billboard", + "keywords": "Wire Cable Color Colour Billboard Display Key", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/WM.md", "tags": ["BLANK", "UTILITY"] }, @@ -514,6 +609,7 @@ "slug":"XF-101", "name":"XF-101", "description": "XF-101 Single Mono Cross Fader", + "keywords": "Single Mono One Cross Fader", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/XF.md", "tags": ["MIXER"] }, @@ -521,6 +617,7 @@ "slug":"XF-102", "name":"XF-102", "description": "XF-102 Dual Mono Cross Fader", + "keywords": "Dual Mono Two Cross Fader", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/XF.md", "tags": ["MIXER", "DUAL"] }, @@ -528,6 +625,7 @@ "slug":"XF-104", "name":"XF-104", "description": "XF-104 Quad Mono Cross Fader", + "keywords": "Quad Mono Four Cross Fader", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/XF.md", "tags": ["MIXER", "QUAD"] }, @@ -535,6 +633,7 @@ "slug":"XF-201", "name":"XF-201", "description": "XF-201 Single Stereo Cross Fader", + "keywords": "Single Stereo One Cross Fader", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/XF.md", "tags": ["MIXER"] }, @@ -542,6 +641,7 @@ "slug":"XF-202", "name":"XF-202", "description": "XF-202 Dual Stereo Cross Fader", + "keywords": "Dual Stereo Two Cross Fader", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/XF.md", "tags": ["MIXER", "DUAL"] }, @@ -549,6 +649,7 @@ "slug":"XF-301", "name":"XF-301", "description": "XF-301 Small Form Factor Stereo Cross Fader", + "keywords": "Single Stereo One Cross Fader", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/XF.md", "tags": ["MIXER"] }, @@ -556,26 +657,31 @@ "slug":"XG-104", "name":"XG-104", "description": "XG-104 XOR Gates", + "keywords": "Quad Four Digital Logic Xor Gates", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/XG.md", "tags": ["LOGIC", "MULTIPLE"] }, - { - "slug":"XG-202", - "name":"XG-202", - "description": "XG-202 4-Input Polyphonic XOR Gates", - "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/XG.md", - "tags": ["LOGIC", "DUAL", "POLYPHONIC"] - }, { "slug":"XG-106", "name":"XG-106", "description": "XG-106 XOR Gates", + "keywords": "Hex Six Digital Logic Xor Gates", "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/XG.md", "tags": ["LOGIC", "MULTIPLE"] }, + { + "slug":"XG-202", + "name":"XG-202", + "description": "XG-202 4-Input Polyphonic XOR Gates", + "keywords": "Dual Two Digital Logic Xor Gates", + "manualUrl": "https://github.com/david-c14/SubmarineFree/blob/main/manual/XG.md", + "tags": ["LOGIC", "DUAL", "POLYPHONIC"] + }, { "slug":"XX-219", "name":"Obsolete", + "hidden":true, + "deprecated":true, "description": "This was Secret Santa 2019", "tags": ["BLANK"] } diff --git a/src/AG1.cpp b/src/AG1.cpp old mode 100755 new mode 100644 index 55cfe4e0..eca4360d --- a/src/AG1.cpp +++ b/src/AG1.cpp @@ -22,6 +22,11 @@ struct AG_1 : DS_Module { AG_1() : DS_Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + for (int i = 0; i < x; i++) { + configInput(INPUT_A_1 + i, "Signal " + std::to_string(i + 1) + "A"); + configInput(INPUT_B_1 + i, "Signal " + std::to_string(i + 1) + "B"); + configOutput(OUTPUT_1 + i, "Signal " + std::to_string(i + 1)); + } } void process(const ProcessArgs &args) override { diff --git a/src/AG2.cpp b/src/AG2.cpp old mode 100755 new mode 100644 index d6a561ec..3824684b --- a/src/AG2.cpp +++ b/src/AG2.cpp @@ -28,6 +28,16 @@ struct AG_2 : DS_Module { AG_2() : DS_Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + configInput(INPUT_A_1, "Signal 1A"); + configInput(INPUT_A_2, "Signal 2A"); + configInput(INPUT_B_1, "Signal 1B"); + configInput(INPUT_B_2, "Signal 2B"); + configInput(INPUT_C_1, "Signal 1C"); + configInput(INPUT_C_2, "Signal 2C"); + configInput(INPUT_D_1, "Signal 1D"); + configInput(INPUT_D_2, "Signal 2D"); + configOutput(OUTPUT_1, "Signal 1"); + configOutput(OUTPUT_2, "Signal 2"); } void process(const ProcessArgs &args) override { diff --git a/src/AO1.cpp b/src/AO1.cpp old mode 100755 new mode 100644 index a232212d..e702ec23 --- a/src/AO1.cpp +++ b/src/AO1.cpp @@ -6,13 +6,28 @@ namespace { static float FunctorClipboard = NAN; + float deviceClipboard[73] = { 0 }; typedef float (*func_t)(float, float, float); + history::ParamChange *changeWithUndo(ParamQuantity *pq, float newValue) { + float oldValue = pq->getValue(); + pq->setValue(newValue); + newValue = pq->getValue(); + history::ParamChange *h = new history::ParamChange(); + h->name = "paste function"; + h->moduleId = pq->module->id; + h->paramId = pq->paramId; + h->oldValue = oldValue; + h->newValue = newValue; + return h; + } + struct Functor { unsigned int category; std::string name; func_t func; + std::string description; }; std::vector categories { @@ -35,7 +50,8 @@ namespace { "Conditional Y and 0", "Conditional X and Y", "Conditional X and C", - "Conditional Y and C" + "Conditional Y and C", + "Rounding" }; #define LAMBDA(e) [](float x, float y, float c)->float { return e ; } @@ -85,247 +101,264 @@ namespace { #define TAU "\xcf\x84" // TAU #define F "\xc6\x92" // frequency #define LAM "\xce\xbb" // lambda +#define LC "\xe2\x8c\x88" // Left Ceiling +#define RC "\xe2\x8c\x89" // Right Ceiling +#define LF "\xe2\x8c\x8a" // Left Floor +#define RF "\xe2\x8c\x8b" // Right Floor std::vector functions { #define CATEGORY 0 - { CATEGORY, "", LAMBDA( 0 ) }, // Passthrough + { CATEGORY, "", LAMBDA( 0 ), "" }, // Passthrough #undef CATEGORY #define CATEGORY 1 - { CATEGORY, C, LAMBDA( c ) }, // Addition - { CATEGORY, X A C, LAMBDA( x + c ) }, - { CATEGORY, Y A C, LAMBDA( y + c ) }, - { CATEGORY, X A Y A C, LAMBDA( x + y + c ) }, + { CATEGORY, C, LAMBDA( c ), "Addition: Constant value" }, // Addition + { CATEGORY, X A C, LAMBDA( x + c ), "Addition: X plus constant" }, + { CATEGORY, Y A C, LAMBDA( y + c ), "Addition: Y plus constant" }, + { CATEGORY, X A Y A C, LAMBDA( x + y + c ), "Addition: X plus Y plus constant" }, #undef CATEGORY #define CATEGORY 2 - { CATEGORY, C S X, LAMBDA( c - x ) }, // Subtraction - { CATEGORY, C S Y, LAMBDA( c - y ) }, - { CATEGORY, X S OP Y A C CP, LAMBDA( x - ( y + c ) ) }, - { CATEGORY, OP X A C CP S Y, LAMBDA( ( x + c ) - y ) }, - { CATEGORY, Y S OP X A C CP, LAMBDA( y - ( x + c ) ) }, - { CATEGORY, OP Y A C CP S X, LAMBDA( ( y + c ) - x ) }, + { CATEGORY, C S X, LAMBDA( c - x ), "Subtraction: Constant less X" }, // Subtraction + { CATEGORY, C S Y, LAMBDA( c - y ), "Subtraction: Constant less Y" }, + { CATEGORY, X S OP Y A C CP, LAMBDA( x - ( y + c ) ), "Subtraction: X less Y and constant" }, + { CATEGORY, OP X A C CP S Y, LAMBDA( ( x + c ) - y ), "Subtraction: X and constant less Y" }, + { CATEGORY, Y S OP X A C CP, LAMBDA( y - ( x + c ) ), "Subtraction: Y less X and constant" }, + { CATEGORY, OP Y A C CP S X, LAMBDA( ( y + c ) - x ), "Subtraction: Y and constant less X" }, #undef CATEGORY #define CATEGORY 3 - { CATEGORY, OP X M Y CP A C, LAMBDA( ( x * y ) + c ) }, // Multiplication - { CATEGORY, OP X A C CP M Y, LAMBDA( ( x + c ) * y ) }, - { CATEGORY, X M OP Y A C CP, LAMBDA( x * ( y + c ) ) }, - { CATEGORY, X M C, LAMBDA( x * c ) }, - { CATEGORY, Y M C, LAMBDA( y * c ) }, - { CATEGORY, X M Y M C, LAMBDA( x * y * c ) }, - { CATEGORY, Pi M OP X A C CP, LAMBDA( M_PI * ( x + c ) ) }, - { CATEGORY, Pi M OP Y A C CP, LAMBDA( M_PI * ( y + c ) ) }, - { CATEGORY, TAU M OP X A C CP, LAMBDA( 2 * M_PI * ( x + c ) ) }, - { CATEGORY, TAU M OP Y A C CP, LAMBDA( 2 * M_PI * ( y + c ) ) }, + { CATEGORY, OP X M Y CP A C, LAMBDA( ( x * y ) + c ), "Multiplication: X by Y plus constant" }, // Multiplication + { CATEGORY, OP X A C CP M Y, LAMBDA( ( x + c ) * y ), "Multiplication: X and constant by Y" }, + { CATEGORY, X M OP Y A C CP, LAMBDA( x * ( y + c ) ), "Multiplication: X by Y and constant" }, + { CATEGORY, X M C, LAMBDA( x * c ), "Multiplication: X by constant" }, + { CATEGORY, Y M C, LAMBDA( y * c ), "Multiplication: Y by constant" }, + { CATEGORY, X M Y M C, LAMBDA( x * y * c ), "Multiplication: X by Y by constant" }, + { CATEGORY, Pi M OP X A C CP, LAMBDA( M_PI * ( x + c ) ), "Multiplication: X and constant by pi" }, + { CATEGORY, Pi M OP Y A C CP, LAMBDA( M_PI * ( y + c ) ), "Multiplication: Y and constant by pi" }, + { CATEGORY, TAU M OP X A C CP, LAMBDA( 2 * M_PI * ( x + c ) ), "Multiplication: X and constant by tau" }, + { CATEGORY, TAU M OP Y A C CP, LAMBDA( 2 * M_PI * ( y + c ) ), "Multiplication: Y and constant by tau" }, #undef CATEGORY #define CATEGORY 4 - { CATEGORY, X D C, LAMBDA( x / c ) }, // Division - { CATEGORY, C D X, LAMBDA( c / x ) }, - { CATEGORY, Y D C, LAMBDA( y / c ) }, - { CATEGORY, C D Y, LAMBDA( c / y ) }, - { CATEGORY, C A OP X D Y CP, LAMBDA( c + ( x / y ) ) }, - { CATEGORY, C A OP Y D X CP, LAMBDA( c + ( y / x ) ) }, - { CATEGORY, X A OP Y D C CP, LAMBDA( x + ( y / c ) ) }, - { CATEGORY, X A OP C D Y CP, LAMBDA( x + ( c / y ) ) }, - { CATEGORY, Y A OP X D C CP, LAMBDA( y + ( x / c ) ) }, - { CATEGORY, Y A OP C D X CP, LAMBDA( y + ( c / x ) ) }, - { CATEGORY, OP X A C CP D Y, LAMBDA( ( x + c ) / y ) }, - { CATEGORY, X D OP Y A C CP, LAMBDA( x / ( y + c ) ) }, - { CATEGORY, OP Y A C CP D X, LAMBDA( ( y + c ) / x ) }, - { CATEGORY, Y D OP X A C CP, LAMBDA( y / ( x + c ) ) }, + { CATEGORY, X D C, LAMBDA( x / c ), "Division: X over constant" }, // Division + { CATEGORY, C D X, LAMBDA( c / x ), "Division: Constant over X" }, + { CATEGORY, Y D C, LAMBDA( y / c ), "Division: Y over constant" }, + { CATEGORY, C D Y, LAMBDA( c / y ), "Division: Constant over Y" }, + { CATEGORY, C A OP X D Y CP, LAMBDA( c + ( x / y ) ), "Division: Constant plus X over Y" }, + { CATEGORY, C A OP Y D X CP, LAMBDA( c + ( y / x ) ), "Division: Constant plus Y over X" }, + { CATEGORY, X A OP Y D C CP, LAMBDA( x + ( y / c ) ), "Division: X plus Y over constant" }, + { CATEGORY, X A OP C D Y CP, LAMBDA( x + ( c / y ) ), "Division: X plus constant over Y" }, + { CATEGORY, Y A OP X D C CP, LAMBDA( y + ( x / c ) ), "Division: Y plus X over constant" }, + { CATEGORY, Y A OP C D X CP, LAMBDA( y + ( c / x ) ), "Division: Y plus constant over Y" }, + { CATEGORY, OP X A C CP D Y, LAMBDA( ( x + c ) / y ), "Division: X and constant over Y" }, + { CATEGORY, X D OP Y A C CP, LAMBDA( x / ( y + c ) ), "Division: X over Y and constant" }, + { CATEGORY, OP Y A C CP D X, LAMBDA( ( y + c ) / x ), "Division: Y and constant over X" }, + { CATEGORY, Y D OP X A C CP, LAMBDA( y / ( x + c ) ), "Division: Y over constant and Y" }, #undef CATEGORY #define CATEGORY 5 - { CATEGORY, OP X A C CP O Y, LAMBDA( fmodf( x + c , y ) ) }, // Modulo - { CATEGORY, OP Y A C CP O X, LAMBDA( fmodf( y + c , x ) ) }, - { CATEGORY, X O OP Y A C CP, LAMBDA( fmodf( x , y + c ) ) }, - { CATEGORY, Y O OP X A C CP, LAMBDA( fmodf( y , x + c) ) }, - { CATEGORY, X O C, LAMBDA( fmodf( x , c ) ) }, - { CATEGORY, Y O C, LAMBDA( fmodf( y , c ) ) }, + { CATEGORY, OP X A C CP O Y, LAMBDA( fmodf( x + c , y ) ), "Modulo: X and constant reduced modulo Y" }, // Modulo + { CATEGORY, OP Y A C CP O X, LAMBDA( fmodf( y + c , x ) ), "Modulo: Y and constant reduced modulo X" }, + { CATEGORY, X O OP Y A C CP, LAMBDA( fmodf( x , y + c ) ), "Modulo: X reduced modulo Y and constant" }, + { CATEGORY, Y O OP X A C CP, LAMBDA( fmodf( y , x + c) ), "Modulo: Y reduced modulo X and constant" }, + { CATEGORY, X O C, LAMBDA( fmodf( x , c ) ), "Modulo: X reduced modulo constant" }, + { CATEGORY, Y O C, LAMBDA( fmodf( y , c ) ), "Modulo: Y reduced module constant" }, #undef CATEGORY #define CATEGORY 6 - { CATEGORY, X S2 A C, LAMBDA( x * x + c ) }, // Quadratic - { CATEGORY, Y S2 A C, LAMBDA( y * y + c ) }, - { CATEGORY, OP X A C CP S2, LAMBDA( ( x + c ) * ( x + c ) ) }, - { CATEGORY, OP Y A C CP S2, LAMBDA( ( y + c ) * ( y + c ) ) }, - { CATEGORY, X S2 A Y A C, LAMBDA( x * x + y + c ) }, - { CATEGORY, Y S2 A X A C, LAMBDA( y * y + x + c ) }, - { CATEGORY, X S2 A C Y, LAMBDA( x * x + c * y ) }, - { CATEGORY, Y S2 A C X, LAMBDA( y * y + c * x ) }, + { CATEGORY, X S2 A C, LAMBDA( x * x + c ), "Quadratic: X squared plus constant" }, // Quadratic + { CATEGORY, Y S2 A C, LAMBDA( y * y + c ), "Quadratic: Y squared plus constant" }, + { CATEGORY, OP X A C CP S2, LAMBDA( ( x + c ) * ( x + c ) ), "Quadratic: X and constant squared" }, + { CATEGORY, OP Y A C CP S2, LAMBDA( ( y + c ) * ( y + c ) ), "Quadratic: Y and constant squared" }, + { CATEGORY, X S2 A Y A C, LAMBDA( x * x + y + c ), "Quadratic: X squared plus Y plus constant" }, + { CATEGORY, Y S2 A X A C, LAMBDA( y * y + x + c ), "Quadratic: Y squared plus X plus constant" }, + { CATEGORY, X S2 A C Y, LAMBDA( x * x + c * y ), "Quadratic: X squared plus Y by constant" }, + { CATEGORY, Y S2 A C X, LAMBDA( y * y + c * x ), "Quadratic: Y squared plus X by constant" }, #undef CATEGORY #define CATEGORY 7 - { CATEGORY, R OP X A C CP, LAMBDA( sqrt( x + c ) ) }, // Square Root - { CATEGORY, R OP Y A C CP, LAMBDA( sqrt( y + c ) ) }, + { CATEGORY, R OP X A C CP, LAMBDA( sqrt( x + c ) ), "Root: Square root of X and constant" }, // Square Root + { CATEGORY, R OP Y A C CP, LAMBDA( sqrt( y + c ) ), "Root: Square root of Y and constant" }, #undef CATEGORY #define CATEGORY 8 - { CATEGORY, C SX, LAMBDA( powf( c , x ) ) }, // Powers - { CATEGORY, C SY, LAMBDA( powf( c , y ) ) }, - { CATEGORY, C SX SA SY, LAMBDA( powf( c , x + y ) ) }, - { CATEGORY, C SX SY, LAMBDA( powf( c , x * y ) ) }, - { CATEGORY, X SC, LAMBDA( powf( x , c ) ) }, - { CATEGORY, Y SC, LAMBDA( powf( y , c ) ) }, - { CATEGORY, X SY SA SC, LAMBDA( powf( x , y + c ) ) }, - { CATEGORY, Y SX SA SC, LAMBDA( powf( y , x + c ) ) }, - { CATEGORY, X SC SY, LAMBDA( powf( x , c * y ) ) }, - { CATEGORY, Y SC SX, LAMBDA( powf( y , c * x ) ) }, + { CATEGORY, C SX, LAMBDA( powf( c , x ) ), "Power: Constant to the power of X" }, // Powers + { CATEGORY, C SY, LAMBDA( powf( c , y ) ), "Power: Constant to the power of Y" }, + { CATEGORY, C SX SA SY, LAMBDA( powf( c , x + y ) ), "Power: Constant to the power of X and Y" }, + { CATEGORY, C SX SY, LAMBDA( powf( c , x * y ) ), "Power: Constant to the power of X by Y" }, + { CATEGORY, X SC, LAMBDA( powf( x , c ) ), "Power: X to the power of constant" }, + { CATEGORY, Y SC, LAMBDA( powf( y , c ) ), "Power: Y to the power of constant" }, + { CATEGORY, X SY SA SC, LAMBDA( powf( x , y + c ) ), "Power: X to the power of Y and constant" }, + { CATEGORY, Y SX SA SC, LAMBDA( powf( y , x + c ) ), "Power: Y to the power of X and constant" }, + { CATEGORY, X SC SY, LAMBDA( powf( x , c * y ) ), "Power: X to the power of Y by constant" }, + { CATEGORY, Y SC SX, LAMBDA( powf( y , c * x ) ), "Power: Y to the power of X by constant" }, #undef CATEGORY #define CATEGORY 9 - { CATEGORY, P X A C P, LAMBDA( std::abs( x + c ) ) }, // Modulus - { CATEGORY, P Y A C P, LAMBDA( std::abs( y + c ) ) }, + { CATEGORY, P X A C P, LAMBDA( std::abs( x + c ) ), "Modulus: Magnitude of X and constant (without the sign)" }, // Modulus + { CATEGORY, P Y A C P, LAMBDA( std::abs( y + c ) ), "Modulus: Magnitude of Y and constant (without the sign)" }, #undef CATEGORY #define CATEGORY 10 - { CATEGORY, MIN OP X A C COMMA Y CP, LAMBDA( std::min( x + c, y ) ) }, // Minmax - { CATEGORY, MIN OP X COMMA C CP, LAMBDA( std::min( x, c ) ) }, - { CATEGORY, MIN OP Y COMMA C CP, LAMBDA( std::min( y, c ) ) }, - { CATEGORY, MAX OP X A C COMMA Y CP, LAMBDA( std::max( x + c, y ) ) }, - { CATEGORY, MAX OP X COMMA C CP, LAMBDA( std::max( x, c ) ) }, - { CATEGORY, MAX OP Y COMMA C CP, LAMBDA( std::max( y, c ) ) }, + { CATEGORY, MIN OP X A C COMMA Y CP, LAMBDA( std::min( x + c, y ) ), "MinMax: Smaller of X and constant or Y" }, // Minmax + { CATEGORY, MIN OP X COMMA C CP, LAMBDA( std::min( x, c ) ), "MinMax: Smaller of X or constant" }, + { CATEGORY, MIN OP Y COMMA C CP, LAMBDA( std::min( y, c ) ), "MinMax: Smaller of Y or constant" }, + { CATEGORY, MAX OP X A C COMMA Y CP, LAMBDA( std::max( x + c, y ) ), "MinMax: Larger of X and constant or Y" }, + { CATEGORY, MAX OP X COMMA C CP, LAMBDA( std::max( x, c ) ), "MinMax: Larger of X and constant" }, + { CATEGORY, MAX OP Y COMMA C CP, LAMBDA( std::max( y, c ) ), "MinMax: Larger of Y and constant" }, #undef CATEGORY #define CATEGORY 11 - { CATEGORY, SIN OP X A C CP, LAMBDA( sin( x + c ) ) }, // Trigonometric - { CATEGORY, SIN OP Y A C CP, LAMBDA( sin( y + c ) ) }, - { CATEGORY, SIN OP X A Y CP, LAMBDA( sin( x + y ) ) }, - { CATEGORY, SIN OP C X CP, LAMBDA( sin( c * x ) ) }, - { CATEGORY, SIN OP C Y CP, LAMBDA( sin( c * y ) ) }, - { CATEGORY, SIN OP X Y CP, LAMBDA( sin( x * y ) ) }, - { CATEGORY, COS OP X A C CP, LAMBDA( cos( x + c ) ) }, - { CATEGORY, COS OP Y A C CP, LAMBDA( cos( y + c ) ) }, - { CATEGORY, COS OP X A Y CP, LAMBDA( cos( x + y ) ) }, - { CATEGORY, COS OP C X CP, LAMBDA( cos( c * x ) ) }, - { CATEGORY, COS OP C Y CP, LAMBDA( cos( c * y ) ) }, - { CATEGORY, COS OP X Y CP, LAMBDA( cos( x * y ) ) }, - { CATEGORY, TAN OP X A C CP, LAMBDA( tan( x + c ) ) }, - { CATEGORY, TAN OP Y A C CP, LAMBDA( tan( y + c ) ) }, - { CATEGORY, TAN OP X A Y CP, LAMBDA( tan( x + y ) ) }, - { CATEGORY, TAN OP C X CP, LAMBDA( tan( c * x ) ) }, - { CATEGORY, TAN OP C Y CP, LAMBDA( tan( c * y ) ) }, - { CATEGORY, TAN OP X Y CP, LAMBDA( tan( x * y ) ) }, + { CATEGORY, SIN OP X A C CP, LAMBDA( sin( x + c ) ), "Trigonometry: Sine of X and constant" }, // Trigonometric + { CATEGORY, SIN OP Y A C CP, LAMBDA( sin( y + c ) ), "Trigonometry: Sine of Y and constant" }, + { CATEGORY, SIN OP X A Y CP, LAMBDA( sin( x + y ) ), "Trigonometry: Sine of X and Y" }, + { CATEGORY, SIN OP C X CP, LAMBDA( sin( c * x ) ), "Trigonometry: Sine of X by constant" }, + { CATEGORY, SIN OP C Y CP, LAMBDA( sin( c * y ) ), "Trigonometry: Sine of Y by constant" }, + { CATEGORY, SIN OP X Y CP, LAMBDA( sin( x * y ) ), "Trigonometry: Sine of X by Y" }, + { CATEGORY, COS OP X A C CP, LAMBDA( cos( x + c ) ), "Trigonometry: Cosine of X and constant" }, + { CATEGORY, COS OP Y A C CP, LAMBDA( cos( y + c ) ), "Trigonometry: Cosine of Y and constant" }, + { CATEGORY, COS OP X A Y CP, LAMBDA( cos( x + y ) ), "Trigonometry: Cosine of X and Y" }, + { CATEGORY, COS OP C X CP, LAMBDA( cos( c * x ) ), "Trigonometry: Cosine of X by constant" }, + { CATEGORY, COS OP C Y CP, LAMBDA( cos( c * y ) ), "Trigonometry: Cosine of Y by constant" }, + { CATEGORY, COS OP X Y CP, LAMBDA( cos( x * y ) ), "Trigonometry: Cosine of X by Y" }, + { CATEGORY, TAN OP X A C CP, LAMBDA( tan( x + c ) ), "Trigonometry: Tangent of X and constant" }, + { CATEGORY, TAN OP Y A C CP, LAMBDA( tan( y + c ) ), "Trigonometry: Tangent of Y and constant" }, + { CATEGORY, TAN OP X A Y CP, LAMBDA( tan( x + y ) ), "Trigonometry: Tangent of X and Y" }, + { CATEGORY, TAN OP C X CP, LAMBDA( tan( c * x ) ), "Trigonometry: Tangent of X by constant" }, + { CATEGORY, TAN OP C Y CP, LAMBDA( tan( c * y ) ), "Trigonometry: Tangent of Y by constant" }, + { CATEGORY, TAN OP X Y CP, LAMBDA( tan( x * y ) ), "Trigonometry: Tangent of X by Y" }, #undef CATEGORY #define CATEGORY 12 - { CATEGORY, ASIN OP X A C CP, LAMBDA( asin( x + c ) ) }, // Inverse Trigonometric - { CATEGORY, ASIN OP Y A C CP, LAMBDA( asin( y + c ) ) }, - { CATEGORY, ASIN OP X A Y CP, LAMBDA( asin( x + y ) ) }, - { CATEGORY, ASIN OP C X CP, LAMBDA( asin( c * x ) ) }, - { CATEGORY, ASIN OP C Y CP, LAMBDA( asin( c * y ) ) }, - { CATEGORY, ASIN OP X Y CP, LAMBDA( asin( x * y ) ) }, - { CATEGORY, ACOS OP X A C CP, LAMBDA( acos( x + c ) ) }, - { CATEGORY, ACOS OP Y A C CP, LAMBDA( acos( y + c ) ) }, - { CATEGORY, ACOS OP X A Y CP, LAMBDA( acos( x + y ) ) }, - { CATEGORY, ACOS OP C X CP, LAMBDA( acos( c * x ) ) }, - { CATEGORY, ACOS OP C Y CP, LAMBDA( acos( c * y ) ) }, - { CATEGORY, ACOS OP X Y CP, LAMBDA( acos( x * y ) ) }, - { CATEGORY, ATAN OP X A C CP, LAMBDA( atan( x + c ) ) }, - { CATEGORY, ATAN OP Y A C CP, LAMBDA( atan( y + c ) ) }, - { CATEGORY, ATAN OP X A Y CP, LAMBDA( atan( x + y ) ) }, - { CATEGORY, ATAN OP C X CP, LAMBDA( atan( c * x ) ) }, - { CATEGORY, ATAN OP C Y CP, LAMBDA( atan( c * y ) ) }, - { CATEGORY, ATAN OP X Y CP, LAMBDA( atan( x * y ) ) }, + { CATEGORY, ASIN OP X A C CP, LAMBDA( asin( x + c ) ), "Trigonometry: Arcsine of X and constant" }, // Inverse Trigonometric + { CATEGORY, ASIN OP Y A C CP, LAMBDA( asin( y + c ) ), "Trigonometry: Arcsine of Y and constant" }, + { CATEGORY, ASIN OP X A Y CP, LAMBDA( asin( x + y ) ), "Trigonometry: Arcsine of X and Y" }, + { CATEGORY, ASIN OP C X CP, LAMBDA( asin( c * x ) ), "Trigonometry: Arcsine of X by constant" }, + { CATEGORY, ASIN OP C Y CP, LAMBDA( asin( c * y ) ), "Trigonometry: Arcsine of Y by constant" }, + { CATEGORY, ASIN OP X Y CP, LAMBDA( asin( x * y ) ), "Trigonometry: Arcsine of X by Y" }, + { CATEGORY, ACOS OP X A C CP, LAMBDA( acos( x + c ) ), "Trigonometry: Arcosine of X and constant" }, + { CATEGORY, ACOS OP Y A C CP, LAMBDA( acos( y + c ) ), "Trigonometry: Arcosine of Y and constant" }, + { CATEGORY, ACOS OP X A Y CP, LAMBDA( acos( x + y ) ), "Trigonometry: Arcosine of X and Y" }, + { CATEGORY, ACOS OP C X CP, LAMBDA( acos( c * x ) ), "Trigonometry: Arcosine of X by constant" }, + { CATEGORY, ACOS OP C Y CP, LAMBDA( acos( c * y ) ), "Trigonometry: Arcosine of Y by constant" }, + { CATEGORY, ACOS OP X Y CP, LAMBDA( acos( x * y ) ), "Trigonometry: Arcoside of X by Y" }, + { CATEGORY, ATAN OP X A C CP, LAMBDA( atan( x + c ) ), "Trigonometry: Arctangent of X and constant" }, + { CATEGORY, ATAN OP Y A C CP, LAMBDA( atan( y + c ) ), "Trigonometry: Arctangent of Y and constant" }, + { CATEGORY, ATAN OP X A Y CP, LAMBDA( atan( x + y ) ), "Trigonometry: Arctangent of X and Y" }, + { CATEGORY, ATAN OP C X CP, LAMBDA( atan( c * x ) ), "Trigonometry: Arctangent of X by constant" }, + { CATEGORY, ATAN OP C Y CP, LAMBDA( atan( c * y ) ), "Trigonometry: Arctangent of Y by constant" }, + { CATEGORY, ATAN OP X Y CP, LAMBDA( atan( x * y ) ), "Trigonometry: Arctangent of X by Y" }, #undef CATEGORY #define CATEGORY 13 - { CATEGORY, LOG OP X A C CP, LAMBDA( log( x + c ) ) }, // Logarithmic - { CATEGORY, LOG OP Y A C CP, LAMBDA( log( y + c ) ) }, - { CATEGORY, LOG2 OP X A C CP, LAMBDA( log2( x + c ) ) }, - { CATEGORY, LOG2 OP Y A C CP, LAMBDA( log2( y + c ) ) }, - { CATEGORY, LOG10 OP X A C CP, LAMBDA( log10( x + c ) ) }, - { CATEGORY, LOG10 OP Y A C CP, LAMBDA( log10( y + c ) ) }, + { CATEGORY, LOG OP X A C CP, LAMBDA( log( x + c ) ), "Logarithmic: Natural logarithm of X and constant" }, // Logarithmic + { CATEGORY, LOG OP Y A C CP, LAMBDA( log( y + c ) ), "Logarithmic: Natural logarithm of Y and constant" }, + { CATEGORY, LOG2 OP X A C CP, LAMBDA( log2( x + c ) ), "Logarithmic: Base-2 logarithm of X and constant" }, + { CATEGORY, LOG2 OP Y A C CP, LAMBDA( log2( y + c ) ), "Logarithmic: Base-2 logarithm of Y and constant" }, + { CATEGORY, LOG10 OP X A C CP, LAMBDA( log10( x + c ) ), "Logarithmic: Base-10 logarithm of X and constant" }, + { CATEGORY, LOG10 OP Y A C CP, LAMBDA( log10( y + c ) ), "Logarithmic: Base-10 logarithm of Y and constant" }, #undef CATEGORY #define CATEGORY 14 - { CATEGORY, E SX SA SC, LAMBDA( exp( x + c ) ) }, // Exponential - { CATEGORY, E SY SA SC, LAMBDA( exp( y + c ) ) }, - { CATEGORY, E SC SX, LAMBDA( exp( c * x ) ) }, - { CATEGORY, E SC SY, LAMBDA( exp( c * y ) ) }, - { CATEGORY, "2" SX SA SC, LAMBDA( powf( 2, x + c ) ) }, - { CATEGORY, "2" SY SA SC, LAMBDA( powf( 2, y + c ) ) }, - { CATEGORY, "2" SC SX, LAMBDA( powf( 2, c * x ) ) }, - { CATEGORY, "2" SC SY, LAMBDA( powf( 2, c * y ) ) }, - { CATEGORY, "10" SX SA SC, LAMBDA( powf( 10, x + c ) ) }, - { CATEGORY, "10" SY SA SC, LAMBDA( powf( 10, y + c ) ) }, - { CATEGORY, "10" SC SX, LAMBDA( powf( 10, c * x ) ) }, - { CATEGORY, "10" SC SY, LAMBDA( powf( 10, c * y ) ) }, + { CATEGORY, E SX SA SC, LAMBDA( exp( x + c ) ), "Exponentiation: e to the power of X and constant" }, // Exponential + { CATEGORY, E SY SA SC, LAMBDA( exp( y + c ) ), "Exponentiation: e to the power of Y and constant" }, + { CATEGORY, E SC SX, LAMBDA( exp( c * x ) ), "Exponentiation: e to the power of X by constant" }, + { CATEGORY, E SC SY, LAMBDA( exp( c * y ) ), "Exponentiation: e to the power of Y by constant" }, + { CATEGORY, "2" SX SA SC, LAMBDA( powf( 2, x + c ) ), "Exponentiation: 2 to the power of X and constant" }, + { CATEGORY, "2" SY SA SC, LAMBDA( powf( 2, y + c ) ), "Exponentiation: 2 to the power of Y and constant" }, + { CATEGORY, "2" SC SX, LAMBDA( powf( 2, c * x ) ), "Exponentiation: 2 to the power of X by constant" }, + { CATEGORY, "2" SC SY, LAMBDA( powf( 2, c * y ) ), "Exponentiation: 2 to the power of Y by constant" }, + { CATEGORY, "10" SX SA SC, LAMBDA( powf( 10, x + c ) ), "Exponentiation: 10 to the power of X and constant" }, + { CATEGORY, "10" SY SA SC, LAMBDA( powf( 10, y + c ) ), "Exponentiation: 10 to the power of Y and constant" }, + { CATEGORY, "10" SC SX, LAMBDA( powf( 10, c * x ) ), "Exponentiation: 10 to the power of X by constant" }, + { CATEGORY, "10" SC SY, LAMBDA( powf( 10, c * y ) ), "Exponentiation: 10 to the power of Y by constant" }, #undef CATEGORY #define CATEGORY 15 - { CATEGORY, IF X G Z T Y H C, LAMBDA( (x > 0) ? y : c ) }, // Conditional X and 0 - { CATEGORY, IF X L Z T Y H C, LAMBDA( (x < 0) ? y : c ) }, - { CATEGORY, IF X Q Z T Y H C, LAMBDA( (x == 0) ? y : c ) }, - { CATEGORY, IF X G Z T C H Y, LAMBDA( (x > 0) ? c : y ) }, - { CATEGORY, IF X L Z T C H Y, LAMBDA( (x < 0) ? c : y ) }, - { CATEGORY, IF X Q Z T C H Y, LAMBDA( (x == 0) ? c : y ) }, - { CATEGORY, IF X G Z T W H Z, LAMBDA( (x > 0) ? 1 : 0 ) }, - { CATEGORY, IF X L Z T W H Z, LAMBDA( (x < 0) ? 1 : 0 ) }, - { CATEGORY, IF X Q Z T W H Z, LAMBDA( (x == 0) ? 1 : 0 ) }, - { CATEGORY, IF X G Z T X H C, LAMBDA( (x > 0) ? x : c ) }, - { CATEGORY, IF X L Z T X H C, LAMBDA( (x < 0) ? x : c ) }, - { CATEGORY, IF X Q Z T X H C, LAMBDA( (x == 0) ? x : c ) }, - { CATEGORY, IF X G Z T C H X, LAMBDA( (x > 0) ? c : x ) }, - { CATEGORY, IF X L Z T C H X, LAMBDA( (x < 0) ? c : x ) }, - { CATEGORY, IF X Q Z T C H X, LAMBDA( (x == 0) ? c : x ) }, + { CATEGORY, IF X G Z T Y H C, LAMBDA( (x > 0) ? y : c ), "Conditional: If X is positive then Y otherwise constant" }, // Conditional X and 0 + { CATEGORY, IF X L Z T Y H C, LAMBDA( (x < 0) ? y : c ), "Conditional: If X is negative then Y otherwise constant" }, + { CATEGORY, IF X Q Z T Y H C, LAMBDA( (x == 0) ? y : c ), "Conditional: If X is zero then Y otherwise constant" }, + { CATEGORY, IF X G Z T C H Y, LAMBDA( (x > 0) ? c : y ), "Conditional: If X is positive then constant otherwise Y" }, + { CATEGORY, IF X L Z T C H Y, LAMBDA( (x < 0) ? c : y ), "Conditional: If X is negative then constant otherwise Y" }, + { CATEGORY, IF X Q Z T C H Y, LAMBDA( (x == 0) ? c : y ), "Conditional: If X is zero then constant otherwise Y" }, + { CATEGORY, IF X G Z T W H Z, LAMBDA( (x > 0) ? 1 : 0 ), "Conditional: If X is positive then 1 otherwise 0" }, + { CATEGORY, IF X L Z T W H Z, LAMBDA( (x < 0) ? 1 : 0 ), "Conditional: If X is negative then 1 otherwise 0" }, + { CATEGORY, IF X Q Z T W H Z, LAMBDA( (x == 0) ? 1 : 0 ), "Conditional: If X is zero then 1 otherwise 0" }, + { CATEGORY, IF X G Z T X H C, LAMBDA( (x > 0) ? x : c ), "Conditional: If X is positive then X otherwise constant" }, + { CATEGORY, IF X L Z T X H C, LAMBDA( (x < 0) ? x : c ), "Conditional: If X is negative then X otherwise constant" }, + { CATEGORY, IF X Q Z T X H C, LAMBDA( (x == 0) ? x : c ), "Conditional: If X is zero then X otherwise constant" }, + { CATEGORY, IF X G Z T C H X, LAMBDA( (x > 0) ? c : x ), "Conditional: If X is positive then constant otherwise X" }, + { CATEGORY, IF X L Z T C H X, LAMBDA( (x < 0) ? c : x ), "Conditional: If X is negative then constant otherwise X" }, + { CATEGORY, IF X Q Z T C H X, LAMBDA( (x == 0) ? c : x ), "Conditional: If X is zero then constant otherwise X" }, #undef CATEGORY #define CATEGORY 16 - { CATEGORY, IF Y G Z T X H C, LAMBDA( (y > 0) ? x : c ) }, // Conditional Y and 0 - { CATEGORY, IF Y L Z T X H C, LAMBDA( (y < 0) ? x : c ) }, - { CATEGORY, IF Y Q Z T X H C, LAMBDA( (y == 0) ? x : c ) }, - { CATEGORY, IF Y G Z T C H X, LAMBDA( (y > 0) ? c : x ) }, - { CATEGORY, IF Y L Z T C H X, LAMBDA( (y < 0) ? c : x ) }, - { CATEGORY, IF Y Q Z T C H X, LAMBDA( (y == 0) ? c : x ) }, - { CATEGORY, IF Y G Z T W H Z, LAMBDA( (y > 0) ? 1 : 0 ) }, - { CATEGORY, IF Y L Z T W H Z, LAMBDA( (y < 0) ? 1 : 0 ) }, - { CATEGORY, IF Y Q Z T W H Z, LAMBDA( (y == 0) ? 1 : 0 ) }, - { CATEGORY, IF Y G Z T Y H C, LAMBDA( (y > 0) ? y : c ) }, - { CATEGORY, IF Y L Z T Y H C, LAMBDA( (y < 0) ? y : c ) }, - { CATEGORY, IF Y Q Z T Y H C, LAMBDA( (y == 0) ? y : c ) }, - { CATEGORY, IF Y G Z T C H Y, LAMBDA( (y > 0) ? c : y ) }, - { CATEGORY, IF Y L Z T C H Y, LAMBDA( (y < 0) ? c : y ) }, - { CATEGORY, IF Y Q Z T C H Y, LAMBDA( (y == 0) ? c : y ) }, + { CATEGORY, IF Y G Z T X H C, LAMBDA( (y > 0) ? x : c ), "Conditional: If Y is positive then X otherwise constant" }, // Conditional Y and 0 + { CATEGORY, IF Y L Z T X H C, LAMBDA( (y < 0) ? x : c ), "Conditional: If Y is negative then X otherwise constant" }, + { CATEGORY, IF Y Q Z T X H C, LAMBDA( (y == 0) ? x : c ), "Conditional: If Y is zero then X otherwise constant" }, + { CATEGORY, IF Y G Z T C H X, LAMBDA( (y > 0) ? c : x ), "Conditional: If Y is positive then constant otherwise X" }, + { CATEGORY, IF Y L Z T C H X, LAMBDA( (y < 0) ? c : x ), "Conditional: If Y is negative then constant otherwise X" }, + { CATEGORY, IF Y Q Z T C H X, LAMBDA( (y == 0) ? c : x ), "Conditional: If Y is zero then constant otherwise X" }, + { CATEGORY, IF Y G Z T W H Z, LAMBDA( (y > 0) ? 1 : 0 ), "Conditional: If Y is positive then 1 otherwise 0" }, + { CATEGORY, IF Y L Z T W H Z, LAMBDA( (y < 0) ? 1 : 0 ), "Conditional: If Y is negative then 1 otherwise 0" }, + { CATEGORY, IF Y Q Z T W H Z, LAMBDA( (y == 0) ? 1 : 0 ), "Conditional: If Y is zero then 1 otherwise 0" }, + { CATEGORY, IF Y G Z T Y H C, LAMBDA( (y > 0) ? y : c ), "Conditional: If Y is positive then Y otherwise constant" }, + { CATEGORY, IF Y L Z T Y H C, LAMBDA( (y < 0) ? y : c ), "Conditional: If Y is negative then Y otherwise constant" }, + { CATEGORY, IF Y Q Z T Y H C, LAMBDA( (y == 0) ? y : c ), "Conditional: If Y is zero then Y otherwise constant" }, + { CATEGORY, IF Y G Z T C H Y, LAMBDA( (y > 0) ? c : y ), "Conditional: If Y is positive then constant otherwise Y" }, + { CATEGORY, IF Y L Z T C H Y, LAMBDA( (y < 0) ? c : y ), "Conditional: If Y is negative then constant otherwise Y" }, + { CATEGORY, IF Y Q Z T C H Y, LAMBDA( (y == 0) ? c : y ), "Conditional: If Y is zero then constant otherwise Y" }, #undef CATEGORY #define CATEGORY 17 - { CATEGORY, IF X G Y T C H Z, LAMBDA( (x > y) ? c : 0 ) }, // Conditional X and Y - { CATEGORY, IF X L Y T C H Z, LAMBDA( (x < y) ? c : 0 ) }, - { CATEGORY, IF X Q Y T C H Z, LAMBDA( (x == y) ? c : 0 ) }, - { CATEGORY, IF Y G X T C H Z, LAMBDA( (y > x) ? c : 0 ) }, - { CATEGORY, IF Y L X T C H Z, LAMBDA( (y < x) ? c : 0 ) }, - { CATEGORY, IF X G Y T X H Z, LAMBDA( (x > y) ? x : 0 ) }, - { CATEGORY, IF X L Y T X H Z, LAMBDA( (x < y) ? x : 0 ) }, - { CATEGORY, IF X Q Y T X H Z, LAMBDA( (x == y) ? x : 0 ) }, - { CATEGORY, IF Y G X T X H Z, LAMBDA( (y > x) ? x : 0 ) }, - { CATEGORY, IF Y L X T X H Z, LAMBDA( (y < x) ? x : 0 ) }, - { CATEGORY, IF X G Y T Y H Z, LAMBDA( (x > y) ? y : 0 ) }, - { CATEGORY, IF X L Y T Y H Z, LAMBDA( (x < y) ? y : 0 ) }, - { CATEGORY, IF X Q Y T Y H Z, LAMBDA( (x == y) ? y : 0 ) }, - { CATEGORY, IF Y G X T Y H Z, LAMBDA( (y > x) ? y : 0 ) }, - { CATEGORY, IF Y L X T Y H Z, LAMBDA( (y < x) ? y : 0 ) }, + { CATEGORY, IF X G Y T C H Z, LAMBDA( (x > y) ? c : 0 ), "Conditional: If X is greater than Y then constant otherwise 0" }, // Conditional X and Y + { CATEGORY, IF X L Y T C H Z, LAMBDA( (x < y) ? c : 0 ), "Conditional: If X is less than Y then constant otherwise 0" }, + { CATEGORY, IF X Q Y T C H Z, LAMBDA( (x == y) ? c : 0 ), "Conditional: If X is equal to Y then constant otherwise 0" }, + { CATEGORY, IF Y G X T C H Z, LAMBDA( (y > x) ? c : 0 ), "Conditional: If Y is greater than X then constant otherwise 0" }, + { CATEGORY, IF Y L X T C H Z, LAMBDA( (y < x) ? c : 0 ), "Conditional: If Y is less than X then constant otherwise 0" }, + { CATEGORY, IF X G Y T X H Z, LAMBDA( (x > y) ? x : 0 ), "Conditional: If X is greater than Y then X otherwise 0" }, + { CATEGORY, IF X L Y T X H Z, LAMBDA( (x < y) ? x : 0 ), "Conditional: If X is less than Y then X otherwise 0" }, + { CATEGORY, IF X Q Y T X H Z, LAMBDA( (x == y) ? x : 0 ), "Conditional: If X is equal to Y then X otherwise 0" }, + { CATEGORY, IF Y G X T X H Z, LAMBDA( (y > x) ? x : 0 ), "Conditional: If Y is greater than X then X otherwise 0" }, + { CATEGORY, IF Y L X T X H Z, LAMBDA( (y < x) ? x : 0 ), "Conditional: If Y is less than X then X otherwise 0" }, + { CATEGORY, IF X G Y T Y H Z, LAMBDA( (x > y) ? y : 0 ), "Conditional: If X is greater than Y then Y otherwise 0" }, + { CATEGORY, IF X L Y T Y H Z, LAMBDA( (x < y) ? y : 0 ), "Conditional: If X is less than Y then Y otherwise 0" }, + { CATEGORY, IF X Q Y T Y H Z, LAMBDA( (x == y) ? y : 0 ), "Conditional: If X is equal to Y then Y otherwise 0" }, + { CATEGORY, IF Y G X T Y H Z, LAMBDA( (y > x) ? y : 0 ), "Conditional: If Y is greater than X then Y otherwise 0" }, + { CATEGORY, IF Y L X T Y H Z, LAMBDA( (y < x) ? y : 0 ), "Conditional: If Y is less than X then Y otherwise 0" }, #undef CATEGORY #define CATEGORY 18 - { CATEGORY, IF X G C T Y H Z, LAMBDA( (x > c) ? y : 0 ) }, // Conditional X and C - { CATEGORY, IF X L C T Y H Z, LAMBDA( (x < c) ? y : 0 ) }, - { CATEGORY, IF X Q C T Y H Z, LAMBDA( (x == c) ? y : 0 ) }, - { CATEGORY, IF C G X T Y H Z, LAMBDA( (c > x) ? y : 0 ) }, - { CATEGORY, IF C L X T Y H Z, LAMBDA( (c < x) ? y : 0 ) }, - { CATEGORY, IF X G C T X H Z, LAMBDA( (x > c) ? x : 0 ) }, - { CATEGORY, IF X L C T X H Z, LAMBDA( (x < c) ? x : 0 ) }, - { CATEGORY, IF X Q C T X H Z, LAMBDA( (x == c) ? x : 0 ) }, - { CATEGORY, IF C G X T X H Z, LAMBDA( (c > x) ? x : 0 ) }, - { CATEGORY, IF C L X T X H Z, LAMBDA( (c < x) ? x : 0 ) }, - { CATEGORY, IF X G C T X H Y, LAMBDA( (x > c) ? x : y ) }, - { CATEGORY, IF X L C T X H Y, LAMBDA( (x < c) ? x : y ) }, - { CATEGORY, IF X Q C T X H Y, LAMBDA( (x == c) ? x : y ) }, - { CATEGORY, IF C G X T X H Y, LAMBDA( (c > x) ? x : y ) }, - { CATEGORY, IF C L X T X H Y, LAMBDA( (c < x) ? x : y ) }, + { CATEGORY, IF X G C T Y H Z, LAMBDA( (x > c) ? y : 0 ), "Conditional: If X is greater than constant then Y otherwise 0" }, // Conditional X and C + { CATEGORY, IF X L C T Y H Z, LAMBDA( (x < c) ? y : 0 ), "Conditional: If X is less than constant then Y otherwise 0" }, + { CATEGORY, IF X Q C T Y H Z, LAMBDA( (x == c) ? y : 0 ), "Conditional: If X is equal to constant then Y otherwise 0" }, + { CATEGORY, IF C G X T Y H Z, LAMBDA( (c > x) ? y : 0 ), "Conditional: If constant is greater than X then Y otherwise 0" }, + { CATEGORY, IF C L X T Y H Z, LAMBDA( (c < x) ? y : 0 ), "Conditional: If constant is less than X then Y otherwise 0" }, + { CATEGORY, IF X G C T X H Z, LAMBDA( (x > c) ? x : 0 ), "Conditional: If X is greater than constant then X otherwise 0" }, + { CATEGORY, IF X L C T X H Z, LAMBDA( (x < c) ? x : 0 ), "Conditional: If X is less than constant then X otherwise 0" }, + { CATEGORY, IF X Q C T X H Z, LAMBDA( (x == c) ? x : 0 ), "Conditional: If X is equal to constant then X otherwise 0" }, + { CATEGORY, IF C G X T X H Z, LAMBDA( (c > x) ? x : 0 ), "Conditional: If constant is greater than X then X otherwise 0" }, + { CATEGORY, IF C L X T X H Z, LAMBDA( (c < x) ? x : 0 ), "Conditional: If constant is less than X then X otherwise 0" }, + { CATEGORY, IF X G C T X H Y, LAMBDA( (x > c) ? x : y ), "Conditional: If X is greater than constant then X otherwise Y" }, + { CATEGORY, IF X L C T X H Y, LAMBDA( (x < c) ? x : y ), "Conditional: If X is less than constant then X otherwise Y" }, + { CATEGORY, IF X Q C T X H Y, LAMBDA( (x == c) ? x : y ), "Conditional: If X is equal to constant then X otherwise Y" }, + { CATEGORY, IF C G X T X H Y, LAMBDA( (c > x) ? x : y ), "Conditional: If constant is greater than X then X otherwise Y" }, + { CATEGORY, IF C L X T X H Y, LAMBDA( (c < x) ? x : y ), "Conditional: If constant is less than X then X otherwise Y" }, #undef CATEGORY #define CATEGORY 19 - { CATEGORY, IF Y G C T X H Z, LAMBDA( (y > c) ? x : 0 ) }, // Conditional Y and C - { CATEGORY, IF Y L C T X H Z, LAMBDA( (y < c) ? x : 0 ) }, - { CATEGORY, IF Y Q C T X H Z, LAMBDA( (y == c) ? x : 0 ) }, - { CATEGORY, IF C G Y T X H Z, LAMBDA( (c > y) ? x : 0 ) }, - { CATEGORY, IF C L Y T X H Z, LAMBDA( (c < y) ? x : 0 ) }, - { CATEGORY, IF Y G C T Y H Z, LAMBDA( (y > c) ? y : 0 ) }, - { CATEGORY, IF Y L C T Y H Z, LAMBDA( (y < c) ? y : 0 ) }, - { CATEGORY, IF Y Q C T Y H Z, LAMBDA( (y == c) ? y : 0 ) }, - { CATEGORY, IF C G Y T Y H Z, LAMBDA( (c > y) ? y : 0 ) }, - { CATEGORY, IF C L Y T Y H Z, LAMBDA( (c < y) ? y : 0 ) }, - { CATEGORY, IF Y G C T Y H X, LAMBDA( (y > c) ? y : x ) }, - { CATEGORY, IF Y L C T Y H X, LAMBDA( (y < c) ? y : x ) }, - { CATEGORY, IF Y Q C T Y H X, LAMBDA( (y == c) ? y : x ) }, - { CATEGORY, IF C G Y T Y H X, LAMBDA( (c > y) ? y : x ) }, - { CATEGORY, IF C L Y T Y H X, LAMBDA( (c < y) ? y : x ) }, - + { CATEGORY, IF Y G C T X H Z, LAMBDA( (y > c) ? x : 0 ), "Conditional: If Y is greater than constant then X otherwise 0" }, // Conditional Y and C + { CATEGORY, IF Y L C T X H Z, LAMBDA( (y < c) ? x : 0 ), "Conditional: If Y is less than constant then X otherwise 0" }, + { CATEGORY, IF Y Q C T X H Z, LAMBDA( (y == c) ? x : 0 ), "Conditional: If Y is equal to constant then X otherwise 0" }, + { CATEGORY, IF C G Y T X H Z, LAMBDA( (c > y) ? x : 0 ), "Conditional: If constant is greater than Y then X otherwise 0" }, + { CATEGORY, IF C L Y T X H Z, LAMBDA( (c < y) ? x : 0 ), "Conditional: If constant is less than Y then X otherwise 0" }, + { CATEGORY, IF Y G C T Y H Z, LAMBDA( (y > c) ? y : 0 ), "Conditional: If Y is greater than constant then Y otherwise 0" }, + { CATEGORY, IF Y L C T Y H Z, LAMBDA( (y < c) ? y : 0 ), "Conditional: If Y is less than constant then Y otherwise 0" }, + { CATEGORY, IF Y Q C T Y H Z, LAMBDA( (y == c) ? y : 0 ), "Conditional: If Y is equal to constant then Y otherwise 0" }, + { CATEGORY, IF C G Y T Y H Z, LAMBDA( (c > y) ? y : 0 ), "Conditional: If constant is greater than Y then Y otherwise 0" }, + { CATEGORY, IF C L Y T Y H Z, LAMBDA( (c < y) ? y : 0 ), "Conditional: If constant is less than Y then Y otherwise 0" }, + { CATEGORY, IF Y G C T Y H X, LAMBDA( (y > c) ? y : x ), "Conditional: If Y is greater than constant then Y otherwise X" }, + { CATEGORY, IF Y L C T Y H X, LAMBDA( (y < c) ? y : x ), "Conditional: If Y is less than constant then Y otherwise X" }, + { CATEGORY, IF Y Q C T Y H X, LAMBDA( (y == c) ? y : x ), "Conditional: If Y is equal to constant then Y otherwise X" }, + { CATEGORY, IF C G Y T Y H X, LAMBDA( (c > y) ? y : x ), "Conditional: If constant is greater than Y then Y otherwise X" }, + { CATEGORY, IF C L Y T Y H X, LAMBDA( (c < y) ? y : x ), "Conditional: If constant is less than Y then Y otherwise X" }, +#undef CATEGORY +#define CATEGORY 20 + { CATEGORY, LF X A C RF, LAMBDA( std::floor(x + c) ), "Rounding: Round down X and C" }, + { CATEGORY, LF Y A C RF, LAMBDA( std::floor(y + c) ), "Rounding: Round down Y and C" }, + { CATEGORY, LF X A Y A C RF, LAMBDA( std::floor(x + y + c) ), "Rounding: Round down X and Y and C" }, + { CATEGORY, LF X M C RF, LAMBDA( std::floor(x * c) ), "Rounding: Round down X by C" }, + { CATEGORY, LF Y M C RF, LAMBDA( std::floor(y * c) ), "Rounding: Round down Y by C" }, + { CATEGORY, LF X M Y C RF, LAMBDA( std::floor(x * y * c) ), "Rounding: Round down X by Y by C" }, + { CATEGORY, LC X A C RC, LAMBDA( std::ceil(x + c) ), "Rounding: Round up X and C" }, + { CATEGORY, LC Y A C RC, LAMBDA( std::ceil(y + c) ), "Rounding: Round up Y and C" }, + { CATEGORY, LC X A Y A C RC, LAMBDA( std::ceil(x + y + c) ), "Rounding: Round up X and Y and C" }, + { CATEGORY, LC X M C RC, LAMBDA( std::ceil(x * c) ), "Rounding: Round up X by C" }, + { CATEGORY, LC Y M C RC, LAMBDA( std::ceil(y * c) ), "Rounding: Round up Y by C" }, + { CATEGORY, LC X M Y C RC, LAMBDA( std::ceil(x * y * c) ), "Rounding: Round up X by Y by C" }, }; #undef X @@ -374,74 +407,66 @@ namespace { #undef TAU #undef F #undef LAM +#undef LC +#undef RC +#undef LF +#undef RF - struct AOKnob : Knob { + struct AOFuncDisplay : Knob { Module *module; int index; - }; - - struct AOFuncLight : LightWidget { - AOKnob *knob; - void draw(const DrawArgs &args) override; - }; - - struct AOFuncDisplay : AOKnob { - AOFuncLight *light; AOFuncDisplay() { box.size.x = 80; box.size.y = 15; snap = true; smooth = false; speed = 0.5f; - light = new AOFuncLight(); - light->box.pos = Vec(0,0); - light->box.size = box.size; - light->knob = this; - addChild(light); } void onButton(const event::Button &e) override; - }; - - void AOFuncLight::draw(const DrawArgs &args) { - if (knob->module) { - nvgFontSize(args.vg, 16); - nvgFontFaceId(args.vg, gScheme.font()->handle); - nvgFillColor(args.vg, SUBLIGHTBLUE); - nvgTextAlign(args.vg, NVG_ALIGN_CENTER); - nvgText(args.vg, 41.5, 13, functions[APP->engine->getParam(knob->module, knob->index)].name.c_str(), NULL); + void drawLayer(const DrawArgs &args, int layer) override { + if ((layer) == 1 && module) { + nvgFontSize(args.vg, 16); + nvgFontFaceId(args.vg, gScheme.font()->handle); + nvgFillColor(args.vg, SUBLIGHTBLUE); + nvgTextAlign(args.vg, NVG_ALIGN_CENTER); + nvgText(args.vg, 41.5, 13, functions[getParamQuantity()->getValue()].name.c_str(), NULL); + } + Widget::drawLayer(args, layer); } - } - - struct AOConstLight : LightWidget { - AOKnob *knob; - void draw(const DrawArgs &args) override; }; - struct AOConstDisplay : AOKnob { - AOConstLight *light; + struct AOConstDisplay : Knob { + Module *module; + int index; AOConstDisplay() { box.size.x = 80; box.size.y = 15; snap = true; speed = 0.005; - light = new AOConstLight(); - light->box.pos = Vec(0,0); - light->box.size = box.size; - light->knob = this; - addChild(light); + } + void drawLayer(const DrawArgs &args, int layer) override { + if ((layer == 1) && module) { + char mtext[41]; + sprintf(mtext, "C=%4.2f", ((int)(getParamQuantity()->getValue()))/100.0f); + nvgFontSize(args.vg, 16); + nvgFontFaceId(args.vg, gScheme.font()->handle); + nvgFillColor(args.vg, SUBLIGHTBLUE); + nvgTextAlign(args.vg, NVG_ALIGN_CENTER); + nvgText(args.vg, 41.5, 13, mtext, NULL); + } + Widget::drawLayer(args, layer); } }; - void AOConstLight::draw(const DrawArgs &args) { - if (knob->module) { - char mtext[41]; - sprintf(mtext, "C=%4.2f", ((int)APP->engine->getParam(knob->module, knob->index))/100.0f); - nvgFontSize(args.vg, 16); - nvgFontFaceId(args.vg, gScheme.font()->handle); - nvgFillColor(args.vg, SUBLIGHTBLUE); - nvgTextAlign(args.vg, NVG_ALIGN_CENTER); - nvgText(args.vg, 41.5, 13, mtext, NULL); + std::vector AODescriptions; + + std::vector AOGetDescriptions() { + if (AODescriptions.size() == 0) { + for (unsigned int i = 0; i < functions.size(); i++) { + AODescriptions.push_back(functions[i].description); + } } + return AODescriptions; } } // end namespace @@ -465,15 +490,23 @@ struct AO1 : Module { }; enum LightIds { NUM_LIGHTS - }; +}; AO1() : Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + std::vector descriptions = AOGetDescriptions(); for (unsigned int ix = 0; ix < x; ix++) { for (unsigned int iy = 0; iy < y; iy++) { - configParam(PARAM_FUNC_1 + ix + iy * x, 0.0f, functions.size() - 1.0f, 0.0f, "Algorithm" ); + configSwitch(PARAM_FUNC_1 + ix + iy * x, 0.0f, functions.size() - 1.0f, 0.0f, "Algorithm", descriptions ); configParam(PARAM_CONST_1 + ix + iy * x, -10000.0f, 10000.0f, 0.0f, "Constant", "", 0.f, 0.01f); + } + configInput(INPUT_X_1 + ix, string::f("Signal X%d", ix + 1)); + configOutput(OUTPUT_X_1 + ix, string::f("Signal X%d", ix + 1)); + } + for (unsigned int iy = 0; iy < y; iy++) { + configInput(INPUT_Y_1 + iy, string::f("Signal Y%d", iy + 1)); + configOutput(OUTPUT_Y_1 + iy, string::f("Signal Y%d", iy + 1)); } } void process(const ProcessArgs &args) override { @@ -504,6 +537,7 @@ namespace { struct AlgorithmMenu : MenuItem { Module *module; int index; + AOFuncDisplay *widget; unsigned int algorithm; void onAction(const event::Action &e) override; }; @@ -511,6 +545,7 @@ namespace { struct CategoryMenu : MenuItem { Module *module; int index; + AOFuncDisplay *widget; unsigned int category; Menu *createChildMenu() override { Menu *menu = new Menu(); @@ -519,6 +554,7 @@ namespace { AlgorithmMenu *am = new AlgorithmMenu(); am->module = module; am->index = index; + am->widget = widget; am->algorithm = i; am->text = functions[i].name; menu->addChild(am); @@ -531,17 +567,19 @@ namespace { struct FCopyMenu : MenuItem { Module *module; int index; + AOFuncDisplay *widget; void onAction(const event::Action &e) override { - FunctorClipboard = APP->engine->getParam(module, index); + FunctorClipboard = widget->getParamQuantity()->getValue(); } }; struct FPasteMenu : MenuItem { Module *module; int index; + AOFuncDisplay *widget; void onAction(const event::Action &e) override { if (!std::isnan(FunctorClipboard)) - APP->engine->setParam(module, index, FunctorClipboard); + APP->history->push(changeWithUndo(widget->getParamQuantity(), FunctorClipboard)); } }; @@ -553,12 +591,14 @@ namespace { FCopyMenu *cm = new FCopyMenu(); cm->module = module; cm->index = index; + cm->widget = this; cm->text = "Copy"; menu->addChild(cm); if (!std::isnan(FunctorClipboard)) { FPasteMenu *pm = new FPasteMenu(); pm->module = module; pm->index = index; + pm->widget = this; pm->text = "Paste"; menu->addChild(pm); } @@ -567,6 +607,7 @@ namespace { AlgorithmMenu *item = new AlgorithmMenu(); item->module = module; item->index = index; + item->widget = this; item->algorithm = 0; item->text = categories[0]; menu->addChild(item); @@ -574,6 +615,7 @@ namespace { CategoryMenu *cm = new CategoryMenu(); cm->module = module; cm->index = index; + cm->widget = this; cm->category = i; cm->text = categories[i]; cm->rightText = SUBMENU; @@ -586,13 +628,15 @@ namespace { } void AlgorithmMenu::onAction(const event::Action &e) { - APP->engine->setParam(module, index, algorithm); + widget->getParamQuantity()->setValue(algorithm); } } // end namespace template struct AOWidget : SchemeModuleWidget { + AOFuncDisplay *funcDisplay[x * y]; + AOConstDisplay *constDisplay[x * y]; AOWidget(AO1 *module) { setModule(module); this->box.size = Vec(y * 90 + 75, 380); @@ -611,10 +655,12 @@ struct AOWidget : SchemeModuleWidget { fd->module = module; fd->index = AO1::PARAM_FUNC_1 + ix + iy * x; addParam(fd); + funcDisplay[iy * x + ix] = fd; AOConstDisplay *cd = createParam(Vec(42.5 + 90 * iy, 78 + 46 * ix), module, AO1::PARAM_CONST_1 + ix + iy * x); cd->module = module; cd->index = AO1::PARAM_CONST_1 + ix + iy * x; addParam(cd); + constDisplay[iy * x + ix] = cd; } } } @@ -672,6 +718,62 @@ struct AOWidget : SchemeModuleWidget { } nvgFill(vg); } + void appendContextMenu(Menu *menu) override { + menu->addChild(new MenuSeparator()); + EventWidgetMenuItem *cm = createMenuItem("Copy"); + cm->clickHandler = [=]() { + this->copy(); + }; + menu->addChild(cm); + if (deviceClipboard[0]) { + if (deviceClipboard[0] <= y) { + EventWidgetMenuItem *pm = createMenuItem("Paste"); + pm->clickHandler = [=]() { + this->paste(); + }; + menu->addChild(pm); + } + else { + MenuLabel *pm = new MenuLabel(); + pm->text = "Paste (device too small)"; + menu->addChild(pm); + } + } + } + void copy() { + unsigned int usedCount = 0; + for (unsigned int iy = 0; iy < y; iy++) { + for (unsigned int ix = 0; ix < x; ix++) { + deviceClipboard[iy * x + ix + 1] = funcDisplay[iy * x + ix]->getParamQuantity()->getValue(); + deviceClipboard[iy * x + ix + 37] = constDisplay[iy * x + ix]->getParamQuantity()->getValue(); + if (deviceClipboard[iy * x + ix + 1]) { + usedCount = iy + 1; + } + } + } + deviceClipboard[0] = usedCount; + } + void paste() { + unsigned int usedCount = deviceClipboard[0]; + if (usedCount > y) + return; + history::ComplexAction *complex = new history::ComplexAction(); + complex->name = "paste from device"; + for (unsigned int iy = 0; iy < usedCount; iy++) { + for (unsigned int ix = 0; ix < x; ix++) { + complex->push(changeWithUndo(funcDisplay[iy * x + ix]->getParamQuantity(), deviceClipboard[iy * x + ix + 1])); + complex->push(changeWithUndo(constDisplay[iy * x + ix]->getParamQuantity(), deviceClipboard[iy * x + ix + 37])); + } + } + for (unsigned int iy = usedCount; iy < y; iy++) { + for (unsigned int ix = 0; ix < x; ix++) { + complex->push(changeWithUndo(funcDisplay[iy * x + ix]->getParamQuantity(), 0)); + complex->push(changeWithUndo(constDisplay[iy * x + ix]->getParamQuantity(), 0)); + } + } + APP->history->push(complex); + + } }; Model *modelAO106 = createModel, AOWidget<6,1>>("A0-106"); diff --git a/src/BB1.cpp b/src/BB1.cpp old mode 100755 new mode 100644 index 3e73064a..5602ed7c --- a/src/BB1.cpp +++ b/src/BB1.cpp @@ -6,8 +6,6 @@ template struct BB_1 : DS_Module { - int doResetFlag = 0; - int doRandomFlag = 0; enum ParamIds { NUM_PARAMS }; @@ -29,10 +27,13 @@ struct BB_1 : DS_Module { BB_1() : DS_Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + configInput(INPUT_CLK, "Clock"); + configInput(INPUT_CV, "Signal"); + for (int i = 0; i < x; i++) { + configOutput(OUTPUT_1 + i, "Signal Delayed by " + std::to_string(i + 1) + " ticks"); + } } void process(const ProcessArgs &args) override { - if (doResetFlag) doReset(); - if (doRandomFlag) doRandomize(); int triggered = true; if (inputs[INPUT_CLK].isConnected()) { triggered = schmittTrigger.redge(this, inputs[INPUT_CLK].getVoltage()); @@ -45,36 +46,16 @@ struct BB_1 : DS_Module { for (int i = 0; i < x; i++) outputs[OUTPUT_1 + i].setVoltage(sample[i]); } - void doRandomize() { - doRandomFlag = 0; + void onRandomize() override { std::default_random_engine generator(std::chrono::system_clock::now().time_since_epoch().count()); std::uniform_real_distribution distribution(voltage0, voltage1); for (int i = 0; i < x; i++) { outputs[OUTPUT_1 + i].setVoltage(sample[i] = distribution(generator)); } } - void doReset() { - doResetFlag = 0; - for (int i = 0; i < x; i++) - outputs[OUTPUT_1 + i].setVoltage(sample[i] = 0.0f); - } - void onRandomize() override { - if (APP->engine->isPaused()) { - doRandomize(); - } - else { - doResetFlag = 0; - doRandomFlag = 1; - } - } void onReset() override { - if (APP->engine->isPaused()) { - doReset(); - } - else { - doRandomFlag = 0; - doResetFlag = 1; - } + for (int i = 0; i < x; i++) + outputs[OUTPUT_1 + i].setVoltage(sample[i] = voltage0); } }; diff --git a/src/DN1.cpp b/src/DN1.cpp old mode 100755 new mode 100644 index 8779bff0..a9b3744a --- a/src/DN1.cpp +++ b/src/DN1.cpp @@ -28,6 +28,7 @@ struct DN_1 : DS_Module { std::uniform_int_distribution distribution(1, 0xffffffffu); for (unsigned int i = 0; i < x; i++) { lfsr[i] = distribution(generator); + configOutput(OUTPUT_1 + i, "Noise Signal " + std::to_string(i + 1)); } } diff --git a/src/DO1.cpp b/src/DO1.cpp old mode 100755 new mode 100644 index 3bb0e407..5650a5db --- a/src/DO1.cpp +++ b/src/DO1.cpp @@ -5,6 +5,39 @@ namespace { NVGcolor colors[26]; + char labels[27] = "-1234+ABCDEFGHIJKLMNOPQRST"; + std::vector connectorLabels { + "-ve Rail", + "Device Input 1", + "Device Input 2", + "Device Input 3", + "Device Input 4", + "+ve Rail", + "Gate A Output", + "Gate B Output", + "Gate C Output", + "Gate D Output", + "Gate E Output", + "Gate F Output", + "Gate G Output", + "Gate H Output", + "Gate I Output", + "Gate J Output", + "Gate K Output", + "Gate L Output", + "Gate M Output", + "Gate N Output", + "Gate O Output", + "Gate P Output", + "Gate Q Output", + "Gate R Output", + "Gate S Output", + "Gate T Output" + }; + + std::vector gateLabels; + unsigned int copyBuffer[107] = { 0 }; // 20 gates, 20 * 4 connectors, 4 output connectors, 3 additional bytes of size information + unsigned int pasteBuffer[107]; // Working space if the copy needs to be compacted before pasting // Based on - Set of 20 Simple, Distinct Colors // Thanks to Sacha Trubetskoy @@ -83,11 +116,19 @@ namespace { typedef uint16_t status_t; - void drawConnector(NVGcontext *vg, float x, float y, NVGcolor color) { + void drawConnector(NVGcontext *vg, float x, float y, NVGcolor color, char label) { + static char lbl[2] = {0,0}; + lbl[0] = label; nvgFillColor(vg, color); nvgBeginPath(vg); nvgCircle(vg, x, y, 4); nvgFill(vg); + nvgFontFaceId(vg, gScheme.font()->handle); + nvgFontSize(vg, 7 * 90 / SVG_DPI); + float bright = color.r * 0.212655 + color.g * 0.715158 + color.b * 0.072187; + nvgFillColor(vg, (bright > 0.5f)?nvgRGB(0,0,0):nvgRGB(255,255,255)); + nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); + nvgText(vg, x, y, lbl, NULL); } inline void drawOutput(NVGcontext *vg, float leftPos) { @@ -383,9 +424,10 @@ namespace { } }; - struct PLGateKnob : TooltipKnob { + struct PLGateKnob : Knob { Module *module; int index; + std::function rightClickHandler; PLGateKnob() { box.size.x = 86; box.size.y = 60; @@ -394,30 +436,33 @@ namespace { } void draw(const DrawArgs &args) override { if (module) { - unsigned int val = (unsigned int)APP->engine->getParam(module, index); + unsigned int val = (unsigned int)(getParamQuantity()->getValue()); if (val >= functions.size()) { val = functions.size() - 1; } functions[val].draw(args, box.size); unsigned int i = box.pos.y / 80; i += 6; - drawConnector(args.vg, box.size.x - 5, box.size.y / 2.0f, colors[i]); + drawConnector(args.vg, box.size.x - 5, box.size.y / 2.0f, colors[i], labels[i]); + } + else if (index == 1) { + scheme::drawLogoPath(args.vg, 0, 0, 4, 0); + nvgStrokeColor(args.vg, SUBLIGHTBLUE); + nvgStrokeWidth(args.vg, 3); + nvgStroke(args.vg); } } void onButton(const event::Button &e) override { if (module) { if (e.button == GLFW_MOUSE_BUTTON_RIGHT && e.action == GLFW_PRESS) { e.consume(this); - unsigned int val = (unsigned int)APP->engine->getParam(module, index); + unsigned int val = (unsigned int)(getParamQuantity()->getValue()); if (val >= functions.size()) { val = functions.size() - 1; } - Menu *menu = createMenu(); - MenuLabel *menuLabel = new MenuLabel(); - menuLabel->text = functions[val].name; - menu->addChild(menuLabel); - menu->addChild(new MenuSeparator()); - menu->addChild(new PLTruthTable(functions[val].truthTable)); + if (rightClickHandler) { + rightClickHandler(index, val); + } return; } } @@ -425,7 +470,7 @@ namespace { } }; - struct PLConnectorKnob : TooltipKnob { + struct PLConnectorKnob : Knob { Module *module; float fade = 0.1f; PLConnectorKnob() { @@ -459,9 +504,6 @@ namespace { nvgBeginPath(args.vg); nvgRect(args.vg, 0, 0, box.size.x, box.size.y); nvgFill(args.vg); - for (unsigned int ix = 0; ix < x + 2; ix++) { - drawConnector(args.vg, box.size.x / (x * 2 + 4.0f) * (ix * 2 + 1), 5, colors[ix]); - } nvgStrokeWidth(args.vg, 2); for (unsigned int ix = 0; ix < x; ix++) { nvgStrokeColor(args.vg, colors[ix + 1]); @@ -470,9 +512,21 @@ namespace { nvgLineTo(args.vg, 15 + ix * 30 - box.pos.x, 30 - box.pos.y); nvgStroke(args.vg); } + for (unsigned int ix = 0; ix < x + 2; ix++) { + drawConnector(args.vg, box.size.x / (x * 2 + 4.0f) * (ix * 2 + 1), 5, colors[ix], labels[ix]); + } Widget::draw(args); } }; + + std::vector getGateLabels() { + if (gateLabels.size() == 0) { + for (unsigned int i = 0; i < functions.size(); i++ ) { + gateLabels.push_back(functions[i].name); + } + } + return gateLabels; + } } template @@ -513,16 +567,20 @@ struct DO1 : DS_Module { status_t statuses[NUM_STATUS] = { 0 }; DO1() { + std::vector gLabels = getGateLabels(); config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); for (unsigned int ix = 0; ix < x; ix++) { - configParam(PARAM_CONNECTOR_OUT_1 + ix, 0.0f, x + y + 1, 0.0f, "Connection" ); + configSwitch(PARAM_CONNECTOR_OUT_1 + ix, 0.0f, x + y + 1, 0.0f, string::f("Device Output %d", ix + 1), connectorLabels ); + configInput(INPUT_1 + ix, string::f("Signal %d", ix + 1)); + configOutput(OUTPUT_1 + ix, string::f("Signal %d", ix + 1)); + configBypass(INPUT_1 + ix, OUTPUT_1 + ix); } for (unsigned int iy = 0; iy < y; iy++) { - configParam(PARAM_GATE_1 + iy, 0.0f, functions.size() - 1.0f, 0.0f, "Gate" ); - configParam(PARAM_CONNECTOR_1 + 4 * iy, 0.0f, 1 + x + iy, 0.0f, "Connection"); - configParam(PARAM_CONNECTOR_2 + 4 * iy, 0.0f, 1 + x + iy, 0.0f, "Connection"); - configParam(PARAM_CONNECTOR_3 + 4 * iy, 0.0f, 1 + x + iy, 0.0f, "Connection"); - configParam(PARAM_CONNECTOR_4 + 4 * iy, 0.0f, 1 + x + iy, 0.0f, "Connection"); + configSwitch(PARAM_GATE_1 + iy, 0.0f, functions.size() - 1.0f, 0.0f, "Gate", gLabels ); + configSwitch(PARAM_CONNECTOR_1 + 4 * iy, 0.0f, 1 + x + iy, 0.0f, string::f("Gate %c Input 1", labels[iy + 6]), connectorLabels); + configSwitch(PARAM_CONNECTOR_2 + 4 * iy, 0.0f, 1 + x + iy, 0.0f, string::f("Gate %c Input 2", labels[iy + 6]), connectorLabels); + configSwitch(PARAM_CONNECTOR_3 + 4 * iy, 0.0f, 1 + x + iy, 0.0f, string::f("Gate %c Input 3", labels[iy + 6]), connectorLabels); + configSwitch(PARAM_CONNECTOR_4 + 4 * iy, 0.0f, 1 + x + iy, 0.0f, string::f("Gate %c Input 4", labels[iy + 6]), connectorLabels); } statuses[STATUS_ALL_ZEROES] = 0; statuses[STATUS_ALL_ONES] = ~statuses[STATUS_ALL_ZEROES]; @@ -569,6 +627,7 @@ template struct DOWidget : SchemeModuleWidget { ScrollWidget *collectionScrollWidget; PLConnectorKnob *knobs[x + 4 * y]; + PLGateKnob *gateKnobs[y]; PLBackground *background; DOWidget(DO1 *module) { setModule(module); @@ -584,9 +643,6 @@ struct DOWidget : SchemeModuleWidget { for (unsigned int ix = 0; ix < x; ix++) { knobs[ix + 4 * y] = createParamCentered(Vec(pos, background->box.size.y - 5), module, DO1::PARAM_CONNECTOR_OUT_1 + ix); knobs[ix + 4 * y]->module = module; - knobs[ix + 4 * y]->getText = [=]()->std::string { - return this->getConnectorText(ix + 4 * y); - }; knobs[ix + 4 * y]->speed = 20.0f / (2 + x + 4 * y); background->addChild(knobs[ix + 4 * y]); pos = pos + posDiff; @@ -595,21 +651,18 @@ struct DOWidget : SchemeModuleWidget { collectionScrollWidget->box.size = Vec(box.size.x - 10, box.size.y - 110); addChild(collectionScrollWidget); for (unsigned int iy = 0; iy < y; iy++) { - PLGateKnob *knob = createParamCentered(Vec(53, 80 * (iy + 1)), module, DO1::PARAM_GATE_1 + iy); - knob->module = module; - knob->index = DO1::PARAM_GATE_1 + iy; - knob->getText = [=]()->std::string { - return this->getGateText(iy); + gateKnobs[iy] = createParamCentered(Vec(53, 80 * (iy + 1)), module, DO1::PARAM_GATE_1 + iy); + gateKnobs[iy]->module = module; + gateKnobs[iy]->index = DO1::PARAM_GATE_1 + iy; + gateKnobs[iy]->rightClickHandler = [=](int index, unsigned int val) { + this->appendGateRightClickMenu(index, val); }; - collectionScrollWidget->container->addChild(knob); + collectionScrollWidget->container->addChild(gateKnobs[iy]); } for (unsigned int iy = 0; iy < y; iy++) { for (unsigned int ix = 0; ix < 4; ix++) { knobs[4 * iy + ix] = createParamCentered(Vec(5, (iy + 1) * 80.0f + ix * 14.0f - 21.0f), module, DO1::PARAM_CONNECTOR_1 + iy * 4 + ix); knobs[4 * iy + ix]->module = module; - knobs[4 * iy + ix]->getText = [=]()->std::string { - return this->getConnectorText(4 * iy + ix); - }; knobs[4 * iy + ix]->speed = 20.0f / (4 * iy + x + 2); collectionScrollWidget->container->addChild(knobs[4 * iy + ix]); } @@ -627,8 +680,308 @@ struct DOWidget : SchemeModuleWidget { } } + void appendGateRightClickMenu(unsigned int index, unsigned int val) { + Menu *menu = createMenu(); + MenuLabel *menuTitle = new MenuLabel(); + menuTitle->text = string::f("Gate %c", labels[index + 6]); + menu->addChild(menuTitle); + + MenuLabel *menuLabel = new MenuLabel(); + menuLabel->text = functions[val].name; + menu->addChild(menuLabel); + menu->addChild(new MenuSeparator()); + + EventWidgetMenuItem *io = createMenuItem("Inputs / Outputs"); + io->rightText = SUBMENU; + io->childMenuHandler = [=]() { + return this->appendGateIOMenu(index); + }; + menu->addChild(io); + + EventWidgetMenuItem *tt = createMenuItem("Truth Table"); + tt->rightText = SUBMENU; + tt->childMenuHandler = [=]() { + Menu *menu = new Menu(); + menu->addChild(new PLTruthTable(functions[val].truthTable)); + return menu; + }; + menu->addChild(tt); + + menu->addChild(new MenuSeparator()); + + if (val == 0) { + EventWidgetMenuItem *moveUp = createMenuItem("Delete and Shuffle Up"); + moveUp->clickHandler = [=]() { + this->MoveItemsUp(index); + }; + menu->addChild(moveUp); + } + else { + EventWidgetMenuItem *moveDown = createMenuItem("Shuffle Down"); + moveDown->clickHandler = [=]() { + this->MoveItemsDown(index); + }; + menu->addChild(moveDown); + } + } + + rack::ui::Menu *appendGateIOMenu(unsigned int index) { + Menu *menu = new Menu(); + unsigned int cval; + bool foundOutput = false; + + cval = knobs[(index - DO1::PARAM_GATE_1) * 4]->getParamQuantity()->getValue(); + if (cval > ((unsigned int)index + 5)) { + cval = index + 5; + } + MenuLabel *menu1 = new MenuLabel(); + menu1->text = string::f("Input 1 from %s", connectorLabels[cval].c_str()); + menu->addChild(menu1); + + cval = knobs[(index - DO1::PARAM_GATE_1) * 4 + 1]->getParamQuantity()->getValue(); + if (cval > ((unsigned int)index + 5)) { + cval = index + 5; + } + MenuLabel *menu2 = new MenuLabel(); + menu2->text = string::f("Input 2 from %s", connectorLabels[cval].c_str()); + menu->addChild(menu2); + + cval = knobs[(index - DO1::PARAM_GATE_1) * 4 + 2]->getParamQuantity()->getValue(); + if (cval > ((unsigned int)index + 5)) { + cval = index + 5; + } + MenuLabel *menu3 = new MenuLabel(); + menu3->text = string::f("Input 3 from %s", connectorLabels[cval].c_str()); + menu->addChild(menu3); + + cval = knobs[(index - DO1::PARAM_GATE_1) * 4 + 3]->getParamQuantity()->getValue(); + if (cval > ((unsigned int)index + 5)) { + cval = index + 5; + } + MenuLabel *menu4 = new MenuLabel(); + menu4->text = string::f("Input 4 from %s", connectorLabels[cval].c_str()); + menu->addChild(menu4); + + for (unsigned int i = index * 4 + 1; i < y * 4; i++) { + cval = knobs[i]->getParamQuantity()->getValue(); + if (cval == (unsigned int)index + 6) { + if (!foundOutput) + menu->addChild(new MenuSeparator()); + MenuLabel *menuOut = new MenuLabel(); + menuOut->text = string::f("Output to Gate %c Input %d", labels[6 + (i / 4)], (i % 4) + 1); + menu->addChild(menuOut); + foundOutput = true; + } + } + + for (unsigned int i = 0; i < 4; i++) { + cval = knobs[y * 4 + i]->getParamQuantity()->getValue(); + if (cval == (unsigned int)index + 6) { + if (!foundOutput) + menu->addChild(new MenuSeparator()); + MenuLabel *menuOut = new MenuLabel(); + menuOut->text = string::f("Output to Device Output %d", i + 1); + menu->addChild(menuOut); + foundOutput = true; + } + } + + return menu; + } + void MoveItemsUp(unsigned int index) { + history::ComplexAction *complex = new history::ComplexAction(); + complex->name = "Shuffle Up"; + MoveItemUp(index, complex); + APP->history->push(complex); + } + void MoveItemUp(unsigned int index, history::ComplexAction *complex) { + if (index == y - 1) { + complex->push(shuffleChange(gateKnobs[index]->getParamQuantity(), 0)); + complex->push(shuffleChange(knobs[index * 4 + 0]->getParamQuantity(), 0)); + complex->push(shuffleChange(knobs[index * 4 + 1]->getParamQuantity(), 0)); + complex->push(shuffleChange(knobs[index * 4 + 2]->getParamQuantity(), 0)); + complex->push(shuffleChange(knobs[index * 4 + 3]->getParamQuantity(), 0)); + return; + } + complex->push(shuffleChange(gateKnobs[index]->getParamQuantity(), gateKnobs[index + 1]->getParamQuantity()->getValue())); + complex->push(shuffleChange(knobs[index * 4 + 0]->getParamQuantity(), knobs[index * 4 + 4]->getParamQuantity()->getValue())); + complex->push(shuffleChange(knobs[index * 4 + 1]->getParamQuantity(), knobs[index * 4 + 5]->getParamQuantity()->getValue())); + complex->push(shuffleChange(knobs[index * 4 + 2]->getParamQuantity(), knobs[index * 4 + 6]->getParamQuantity()->getValue())); + complex->push(shuffleChange(knobs[index * 4 + 3]->getParamQuantity(), knobs[index * 4 + 7]->getParamQuantity()->getValue())); + for (unsigned int i = index * 4 + 4; i < (y * 4 + 4); i++) { + ParamQuantity *pq = knobs[i]->getParamQuantity(); + if (pq->getValue() == index + 7) { + complex->push(shuffleChange(pq, index + 6)); + } + } + MoveItemUp(index + 1, complex); + } + void MoveItemsDown(unsigned int index) { + history::ComplexAction *complex = new history::ComplexAction(); + complex->name = "Shuffle Down"; + if (MoveItemDown(index, complex)) { + complex->push(shuffleChange(gateKnobs[index]->getParamQuantity(), 0)); + complex->push(shuffleChange(knobs[index * 4 + 0]->getParamQuantity(), 0)); + complex->push(shuffleChange(knobs[index * 4 + 1]->getParamQuantity(), 0)); + complex->push(shuffleChange(knobs[index * 4 + 2]->getParamQuantity(), 0)); + complex->push(shuffleChange(knobs[index * 4 + 3]->getParamQuantity(), 0)); + APP->history->push(complex); + } + + } + bool MoveItemDown(unsigned int index, history::ComplexAction *complex) { + if (index >= y) + return false; + unsigned int val = gateKnobs[index]->getParamQuantity()->getValue(); + if (val == 0) { + return true; + } + if (!MoveItemDown(index + 1, complex)) { + return false; + } + complex->push(shuffleChange(gateKnobs[index + 1]->getParamQuantity(), val)); + complex->push(shuffleChange(knobs[index * 4 + 4]->getParamQuantity(), knobs[index * 4 + 0]->getParamQuantity()->getValue())); + complex->push(shuffleChange(knobs[index * 4 + 5]->getParamQuantity(), knobs[index * 4 + 1]->getParamQuantity()->getValue())); + complex->push(shuffleChange(knobs[index * 4 + 6]->getParamQuantity(), knobs[index * 4 + 2]->getParamQuantity()->getValue())); + complex->push(shuffleChange(knobs[index * 4 + 7]->getParamQuantity(), knobs[index * 4 + 3]->getParamQuantity()->getValue())); + + for (unsigned int i = index * 4; i < (y * 4 + 4); i++) { + ParamQuantity *pq = knobs[i]->getParamQuantity(); + if (pq->getValue() == index + 6) { + complex->push(shuffleChange(pq, index + 7)); + } + } + return true; + } + + history::ParamChange *shuffleChange(ParamQuantity *pq, float newValue) { + float oldValue = pq->getValue(); + pq->setValue(newValue); + newValue = pq->getValue(); + history::ParamChange *h = new history::ParamChange(); + h->name = "change parameter"; + h->moduleId = module->id; + h->paramId = pq->paramId; + h->oldValue = oldValue; + h->newValue = newValue; + return h; + } + + void copyToBuffer() { + unsigned int gateCount = 0; // Number of gates actually used. + unsigned int usedCount = 0; // Highest numbered gate in use. + copyBuffer[0] = y; + for (unsigned int i = 0; i < y; i++) { + copyBuffer[i * 5 + 3] = gateKnobs[i]->getParamQuantity()->getValue(); + copyBuffer[i * 5 + 4] = knobs[i * 4 + 0]->getParamQuantity()->getValue(); + copyBuffer[i * 5 + 5] = knobs[i * 4 + 1]->getParamQuantity()->getValue(); + copyBuffer[i * 5 + 6] = knobs[i * 4 + 2]->getParamQuantity()->getValue(); + copyBuffer[i * 5 + 7] = knobs[i * 4 + 3]->getParamQuantity()->getValue(); + if (copyBuffer[i * 5 + 3] != 0) { + gateCount++; + usedCount = i + 1; + } + } + copyBuffer[103] = knobs[y * 4 + 0]->getParamQuantity()->getValue(); + copyBuffer[104] = knobs[y * 4 + 1]->getParamQuantity()->getValue(); + copyBuffer[105] = knobs[y * 4 + 2]->getParamQuantity()->getValue(); + copyBuffer[106] = knobs[y * 4 + 3]->getParamQuantity()->getValue(); + copyBuffer[1] = usedCount; + copyBuffer[2] = gateCount; + } + + void pasteFromBuffer() { + unsigned int deviceSize = copyBuffer[0]; + unsigned int usedCount = copyBuffer[1]; + unsigned int gateCount = copyBuffer[2]; + if (!deviceSize) + return; + if (gateCount > y) + return; + if (usedCount > y) { + compactBuffer(); + pasteFromBuffer(pasteBuffer); + } + else { + pasteFromBuffer(copyBuffer); + } + } + + void compactBuffer() { + for (unsigned int i = 0; i < 107; i++) { + pasteBuffer[i] = copyBuffer[i]; + } + int shuffleDistance = 0; + for (unsigned int i = 0; i < 20; i++) { + if (pasteBuffer[i * 5 + 3] == 0) { + shuffleDistance++; + continue; + } + if (shuffleDistance == 0) { + continue; + } + unsigned int o = i - shuffleDistance; + pasteBuffer[o * 5 + 3] = pasteBuffer[i * 5 + 3]; + pasteBuffer[o * 5 + 4] = pasteBuffer[i * 5 + 4]; + pasteBuffer[o * 5 + 5] = pasteBuffer[i * 5 + 5]; + pasteBuffer[o * 5 + 6] = pasteBuffer[i * 5 + 6]; + pasteBuffer[o * 5 + 7] = pasteBuffer[i * 5 + 7]; + for(unsigned int j = 0; j < 20; j++) { + if (pasteBuffer[j * 5 + 4] == (i + 6)) + pasteBuffer[j * 5 + 4] -= shuffleDistance; + if (pasteBuffer[j * 5 + 5] == (i + 6)) + pasteBuffer[j * 5 + 5] -= shuffleDistance; + if (pasteBuffer[j * 5 + 6] == (i + 6)) + pasteBuffer[j * 5 + 6] -= shuffleDistance; + if (pasteBuffer[j * 5 + 7] == (i + 6)) + pasteBuffer[j * 5 + 7] -= shuffleDistance; + } + if (pasteBuffer[103] == (i + 6)) + pasteBuffer[103] -= shuffleDistance; + if (pasteBuffer[104] == (i + 6)) + pasteBuffer[104] -= shuffleDistance; + if (pasteBuffer[105] == (i + 6)) + pasteBuffer[105] -= shuffleDistance; + if (pasteBuffer[106] == (i + 6)) + pasteBuffer[106] -= shuffleDistance; + pasteBuffer[i * 5 + 3] = 0; + pasteBuffer[i * 5 + 4] = 0; + pasteBuffer[i * 5 + 5] = 0; + pasteBuffer[i * 5 + 6] = 0; + pasteBuffer[i * 5 + 7] = 0; + } + pasteBuffer[1] = pasteBuffer[2]; + } + + void pasteFromBuffer(unsigned int * buffer) { + unsigned int usedCount = buffer[1]; + if (usedCount > y) + return; + history::ComplexAction *complex = new history::ComplexAction(); + complex->name = "Paste"; + for (unsigned int i = 0; i < usedCount; i++) { + complex->push(shuffleChange(gateKnobs[i]->getParamQuantity(), buffer[i * 5 + 3])); + complex->push(shuffleChange(knobs[i * 4 + 0]->getParamQuantity(), buffer[i * 5 + 4])); + complex->push(shuffleChange(knobs[i * 4 + 1]->getParamQuantity(), buffer[i * 5 + 5])); + complex->push(shuffleChange(knobs[i * 4 + 2]->getParamQuantity(), buffer[i * 5 + 6])); + complex->push(shuffleChange(knobs[i * 4 + 3]->getParamQuantity(), buffer[i * 5 + 7])); + } + for (unsigned int i = usedCount; i < y; i++) { + complex->push(shuffleChange(gateKnobs[i]->getParamQuantity(), 0)); + complex->push(shuffleChange(knobs[i * 4 + 0]->getParamQuantity(), 0)); + complex->push(shuffleChange(knobs[i * 4 + 1]->getParamQuantity(), 0)); + complex->push(shuffleChange(knobs[i * 4 + 2]->getParamQuantity(), 0)); + complex->push(shuffleChange(knobs[i * 4 + 3]->getParamQuantity(), 0)); + } + complex->push(shuffleChange(knobs[y * 4 + 0]->getParamQuantity(), buffer[103])); + complex->push(shuffleChange(knobs[y * 4 + 1]->getParamQuantity(), buffer[104])); + complex->push(shuffleChange(knobs[y * 4 + 2]->getParamQuantity(), buffer[105])); + complex->push(shuffleChange(knobs[y * 4 + 3]->getParamQuantity(), buffer[106])); + APP->history->push(complex); + } + std::string getGateName(unsigned int index) { - unsigned int val = (unsigned int)APP->engine->getParam(module, DO1::PARAM_GATE_1 + index); + unsigned int val = (unsigned int)(gateKnobs[index]->getParamQuantity()->getValue()); if (val >= functions.size()) { val = functions.size() - 1; } @@ -655,7 +1008,7 @@ struct DOWidget : SchemeModuleWidget { if (!module) return std::string("Browser"); std::string connectorName = getConnectorNameText(index); - unsigned int val = (unsigned int)APP->engine->getParam(module, DO1::PARAM_CONNECTOR_1 + index); + unsigned int val = (unsigned int)(knobs[index]->getParamQuantity()->getValue()); if (val > x + y + 1) val = x + y + 1; if (val == 0) @@ -667,19 +1020,21 @@ struct DOWidget : SchemeModuleWidget { return connectorName + string::f("Gate %d: ", val - x -1) + getGateName(val - x - 2); } - void drawWire(const DrawArgs &args, float sx, float sy, float dx, float dy, NVGcolor color, float fade) { - drawConnector(args.vg, sx, sy, color); + void drawWire(const DrawArgs &args, float sx, float sy, float dx, float dy, NVGcolor color, float fade, char label) { color.a = fade; nvgBeginPath(args.vg); nvgMoveTo(args.vg, sx, sy); nvgLineTo(args.vg, dx, dy); - nvgLineCap(args.vg, NVG_ROUND); + nvgLineCap(args.vg, NVG_BUTT); nvgStrokeColor(args.vg, nvgRGBAf(color.r / 2.0f, color.g / 2.0f, color.b / 2.0f, fade)); nvgStrokeWidth(args.vg, 3); nvgStroke(args.vg); nvgStrokeColor(args.vg, color); nvgStrokeWidth(args.vg, 2); nvgStroke(args.vg); + color.a = 1; + drawConnector(args.vg, sx, sy, color, label); + drawConnector(args.vg, dx, dy, color, label); } void drawConnectors(const DrawArgs &args) { if (!module) @@ -709,7 +1064,7 @@ struct DOWidget : SchemeModuleWidget { startX = (background->box.size.x / (x * 2)) * ((i - 4 * y) * 2 + 1); startY = background->box.size.y - 5; } - unsigned int val = (unsigned int)APP->engine->getParam(module, DO1::PARAM_CONNECTOR_1 + i); + unsigned int val = (unsigned int)(knobs[i]->getParamQuantity()->getValue()); if (val > (x + y + 1)) { val = (x + y + 1); } @@ -728,7 +1083,7 @@ struct DOWidget : SchemeModuleWidget { nvgScissor(args.vg, args.clipBox.pos.x, scissorTop, args.clipBox.size.x, scissorBottom); NVGcolor color = colors[val]; float fade = val?knobs[i]->fade:0.0f; - drawWire(args, startX, startY, destX, destY, color, fade); + drawWire(args, startX, startY, destX, destY, color, fade, labels[val]); nvgResetScissor(args.vg); } } @@ -738,6 +1093,26 @@ struct DOWidget : SchemeModuleWidget { drawBase(vg, workingSpace); } void appendContextMenu(Menu *menu) override { + menu->addChild(new MenuSeparator()); + EventWidgetMenuItem *copy = createMenuItem("Copy"); + copy->clickHandler = [=]() { + this->copyToBuffer(); + }; + menu->addChild(copy); + if (copyBuffer[0] != 0) { + if (copyBuffer[2] <= y) { + EventWidgetMenuItem *paste = createMenuItem("Paste"); + paste->clickHandler = [=]() { + this->pasteFromBuffer(); + }; + menu->addChild(paste); + } + else { + MenuLabel *paste = new MenuLabel(); + paste->text = "Paste (device is too small)"; + menu->addChild(paste); + } + } SchemeModuleWidget::appendContextMenu(menu); DS_Module *dsMod = dynamic_cast(module); if (dsMod) { diff --git a/src/EN1.cpp b/src/EN1.cpp old mode 100755 new mode 100644 index cb20a246..e89e4ec1 --- a/src/EN1.cpp +++ b/src/EN1.cpp @@ -39,12 +39,25 @@ struct EN_104 : Module { () : Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); for(unsigned int i = 0; i < 4; i++) { - configParam(PARAM_A1 + i, 0.0f, 1.0f, 0.25f, string::f("Operator #%d Attack Rack", i + 1), " ms", 10000.0f, 1.0f); + configParam(PARAM_A1 + i, 0.0f, 1.0f, 0.25f, string::f("Operator #%d Attack Rate", i + 1), " ms", 10000.0f, 1.0f); configParam(PARAM_D1 + i, 0.0f, 1.0f, 0.25f, string::f("Operator #%d Decay Rate", i + 1), " ms", 10000.0f, 1.0f); configParam(PARAM_S1 + i, 0.0f, 1.0f, 0.8f, string::f("Operator #%d Sustain Level", i + 1), "%", 0.0f, 100.0f); configParam(PARAM_R1 + i, 0.0f, 1.0f, 0.25f, string::f("Operator #%d Release Rate", i + 1), " ms", 10000.0f, 1.0f); configParam(PARAM_T1 + i, 0.0f, 1.0f, 1.0f, string::f("Operator #%d Total Level", i + 1), "%", 0.0f, 100.0f); + configInput(INPUT_1 + i, string::f("Operator #%d", i + 1)); + configInput(INPUT_A1 + i, string::f("Operator #%d Attack Rate", i + 1)); + configInput(INPUT_D1 + i, string::f("Operator #%d Decay Rate", i + 1)); + configInput(INPUT_S1 + i, string::f("Operator #%d Sustain Level", i + 1)); + configInput(INPUT_R1 + i, string::f("Operator #%d Release Rate", i + 1)); + configInput(INPUT_T1 + i, string::f("Operator #%d Total Level", i + 1)); + configOutput(OUTPUT_1 + i, string::f("Operator #%d", i + 1)); + configLight(LIGHT_A1 + i, string::f("Operator #%d Attack Phase", i + 1)); + configLight(LIGHT_D1 + i, string::f("Operator #%d Decay Phase", i + 1)); + configLight(LIGHT_S1 + i, string::f("Operator #%d Sustain Phase", i + 1)); + configLight(LIGHT_R1 + i, string::f("Operator #%d Release Phase", i + 1)); } + configInput(INPUT_TRIGGER, "Trigger"); + configInput(INPUT_GATE, "Gate"); } dsp::SchmittTrigger trigger; @@ -57,16 +70,16 @@ struct EN_104 : Module { __m128 release; __m128 phase = _mm_set_ps1(0.0f); __m128 total; - void process(const ProcessArgs &args) override; - void getParams(const ProcessArgs &args); -}; - -void EN_104::getParams(const ProcessArgs &args) { alignas(16) float a[4]; alignas(16) float d[4]; alignas(16) float s[4]; alignas(16) float r[4]; alignas(16) float t[4]; + void process(const ProcessArgs &args) override; + void getParams(const ProcessArgs &args); +}; + +void EN_104::getParams(const ProcessArgs &args) { float delta = args.sampleTime * 0.1f; for (unsigned int i = 0; i < 4; i++) { a[i] = clamp(params[PARAM_A1 + i].getValue() + inputs[INPUT_A1 + i].getVoltage() * 0.1f, 0.0f, 1.0f); @@ -94,6 +107,8 @@ void EN_104::getParams(const ProcessArgs &args) { void EN_104::process(const ProcessArgs &args) { alignas(16) float v[4]; + alignas(16) float p[4]; + alignas(16) float l[4]; if (!skipParams++) { getParams(args); } @@ -109,6 +124,12 @@ void EN_104::process(const ProcessArgs &args) { triggered = gate.process(rescale(gateVal, 2.4f, 2.5f, 0.0f, 1.0f)); } if (gated) { + // Gate is open + // minGate is the comparison level for sustain, either the sustain level, or current level if already below. + // set the phase to Attack if triggered + // add the attack rate if in the Attack phase, else add the decay rate + // set the phase to decay if we have reached the peak. + // set the level between 1 and minGate (because the gate is open and we are sustaining) __m128 minGate = _mm_min_ps(level, sustain); phase = _mm_or_ps(phase, _mm_castsi128_ps(_mm_set1_epi8(triggered * 255))); level = _mm_add_ps(level, _mm_and_ps(phase, attack)); @@ -116,9 +137,23 @@ void EN_104::process(const ProcessArgs &args) { phase = _mm_and_ps(phase, _mm_cmpge_ps(_mm_set_ps1(1.0f), level)); level = _mm_min_ps(level, _mm_set_ps1(1.0f)); level = _mm_max_ps(level, _mm_andnot_ps(phase, minGate)); + _mm_store_ps(l, level); _mm_store_ps(v, _mm_mul_ps(_mm_mul_ps(level, total), voltage)); + _mm_store_ps(p, phase); + for (int i = 0; i < 4; i++) { + lights[LIGHT_A1 + i].setBrightness(p[i] != 0); + lights[LIGHT_D1 + i].setBrightness((p[i] == 0) && (l[i] > s[i])); + lights[LIGHT_S1 + i].setBrightness((p[i] == 0) && (l[i] <= s[i])); + lights[LIGHT_R1 + i].setBrightness(0); + outputs[OUTPUT_1 + i].setVoltage(v[i]); + } } else { + // Gate is closed + // set the phase to Attack if triggered + // add the attack rate if in the Attack phase, else add the release rate + // set the phase to Decay if we have reached the peak. + // set the level between 1 and 0. phase = _mm_or_ps(phase, _mm_castsi128_ps(_mm_set1_epi8(triggered * 255))); level = _mm_add_ps(level, _mm_and_ps(phase, attack)); level = _mm_sub_ps(level, _mm_andnot_ps(phase, release)); @@ -126,9 +161,14 @@ void EN_104::process(const ProcessArgs &args) { level = _mm_min_ps(level, _mm_set_ps1(1.0f)); level = _mm_max_ps(level, _mm_set_ps1(0.0f)); _mm_store_ps(v, _mm_mul_ps(_mm_mul_ps(level, total), voltage)); - } - for (int i = 0; i < 4; i++) { - outputs[OUTPUT_1 + i].setVoltage(v[i]); + _mm_store_ps(p, phase); + for (int i = 0; i < 4; i++) { + lights[LIGHT_A1 + i].setBrightness(p[i] != 0); + lights[LIGHT_D1 + i].setBrightness(0); + lights[LIGHT_S1 + i].setBrightness(0); + lights[LIGHT_R1 + i].setBrightness(p[i] == 0 && v[i] != 0); + outputs[OUTPUT_1 + i].setVoltage(v[i]); + } } } @@ -153,10 +193,10 @@ struct EN104 : SchemeModuleWidget { addInput(createInputCentered(Vec(75, 137 + 70 * i), module, EN_104::INPUT_S1 + i)); addInput(createInputCentered(Vec(105, 137 + 70 * i), module, EN_104::INPUT_R1 + i)); addInput(createInputCentered(Vec(135, 137 + 70 * i), module, EN_104::INPUT_T1 + i)); - addChild(createLightCentered>(Vec(23, 80 + 70 * i), module, EN_104::LIGHT_A1 + i)); - addChild(createLightCentered>(Vec(53, 80 + 70 * i), module, EN_104::LIGHT_D1 + i)); - addChild(createLightCentered>(Vec(83, 80 + 70 * i), module, EN_104::LIGHT_S1 + i)); - addChild(createLightCentered>(Vec(113, 80 + 70 * i), module, EN_104::LIGHT_R1 + i)); + addChild(createLightCentered>(Vec(23, 150 + 70 * i), module, EN_104::LIGHT_A1 + i)); + addChild(createLightCentered>(Vec(53, 150 + 70 * i), module, EN_104::LIGHT_D1 + i)); + addChild(createLightCentered>(Vec(83, 150 + 70 * i), module, EN_104::LIGHT_S1 + i)); + addChild(createLightCentered>(Vec(113, 150 + 70 * i), module, EN_104::LIGHT_R1 + i)); } } void render(NVGcontext *vg, SchemeCanvasWidget *canvas) override { diff --git a/src/EO1.cpp b/src/EO1.cpp old mode 100755 new mode 100644 index 942ef3d3..be895f09 --- a/src/EO1.cpp +++ b/src/EO1.cpp @@ -58,19 +58,22 @@ struct EO_102 : Module { EO_102() : Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); for (unsigned int i = 0; i < 2; i++) { - configParam(PARAM_MODE_1 + i, 0.0f, 1.0f, 0.0f, string::f("Channel %c display mode", 'A' + (unsigned char)i)); + configSwitch(PARAM_MODE_1 + i, 0.0f, 1.0f, 0.0f, string::f("Channel %c display mode", 'A' + (unsigned char)i), { "Signal", "Envelope" }); configParam(PARAM_OFFSET_1 + i, -10.0f, 10.0f, 0.0f, string::f("Channel %c offset", 'A' + (unsigned char)i)); configParam(PARAM_SCALE_1 + i, -5.0f, 5.0f, 0.0f, string::f("Channel %c scale", 'A' + (unsigned char)i)); + configInput(INPUT_1 + i, string::f("Channel %c signal", 'A' + (unsigned char)i)); } configParam(PARAM_TIME, -6.0f, -16.0f, -14.0f, "Time base"); configParam(PARAM_PRE, 0.0f, 1.0f * PRE_SIZE, 0.0f, "Pre-trigger buffer size"); configParam(PARAM_TRIGGER, -10.0f, 10.0f, 0.0f, "Trigger level"); - configParam(PARAM_RUNMODE, 0.0f, 1.0f, 0.0f, "One-shot mode"); - configParam(PARAM_RUN, 0.0f, 1.0f, 1.0f, "Run"); + configSwitch(PARAM_RUNMODE, 0.0f, 1.0f, 0.0f, "One-shot mode", { "Continuous", "One-Shot" }); + configSwitch(PARAM_RUN, 0.0f, 1.0f, 1.0f, "Run", { "Stopped", "Running" }); configParam(PARAM_INDEX_1, 0.0f, 1.0f, 0.0f, "Left index position"); configParam(PARAM_INDEX_2, 0.0f, 1.0f, 1.0f, "Right index position"); configParam(PARAM_INDEX_3, 0.0f, 1.0f, 0.2f, "Horizontal index position"); - configParam(PARAM_COLORS, 0.0f, 1.0f, 0.0f, "Match cable colors"); + configSwitch(PARAM_COLORS, 0.0f, 1.0f, 0.0f, "Match cable colors", { "Off", "On" }); + configInput(INPUT_EXT, "External Trigger"); + configLight(LIGHT_TRIGGER, "Trigger"); } void startFrame() { @@ -180,7 +183,7 @@ struct EO_102 : Module { namespace { - struct EO_Display : LightWidget { + struct EO_Display : Widget { EO_102 *module; PortWidget *ports[2]; @@ -315,35 +318,38 @@ namespace { nvgStroke(vg); } - void draw(const DrawArgs &args) override { - if (!module) { - drawEasterEgg(args.vg); - return; - } - NVGcolor col = SUBLIGHTBLUETRANS; - for (int i = 0; i < 2; i++) { - if (module->inputs[EO_102::INPUT_1 + i].isConnected()) { - if (module->params[EO_102::PARAM_COLORS].getValue()) { - col = APP->scene->rack->getTopCable(ports[i])->color; - col.a = 1.0f; + void drawLayer(const DrawArgs &args, int layer) override { + if (layer == 1) { + if (!module) { + drawEasterEgg(args.vg); + return; + } + NVGcolor col = SUBLIGHTBLUETRANS; + for (int i = 0; i < 2; i++) { + if (module->inputs[EO_102::INPUT_1 + i].isConnected()) { + if (module->params[EO_102::PARAM_COLORS].getValue()) { + col = APP->scene->rack->getTopCable(ports[i])->color; + col.a = 1.0f; + } + drawTrace(args.vg, module->buffer[i], module->params[EO_102::PARAM_OFFSET_1 + i].getValue(), module->params[EO_102::PARAM_SCALE_1 + i].getValue(), col, module->traceMode[i]); } - drawTrace(args.vg, module->buffer[i], module->params[EO_102::PARAM_OFFSET_1 + i].getValue(), module->params[EO_102::PARAM_SCALE_1 + i].getValue(), col, module->traceMode[i]); + col = SUBLIGHTREDTRANS; } - col = SUBLIGHTREDTRANS; + drawIndex(args.vg, clamp(module->params[EO_102::PARAM_INDEX_1].getValue(), 0.0f, 1.0f)); + drawIndex(args.vg, clamp(module->params[EO_102::PARAM_INDEX_2].getValue(), 0.0f, 1.0f)); + drawIndexV(args.vg, clamp(module->params[EO_102::PARAM_INDEX_3].getValue(), 0.0f, 1.0f)); + if (module->inputs[EO_102::INPUT_EXT].isConnected()) + drawTrigger(args.vg, module->params[EO_102::PARAM_TRIGGER].getValue(), 0.0f, 1.0f); + else + drawTrigger(args.vg, module->params[EO_102::PARAM_TRIGGER].getValue(), module->params[EO_102::PARAM_OFFSET_1].getValue(), module->params[EO_102::PARAM_SCALE_1].getValue()); + drawMask(args.vg, clamp(module->params[EO_102::PARAM_PRE].getValue(), 0.0f, 1.0f * PRE_SIZE) / BUFFER_SIZE); + drawPre(args.vg, 1.0f * module->preCount / BUFFER_SIZE); } - drawIndex(args.vg, clamp(module->params[EO_102::PARAM_INDEX_1].getValue(), 0.0f, 1.0f)); - drawIndex(args.vg, clamp(module->params[EO_102::PARAM_INDEX_2].getValue(), 0.0f, 1.0f)); - drawIndexV(args.vg, clamp(module->params[EO_102::PARAM_INDEX_3].getValue(), 0.0f, 1.0f)); - if (module->inputs[EO_102::INPUT_EXT].isConnected()) - drawTrigger(args.vg, module->params[EO_102::PARAM_TRIGGER].getValue(), 0.0f, 1.0f); - else - drawTrigger(args.vg, module->params[EO_102::PARAM_TRIGGER].getValue(), module->params[EO_102::PARAM_OFFSET_1].getValue(), module->params[EO_102::PARAM_SCALE_1].getValue()); - drawMask(args.vg, clamp(module->params[EO_102::PARAM_PRE].getValue(), 0.0f, 1.0f * PRE_SIZE) / BUFFER_SIZE); - drawPre(args.vg, 1.0f * module->preCount / BUFFER_SIZE); + Widget::drawLayer(args, layer); } }; - struct EO_Measure : LightWidget { + struct EO_Measure : Widget { EO_102 *module; char measureText[41] = ""; NVGcolor col; @@ -351,13 +357,16 @@ namespace { virtual void updateText() { } - void draw(const DrawArgs &args) override { - updateText(); - nvgFontSize(args.vg, 14); - nvgFontFaceId(args.vg, gScheme.font()->handle); - nvgFillColor(args.vg, col); - nvgTextAlign(args.vg, NVG_ALIGN_CENTER); - nvgText(args.vg, box.size.x / 2, 12, measureText, NULL); + void drawLayer(const DrawArgs &args, int layer) override { + if (layer == 1) { + updateText(); + nvgFontSize(args.vg, 14); + nvgFontFaceId(args.vg, gScheme.font()->handle); + nvgFillColor(args.vg, col); + nvgTextAlign(args.vg, NVG_ALIGN_CENTER); + nvgText(args.vg, box.size.x / 2, 12, measureText, NULL); + } + Widget::drawLayer(args, layer); } }; diff --git a/src/FF1.cpp b/src/FF1.cpp old mode 100755 new mode 100644 index 8a4348aa..4907160b --- a/src/FF1.cpp +++ b/src/FF1.cpp @@ -6,8 +6,6 @@ template struct FF_1 : DS_Module { - int doResetFlag = 0; - int doRandomFlag = 0; enum ParamIds { NUM_PARAMS }; @@ -28,11 +26,13 @@ struct FF_1 : DS_Module { FF_1() : DS_Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + configInput(INPUT, "Clock"); + for (int i = 0; i < deviceCount; i++) { + configOutput(OUTPUT_1 + i, "Signal " + std::to_string(i + 1)); + } } void process(const ProcessArgs &args) override { - if (doResetFlag) doReset(); - if (doRandomFlag) doRandomize(); if (inputs[INPUT].isConnected()) { if (schmittTrigger[0].redge(this, inputs[INPUT].getVoltage())) state[0] = !state[0]; @@ -44,8 +44,7 @@ struct FF_1 : DS_Module { outputs[OUTPUT_1 + i].setVoltage(state[i]?voltage1:voltage0); } } - void doRandomize() { - doRandomFlag = 0; + void onRandomize() override { std::default_random_engine generator(std::chrono::system_clock::now().time_since_epoch().count()); std::uniform_int_distribution distribution(0,1); state[0] = distribution(generator); @@ -56,32 +55,13 @@ struct FF_1 : DS_Module { outputs[OUTPUT_1 + i].setVoltage(state[i]?voltage1:voltage0); } } - void doReset() { - doResetFlag = 0; + void onReset() override { for (int i = 0; i < deviceCount; i++) { state[i] = 0; if (i) schmittTrigger[i].reset(); outputs[OUTPUT_1 + i].setVoltage(voltage0); } } - void onRandomize() override { - if (APP->engine->isPaused()) { - doRandomize(); - } - else { - doResetFlag = 0; - doRandomFlag = 1; - } - } - void onReset() override { - if (APP->engine->isPaused()) { - doReset(); - } - else { - doRandomFlag = 0; - doResetFlag = 1; - } - } }; struct FF110 : SchemeModuleWidget { diff --git a/src/FF2.cpp b/src/FF2.cpp old mode 100755 new mode 100644 index bd9c810b..e0321959 --- a/src/FF2.cpp +++ b/src/FF2.cpp @@ -6,8 +6,6 @@ template struct FF_2 : DS_Module { - int doResetFlag = 0; - int doRandomFlag = 0; enum ParamIds { NUM_PARAMS }; @@ -28,10 +26,12 @@ struct FF_2 : DS_Module { FF_2() : DS_Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + for (int i = 0; i < x; i++) { + configInput(INPUT_1 + i, "Clock " + std::to_string(i + 1)); + configOutput(OUTPUT_1 + i, "Cascaded Signal " + std::to_string(i + 1)); + } } void process(const ProcessArgs &args) override { - if (doResetFlag) doReset(); - if (doRandomFlag) doRandomize(); for (int i = 0; i < x; i++) { if (inputs[INPUT_1 + i].isConnected()) { if (schmittTrigger[i].redge(this, inputs[INPUT_1 + i].getVoltage())) @@ -46,8 +46,7 @@ struct FF_2 : DS_Module { outputs[OUTPUT_1 + i].setVoltage(state[i]?voltage1:voltage0); } } - void doRandomize() { - doRandomFlag = 0; + void onRandomize() override { std::default_random_engine generator(std::chrono::system_clock::now().time_since_epoch().count()); std::uniform_int_distribution distribution(0,1); for (int i = 0; i < x; i++) { @@ -56,32 +55,13 @@ struct FF_2 : DS_Module { outputs[OUTPUT_1 + i].setVoltage(state[i]?voltage1:voltage0); } } - void doReset() { - doResetFlag = 0; + void onReset() override { for (int i = 0; i < x; i++) { state[i] = 0; if (!inputs[INPUT_1 + i].isConnected()) schmittTrigger[i].reset(); outputs[OUTPUT_1 + i].setVoltage(voltage0); } } - void onRandomize() override { - if (APP->engine->isPaused()) { - doRandomize(); - } - else { - doResetFlag = 0; - doRandomFlag = 1; - } - } - void onReset() override { - if (APP->engine->isPaused()) { - doReset(); - } - else { - doRandomFlag = 0; - doResetFlag = 1; - } - } }; struct FF206 : SchemeModuleWidget { diff --git a/src/HS1.cpp b/src/HS1.cpp old mode 100755 new mode 100644 index 108e7b27..cf66c6fe --- a/src/HS1.cpp +++ b/src/HS1.cpp @@ -46,12 +46,16 @@ struct HS_101 : Module { HS_101() : Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); configParam(PARAM_TIME, -10.0f, 6.0f, -4.0f, "Time base", "s", 2.0f); - configParam(PARAM_RUN, 0.0f, 1.0f, 1.0f, "Run"); + configSwitch(PARAM_RUN, 0, 1, 1, "Run", { "Stopped", "Running" }); configParam(PARAM_X_PAN, 0.0f, 1.0f, 0.5f, "X Pan", "%", 0.0f, 100.0f); configParam(PARAM_X_SCALE, 0.0f, +18.0f, 0.0f, "X Zoom", "x", 2.0f); configParam(PARAM_Y_PAN, 0.0f, 1.0f, 0.5f, "Y Pan", "%", 0.0f, 100.0f); configParam(PARAM_Y_SCALE, 0.0f, +20.0f, 0.0f, "Y Zoom", "x", 2.0f); - configParam(PARAM_COLORS, 0.0f, 1.0f, 0.0f, "Match cable colors"); + configSwitch(PARAM_COLORS, 0.0f, 1.0f, 0.0f, "Match cable colors", { "Off", "On" }); + configInput(INPUT_1, "Signal"); + configInput(INPUT_TRIGGER, "Trigger"); + configOutput(OUTPUT_TRIGGER, "Trigger"); + configLight(LIGHT_STORING, "Storing"); } ~HS_101() { @@ -153,7 +157,8 @@ struct HS_101 : Module { namespace { - struct HS_DisplayLight : LightWidget { + struct HS_Display : OpaqueWidget { + ui::Tooltip *tooltip = NULL; HS_101 *module; PortWidget *port; int minX, maxX; @@ -161,20 +166,23 @@ namespace { float minY, maxY; int mipEntry = -1; - void draw(const DrawArgs &args) override { - if (!module) { - drawEasterEgg(args.vg); - return; - } - if (!module->dataCaptured) { - return; - } - NVGcolor col = SUBLIGHTBLUETRANS; - if (module->params[HS_101::PARAM_COLORS].getValue()) { - col = APP->scene->rack->getTopCable(port)->color; - col.a = 1.0f; + void drawLayer(const DrawArgs &args, int layer) override { + if (layer == 1) { + if (!module) { + drawEasterEgg(args.vg); + return; + } + if (!module->dataCaptured) { + return; + } + NVGcolor col = SUBLIGHTBLUETRANS; + if (module->params[HS_101::PARAM_COLORS].getValue()) { + col = APP->scene->rack->getTopCable(port)->color; + col.a = 1.0f; + } + drawTrace(args.vg, col, module->buffer, module->bufferCount); } - drawTrace(args.vg, col, module->buffer, module->bufferCount); + Widget::drawLayer(args, layer); } void drawTrace(NVGcontext *vg, NVGcolor col, float *values, int bufferSize) { @@ -265,12 +273,6 @@ namespace { nvgStrokeColor(vg, SUBLIGHTBLUETRANS); nvgStroke(vg); } - }; - - struct HS_Display : OpaqueWidget { - HS_DisplayLight *light; - ui::Tooltip *tooltip = NULL; - void setTooltip(ui::Tooltip *tooltip) { if (this->tooltip) { this->tooltip->requestDelete(); @@ -282,9 +284,9 @@ namespace { } } void onEnter(const event::Enter& e) override { - if (light->module) { + if (module) { std::string text; - text = light->module->dataCaptured?"":"No Data"; + text = module->dataCaptured?"":"No Data"; ui::Tooltip *tooltip = new ui::Tooltip; tooltip->text = text; setTooltip(tooltip); @@ -311,22 +313,22 @@ namespace { return string::f("%6.3f", input); } void onHover(const event::Hover& e) override { - if (light->module) { - if (light->module->dataCaptured) { + if (module) { + if (module->dataCaptured) { if (tooltip) { - float voltage = rescale(e.pos.y, box.size.y - 2, 2, light->minY, light->maxY); - int sample = rescale(e.pos.x, 0, box.size.x, light->originalMinX, light->originalMaxX); - float time = rescale(sample, 0, light->module->bufferCount, 0, light->module->time); - int mipSample = rescale(e.pos.x, 0, box.size.x, light->minX, light->maxX); + float voltage = rescale(e.pos.y, box.size.y - 2, 2, minY, maxY); + int sample = rescale(e.pos.x, 0, box.size.x, originalMinX, originalMaxX); + float time = rescale(sample, 0, module->bufferCount, 0, module->time); + int mipSample = rescale(e.pos.x, 0, box.size.x, minX, maxX); std::string text; - if (light->mipEntry == -1) { - float voltageAtSample = light->module->buffer[sample]; + if (mipEntry == -1) { + float voltageAtSample = module->buffer[sample]; text = "Sampled Voltage: " + scale(voltageAtSample) + "V"; } else { - float minVoltage = light->module->mipEntries[light->mipEntry][mipSample * 2]; - float maxVoltage = light->module->mipEntries[light->mipEntry][mipSample * 2 + 1]; + float minVoltage = module->mipEntries[mipEntry][mipSample * 2]; + float maxVoltage = module->mipEntries[mipEntry][mipSample * 2 + 1]; text = "Signal Voltage: " + scale(minVoltage) + "V - " + scale(maxVoltage) + "V"; } text = "Voltage: " + scale(voltage) + "V\n" + @@ -348,44 +350,47 @@ namespace { } }; - struct HS_Info : LightWidget { + struct HS_Info : Widget { HS_101 *module; HS_Display *display; - void draw(const DrawArgs &args) override { - nvgFontSize(args.vg, 12); - nvgFontFaceId(args.vg, gScheme.font()->handle); - nvgFillColor(args.vg, SUBLIGHTBLUE); - nvgTextAlign(args.vg, NVG_ALIGN_LEFT | NVG_ALIGN_BASELINE); - if (!module) { - nvgFontSize(args.vg, 18); - nvgText(args.vg, 2, 12, "Submarine", NULL); - nvgText(args.vg, 2, 24, "High Resolution", NULL); - nvgText(args.vg, 2, 36, "Storage Scope", NULL); - return; - } - - if (module->running) { - int percentage = (100 * module->bufferIndex) / module->bufferCount; - nvgText(args.vg, 2, 12, string::f("Storing %d%%", percentage).c_str(), NULL); - } - else { - if (module->dataCaptured) { - nvgText(args.vg, 2, 12, "Stored", NULL); + void drawLayer(const DrawArgs &args, int layer) override { + if (layer == 1) { + nvgFontSize(args.vg, 12); + nvgFontFaceId(args.vg, gScheme.font()->handle); + nvgFillColor(args.vg, SUBLIGHTBLUE); + nvgTextAlign(args.vg, NVG_ALIGN_LEFT | NVG_ALIGN_BASELINE); + if (!module) { + nvgFontSize(args.vg, 18); + nvgText(args.vg, 2, 12, "Submarine", NULL); + nvgText(args.vg, 2, 24, "High Resolution", NULL); + nvgText(args.vg, 2, 36, "Storage Scope", NULL); + return; + } + + if (module->running) { + int percentage = (100 * module->bufferIndex) / module->bufferCount; + nvgText(args.vg, 2, 12, string::f("Storing %d%%", percentage).c_str(), NULL); } else { - nvgText(args.vg, 2, 12, "No Data", NULL); + if (module->dataCaptured) { + nvgText(args.vg, 2, 12, "Stored", NULL); + } + else { + nvgText(args.vg, 2, 12, "No Data", NULL); + } } + nvgText(args.vg, 2, 24, string::f("%.3fs", module->time).c_str(), NULL); + if (std::isfinite(module->minValue)) + nvgText(args.vg, 2, 36, string::f("min %.3fV", module->minValue).c_str(), NULL); + nvgTextAlign(args.vg, NVG_ALIGN_RIGHT | NVG_ALIGN_BASELINE); + if (display->mipEntry > -1) { + nvgText(args.vg, box.size.x -2, 12, string::f("Mipped %dx", 4 << (2 * display->mipEntry)).c_str(), NULL); + } + nvgText(args.vg, box.size.x - 2, 24, string::f("%.3fMb", module->bufferSize / 1000000.0f).c_str(), NULL); + if (std::isfinite(module->maxValue)) + nvgText(args.vg, box.size.x - 2, 36, string::f("max %.3fV", module->maxValue).c_str(), NULL); } - nvgText(args.vg, 2, 24, string::f("%.3fs", module->time).c_str(), NULL); - if (std::isfinite(module->minValue)) - nvgText(args.vg, 2, 36, string::f("min %.3fV", module->minValue).c_str(), NULL); - nvgTextAlign(args.vg, NVG_ALIGN_RIGHT | NVG_ALIGN_BASELINE); - if (display->light->mipEntry > -1) { - nvgText(args.vg, box.size.x -2, 12, string::f("Mipped %dx", 4 << (2 * display->light->mipEntry)).c_str(), NULL); - } - nvgText(args.vg, box.size.x - 2, 24, string::f("%.3fMb", module->bufferSize / 1000000.0f).c_str(), NULL); - if (std::isfinite(module->maxValue)) - nvgText(args.vg, box.size.x - 2, 36, string::f("max %.3fV", module->maxValue).c_str(), NULL); + Widget::drawLayer(args, layer); } }; @@ -398,17 +403,11 @@ struct HS101 : SchemeModuleWidget { this->box.size = Vec(450, 380); addChild(new SchemePanel(this->box.size)); - HS_DisplayLight *light = new HS_DisplayLight(); - light->module = module; - light->box.pos = Vec(2.5, 14); - light->box.size = Vec(445, 310); - HS_Display *display = new HS_Display(); - display->light = light; + display->module = module; display->box.pos = Vec(2.5, 14); display->box.size = Vec(445, 310); addChild(display); - addChild(light); HS_Info *info = new HS_Info(); info->module = module; @@ -419,7 +418,7 @@ struct HS101 : SchemeModuleWidget { PortWidget *port = createInputCentered(Vec(17, 341), module, HS_101::INPUT_1); addInput(port); - light->port = port; + display->port = port; addInput(createInputCentered(Vec(47, 341), module, HS_101::INPUT_TRIGGER)); addOutput(createOutputCentered(Vec(72, 341), module, HS_101::OUTPUT_TRIGGER)); diff --git a/src/LA1.cpp b/src/LA1.cpp old mode 100755 new mode 100644 index 9e14d496..259ae1eb --- a/src/LA1.cpp +++ b/src/LA1.cpp @@ -60,15 +60,33 @@ struct LA_108 : DS_Module { LA_108() : DS_Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); - configParam(PARAM_TRIGGER, 0.0f, 8.0f, 0.0f, "Trigger input", "", 0.f, 1.f, 1.f); - configParam(PARAM_EDGE, 0.0f, 1.0f, 0.0f, "Trigger on falling edge"); - configParam(PARAM_RUN, 0.0f, 1.0f, 0.0f, "One shot mode"); - configParam(PARAM_RESET, 0.0f, 1.0f, 0.0f, "Reset"); - configParam(PARAM_TIME, -2.0f, -16.0f, -14.0f, "Time base"); - configParam(PARAM_INDEX_1, 0.0f, 1.0f, 0.0f, "Left index position"); - configParam(PARAM_INDEX_2, 0.0f, 1.0f, 1.0f, "Right index position"); - configParam(PARAM_PRE, 0.0f, 32.0f, 0.0f, "Pre-trigger buffer size"); - configParam(PARAM_COLORS, 0.0f, 1.0f, 0.0f, "Match cable colors"); + configSwitch(PARAM_TRIGGER, 0, 8, 0, "Trigger Input", { "Signal 1", "Signal 2", "Signal 3", "Signal 4", "Signal 5", "Signal 6", "Signal 7", "Signal 8", "External" }); + configSwitch(PARAM_EDGE, 0, 1, 0, "Trigger on", { "Rising Edge", "Falling Edge" }); + configSwitch(PARAM_RUN, 0, 1, 0, "Trigger Mode", { "Continuous", "One-Shot" }); + configSwitch(PARAM_RESET, 0, 1, 0, "Reset", { "Off", "Waiting" }); + configParam(PARAM_TIME, -2.0f, -16.0f, -14.0f, "Time Base", " Samples per point", 2.0f, 65536, 0.0f); + configParam(PARAM_INDEX_1, 0.0f, 1.0f, 0.0f, "Left Index Position", "%", 0.0f, 100.0f, 0.0f); + configParam(PARAM_INDEX_2, 0.0f, 1.0f, 1.0f, "Right Index Position", "%", 0.0f, 100.0f, 0.0f); + configParam(PARAM_PRE, 0.0f, 32.0f, 0.0f, "Pre-trigger Buffer Size", " Points"); + configSwitch(PARAM_COLORS, 0, 1, 0, "Match cable colors", { "Off", "On" }); + configInput(INPUT_1, "Signal 1"); + configInput(INPUT_2, "Signal 2"); + configInput(INPUT_3, "Signal 3"); + configInput(INPUT_4, "Signal 4"); + configInput(INPUT_5, "Signal 5"); + configInput(INPUT_6, "Signal 6"); + configInput(INPUT_7, "Signal 7"); + configInput(INPUT_8, "Signal 8"); + configInput(INPUT_EXT, "External Trigger"); + configLight(LIGHT_1, "Trigger on Signal 1"); + configLight(LIGHT_2, "Trigger on Signal 2"); + configLight(LIGHT_3, "Trigger on Signal 3"); + configLight(LIGHT_4, "Trigger on Signal 4"); + configLight(LIGHT_5, "Trigger on Signal 5"); + configLight(LIGHT_6, "Trigger on Signal 6"); + configLight(LIGHT_7, "Trigger on Signal 7"); + configLight(LIGHT_8, "Trigger on Signal 8"); + configLight(LIGHT_EXT, "Trigger on External Signal"); } void startFrame() { @@ -163,7 +181,7 @@ struct LA_108 : DS_Module { }; namespace { - struct LA_Display : LightWidget { + struct LA_Display : Widget { LA_108 *module; PortWidget *ports[8]; @@ -266,21 +284,24 @@ namespace { nvgFill(vg); } - void draw(const DrawArgs &args) override { + void drawLayer(const DrawArgs &args, int layer) override { if (!module) { drawEasterEgg(args.vg); return; } - for (int i = 0; i < 8; i++) { - if (module->inputs[LA_108::INPUT_1 + i].isConnected()) { - NVGcolor col = getColor(i); - drawTrace(args.vg, module->buffer[i], 32.5f + 35 * i, col); + if (layer == 1) { + for (int i = 0; i < 8; i++) { + if (module->inputs[LA_108::INPUT_1 + i].isConnected()) { + NVGcolor col = getColor(i); + drawTrace(args.vg, module->buffer[i], 32.5f + 35 * i, col); + } } + drawIndex(args.vg, clamp(module->params[LA_108::PARAM_INDEX_1].getValue(), 0.0f, 1.0f)); + drawIndex(args.vg, clamp(module->params[LA_108::PARAM_INDEX_2].getValue(), 0.0f, 1.0f)); + drawMask(args.vg, clamp(module->params[LA_108::PARAM_PRE].getValue(), 0.0f, 32.0f) / BUFFER_SIZE); + drawPre(args.vg, 1.0f * module->preCount / BUFFER_SIZE); } - drawIndex(args.vg, clamp(module->params[LA_108::PARAM_INDEX_1].getValue(), 0.0f, 1.0f)); - drawIndex(args.vg, clamp(module->params[LA_108::PARAM_INDEX_2].getValue(), 0.0f, 1.0f)); - drawMask(args.vg, clamp(module->params[LA_108::PARAM_PRE].getValue(), 0.0f, 32.0f) / BUFFER_SIZE); - drawPre(args.vg, 1.0f * module->preCount / BUFFER_SIZE); + Widget::drawLayer(args, layer); } NVGcolor getColor(int i) { @@ -292,42 +313,42 @@ namespace { } }; - struct LA_Measure : LightWidget { + struct LA_Measure : Widget { LA_108 *module; char measureText[41]; - void draw(const DrawArgs &args) override { - if (!module) { - return; + void drawLayer(const DrawArgs &args, int layer) override { + if (module && (layer == 1)) { + float deltaTime = powf(2.0f, module->params[LA_108::PARAM_TIME].getValue()); + int frameCount = (int)ceilf(deltaTime * APP->engine->getSampleRate()); + frameCount *= BUFFER_SIZE; + float width = (float)frameCount * fabs(module->params[LA_108::PARAM_INDEX_1].getValue() - module->params[LA_108::PARAM_INDEX_2].getValue()) / APP->engine->getSampleRate(); + + if (width < 0.00000995f) + sprintf(measureText, "%4.3f\xc2\xb5s", width * 1000000.0f); + else if (width < 0.0000995f) + sprintf(measureText, "%4.2f\xc2\xb5s", width * 1000000.0f); + else if (width < 0.000995f) + sprintf(measureText, "%4.1f\xc2\xb5s", width * 1000000.0f); + else if (width < 0.00995f) + sprintf(measureText, "%4.3fms", width * 1000.0f); + else if (width < 0.0995f) + sprintf(measureText, "%4.2fms", width * 1000.0f); + else if (width < 0.995f) + sprintf(measureText, "%4.1fms", width * 1000.0f); + else if (width < 9.95f) + sprintf(measureText, "%4.3fs", width); + else if (width < 99.5f) + sprintf(measureText, "%4.2fs", width); + else + sprintf(measureText, "%4.1fs", width); + nvgFontSize(args.vg, 14); + nvgFontFaceId(args.vg, gScheme.font()->handle); + nvgFillColor(args.vg, SUBLIGHTBLUE); + nvgTextAlign(args.vg, NVG_ALIGN_CENTER); + nvgText(args.vg, 27, 12, measureText, NULL); } - float deltaTime = powf(2.0f, module->params[LA_108::PARAM_TIME].getValue()); - int frameCount = (int)ceilf(deltaTime * APP->engine->getSampleRate()); - frameCount *= BUFFER_SIZE; - float width = (float)frameCount * fabs(module->params[LA_108::PARAM_INDEX_1].getValue() - module->params[LA_108::PARAM_INDEX_2].getValue()) / APP->engine->getSampleRate(); - - if (width < 0.00000995f) - sprintf(measureText, "%4.3f\xc2\xb5s", width * 1000000.0f); - else if (width < 0.0000995f) - sprintf(measureText, "%4.2f\xc2\xb5s", width * 1000000.0f); - else if (width < 0.000995f) - sprintf(measureText, "%4.1f\xc2\xb5s", width * 1000000.0f); - else if (width < 0.00995f) - sprintf(measureText, "%4.3fms", width * 1000.0f); - else if (width < 0.0995f) - sprintf(measureText, "%4.2fms", width * 1000.0f); - else if (width < 0.995f) - sprintf(measureText, "%4.1fms", width * 1000.0f); - else if (width < 9.95f) - sprintf(measureText, "%4.3fs", width); - else if (width < 99.5f) - sprintf(measureText, "%4.2fs", width); - else - sprintf(measureText, "%4.1fs", width); - nvgFontSize(args.vg, 14); - nvgFontFaceId(args.vg, gScheme.font()->handle); - nvgFillColor(args.vg, SUBLIGHTBLUE); - nvgTextAlign(args.vg, NVG_ALIGN_CENTER); - nvgText(args.vg, 27, 12, measureText, NULL); + Widget::drawLayer(args, layer); } }; diff --git a/src/LA2.cpp b/src/LA2.cpp new file mode 100644 index 00000000..41ca78eb --- /dev/null +++ b/src/LA2.cpp @@ -0,0 +1,503 @@ +//SubTag DS W22 + +/* Portions of this code derive from Fundamental/src/Scope.cpp - Copyright © 2016 by Andrew Belt */ +#include +#include "shared/DS.hpp" + +#define BUFFER_SIZE 512 + +struct LA_216 : DS_Module { + enum ParamIds { + PARAM_TRIGGER, + PARAM_EDGE, + PARAM_TIME, + PARAM_INDEX_1, + PARAM_INDEX_2, + PARAM_RUN, + PARAM_RESET, + PARAM_PRE, + PARAM_COLORS, + NUM_PARAMS + }; + enum InputIds { + INPUT_1, + INPUT_2, + INPUT_EXT, + NUM_INPUTS + }; + enum OutputIds { + NUM_OUTPUTS + }; + enum LightIds { + LIGHT_1, + LIGHT_2 = LIGHT_1 + 16, + LIGHT_EXT = LIGHT_2 + 16, + NUM_LIGHTS + }; + + float buffer[32][BUFFER_SIZE] = {}; + int bufferIndex = 0; + float frameIndex = 0; + + float preBuffer[32][32] = {}; + int preBufferIndex = 0; + float preFrameIndex = 0; + int preCount = 0; + + DS_Schmitt trigger; + + LA_216() : DS_Module() { + config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + configSwitch(PARAM_TRIGGER, 0, 32, 0, "Trigger Input", { "Signal 1-1", "Signal 1-2", "Signal 1-3", "Signal 1-4", "Signal 1-5", "Signal 1-6", "Signal 1-7", "Signal 1-8", + "Signal 1-9", "Signal 1-10", "Signal 1-11", "Signal 1-12", "Signal 1-13", "Signal 1-14", "Signal 1-15", "Signal 1-16", + "Signal 2-1", "Signal 2-2", "Signal 2-3", "Signal 2-4", "Signal 2-5", "Signal 2-6", "Signal 2-7", "Signal 2-8", + "Signal 2-9", "Signal 2-10", "Signal 2-11", "Signal 2-12", "Signal 2-13", "Signal 2-14", "Signal 2-15", "Signal 2-16", + "External" }); + configSwitch(PARAM_EDGE, 0, 1, 0, "Trigger on", { "Rising Edge", "Falling Edge" }); + configSwitch(PARAM_RUN, 0, 1, 0, "Trigger Mode", { "Continuous", "One-Shot" }); + configSwitch(PARAM_RESET, 0, 1, 0, "Reset", { "Off", "Waiting" }); + configParam(PARAM_TIME, -2.0f, -16.0f, -14.0f, "Time Base", " Samples per point", 2.0f, 65536, 0.0f); + configParam(PARAM_INDEX_1, 0.0f, 1.0f, 0.0f, "Left Index Position", "%", 0.0f, 100.0f, 0.0f); + configParam(PARAM_INDEX_2, 0.0f, 1.0f, 1.0f, "Right Index Position", "%", 0.0f, 100.0f, 0.0f); + configParam(PARAM_PRE, 0.0f, 32.0f, 0.0f, "Pre-trigger Buffer Size", " Points"); + configSwitch(PARAM_COLORS, 0, 1, 0, "Match cable colors", { "Off", "On" }); + configInput(INPUT_1, "Signal 1"); + configInput(INPUT_2, "Signal 2"); + configInput(INPUT_EXT, "External Trigger"); + configLight(LIGHT_1 + 0, "Trigger on Signal 1-1"); + configLight(LIGHT_1 + 1, "Trigger on Signal 1-2"); + configLight(LIGHT_1 + 2, "Trigger on Signal 1-3"); + configLight(LIGHT_1 + 3, "Trigger on Signal 1-4"); + configLight(LIGHT_1 + 4, "Trigger on Signal 1-5"); + configLight(LIGHT_1 + 5, "Trigger on Signal 1-6"); + configLight(LIGHT_1 + 6, "Trigger on Signal 1-7"); + configLight(LIGHT_1 + 7, "Trigger on Signal 1-8"); + configLight(LIGHT_1 + 8, "Trigger on Signal 1-9"); + configLight(LIGHT_1 + 9, "Trigger on Signal 1-10"); + configLight(LIGHT_1 + 10, "Trigger on Signal 1-11"); + configLight(LIGHT_1 + 11, "Trigger on Signal 1-12"); + configLight(LIGHT_1 + 12, "Trigger on Signal 1-13"); + configLight(LIGHT_1 + 13, "Trigger on Signal 1-14"); + configLight(LIGHT_1 + 14, "Trigger on Signal 1-15"); + configLight(LIGHT_1 + 15, "Trigger on Signal 1-16"); + configLight(LIGHT_2 + 0, "Trigger on Signal 2-1"); + configLight(LIGHT_2 + 1, "Trigger on Signal 2-2"); + configLight(LIGHT_2 + 2, "Trigger on Signal 2-3"); + configLight(LIGHT_2 + 3, "Trigger on Signal 2-4"); + configLight(LIGHT_2 + 4, "Trigger on Signal 2-5"); + configLight(LIGHT_2 + 5, "Trigger on Signal 2-6"); + configLight(LIGHT_2 + 6, "Trigger on Signal 2-7"); + configLight(LIGHT_2 + 7, "Trigger on Signal 2-8"); + configLight(LIGHT_2 + 8, "Trigger on Signal 2-9"); + configLight(LIGHT_2 + 9, "Trigger on Signal 2-10"); + configLight(LIGHT_2 + 10, "Trigger on Signal 2-11"); + configLight(LIGHT_2 + 11, "Trigger on Signal 2-12"); + configLight(LIGHT_2 + 12, "Trigger on Signal 2-13"); + configLight(LIGHT_2 + 13, "Trigger on Signal 2-14"); + configLight(LIGHT_2 + 14, "Trigger on Signal 2-15"); + configLight(LIGHT_2 + 15, "Trigger on Signal 2-16"); + configLight(LIGHT_EXT, "Trigger on External Signal"); + } + + void startFrame() { + frameIndex = 0; + preCount = (int)(params[PARAM_PRE].getValue() + 0.5f); + if (preCount) { + for (int i = 0; i < 32; i++) { + for (int s = 0; s < preCount; s++) { + buffer[i][s] = preBuffer[i][(preBufferIndex + 64 - preCount + s) % 32]; + } + } + bufferIndex = preCount; + return; + } + bufferIndex = 0; + } + + void process(const ProcessArgs &args) override { + // Set trigger lights + for (int i = 0; i < 33; i++) + lights[LIGHT_1 + i].setBrightness(params[PARAM_TRIGGER].getValue() == i); + // Compute time + float deltaTime = powf(2.0f, params[PARAM_TIME].getValue()); + int frameCount = (int)ceilf(deltaTime * args.sampleRate); + + // Add frame to preBuffer + if (++preFrameIndex >= frameCount) { + preFrameIndex = 0; + for (int i = 0; i < 16; i++) { + preBuffer[i][preBufferIndex] = inputs[INPUT_1].getVoltage(i); + preBuffer[i + 16][preBufferIndex] = inputs[INPUT_2].getVoltage(i); + } + preBufferIndex++; + if (preBufferIndex >= 32) + preBufferIndex = 0; + } + + // Add frame to buffer + if (bufferIndex < BUFFER_SIZE) { + if (++frameIndex >= frameCount) { + frameIndex = 0; + for (int i = 0; i < 16; i++) { + buffer[i][bufferIndex] = inputs[INPUT_1].getVoltage(i); + buffer[i + 16][bufferIndex] = inputs[INPUT_2].getVoltage(i); + } + bufferIndex++; + } + } + + int triggerInput = (int)(clamp(params[PARAM_TRIGGER].getValue(), 0.0f, 32.0f)); + int triggerChannel = triggerInput % 16; + triggerInput = triggerInput / 16; + int edge = (params[PARAM_EDGE].getValue() > 0.5f); + + // Are we waiting on the next trigger? + if (bufferIndex >= BUFFER_SIZE) { + // Trigger immediately if nothing connected to trigger input + if (!inputs[triggerInput].isConnected()) { + startFrame(); + return; + } + if (inputs[triggerInput].getChannels() < (triggerChannel + 1)) { + startFrame(); + return; + } + + // Reset the Schmitt trigger so we don't trigger immediately if the input is high + if (frameIndex == 0) { + //trigger.set(edge); + } + frameIndex++; + + float gate = inputs[triggerInput].getVoltage(triggerChannel); + int triggered = trigger.edge(this, gate, edge); + + if (params[PARAM_RUN].getValue() < 0.5f) { // Continuous run mode + params[PARAM_RESET].setValue(0.0f); + // Reset if triggered + float holdTime = 0.1f; + if (triggered) { + startFrame(); + return; + } + + // Reset if we've waited too long + if (frameIndex >= args.sampleRate * holdTime) { + startFrame(); + return; + } + } + else { + if (params[PARAM_RESET].getValue() > 0.5f) { + if (triggered) { + startFrame(); + params[PARAM_RESET].setValue(0.0f); + return; + } + } + } + } + } +}; + +namespace { + struct LA_Display : Widget { + LA_216 *module; + PortWidget *ports[2]; + + void drawTrace(NVGcontext *vg, float *values, float offset, NVGcolor col) { + if (!values) + return; + nvgSave(vg); + Rect b = Rect(Vec(0, 0), box.size); + nvgScissor(vg, b.pos.x, b.pos.y, b.size.x, b.size.y); + nvgBeginPath(vg); + for (int i = 0; i < BUFFER_SIZE; i++) { + float x, y; + x = (float)i / (BUFFER_SIZE - 1) * b.size.x; + y = module->voltage0 -clamp(values[i], module->voltage0, module->voltage1); + y *= 20.0f / (module->voltage1 - module->voltage0); + y += offset; + if (i == 0) + nvgMoveTo(vg, x, y); + else + nvgLineTo(vg, x, y); + } + nvgStrokeColor(vg, col); + nvgLineCap(vg, NVG_ROUND); + nvgMiterLimit(vg, 2.0f); + nvgStrokeWidth(vg, 1.5f); + nvgGlobalCompositeOperation(vg, NVG_LIGHTER); + nvgStroke(vg); + nvgResetScissor(vg); + nvgRestore(vg); + } + + void drawIndex(NVGcontext *vg, float value) { + Rect b = Rect(Vec(0, 0), box.size); + nvgScissor(vg, b.pos.x, b.pos.y, b.size.x, b.size.y); + value = value * b.size.x; + + nvgStrokeColor(vg, nvgRGBA(0xff, 0xff, 0xff, 0x40)); + { + nvgBeginPath(vg); + nvgMoveTo(vg, value, 0); + nvgLineTo(vg, value, b.size.y); + nvgClosePath(vg); + } + nvgStroke(vg); + nvgResetScissor(vg); + } + + void drawPre(NVGcontext *vg, float value) { + if (value == 0.0f) + return; + Rect b = Rect(Vec(0, 0), box.size); + nvgScissor(vg, b.pos.x, b.pos.y, b.size.x, b.size.y); + value = value * b.size.x; + + nvgStrokeColor(vg, nvgRGBA(0xff, 0x40, 0x40, 0x80)); + { + nvgBeginPath(vg); + nvgMoveTo(vg, value, 0); + nvgLineTo(vg, value, b.size.y); + nvgClosePath(vg); + } + nvgStroke(vg); + nvgResetScissor(vg); + } + + void drawMask(NVGcontext *vg, float value) { + if (value == 0.0f) + return; + Rect b = Rect(Vec(0, 0), box.size); + nvgScissor(vg, b.pos.x, b.pos.y, b.size.x, b.size.y); + value = value * b.size.x; + + nvgFillColor(vg, nvgRGBA(0xff, 0x40, 0x40, 0x40)); + { + nvgBeginPath(vg); + nvgRect(vg, 0, 0, value, b.size.y); + nvgClosePath(vg); + } + nvgFill(vg); + nvgResetScissor(vg); + } + + void drawEasterEgg(NVGcontext *vg) { + nvgStrokeColor(vg, SUBLIGHTBLUE); + nvgStrokeWidth(vg, 1); + scheme::drawLogoPath(vg, 0, 1.0f, 1.333f, 0); + nvgStroke(vg); + scheme::drawLogoPath(vg, 14, 23.0f, 1.333f, 0); + nvgStroke(vg); + scheme::drawLogoPath(vg, 28, 45.0f, 1.333f, 0); + nvgStroke(vg); + scheme::drawLogoPath(vg, 42, 67.0f, 1.333f, 0); + nvgStroke(vg); + scheme::drawLogoPath(vg, 56, 89.0f, 1.333f, 0); + nvgStroke(vg); + scheme::drawLogoPath(vg, 70, 111.0f, 1.333f, 0); + nvgStroke(vg); + scheme::drawLogoPath(vg, 84, 133.0f, 1.333f, 0); + nvgStroke(vg); + scheme::drawLogoPath(vg, 98, 155.0f, 1.333f, 0); + nvgStroke(vg); + scheme::drawLogoPath(vg, 112, 177.0f, 1.333f, 0); + nvgStroke(vg); + scheme::drawLogoPath(vg, 126, 199.0f, 1.333f, 0); + nvgStroke(vg); + scheme::drawLogoPath(vg, 140, 221.0f, 1.333f, 0); + nvgStroke(vg); + scheme::drawLogoPath(vg, 154, 243.0f, 1.333f, 0); + nvgStroke(vg); + scheme::drawLogoPath(vg, 168, 265.0f, 1.333f, 0); + nvgStroke(vg); + scheme::drawLogoPath(vg, 182, 287.0f, 1.333f, 0); + nvgStroke(vg); + scheme::drawLogoPath(vg, 196, 309.0f, 1.333f, 0); + nvgStroke(vg); + scheme::drawLogoPath(vg, 210, 331.0f, 1.333f, 0); + nvgStroke(vg); + } + + void drawLayer(const DrawArgs &args, int layer) override { + if (!module) { + drawEasterEgg(args.vg); + return; + } + if (layer == 1) { + for (int i = 0; i < 2; i++) { + if (module->inputs[LA_216::INPUT_1 + i].isConnected()) { + NVGcolor col = getColor(i); + for (int c = 0; c < module->inputs[LA_216::INPUT_1 + i].getChannels(); c++) { + drawTrace(args.vg, module->buffer[i * 16 + c], 21.5f + 22 * c, col); + } + } + } + drawIndex(args.vg, clamp(module->params[LA_216::PARAM_INDEX_1].getValue(), 0.0f, 1.0f)); + drawIndex(args.vg, clamp(module->params[LA_216::PARAM_INDEX_2].getValue(), 0.0f, 1.0f)); + drawMask(args.vg, clamp(module->params[LA_216::PARAM_PRE].getValue(), 0.0f, 32.0f) / BUFFER_SIZE); + drawPre(args.vg, 1.0f * module->preCount / BUFFER_SIZE); + } + Widget::drawLayer(args, layer); + } + + NVGcolor getColor(int i) { + if (!module->params[LA_216::PARAM_COLORS].getValue()) { + return i?SUBLIGHTREDTRANS:SUBLIGHTBLUETRANS; + } + NVGcolor col = APP->scene->rack->getTopCable(ports[i])->color; + col.a = 1.0f; + return col; + } + }; + + struct LA_Measure : Widget { + LA_216 *module; + char measureText[41]; + + void drawLayer(const DrawArgs &args, int layer) override { + if (module && (layer == 1)) { + float deltaTime = powf(2.0f, module->params[LA_216::PARAM_TIME].getValue()); + int frameCount = (int)ceilf(deltaTime * APP->engine->getSampleRate()); + frameCount *= BUFFER_SIZE; + float width = (float)frameCount * fabs(module->params[LA_216::PARAM_INDEX_1].getValue() - module->params[LA_216::PARAM_INDEX_2].getValue()) / APP->engine->getSampleRate(); + + if (width < 0.00000995f) + sprintf(measureText, "%4.3f\xc2\xb5s", width * 1000000.0f); + else if (width < 0.0000995f) + sprintf(measureText, "%4.2f\xc2\xb5s", width * 1000000.0f); + else if (width < 0.000995f) + sprintf(measureText, "%4.1f\xc2\xb5s", width * 1000000.0f); + else if (width < 0.00995f) + sprintf(measureText, "%4.3fms", width * 1000.0f); + else if (width < 0.0995f) + sprintf(measureText, "%4.2fms", width * 1000.0f); + else if (width < 0.995f) + sprintf(measureText, "%4.1fms", width * 1000.0f); + else if (width < 9.95f) + sprintf(measureText, "%4.3fs", width); + else if (width < 99.5f) + sprintf(measureText, "%4.2fs", width); + else + sprintf(measureText, "%4.1fs", width); + nvgFontSize(args.vg, 14); + nvgFontFaceId(args.vg, gScheme.font()->handle); + nvgFillColor(args.vg, SUBLIGHTBLUE); + nvgTextAlign(args.vg, NVG_ALIGN_CENTER); + nvgText(args.vg, 27, 12, measureText, NULL); + } + Widget::drawLayer(args, layer); + } + }; + +} // end namespace + +struct LA216 : SchemeModuleWidget { + LightButton *resetButton; + LA216(LA_216 *module) { + setModule(module); + this->box.size = Vec(330, 380); + addChild(new SchemePanel(this->box.size)); + + LA_Display * display = new LA_Display(); + display->module = module; + display->box.pos = Vec(72, 14); + display->box.size = Vec(box.size.x - 74, 352); + addChild(display); + + LA_Measure * measure = new LA_Measure(); + measure->module = module; + measure->box.pos = Vec(5.5, 307); + measure->box.size = Vec(54, 16); + addChild(measure); + + for (int i = 0; i < 2; i++) { + PortWidget *port = createInputCentered(Vec(16.5 + 32 * i, 32.5), module, LA_216::INPUT_1 + i); + addInput(port); + display->ports[i] = port; + for (int c = 0; c < 16; c++) { + addChild(createLightCentered>(Vec(63.5 + 4 * i, 26.5 + 22 * c), module, LA_216::LIGHT_1 + i * 16 + c)); + } + } + + addInput(createInputCentered(Vec(16.5, 65.5), module, LA_216::INPUT_EXT)); + addChild(createLightCentered>(Vec(31.5, 74.5), module, LA_216::LIGHT_EXT)); + + addParam(createParamCentered>>(Vec(32.5, 208.5), module, LA_216::PARAM_TRIGGER)); + addParam(createParamCentered(Vec(43, 65.5), module, LA_216::PARAM_EDGE)); + addParam(createParamCentered(Vec(20, 115.5), module, LA_216::PARAM_RUN)); + resetButton = createParamCentered(Vec(16.5, 163), module, LA_216::PARAM_RESET); + addParam(resetButton); + addParam(createParamCentered>(Vec(32.5, 270), module, LA_216::PARAM_TIME)); + addParam(createParamCentered>(Vec(18.5, 337), module, LA_216::PARAM_INDEX_1)); + addParam(createParamCentered>(Vec(46.5, 337), module, LA_216::PARAM_INDEX_2)); + addParam(createParamCentered>>(Vec(48.5, 163), module, LA_216::PARAM_PRE)); + } + void appendContextMenu(Menu *menu) override { + SchemeModuleWidget::appendContextMenu(menu); + DS_Module *dsMod = dynamic_cast(module); + if (dsMod) { + dsMod->appendContextMenu(menu); + EventWidgetMenuItem *vmi = createMenuItem("Match Cable Colors"); + vmi->stepHandler = [=]() { + vmi->rightText = CHECKMARK(module->params[LA_216::PARAM_COLORS].getValue()); + }; + vmi->clickHandler = [=]() { + bool val = module->params[LA_216::PARAM_COLORS].getValue(); + module->params[LA_216::PARAM_COLORS].setValue(!val); + }; + menu->addChild(vmi); + } + } + void render(NVGcontext *vg, SchemeCanvasWidget *canvas) override { + drawBase(vg, "LA-216"); + + //Scope + nvgFillColor(vg, nvgRGB(0x00, 0x00, 0x00)); + nvgBeginPath(vg); + nvgRoundedRect(vg, 72, 14, 256, 352, 2); + nvgRoundedRect(vg, 5, 307, 55, 16, 2); + nvgFill(vg); + + //Grid + nvgStrokeColor(vg, nvgRGB(0x33, 0x33, 0x33)); + nvgStrokeWidth(vg, 1); + nvgBeginPath(vg); + for (int i = 0; i < 16; i++) { + nvgMoveTo(vg, 72, 15.5 + 22 * i); + nvgLineTo(vg, 328, 15.5 + 22 * i); + nvgMoveTo(vg, 72, 34.5 + 22 * i); + nvgLineTo(vg, 328, 34.5 + 22 * i); + } + nvgStroke(vg); + + //Silkscreen + nvgStrokeColor(vg, gScheme.getContrast(module)); + nvgBeginPath(vg); + nvgMoveTo(vg, 53.5, 61.5); + nvgLineTo(vg, 56.5, 61.5); + nvgLineTo(vg, 56.5, 55.5); + nvgLineTo(vg, 59.5, 55.5); + nvgMoveTo(vg, 53.5, 68.5); + nvgLineTo(vg, 56.5, 68.5); + nvgLineTo(vg, 56.5, 74.5); + nvgLineTo(vg, 59.5, 74.5); + nvgStroke(vg); + + drawText(vg, 16.5, 93, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "EXT.TR"); + drawText(vg, 48.5, 93, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "EDGE"); + drawText(vg, 35, 140, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "MODE"); + drawText(vg, 30, 113, NVG_ALIGN_LEFT | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "CONT"); + drawText(vg, 30, 125, NVG_ALIGN_LEFT | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "ONCE"); + drawText(vg, 16.5, 183, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "RESET"); + drawText(vg, 32.5, 240, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "TRIGGER"); + drawText(vg, 32.5, 302, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "TIME"); + drawText(vg, 32.5, 360, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "L INDEX R"); + drawText(vg, 48.5, 183, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "PRE."); + + } +}; + +Model *modelLA216 = createModel("LA-216"); diff --git a/src/LD1.cpp b/src/LD1.cpp old mode 100755 new mode 100644 index 9699bdd3..08b43fbf --- a/src/LD1.cpp +++ b/src/LD1.cpp @@ -26,8 +26,10 @@ struct LD_1 : DS_Module { LD_1() : DS_Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); for (unsigned int i = 0; i < x; i++) { - configParam(PARAM_CUTOFF_1 + i, -10.0f, 10.0f, 5.0f, "Cutoff centre", " V"); - configParam(PARAM_WIDTH_1 + i, 0.0f, 5.0f, 1.0f, "Hysteresis", " V"); + configParam(PARAM_CUTOFF_1 + i, -10.0f, 10.0f, 5.0f, "Signal " + std::to_string(i + 1) + " Cutoff Centre", " V"); + configParam(PARAM_WIDTH_1 + i, 0.0f, 5.0f, 1.0f, "Signal " + std::to_string(i + 1) + " Hysteresis", " V"); + configInput(INPUT_1 + i, "Signal " + std::to_string(i + 1)); + configOutput(OUTPUT_1 + i, "Signal " + std::to_string(i + 1)); } } void process(const ProcessArgs &args) override { @@ -44,12 +46,13 @@ namespace { float cutoff; float width; unsigned int deviceCount; - int cutoffParamIndex; - int widthParamIndex; + ParamWidget** cutoffWidgets; + ParamWidget** widthWidgets; void onAction(const event::Action &e) override { for (unsigned int i = 0; i < deviceCount; i++) { - APP->engine->setParam(module, cutoffParamIndex + i, cutoff); - APP->engine->setParam(module, widthParamIndex + i, width); + + cutoffWidgets[i]->getParamQuantity()->setValue(cutoff); + widthWidgets[i]->getParamQuantity()->setValue(width); } } }; @@ -59,6 +62,8 @@ namespace { unsigned int deviceCount; int cutoffParamIndex; int widthParamIndex; + ParamWidget **cutoffWidgets; + ParamWidget **widthWidgets; Menu *createChildMenu() override { Menu *menu = new Menu(); LDMenuItem *menuItem = createMenuItem("Cutoff 5V"); @@ -66,32 +71,32 @@ namespace { menuItem->cutoff = 5.0f; menuItem->width = 1.0f; menuItem->deviceCount = deviceCount; - menuItem->cutoffParamIndex = cutoffParamIndex; - menuItem->widthParamIndex = widthParamIndex; + menuItem->cutoffWidgets = cutoffWidgets; + menuItem->widthWidgets = widthWidgets; menu->addChild(menuItem); menuItem = createMenuItem("Cutoff 0V"); menuItem->module = module; menuItem->cutoff = 0.0f; menuItem->width = 0.0f; menuItem->deviceCount = deviceCount; - menuItem->cutoffParamIndex = cutoffParamIndex; - menuItem->widthParamIndex = widthParamIndex; + menuItem->cutoffWidgets = cutoffWidgets; + menuItem->widthWidgets = widthWidgets; menu->addChild(menuItem); menuItem = createMenuItem("Cutoff 2.5V"); menuItem->module = module; menuItem->cutoff = 2.5f; menuItem->width = 0.5f; menuItem->deviceCount = deviceCount; - menuItem->cutoffParamIndex = cutoffParamIndex; - menuItem->widthParamIndex = widthParamIndex; + menuItem->cutoffWidgets = cutoffWidgets; + menuItem->widthWidgets = widthWidgets; menu->addChild(menuItem); menuItem = createMenuItem("TTL Levels"); menuItem->module = module; menuItem->cutoff = 1.4f; menuItem->width = 0.6f; menuItem->deviceCount = deviceCount; - menuItem->cutoffParamIndex = cutoffParamIndex; - menuItem->widthParamIndex = widthParamIndex; + menuItem->cutoffWidgets = cutoffWidgets; + menuItem->widthWidgets = widthWidgets; menu->addChild(menuItem); return menu; @@ -102,6 +107,8 @@ namespace { struct LD103 : SchemeModuleWidget { static const int deviceCount = 3; + ParamWidget* cutoffWidgets[deviceCount]; + ParamWidget* widthWidgets[deviceCount]; LD103(LD_1 *module) { setModule(module); this->box.size = Vec(30, 380); @@ -112,9 +119,10 @@ struct LD103 : SchemeModuleWidget { addInput(createInputCentered(Vec(15,31.5 + offset), module, LD_1<3>::INPUT_1 + i)); addOutput(createOutputCentered(Vec(15,115.5 + offset), module, LD_1<3>::OUTPUT_1 + i)); - - addParam(createParamCentered>(Vec(15, 57.5 + offset), module, LD_1<3>::PARAM_CUTOFF_1 + i)); - addParam(createParamCentered>(Vec(15, 89.5 + offset), module, LD_1<3>::PARAM_WIDTH_1 + i)); + cutoffWidgets[i] = createParamCentered>(Vec(15, 57.5 + offset), module, LD_1<3>::PARAM_CUTOFF_1 + i); + widthWidgets[i] = createParamCentered>(Vec(15, 89.5 + offset), module, LD_1<3>::PARAM_WIDTH_1 + i); + addParam(cutoffWidgets[i]); + addParam(widthWidgets[i]); } } void appendContextMenu(Menu *menu) override { @@ -123,8 +131,8 @@ struct LD103 : SchemeModuleWidget { LDParentMenuItem *menuItem = createMenuItem("Input Range"); menuItem->module = module; menuItem->deviceCount = deviceCount; - menuItem->cutoffParamIndex = LD_1<3>::PARAM_CUTOFF_1; - menuItem->widthParamIndex = LD_1<3>::PARAM_WIDTH_1; + menuItem->cutoffWidgets = cutoffWidgets; + menuItem->widthWidgets = widthWidgets; menuItem->rightText = SUBMENU; menu->addChild(menuItem); } @@ -153,6 +161,8 @@ struct LD103 : SchemeModuleWidget { struct LD106 : SchemeModuleWidget { static const int deviceCount = 6; + ParamWidget* cutoffWidgets[deviceCount]; + ParamWidget* widthWidgets[deviceCount]; LD106(LD_1 *module) { setModule(module); this->box.size = Vec(90, 380); @@ -164,8 +174,10 @@ struct LD106 : SchemeModuleWidget { addOutput(createOutputCentered(Vec(74.5,31.5 + offset), module, LD_1<6>::OUTPUT_1 + i)); - addParam(createParamCentered>(Vec(16, 59 + offset), module, LD_1<6>::PARAM_CUTOFF_1 + i)); - addParam(createParamCentered>(Vec(74, 59 + offset), module, LD_1<6>::PARAM_WIDTH_1 + i)); + cutoffWidgets[i] = createParamCentered>(Vec(16, 59 + offset), module, LD_1<6>::PARAM_CUTOFF_1 + i); + widthWidgets[i] = createParamCentered>(Vec(74, 59 + offset), module, LD_1<6>::PARAM_WIDTH_1 + i); + addParam(cutoffWidgets[i]); + addParam(widthWidgets[i]); } } void appendContextMenu(Menu *menu) override{ @@ -175,8 +187,8 @@ struct LD106 : SchemeModuleWidget { menuItem->module = module; menuItem->rightText = SUBMENU; menuItem->deviceCount = deviceCount; - menuItem->cutoffParamIndex = LD_1<6>::PARAM_CUTOFF_1; - menuItem->widthParamIndex = LD_1<6>::PARAM_WIDTH_1; + menuItem->cutoffWidgets = cutoffWidgets; + menuItem->widthWidgets = widthWidgets; menu->addChild(menuItem); } DS_Module *dsMod = dynamic_cast(module); diff --git a/src/LT1.cpp b/src/LT1.cpp old mode 100755 new mode 100644 index 8c51de25..085ac096 --- a/src/LT1.cpp +++ b/src/LT1.cpp @@ -10,27 +10,40 @@ namespace { int clipboardColumn = -1; const int bulkParamSize = sizeof(float) * 256; - template - K* createBulkParamCentered(math::Vec pos, float minValue, float maxValue, float defaultValue, std::string label = "", std::string unit = "", float displayBase = 0.f, float displayMultiplier = 1.f, float displayOffset = 0.f) { - K* widget = new K(); - widget->box.pos = pos.minus(widget->box.size.div(2)); - widget->minValue = minValue; - widget->maxValue = maxValue; - widget->defaultValue = defaultValue; - widget->label = label; - widget->unit = unit; - widget->displayBase = displayBase; - widget->displayMultiplier = displayMultiplier; - widget->displayOffset = displayOffset; - return widget; - } - + struct LTKnob : LightKnob + { + std::function contextMenuCallback; + void appendContextMenu(ui::Menu *menu) override { + ParamWidget::appendContextMenu(menu); + if (contextMenuCallback) { + contextMenuCallback(menu); + } + } + void onDoubleClick(const DoubleClickEvent &e) override { + engine::ParamQuantity *pq = getParamQuantity(); + if (pq && pq->resetEnabled) { + float oldValue = pq->getValue(); + pq->reset(); + float newValue = pq->getValue(); + if (oldValue != newValue) { + history::ParamChange* h = new history::ParamChange(); + h->name = "reset parameter"; + h->moduleId = module->id; + h->paramId = paramId; + h->oldValue = oldValue; + h->newValue = newValue; + APP->history->push(h); + } + } + } + }; } struct LT_116 : Module { enum ParamIds { PARAM_OUTPUT_CHANNELS, - NUM_PARAMS + PARAM_COEFF_1, + NUM_PARAMS = PARAM_COEFF_1 + 256 }; enum InputIds { INPUT_1, @@ -45,6 +58,7 @@ struct LT_116 : Module { }; alignas(16) float bulkParams[256] = {.0f}; + unsigned char tick = 0; int numberOfInputs = 1; int numberOfOutputs = 16; @@ -52,16 +66,25 @@ struct LT_116 : Module { LT_116() : Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); configParam(PARAM_OUTPUT_CHANNELS, 1.0f, 16.0f, 16.0f, "Number of channels in output"); + configInput(INPUT_1, "Signal"); + configOutput(OUTPUT_1, "Signal"); + for (unsigned int i = 0; i < 16; i++) { + for (unsigned int j = 0; j < 16; j++) { + configParam(PARAM_COEFF_1 + i * 16 + j, -INFINITY, +INFINITY, .0f, string::f("Coefficient [%d,%d]", j + 1, i + 1)); + } + } + configBypass(INPUT_1, OUTPUT_1); } json_t *dataToJson() override { json_t *rootJ = json_object(); json_t *arr = json_array(); - for (unsigned int i = 0; i < 256; i++) { - if (std::isnan(bulkParams[i])) { + for (unsigned int i = 0; i < 256; i++) { + float val = params[PARAM_COEFF_1 + i].getValue(); + if (std::isnan(val)) { json_array_append_new(arr, json_real(0.0f)); } else { - json_array_append_new(arr, json_real(bulkParams[i])); + json_array_append_new(arr, json_real(val)); } } json_object_set_new(rootJ, "coefficients", arr); @@ -77,13 +100,23 @@ struct LT_116 : Module { for (int i = 0; i < size; i++) { json_t *j1 = json_array_get(arr, i); if (j1) { - bulkParams[i] = json_real_value(j1); + params[PARAM_COEFF_1 + i].setValue(json_real_value(j1)); } } + gatherBulkParams(); + tick = 1; + } + } + void gatherBulkParams() { + for (unsigned int i = 0; i < 256; i++) { + bulkParams[i] = params[PARAM_COEFF_1 + i].getValue(); } } void process(const ProcessArgs &args) override { + if (!tick++) { + gatherBulkParams(); + } numberOfInputs = inputs[INPUT_1].getChannels(); numberOfOutputs = params[PARAM_OUTPUT_CHANNELS].getValue(); @@ -119,26 +152,22 @@ struct LT_116 : Module { }; struct LT116 : SchemeModuleWidget { - BulkLightKnob *knobs[256]; - float *bulkParams; + LTKnob *knobs[256]; + alignas(16) float bulkParams[256]; LT116(LT_116 *module) { setModule(module); - if (module) - bulkParams = module->bulkParams; this->box.size = Vec(300, 380); addChild(new SchemePanel(this->box.size)); for (unsigned int i = 0; i < 16; i++) { for (unsigned int j = 0; j < 16; j++) { int index = i * 16 + j; - knobs[index] = createBulkParamCentered>(Vec(15 + j * 18, 30 + i * 18), -INFINITY, +INFINITY, .0f, string::f("Coefficient [%d,%d]", j + 1, i + 1)); + knobs[index] = createParamCentered>(Vec(15 + j * 18, 30 + i * 18), module, LT_116::PARAM_COEFF_1 + index); + if (module) { - knobs[index]->value = &(bulkParams[index]); knobs[index]->contextMenuCallback = [=](Menu *menu) { this->appendOperationMenu(menu, i, j); }; - knobs[index]->module = module; - knobs[index]->paramId = index; } addChild(knobs[index]); @@ -148,15 +177,6 @@ struct LT116 : SchemeModuleWidget { addOutput(createOutputCentered(Vec(265, 330), module, LT_116::OUTPUT_1)); addParam(createParamCentered>>(Vec(200, 330), module, LT_116::PARAM_OUTPUT_CHANNELS)); } - float *getBulkParam(int id) override { - if (id < 0) - return NULL; - if (id > 255) - return NULL; - if (module) - return bulkParams + id; - return NULL; - } void appendOperationMenu(Menu *menu, int row, int column) { if (!module) { return; @@ -342,25 +362,37 @@ struct LT116 : SchemeModuleWidget { drawText(vg, 50, 330, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, 16, gScheme.getContrast(module), "\xE2\x86\x93"); drawText(vg, 240, 330, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, 16, gScheme.getContrast(module), "\xE2\x86\x92"); } + void getKnobs(float* values) { + for (unsigned int i = 0; i < 256; i++) { + values[i] = knobs[i]->getParamQuantity()->getValue(); + } + } + void setKnobs(const float *values) { + for (unsigned int i = 0; i < 256; i++) { + knobs[i]->getParamQuantity()->setValue(values[i]); + } + } void bulkChangeWithHistory(std::string label, std::function func) { float oldValues[256]; float newValues[256]; + getKnobs(bulkParams); memcpy(oldValues, bulkParams, bulkParamSize); func(bulkParams); memcpy(newValues, bulkParams, bulkParamSize); - int moduleId = module->id; + setKnobs(newValues); + int64_t moduleId = module->id; APP->history->push(new EventWidgetAction( label, [=]() { LT116 *mw = dynamic_cast(APP->scene->rack->getModule(moduleId)); if (mw) { - memcpy(mw->bulkParams, oldValues, bulkParamSize); + mw->setKnobs(oldValues); } }, [=]() { LT116 *mw = dynamic_cast(APP->scene->rack->getModule(moduleId)); if (mw) { - memcpy(mw->bulkParams, newValues, bulkParamSize); + mw->setKnobs(newValues); } } )); @@ -368,6 +400,7 @@ struct LT116 : SchemeModuleWidget { void bulkChangeWithHistory(std::string label, float *values) { bulkChangeWithHistory(label, [=](float *params) { memcpy(params, values, bulkParamSize); + setKnobs(values); }); } @@ -398,44 +431,46 @@ struct LT116 : SchemeModuleWidget { } void copy() { clipboardUsed = true; - memcpy(clipboard, bulkParams, bulkParamSize); + getKnobs(clipboard); clipboardRow = clipboardColumn = -1; } void copyRow(int row) { clipboardUsed = true; - memcpy(clipboard, bulkParams, bulkParamSize); + getKnobs(clipboard); clipboardRow = row; clipboardColumn = -1; } void copyColumn(int column) { clipboardUsed = true; - memcpy(clipboard, bulkParams, bulkParamSize); + getKnobs(clipboard); clipboardRow = -1; clipboardColumn = column; } void copyCell(int row, int column) { clipboardUsed = true; - memcpy(clipboard, bulkParams, bulkParamSize); + getKnobs(clipboard); clipboardRow = row; clipboardColumn = column; } void pasteCell(int row, int column) { + getKnobs(bulkParams); float oldValue = bulkParams[column + 16 * row]; bulkParams[column + 16 * row] = clipboard[clipboardColumn + 16 * clipboardRow]; float newValue = bulkParams[column + 16 * row]; - int moduleId = module->id; + setKnobs(bulkParams); + int64_t moduleId = module->id; APP->history->push(new EventWidgetAction( "LT116 paste cell", [=]() { LT116 *mw = dynamic_cast(APP->scene->rack->getModule(moduleId)); if (mw) { - mw->bulkParams[column + 16 * row] = oldValue; + mw->knobs[column + 16 * row]->getParamQuantity()->setValue(oldValue); } }, [=]() { LT116 *mw = dynamic_cast(APP->scene->rack->getModule(moduleId)); if (mw) { - mw->bulkParams[column + 16 * row] = newValue; + mw->knobs[column + 16 * row]->getParamQuantity()->setValue(newValue); } } )); @@ -480,22 +515,24 @@ struct LT116 : SchemeModuleWidget { } } void pasteMultiplyCell(int row, int column) { + getKnobs(bulkParams); float oldValue = bulkParams[column + 16 * row]; bulkParams[column + 16 * row] *= clipboard[clipboardColumn + 16 * clipboardRow]; float newValue = bulkParams[column + 16 * row]; - int moduleId = module->id; + setKnobs(bulkParams); + int64_t moduleId = module->id; APP->history->push(new EventWidgetAction( "LT116 paste multiply cell", [=]() { LT116 *mw = dynamic_cast(APP->scene->rack->getModule(moduleId)); if (mw) { - mw->bulkParams[column + 16 * row] = oldValue; + mw->knobs[column + 16 * row]->getParamQuantity()->setValue(oldValue); } }, [=]() { LT116 *mw = dynamic_cast(APP->scene->rack->getModule(moduleId)); if (mw) { - mw->bulkParams[column + 16 * row] = newValue; + mw->knobs[column + 16 * row]->getParamQuantity()->setValue(newValue); } } )); @@ -549,22 +586,24 @@ struct LT116 : SchemeModuleWidget { } } void pasteAddCell(int row, int column) { + getKnobs(bulkParams); float oldValue = bulkParams[column + 16 * row]; bulkParams[column + 16 * row] += clipboard[clipboardColumn + 16 * clipboardRow]; float newValue = bulkParams[column + 16 * row]; - int moduleId = module->id; + setKnobs(bulkParams); + int64_t moduleId = module->id; APP->history->push(new EventWidgetAction( "LT116 paste add cell", [=]() { LT116 *mw = dynamic_cast(APP->scene->rack->getModule(moduleId)); if (mw) { - mw->bulkParams[column + 16 * row] = oldValue; + mw->knobs[column + 16 * row]->getParamQuantity()->setValue(oldValue); } }, [=]() { LT116 *mw = dynamic_cast(APP->scene->rack->getModule(moduleId)); if (mw) { - mw->bulkParams[column + 16 * row] = newValue; + mw->knobs[column + 16 * row]->getParamQuantity()->setValue(newValue); } } )); @@ -618,22 +657,24 @@ struct LT116 : SchemeModuleWidget { } } void pasteSubtractCell(int row, int column) { + getKnobs(bulkParams); float oldValue = bulkParams[column + 16 * row]; bulkParams[column + 16 * row] -= clipboard[clipboardColumn + 16 * clipboardRow]; float newValue = bulkParams[column + 16 * row]; - int moduleId = module->id; + setKnobs(bulkParams); + int64_t moduleId = module->id; APP->history->push(new EventWidgetAction( "LT116 paste subtract cell", [=]() { LT116 *mw = dynamic_cast(APP->scene->rack->getModule(moduleId)); if (mw) { - mw->bulkParams[column + 16 * row] = oldValue; + mw->knobs[column + 16 * row]->getParamQuantity()->setValue(oldValue); } }, [=]() { LT116 *mw = dynamic_cast(APP->scene->rack->getModule(moduleId)); if (mw) { - mw->bulkParams[column + 16 * row] = newValue; + mw->knobs[column + 16 * row]->getParamQuantity()->setValue(newValue); } } )); @@ -726,7 +767,10 @@ struct LT116 : SchemeModuleWidget { } void normaliseAll() { bulkChangeWithHistory("LT116 normalise all columns", [=](float *params) { - __m128 a1, a2, a3, a4 = _mm_setzero_ps(); + __m128 a1 = _mm_setzero_ps(); + __m128 a2 = _mm_setzero_ps(); + __m128 a3 = _mm_setzero_ps(); + __m128 a4 = _mm_setzero_ps(); for (int i = 0; i < 256; i += 16) { __m128 s = _mm_load_ps(params + i); a1 = _mm_add_ps(a1, s); diff --git a/src/MZ9.cpp b/src/MZ9.cpp old mode 100755 new mode 100644 index a225c784..69f3bc75 --- a/src/MZ9.cpp +++ b/src/MZ9.cpp @@ -22,7 +22,10 @@ struct MZ_909: Module { MZ_909() : Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); - configParam(PARAM_ON, 1.0f, 2.0f, 1.0f, "On"); + configSwitch(PARAM_ON, 1.0f, 2.0f, 1.0f, "Power", { "On", "More On" }); + configInput(INPUT_1, "Signal"); + configOutput(OUTPUT_1, "Mastererized Signal"); + } void process(const ProcessArgs &args) override { @@ -58,7 +61,7 @@ struct MZ909 : SchemeModuleWidget { SchemeModuleWidget::step(); if (module) { unsigned int count = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); - if (module->params[MZ_909::PARAM_ON].getValue() > 1.5f) + if (onButton->getParamQuantity()->getValue() > 1.5f) count *= 2; count %= 1000; float lerp = ((float)count - 500.0f) / 500.0f; diff --git a/src/NG1.cpp b/src/NG1.cpp old mode 100755 new mode 100644 index 9f3b98a8..509a897d --- a/src/NG1.cpp +++ b/src/NG1.cpp @@ -21,6 +21,10 @@ struct NG_1 : DS_Module { NG_1() : DS_Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + for (int i = 0; i < x; i++) { + configInput(INPUT_1 + i, "Signal " + std::to_string(i + 1)); + configOutput(OUTPUT_1 + i, "Signal " + std::to_string(i + 1)); + } } void process(const ProcessArgs &args) override { for (int i = 0; i < x; i++) { diff --git a/src/NG2.cpp b/src/NG2.cpp old mode 100755 new mode 100644 index b86b3982..cc5dff84 --- a/src/NG2.cpp +++ b/src/NG2.cpp @@ -20,6 +20,10 @@ struct NG_2 : DS_Module { NG_2() : DS_Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + for (int i = 0; i < 6; i++) { + configInput(INPUT_1 + i, "Signal " + std::to_string(i + 1)); + configOutput(OUTPUT_1 + i, "Signal " + std::to_string(i + 1)); + } } void process(const ProcessArgs &args) override { for (int i = 0; i < 6; i++) { diff --git a/src/OA1.cpp b/src/OA1.cpp old mode 100755 new mode 100644 index d12d5c75..5a87f021 --- a/src/OA1.cpp +++ b/src/OA1.cpp @@ -24,6 +24,13 @@ struct OA_1 : DS_Module { OA_1() : DS_Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + configInput(INPUT_REF_HI, "Reference Signal 1"); + configInput(INPUT_REF_LO, "Reference Signal 2"); + for (int i = 0; i < x; i++) { + configInput(INPUT_A_1 + i, "Signal " + std::to_string(i + 1) + "A"); + configInput(INPUT_B_1 + i, "Signal " + std::to_string(i + 1) + "B"); + configOutput(OUTPUT_1 + i, "Signal " + std::to_string(i + 1)); + } } void process(const ProcessArgs &args) override { diff --git a/src/OG1.cpp b/src/OG1.cpp old mode 100755 new mode 100644 index fac327f2..b2f3b7e7 --- a/src/OG1.cpp +++ b/src/OG1.cpp @@ -22,6 +22,11 @@ struct OG_1 : DS_Module { OG_1() : DS_Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + for (int i = 0; i < x; i++) { + configInput(INPUT_A_1 + i, "Signal " + std::to_string(i + 1) + "A"); + configInput(INPUT_B_1 + i, "Signal " + std::to_string(i + 1) + "B"); + configOutput(OUTPUT_1 + i, "Signal " + std::to_string(i + 1)); + } } void process(const ProcessArgs &args) override { int setCount = 0; diff --git a/src/OG2.cpp b/src/OG2.cpp old mode 100755 new mode 100644 index 82c679b3..d07d2f0a --- a/src/OG2.cpp +++ b/src/OG2.cpp @@ -28,6 +28,16 @@ struct OG_2 : DS_Module { OG_2() : DS_Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + configInput(INPUT_A_1, "Signal 1A"); + configInput(INPUT_A_2, "Signal 2A"); + configInput(INPUT_B_1, "Signal 1B"); + configInput(INPUT_B_2, "Signal 2B"); + configInput(INPUT_C_1, "Signal 1C"); + configInput(INPUT_C_2, "Signal 2C"); + configInput(INPUT_D_1, "Signal 1D"); + configInput(INPUT_D_2, "Signal 2D"); + configOutput(OUTPUT_1, "Signal 1"); + configOutput(OUTPUT_2, "Signal 2"); } void process(const ProcessArgs &args) override { diff --git a/src/PG1.cpp b/src/PG1.cpp old mode 100755 new mode 100644 index c23e0165..3ceab2d4 --- a/src/PG1.cpp +++ b/src/PG1.cpp @@ -25,7 +25,9 @@ struct PG_1 : DS_Module { PG_1() : DS_Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); for (unsigned int i = 0; i < x; i++) { - configParam(PARAM_1 + i, -5.0f, 2.0f, -2.0f, "Pulse width", " s", 10.f); + configParam(PARAM_1 + i, -5.0f, 2.0f, -2.0f, "Signal " + std::to_string(i + 1) + " Pulse Width", " s", 10.f); + configInput(INPUT_1 + i, "Signal " + std::to_string(i + 1)); + configOutput(OUTPUT_1 + i, "Signal " + std::to_string(i + 1)); } } void process(const ProcessArgs &args) override { diff --git a/src/PO1.cpp b/src/PO1.cpp old mode 100755 new mode 100644 index ab7dc07c..141ec437 --- a/src/PO1.cpp +++ b/src/PO1.cpp @@ -52,11 +52,36 @@ struct PO_101 : Module { PO_101() : Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); configParam(PARAM_FINE, -1.0f, +1.0f, 0.0f, "Fine frequency"); - configParam(PARAM_WAVE, 0.0f, +4.0f, 0.0f, "Wave shape"); + configSwitch(PARAM_WAVE, 0.0f, +4.0f, 0.0f, "Wave shape", { "Sine", "Triangle", "Sawtooth", "Square", "Rectified Sine" }); for (unsigned int i = 0; i < 4; i++) { - configParam(PARAM_PHASE_1 + i, -1.0f, +1.0f, 0.0f, "Phase shift", "\xc2\xb0", 0.f, 360.f); + configParam(PARAM_PHASE_1 + i, -1.0f, +1.0f, 0.0f, string::f("Phase shift #%d", i + 1), "\xc2\xb0", 0.f, 360.f); } configParam(PARAM_TUNE, -54.0f, +54.0f, 0.0f, "Frequency", " Hz", dsp::FREQ_SEMITONE, dsp::FREQ_C4); + configInput(INPUT_NOTE_CV, "CV"); + configInput(INPUT_PHASE_1, "Phase shift #1"); + configInput(INPUT_PHASE_2, "Phase shift #2"); + configInput(INPUT_PHASE_3, "Phase shift #3"); + configInput(INPUT_PHASE_4, "Phase shift #4"); + configOutput(OUTPUT_1, "0\xc2\xb0"); + configOutput(OUTPUT_2, "30\xc2\xb0"); + configOutput(OUTPUT_3, "45\xc2\xb0"); + configOutput(OUTPUT_4, "60\xc2\xb0"); + configOutput(OUTPUT_5, "90\xc2\xb0"); + configOutput(OUTPUT_6, "120\xc2\xb0"); + configOutput(OUTPUT_7, "135\xc2\xb0"); + configOutput(OUTPUT_8, "150\xc2\xb0"); + configOutput(OUTPUT_9, "180\xc2\xb0"); + configOutput(OUTPUT_10, "210\xc2\xb0"); + configOutput(OUTPUT_11, "225\xc2\xb0"); + configOutput(OUTPUT_12, "240\xc2\xb0"); + configOutput(OUTPUT_13, "270\xc2\xb0"); + configOutput(OUTPUT_14, "300\xc2\xb0"); + configOutput(OUTPUT_15, "315\xc2\xb0"); + configOutput(OUTPUT_16, "330\xc2\xb0"); + configOutput(OUTPUT_17, "Custom #1"); + configOutput(OUTPUT_18, "Custom #2"); + configOutput(OUTPUT_19, "Custom #3"); + configOutput(OUTPUT_20, "Custom #4"); } void process(const ProcessArgs &args) override; float phase = 0.0f; diff --git a/src/PO2.cpp b/src/PO2.cpp old mode 100755 new mode 100644 index 7e25cbcb..e9a4ae56 --- a/src/PO2.cpp +++ b/src/PO2.cpp @@ -56,6 +56,10 @@ struct PO_204 : Module { configParam(PARAM_WAVE_1 + i, 0.0f, 10.0f, 5.0f, string::f("Operator #%d wave shape", i + 1)); configParam(PARAM_PHASE_1 + i, -1.0f, +1.0f, 0.0f, string::f("Operator #%d phase shift", i + 1), "\xc2\xb0", 0.f, 360.f); configParam(PARAM_MULT_1 + i, 1.0f, 16.0f, 1.0f, string::f("Operator #%d frequency multiplier", i + 1)); + configInput(INPUT_WAVE_1 + i, string::f("Operator #%d wave shape", i + 1)); + configInput(INPUT_PHASE_1 + i, string::f("Operator #%d phase shift", i + 1)); + configInput(INPUT_MULT_1 + i, string::f("Operator #%d frequency multiplier", i + 1)); + configOutput(OUTPUT_1 + i, string::f("Signal #%d", i + 1)); } } void process(const ProcessArgs &args) override; diff --git a/src/SN1.cpp b/src/SN1.cpp old mode 100755 new mode 100644 index c06ce31c..cfee0b17 --- a/src/SN1.cpp +++ b/src/SN1.cpp @@ -109,14 +109,17 @@ struct SN_1 : Module { SN_1() : Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); - configParam(PARAM_FREQ, -54.0f, +54.0f, 0.0f, "Frequency", " Hz", dsp::FREQ_SEMITONE, dsp::FREQ_C4); + configParam(PARAM_FREQ, -126.0f, +54.0f, 0.0f, "Frequency", " Hz", dsp::FREQ_SEMITONE, dsp::FREQ_C4); configParam(PARAM_EVOL, 0.0f, 1.0f, 0.0f, "Evolution"); configParam(PARAM_LENGTH, 2.0f, maxGridWidth, effectiveGridWidth, "Cycle Length"); - configParam(PARAM_HARM_2, 0.0f, 1.0f, 0.0f, "2x Harmonic"); - configParam(PARAM_HARM_3, 0.0f, 1.0f, 0.0f, "3x Harmonic"); - configParam(PARAM_HARM_4, 0.0f, 1.0f, 0.0f, "4x Harmonic"); - configParam(PARAM_HARM_5, 0.0f, 1.0f, 0.0f, "5x Harmonic"); - configParam(PARAM_HARM_8, 0.0f, 1.0f, 0.0f, "8x Harmonic"); + configSwitch(PARAM_HARM_2, 0.0f, 1.0f, 0.0f, "2x Harmonic", { "Off", "On" }); + configSwitch(PARAM_HARM_3, 0.0f, 1.0f, 0.0f, "3x Harmonic", { "Off", "On" }); + configSwitch(PARAM_HARM_4, 0.0f, 1.0f, 0.0f, "4x Harmonic", { "Off", "On" }); + configSwitch(PARAM_HARM_5, 0.0f, 1.0f, 0.0f, "5x Harmonic", { "Off", "On" }); + configSwitch(PARAM_HARM_8, 0.0f, 1.0f, 0.0f, "8x Harmonic", { "Off", "On" }); + configInput(INPUT_FREQ, "Frequency"); + configInput(INPUT_EVOL, "Evolution"); + configOutput(OUTPUT_1, "Signal"); initLFSR(lfsr); initGridRow(); shiftGridRows(); @@ -291,7 +294,7 @@ struct SN101 : SchemeModuleWidget { } void step() override { if (module) { - lengthKnob->color = (APP->engine->getParam(module, SN_1::PARAM_LENGTH) == dynamic_cast(module)->effectiveGridWidth)?SUBLIGHTBLUE:SUBLIGHTRED; + lengthKnob->color = (lengthKnob->getParamQuantity()->getValue() == dynamic_cast(module)->effectiveGridWidth)?SUBLIGHTBLUE:SUBLIGHTRED; } SchemeModuleWidget::step(); } diff --git a/src/SS1.cpp b/src/SS1.cpp old mode 100755 new mode 100644 index 2539e063..ae027087 --- a/src/SS1.cpp +++ b/src/SS1.cpp @@ -6,6 +6,9 @@ struct SS_112 : Module { static constexpr int deviceCount = 12; SS_112() : Module() { config(0, deviceCount, 0, 0); + for (unsigned int i = 0; i < deviceCount; i++) { + configInput(i, "Signal Sink"); + } } }; @@ -37,6 +40,14 @@ struct SS_208 : Module { values[5] = powf(3.0f, 0.5f); values[6] = powf(5.0f, 0.5f); values[7] = powf(7.0f, 0.5f); + configOutput(0, "\xcf\x80 V"); + configOutput(1, "\xcf\x84 V"); + configOutput(2, "\xe2\x84\xaf V"); + configOutput(3, "\xe2\x88\x9a\xc2\xbd V"); + configOutput(4, "\xe2\x88\x9a" "2 V"); + configOutput(5, "\xe2\x88\x9a" "3 V"); + configOutput(6, "\xe2\x88\x9a" "5 V"); + configOutput(7, "\xe2\x88\x9a" "7 V"); } void process(const ProcessArgs &args) override { outputs[0].setVoltage(values[0]); @@ -78,6 +89,7 @@ struct SS_212 : Module { void setValues() { for (int i = 0; i < deviceCount; i++) { outputs[i].setVoltage(v + 1.0f * i / 12.0f); + configOutput(i, string::f("%f V", v + 1.0f * i / 12.0f)); } } @@ -156,6 +168,9 @@ struct SS_221 : Module { static constexpr int deviceCount = 21; SS_221() : Module() { config(0, 0, deviceCount, 0); + for (int i = 0; i < deviceCount; i++) { + configOutput(i, string::f("%d V", 10 - i)); + } } void process(const ProcessArgs &args) override { for (int i = 0; i < deviceCount; i++) { @@ -204,6 +219,9 @@ struct SS_220 : Module { static constexpr int deviceSetCount = 10; SS_220() : Module() { config(0, 0, deviceCount * deviceSetCount, 0); + for (unsigned int i = 0; i < deviceCount * deviceSetCount; i++) { + configOutput(i, string::f("%f V", 5.0f - i / 12.0f)); + } } void process(const ProcessArgs &args) override { for (int j = 0; j < deviceSetCount; j++) { diff --git a/src/SubmarineFree.cpp b/src/SubmarineFree.cpp index 0dd64c80..420bfb44 100755 --- a/src/SubmarineFree.cpp +++ b/src/SubmarineFree.cpp @@ -33,6 +33,7 @@ void init(rack::Plugin *p) { p->addModel(modelFF212); p->addModel(modelHS101); p->addModel(modelLA108); + p->addModel(modelLA216); p->addModel(modelLD103); p->addModel(modelLD106); p->addModel(modelLT116); @@ -70,8 +71,10 @@ void init(rack::Plugin *p) { p->addModel(modelVM101); p->addModel(modelVM102); + p->addModel(modelVM104); p->addModel(modelVM201); p->addModel(modelVM202); + p->addModel(modelVM204); p->addModel(modelWK101); p->addModel(modelWK205); diff --git a/src/SubmarineFree.hpp b/src/SubmarineFree.hpp index 083c585c..02e6284e 100755 --- a/src/SubmarineFree.hpp +++ b/src/SubmarineFree.hpp @@ -48,6 +48,7 @@ extern Model *modelFF212; extern Model *modelHS101; extern Model *modelLA108; +extern Model *modelLA216; extern Model *modelLD103; extern Model *modelLD106; @@ -93,8 +94,10 @@ extern Model *modelTM105; extern Model *modelVM101; extern Model *modelVM102; +extern Model *modelVM104; extern Model *modelVM201; extern Model *modelVM202; +extern Model *modelVM204; extern Model *modelWK101; extern Model *modelWK205; diff --git a/src/TD1.cpp b/src/TD1.cpp old mode 100755 new mode 100644 index f352f961..45b7e931 --- a/src/TD1.cpp +++ b/src/TD1.cpp @@ -1,26 +1,14 @@ //SubTag W16 AM WP #include "SubmarineFree.hpp" -#include "window.hpp" -#include "shared/torpedo.hpp" struct TD_116; -namespace { - struct TDInput : Torpedo::PatchInputPort { - TD_116 *tdModule; - TDInput(TD_116 *module, unsigned int portNum) : Torpedo::PatchInputPort((Module *)module, portNum) { tdModule = module; } - void received(std::string pluginName, std::string moduleName, json_t *rootJ) override; - NVGcolor decodeColor(std::string colorStr); - }; -} // end namespace - struct TD_116 : Module { - TDInput inPort = TDInput(this, 0); - Torpedo::PatchOutputPort outPort = Torpedo::PatchOutputPort(this, 0); TD_116() : Module () { config(0, 1, 1, 0); - outPort.size(1); + configInput(0, "Deprecated"); + configOutput(0, "Deprecated"); } void processExpander(float *message) { if (!std::isnan(message[0])) { @@ -53,18 +41,10 @@ struct TD_116 : Module { processExpander((float *)(rightExpander.module->leftExpander.consumerMessage)); } } - inPort.process(); - outPort.process(); } void sendText(std::string textValue) { text = textValue; - - json_t *rootJ = json_object();; - - // text - json_object_set_new(rootJ, "text", json_string(text.c_str())); - outPort.send("SubmarineFree", "TDNotesText", rootJ); } void onReset() override { reset = 1; @@ -142,40 +122,6 @@ namespace { } }; - NVGcolor TDInput::decodeColor(std::string colorStr) { - int r = (colorStr[0] - 'A') * 16 + (colorStr[1] - 'A'); - int g = (colorStr[2] - 'A') * 16 + (colorStr[3] - 'A'); - int b = (colorStr[4] - 'A') * 16 + (colorStr[5] - 'A'); - return nvgRGB(r, g, b); - } - - void TDInput::received(std::string pluginName, std::string moduleName, json_t *rootJ) { - if (pluginName.compare("SubmarineFree")) return; - if (!moduleName.compare("TDNotesText")) { - json_t *text = json_object_get(rootJ, "text"); - if (text) { - tdModule->text.assign(json_string_value(text)); - tdModule->isDirty = true; - } - } - else if (!moduleName.compare("TDNotesColor")) { - json_t *size = json_object_get(rootJ, "size"); - if (size) { - tdModule->fontSize = json_number_value(size); - tdModule->isDirtyC = true; - } - json_t *fg = json_object_get(rootJ, "fg"); - if (fg) { - tdModule->fg = decodeColor(std::string(json_string_value(fg))); - tdModule->isDirtyC = true; - } - json_t *bg = json_object_get(rootJ, "bg"); - if (bg) { - tdModule->bg = decodeColor(std::string(json_string_value(bg))); - tdModule->isDirtyC = true; - } - } - } } // end namespace struct TD116 : SchemeModuleWidget { @@ -186,8 +132,8 @@ struct TD116 : SchemeModuleWidget { this->box.size = Vec(240, 380); addChild(new SchemePanel(this->box.size)); - addInput(createInputCentered(Vec(16.5,31.5), module, 0)); - addOutput(createOutputCentered(Vec(223.5,31.5), module, 0)); + addInput(createInputCentered(Vec(16.5,31.5), module, 0)); + addOutput(createOutputCentered(Vec(223.5,31.5), module, 0)); textField = createWidget(mm2px(Vec(3.39962, 15.8373))); textField->box.size = mm2px(Vec(74.480, 102.753)); @@ -196,32 +142,6 @@ struct TD116 : SchemeModuleWidget { addChild(textField); } - void fromJson(json_t *rootJ) override { - ModuleWidget::fromJson(rootJ); - TD_116 *tdModule = dynamic_cast(module); - if (tdModule) { - textField->text = tdModule->text; - textField->fontSize = tdModule->fontSize; - textField->color = tdModule->fg; - textField->bgColor = tdModule->bg; - } - - json_t *textJ = json_object_get(rootJ, "text"); - if (textJ) - textField->text = json_string_value(textJ); - json_t *sizeJ = json_object_get(rootJ, "size"); - if (sizeJ) - textField->fontSize = json_number_value(sizeJ); - json_t *fgJ = json_object_get(rootJ, "fg"); - if (fgJ) { - textField->color = color::fromHexString(json_string_value(fgJ)); - } - json_t *bgJ = json_object_get(rootJ, "bg"); - if (bgJ) { - textField->bgColor = color::fromHexString(json_string_value(bgJ)); - } - } - void step() override { TD_116 *tdModule = dynamic_cast(module); if (!tdModule) { @@ -253,13 +173,11 @@ struct TD116 : SchemeModuleWidget { void appendContextMenu(Menu *menu) override { SchemeModuleWidget::appendContextMenu(menu); - textField->appendContextMenu(menu); + textField->appendContextMenu(menu); } void render(NVGcontext *vg, SchemeCanvasWidget *canvas) override { drawBase(vg, "TD-116"); - drawText(vg, 30, 36, NVG_ALIGN_LEFT | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "SYNC IN"); - drawText(vg, 210, 36, NVG_ALIGN_RIGHT | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "SYNC OUT"); } }; diff --git a/src/TD2.cpp b/src/TD2.cpp old mode 100755 new mode 100644 index 5a69463a..65a5d74b --- a/src/TD2.cpp +++ b/src/TD2.cpp @@ -1,7 +1,7 @@ //SubTag W2 WP AM #include "SubmarineFree.hpp" -#include "window.hpp" + struct TDVText : SubText { TDVText() { @@ -31,11 +31,14 @@ struct TDVText : SubText { struct TD_202 : Module { NVGcolor fg; NVGcolor bg; + bool txtDirty = false; bool fgDirty = false; bool bgDirty = false; std::string text = ""; TD_202() : Module() { - config(0, 0, 0, 0); + config(0, 0, 0, 2); + configLight(0, "Module Link"); + configLight(1, "Module Link"); } int reset = 0; void onReset() override { @@ -53,16 +56,22 @@ struct TD_202 : Module { } } void process(const ProcessArgs &args) override { + bool left = false; + bool right = false; if (leftExpander.module) { if ((leftExpander.module->model == modelTF101) || (leftExpander.module->model == modelTF102)) { processExpander((float *)(leftExpander.module->rightExpander.consumerMessage)); + left = true; } } if (rightExpander.module) { if ((rightExpander.module->model == modelTF101) || (rightExpander.module->model == modelTF102)) { processExpander((float *)(rightExpander.module->leftExpander.consumerMessage)); + right = true; } } + lights[0].setBrightness(left); + lights[1].setBrightness(right); } json_t *dataToJson() override { json_t *rootJ = json_object(); @@ -76,15 +85,19 @@ struct TD_202 : Module { void dataFromJson(json_t *rootJ) override { json_t *textJ = json_object_get(rootJ, "text"); - if (textJ) + if (textJ) { text = json_string_value(textJ); - json_t *fgJ = json_object_get(rootJ, "fg"); - if (fgJ) { + txtDirty = true; + } + json_t *fgJ = json_object_get(rootJ, "fg"); + if (fgJ) { fg = color::fromHexString(json_string_value(fgJ)); + fgDirty = true; } json_t *bgJ = json_object_get(rootJ, "bg"); if (bgJ) { bg = color::fromHexString(json_string_value(bgJ)); + bgDirty = true; } } @@ -93,47 +106,35 @@ struct TD_202 : Module { struct TD202 : SchemeModuleWidget { TDVText *textField; + void textChanged() { + TD_202 *tdm = dynamic_cast(module); + if (tdm) + tdm->text = textField->text; + } + TD202(Module *module) { setModule(module); this->box.size = Vec(30, 380); addChild(new SchemePanel(this->box.size)); - MouseTransformWidget *tw = createWidget(Vec(2, 15)); + MouseTransformWidget *tw = createWidget(Vec(2.5, 15)); tw->rotate(M_PI / 2.0f); addChild(tw); textField = createWidget(Vec(0, -25)); textField->box.size = Vec(350, 30); + textField->changeHandler = [=]() { textChanged(); }; tw->addChild(textField); - } - void fromJson(json_t *rootJ) override { - ModuleWidget::fromJson(rootJ); - - TD_202 *tdModule = dynamic_cast(module); - if (tdModule) { - textField->text = tdModule->text; - textField->color = tdModule->fg; - textField->bgColor = tdModule->bg; - } - - json_t *textJ = json_object_get(rootJ, "text"); - if (textJ) - textField->text = json_string_value(textJ); - json_t *fgJ = json_object_get(rootJ, "fg"); - if (fgJ) { - textField->color = color::fromHexString(json_string_value(fgJ)); - } - json_t *bgJ = json_object_get(rootJ, "bg"); - if (bgJ) { - textField->bgColor = color::fromHexString(json_string_value(bgJ)); - } + addChild(createLightCentered(Vec(3, 14), module, 0)); + addChild(createLightCentered(Vec(27, 14), module, 1)); } void step() override { SchemeModuleWidget::step(); TD_202 *tdModule = dynamic_cast(module); if (!tdModule) { + textField->text = "Submarine TD-202"; return; } if (tdModule->reset) { @@ -151,6 +152,10 @@ struct TD202 : SchemeModuleWidget { textField->bgColor = tdModule->bg; tdModule->bgDirty = false; } + if (tdModule->txtDirty) { + textField->text = tdModule->text; + tdModule->txtDirty = false; + } tdModule->text = textField->text; tdModule->fg = textField->color; tdModule->bg = textField->bgColor; @@ -164,6 +169,7 @@ struct TD202 : SchemeModuleWidget { void render(NVGcontext *vg, SchemeCanvasWidget *canvas) override { drawBase(vg, "TD-202"); } + }; Model *modelTD202 = createModel("TD-202"); diff --git a/src/TD3.cpp b/src/TD3.cpp old mode 100755 new mode 100644 index 07b0155b..b4d3012b --- a/src/TD3.cpp +++ b/src/TD3.cpp @@ -1,11 +1,12 @@ //SubTag W16 WP AM #include "SubmarineFree.hpp" -#include "window.hpp" struct TD_316 : Module { TD_316() : Module () { - config(0, 0, 0, 0); + config(0, 0, 0, 2); + configLight(0, "Module Link"); + configLight(1, "Module Link"); } void processExpander(float *message) { if (!std::isnan(message[0])) { @@ -22,16 +23,22 @@ struct TD_316 : Module { } } void process(const ProcessArgs &args) override { + bool left = false; + bool right = false; if (leftExpander.module) { if ((leftExpander.module->model == modelTF101) || (leftExpander.module->model == modelTF102)) { processExpander((float *)(leftExpander.module->rightExpander.consumerMessage)); + left = true; } } if (rightExpander.module) { if ((rightExpander.module->model == modelTF101) || (rightExpander.module->model == modelTF102)) { processExpander((float *)(rightExpander.module->leftExpander.consumerMessage)); + right = true; } } + lights[0].setBrightness(left); + lights[1].setBrightness(right); } void onReset() override { reset = 1; @@ -50,22 +57,27 @@ struct TD_316 : Module { json_t *widthJ = json_object_get(rootJ, "width"); if (widthJ) { moduleSize = clamp(json_number_value(widthJ), 75.0f, 300.0f); + moduleSizeDirty = true; } json_t *textJ = json_object_get(rootJ, "text"); if (textJ) { text = json_string_value(textJ); + textDirty = true; } json_t *sizeJ = json_object_get(rootJ, "size"); if (sizeJ) { fontSize = json_number_value(sizeJ); + fontSizeDirty = true; } json_t *fgJ = json_object_get(rootJ, "fg"); if (fgJ) { fg = color::fromHexString(json_string_value(fgJ)); + fgDirty = true; } json_t *bgJ = json_object_get(rootJ, "bg"); if (bgJ) { bg = color::fromHexString(json_string_value(bgJ)); + bgDirty = true; } } @@ -77,6 +89,7 @@ struct TD_316 : Module { bool bgDirty = false; bool fontSizeDirty = false; bool textDirty = false; + bool moduleSizeDirty = false; float moduleSize = 240.0; std::string text; }; @@ -107,53 +120,41 @@ namespace { struct TD316 : SchemeModuleWidget { TD3Text *textField; SchemePanel *schemePanel; + LightWidget *light; TD316(TD_316 *module) { setModule(module); this->box.size = Vec(240, 380); schemePanel = new SchemePanel(this->box.size, 75.0f, 300.0f); + schemePanel->resizeHandler = [=]() { onResized(); }; addChild(schemePanel); textField = createWidget(Vec(4, 18)); textField->box.size = Vec(232, 344); textField->multiline = true; addChild(textField); - } - - void fromJson(json_t *rootJ) override { - ModuleWidget::fromJson(rootJ); - TD_316 *td = dynamic_cast(module); - if (td) { - textField->text = td->text; - textField->fontSize = td->fontSize; - textField->color = td->fg; - textField->bgColor = td->bg; - box.size.x = td->moduleSize; - schemePanel->resize(this, box); - } + addChild(createLightCentered(Vec(3, 14), module, 0)); + light = createLightCentered(Vec(237, 14), module, 1); + addChild(light); - json_t *textJ = json_object_get(rootJ, "text"); - if (textJ) - textField->text = json_string_value(textJ); - json_t *sizeJ = json_object_get(rootJ, "size"); - if (sizeJ) - textField->fontSize = json_number_value(sizeJ); - json_t *fgJ = json_object_get(rootJ, "fg"); - if (fgJ) { - textField->color = color::fromHexString(json_string_value(fgJ)); - } - json_t *bgJ = json_object_get(rootJ, "bg"); - if (bgJ) { - textField->bgColor = color::fromHexString(json_string_value(bgJ)); - } - } void step() override { TD_316 *tdModule = dynamic_cast(module); if (!tdModule) { + textField->text = "\n\n\n\n:Submarine TD-316:"; + textField->fontSize = 24; return; } + if (tdModule->moduleSizeDirty) { + box.size.x = tdModule->moduleSize; + schemePanel->resize(this, box); + tdModule->moduleSizeDirty = false; + } + if (tdModule->textDirty) { + textField->text = tdModule->text; + tdModule->textDirty = false; + } if (tdModule->fontSizeDirty) { textField->fontSize = tdModule->fontSize; tdModule->fontSizeDirty = false; @@ -198,6 +199,7 @@ struct TD316 : SchemeModuleWidget { TD_316 *td = dynamic_cast(module); td->moduleSize = box.size.x; } + light->box.pos.x = box.size.x - 5; } }; diff --git a/src/TD4.cpp b/src/TD4.cpp old mode 100755 new mode 100644 index e32ad833..75912400 --- a/src/TD4.cpp +++ b/src/TD4.cpp @@ -1,7 +1,6 @@ //SubTag W10 WP AM #include "SubmarineFree.hpp" -#include "window.hpp" namespace { @@ -15,7 +14,6 @@ namespace { struct TD4Text : OpaqueWidget { TD4Data *data = NULL; - std::shared_ptr font; std::function addMenuHandler; std::function posHandler; int oldPosition = 0; @@ -24,28 +22,31 @@ namespace { delete data; } TD4Text(float width) { - font = APP->window->loadFont(asset::system("res/fonts/ShareTechMono-Regular.ttf")); this->box.size = Vec(width - 8.0f, 20); } - void draw(const DrawArgs &args) override { - nvgFontFaceId(args.vg, font->handle); - nvgFontSize(args.vg, data->fontSize); - nvgFillColor(args.vg, data->color); - nvgSave(args.vg); - nvgScissor(args.vg, args.clipBox.pos.x, args.clipBox.pos.y, args.clipBox.size.x, args.clipBox.size.y); - if (data->alignment & NVG_ALIGN_LEFT) { - nvgTextAlign(args.vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); - nvgText(args.vg, 0, box.size.y / 2, data->text.c_str(), NULL); - } - else if (data->alignment & NVG_ALIGN_RIGHT) { - nvgTextAlign(args.vg, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE); - nvgText(args.vg, box.size.x, box.size.y / 2, data->text.c_str(), NULL); - } - else { - nvgTextAlign(args.vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); - nvgText(args.vg, box.size.x / 2, box.size.y / 2, data->text.c_str(), NULL); + void drawLayer(const DrawArgs &args, int layer) override { + if (layer == 1) { + std::shared_ptr font = APP->window->loadFont(asset::system("res/fonts/ShareTechMono-Regular.ttf")); + nvgFontFaceId(args.vg, font->handle); + nvgFontSize(args.vg, data->fontSize); + nvgFillColor(args.vg, data->color); + nvgSave(args.vg); + nvgScissor(args.vg, args.clipBox.pos.x, args.clipBox.pos.y, args.clipBox.size.x, args.clipBox.size.y); + if (data->alignment & NVG_ALIGN_LEFT) { + nvgTextAlign(args.vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); + nvgText(args.vg, 0, box.size.y / 2, data->text.c_str(), NULL); + } + else if (data->alignment & NVG_ALIGN_RIGHT) { + nvgTextAlign(args.vg, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE); + nvgText(args.vg, box.size.x, box.size.y / 2, data->text.c_str(), NULL); + } + else { + nvgTextAlign(args.vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); + nvgText(args.vg, box.size.x / 2, box.size.y / 2, data->text.c_str(), NULL); + } + nvgRestore(args.vg); } - nvgRestore(args.vg); + Widget::drawLayer(args, layer); } void onButton(const event::Button &e) override { if (e.button == GLFW_MOUSE_BUTTON_RIGHT && e.action == GLFW_PRESS) { @@ -110,8 +111,9 @@ struct TD_410 : Module { } void dataFromJson(json_t *rootJ) override { json_t *sizeJ = json_object_get(rootJ, "width"); - if (sizeJ) + if (sizeJ) { moduleSize = clamp(json_number_value(sizeJ), 75.0f, 300.0f); + } json_t *a1 = json_object_get(rootJ, "items"); if (a1) { int asize = json_array_size(a1); @@ -140,11 +142,13 @@ struct TD_410 : Module { item->fontSize = json_number_value(fSize); } dataItems.push_back(item); + lblDirty = true; } } } } float moduleSize = 150.0f; + bool lblDirty = false; }; struct TD410 : SchemeModuleWidget { @@ -153,61 +157,12 @@ struct TD410 : SchemeModuleWidget { TD410(TD_410 *module) { setModule(module); - this->box.size = Vec(150, 380); + this->box.size = Vec(module ? (module->moduleSize) : 150, 380); schemePanel = new SchemePanel(this->box.size, 75.0f, 300.0f); + schemePanel->resizeHandler = [=]() { onResized(); }; addChild(schemePanel); } - void fromJson(json_t *rootJ) override { - ModuleWidget::fromJson(rootJ); - TD_410 *tdModule = dynamic_cast(module); - if (!tdModule) return; - - for(TD4Data *data : tdModule->dataItems) { - TD4Text *item = new TD4Text(box.size.x); - item->data = data; - item->box.pos = Vec(4, 18); - addClickHandler(item); - item->box.size.y = data->fontSize = clampFontSize(data->fontSize); - item->box.pos.y = data->position = clampPosition(data->position); - addText(item); - } - json_t *a1 = json_object_get(rootJ, "items"); - if (a1) { - int asize = json_array_size(a1); - for (int j = 0; j < asize; j++) { - json_t *i = json_array_get(a1, j); - if (i) { - TD4Data *data = new TD4Data; - tdModule->dataItems.push_back(data); - TD4Text *item = new TD4Text(box.size.x); - item->data = data; - item->box.pos = Vec(4, 18); - addClickHandler(item); - json_t *text = json_object_get(i, "text"); - if (text) { - data->text = json_string_value(text); - } - json_t *color = json_object_get(i, "color"); - if (color) { - data->color = color::fromHexString(json_string_value(color)); - } - json_t *pos = json_object_get(i, "position"); - if (pos) { - item->box.pos.y = data->position = clampPosition(json_number_value(pos)); - } - json_t *align = json_object_get(i, "alignment"); - if (align) { - data->alignment = json_number_value(align); - } - addText(item); - } - } - } - box.size.x = tdModule->moduleSize; - schemePanel->resize(this, box); - } - int clampPosition(int input) { return clamp(input, 13, (int)(box.size.y) - 36); } @@ -411,7 +366,7 @@ struct TD410 : SchemeModuleWidget { textItem->data->text = newText; if (!module) return; - int moduleId = module->id; + int64_t moduleId = module->id; unsigned int id = index(textItem); APP->history->push(new EventWidgetAction( @@ -441,7 +396,7 @@ struct TD410 : SchemeModuleWidget { textItem->data->color = newColor; if (!module) return; - int moduleId = module->id; + int64_t moduleId = module->id; unsigned int id = index(textItem); APP->history->push(new EventWidgetAction( @@ -472,7 +427,7 @@ struct TD410 : SchemeModuleWidget { textItem->data->alignment = newAlignment; if (!module) return; - int moduleId = module->id; + int64_t moduleId = module->id; unsigned int id = index(textItem); APP->history->push(new EventWidgetAction( @@ -505,7 +460,7 @@ struct TD410 : SchemeModuleWidget { return; if (!module) return; - int moduleId = module->id; + int64_t moduleId = module->id; unsigned int id = index(textItem); APP->history->push(new EventWidgetAction( @@ -540,7 +495,7 @@ struct TD410 : SchemeModuleWidget { int newPosition = textItem->box.pos.y = textItem->data->position = clampPosition(textItem->data->position); if (!module) return; - int moduleId = module->id; + int64_t moduleId = module->id; unsigned int id = index(textItem); APP->history->push(new EventWidgetAction( @@ -583,6 +538,15 @@ struct TD410 : SchemeModuleWidget { nvgBeginPath(vg); nvgRect(vg, 4, 15, box.size.x - 8, box.size.y - 30); nvgFill(vg); + if (!module) { + std::shared_ptr font = APP->window->loadFont(asset::system("res/fonts/ShareTechMono-Regular.ttf")); + nvgFontFaceId(vg, font->handle); + nvgFontSize(vg, 25); + nvgFillColor(vg, SUBLIGHTBLUE); + nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); + nvgText(vg, box.size.x / 2, box.size.y / 2, "Submarine", NULL); + nvgText(vg, box.size.x / 2, box.size.y / 2 + 30, "TD-410", NULL); + } } void removeText(TD4Text *text) { @@ -627,7 +591,7 @@ struct TD410 : SchemeModuleWidget { int alignment = textItem->data->alignment; addText(text, color, position, alignment, fontSize); unsigned int id = textItems.size() - 1; - int moduleId = module->id; + int64_t moduleId = module->id; APP->history->push(new EventWidgetAction( "TD-410 Duplicate Label", [=]() { @@ -685,7 +649,7 @@ struct TD410 : SchemeModuleWidget { addText(newItem); if (!module) return; - int moduleId = module->id; + int64_t moduleId = module->id; int id = index(newItem); NVGcolor color = newItem->data->color; std::string text = newItem->data->text; @@ -711,7 +675,7 @@ struct TD410 : SchemeModuleWidget { } void removeTextWithHistory(TD4Text *oldItem) { - int moduleId = module->id; + int64_t moduleId = module->id; unsigned int id = index(oldItem); NVGcolor color = oldItem->data->color; std::string text = oldItem->data->text; @@ -738,8 +702,8 @@ struct TD410 : SchemeModuleWidget { )); } - TD410 *getModuleWidgetById(int moduleId) { - for (Widget *widget : APP->scene->rack->moduleContainer->children) { + TD410 *getModuleWidgetById(int64_t moduleId) { + for (Widget *widget : APP->scene->rack->getModuleContainer()->children) { TD410 *mw = dynamic_cast(widget); if (mw) { if (mw->module) { @@ -752,6 +716,26 @@ struct TD410 : SchemeModuleWidget { return NULL; } + void step() override { + TD_410 *tdm = dynamic_cast(module); + if (!tdm) + return; + if (tdm->lblDirty) { + + for (TD4Data *data : tdm->dataItems) { + TD4Text *item = new TD4Text(box.size.x); + item->data = data; + item->box.pos = Vec(4, 18); + addClickHandler(item); + item->box.size.y = data->fontSize = clampFontSize(data->fontSize); + item->box.pos.y = data->position = clampPosition(data->position); + addText(item); + } + tdm->lblDirty = false; + } + + } + void onResize(const event::Resize &e) override { ModuleWidget::onResize(e); onResized(); diff --git a/src/TD5.cpp b/src/TD5.cpp old mode 100755 new mode 100644 index ea58c4e6..1f1b763b --- a/src/TD5.cpp +++ b/src/TD5.cpp @@ -1,7 +1,6 @@ //SubTag W10 WP AM #include "SubmarineFree.hpp" -#include "window.hpp" namespace { @@ -16,7 +15,6 @@ namespace { struct TD5Text : OpaqueWidget { TD5Data *data = NULL; - std::shared_ptr font; std::function addMenuHandler; std::function posHandler; int oldPosition = 0; @@ -25,41 +23,44 @@ namespace { delete(data); } TD5Text() { - font = APP->window->loadFont(asset::system("res/fonts/ShareTechMono-Regular.ttf")); this->box.size = Vec(20, 350); } - void draw(const DrawArgs &args) override { - nvgFontFaceId(args.vg, font->handle); - nvgFontSize(args.vg, data->fontSize); - nvgFillColor(args.vg, data->color); - nvgSave(args.vg); - nvgScissor(args.vg, args.clipBox.pos.x, args.clipBox.pos.y, args.clipBox.size.x, args.clipBox.size.y); - int alignment = data->alignment; - if (data->flip) { - nvgTranslate(args.vg, 0, box.size.y); - nvgRotate(args.vg, M_PI * -0.5f); - if (data->alignment == 1) - alignment = 4; - else if (data->alignment == 4) - alignment = 1; - } - else { - nvgTranslate(args.vg, box.size.x, 0); - nvgRotate(args.vg, M_PI * 0.5f); - } - if (alignment & NVG_ALIGN_LEFT) { - nvgTextAlign(args.vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); - nvgText(args.vg, 0, box.size.x / 2, data->text.c_str(), NULL); - } - else if (alignment & NVG_ALIGN_RIGHT) { - nvgTextAlign(args.vg, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE); - nvgText(args.vg, box.size.y, box.size.x / 2, data->text.c_str(), NULL); - } - else { - nvgTextAlign(args.vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); - nvgText(args.vg, box.size.y / 2, box.size.x / 2, data->text.c_str(), NULL); + void drawLayer(const DrawArgs &args, int layer) override { + if (layer == 1) { + std::shared_ptr font = APP->window->loadFont(asset::system("res/fonts/ShareTechMono-Regular.ttf")); + nvgFontFaceId(args.vg, font->handle); + nvgFontSize(args.vg, data->fontSize); + nvgFillColor(args.vg, data->color); + nvgSave(args.vg); + nvgScissor(args.vg, args.clipBox.pos.x, args.clipBox.pos.y, args.clipBox.size.x, args.clipBox.size.y); + int alignment = data->alignment; + if (data->flip) { + nvgTranslate(args.vg, 0, box.size.y); + nvgRotate(args.vg, M_PI * -0.5f); + if (data->alignment == 1) + alignment = 4; + else if (data->alignment == 4) + alignment = 1; + } + else { + nvgTranslate(args.vg, box.size.x, 0); + nvgRotate(args.vg, M_PI * 0.5f); + } + if (alignment & NVG_ALIGN_LEFT) { + nvgTextAlign(args.vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); + nvgText(args.vg, 0, box.size.x / 2, data->text.c_str(), NULL); + } + else if (alignment & NVG_ALIGN_RIGHT) { + nvgTextAlign(args.vg, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE); + nvgText(args.vg, box.size.y, box.size.x / 2, data->text.c_str(), NULL); + } + else { + nvgTextAlign(args.vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); + nvgText(args.vg, box.size.y / 2, box.size.x / 2, data->text.c_str(), NULL); + } + nvgRestore(args.vg); } - nvgRestore(args.vg); + Widget::drawLayer(args, layer); } void onButton(const event::Button &e) override { if (e.button == GLFW_MOUSE_BUTTON_RIGHT && e.action == GLFW_PRESS) { @@ -125,8 +126,9 @@ struct TD_510 : Module { } void dataFromJson(json_t *rootJ) override { json_t *sizeJ = json_object_get(rootJ, "width"); - if (sizeJ) + if (sizeJ) { moduleSize = clamp(json_number_value(sizeJ), 75.0f, 300.0f); + } json_t *a1 = json_object_get(rootJ, "items"); if (a1) { int asize = json_array_size(a1); @@ -159,11 +161,13 @@ struct TD_510 : Module { item->flip = json_number_value(flip); } dataItems.push_back(item); + lblDirty = true; } } } } float moduleSize = 150.0f; + bool lblDirty = false; }; struct TD510 : SchemeModuleWidget { @@ -172,61 +176,12 @@ struct TD510 : SchemeModuleWidget { TD510(TD_510 *module) { setModule(module); - this->box.size = Vec(150, 380); + this->box.size = Vec(module ? (module->moduleSize) : 150, 380); schemePanel = new SchemePanel(this->box.size, 75.0f, 300.0f); + schemePanel->resizeHandler = [=]() { onResized(); }; addChild(schemePanel); } - void fromJson(json_t *rootJ) override { - ModuleWidget::fromJson(rootJ); - TD_510 *tdModule = dynamic_cast(module); - if (!tdModule) return; - - for(TD5Data *data : tdModule->dataItems) { - TD5Text *item = new TD5Text(); - item->data = data; - item->box.pos = Vec(4, 15); - addClickHandler(item); - item->box.size.x = data->fontSize = clampFontSize(data->fontSize); - item->box.pos.x = data->position; - addText(item); - } - box.size.x = tdModule->moduleSize; - json_t *a1 = json_object_get(rootJ, "items"); - if (a1) { - int asize = json_array_size(a1); - for (int j = 0; j < asize; j++) { - json_t *i = json_array_get(a1, j); - if (i) { - TD5Data *data = new TD5Data; - tdModule->dataItems.push_back(data); - TD5Text *item = new TD5Text(); - item->data = data; - item->box.pos = Vec(4, 15); - addClickHandler(item); - json_t *text = json_object_get(i, "text"); - if (text) { - data->text = json_string_value(text); - } - json_t *color = json_object_get(i, "color"); - if (color) { - data->color = color::fromHexString(json_string_value(color)); - } - json_t *pos = json_object_get(i, "position"); - if (pos) { - item->box.pos.x = data->position = json_number_value(pos); - } - json_t *align = json_object_get(i, "alignment"); - if (align) { - data->alignment = json_number_value(align); - } - addText(item); - } - } - } - schemePanel->resize(this, box); - } - int clampPosition(int input) { return clamp(input, 4, (int)(box.size.x) - 28); } @@ -439,7 +394,7 @@ struct TD510 : SchemeModuleWidget { textItem->data->text = newText; if (!module) return; - int moduleId = module->id; + int64_t moduleId = module->id; unsigned int id = index(textItem); APP->history->push(new EventWidgetAction( @@ -469,7 +424,7 @@ struct TD510 : SchemeModuleWidget { textItem->data->color = newColor; if (!module) return; - int moduleId = module->id; + int64_t moduleId = module->id; unsigned int id = index(textItem); APP->history->push(new EventWidgetAction( @@ -500,7 +455,7 @@ struct TD510 : SchemeModuleWidget { textItem->data->alignment = newAlignment; if (!module) return; - int moduleId = module->id; + int64_t moduleId = module->id; unsigned int id = index(textItem); APP->history->push(new EventWidgetAction( @@ -533,7 +488,7 @@ struct TD510 : SchemeModuleWidget { return; if (!module) return; - int moduleId = module->id; + int64_t moduleId = module->id; unsigned int id = index(textItem); APP->history->push(new EventWidgetAction( @@ -568,7 +523,7 @@ struct TD510 : SchemeModuleWidget { int newPosition = textItem->box.pos.x = textItem->data->position = clampPosition(textItem->data->position); if (!module) return; - int moduleId = module->id; + int64_t moduleId = module->id; unsigned int id = index(textItem); APP->history->push(new EventWidgetAction( @@ -600,7 +555,7 @@ struct TD510 : SchemeModuleWidget { if (!module) return; textItem->data->flip = flip; - int moduleId = module->id; + int64_t moduleId = module->id; unsigned int id = index(textItem); APP->history->push(new EventWidgetAction( @@ -642,6 +597,18 @@ struct TD510 : SchemeModuleWidget { nvgBeginPath(vg); nvgRect(vg, 4, 15, box.size.x - 8, box.size.y - 30); nvgFill(vg); + if (!module) { + std::shared_ptr font = APP->window->loadFont(asset::system("res/fonts/ShareTechMono-Regular.ttf")); + nvgFontFaceId(vg, font->handle); + nvgFontSize(vg, 25); + nvgFillColor(vg, SUBLIGHTBLUE); + nvgSave(vg); + nvgTranslate(vg, box.size.x, 0); + nvgRotate(vg, M_PI * 0.5f); + nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); + nvgText(vg, box.size.y / 2, box.size.x / 2, "Submarine TD-510", NULL); + nvgRestore(vg); + } } void removeText(TD5Text *text) { @@ -669,6 +636,7 @@ struct TD510 : SchemeModuleWidget { TD5Text *newItem = new TD5Text(); newItem->data = newData; newItem->box.size.x = fontSize; + newItem->box.size.y = box.size.y - 30; newItem->box.pos = Vec(newData->position = position, 15); addClickHandler(newItem); newData->color = color; @@ -688,7 +656,7 @@ struct TD510 : SchemeModuleWidget { int flip = textItem->data->flip; addText(text, color, position, alignment, fontSize, flip); unsigned int id = textItems.size() - 1; - int moduleId = module->id; + int64_t moduleId = module->id; APP->history->push(new EventWidgetAction( "TD-510 Duplicate Label", [=]() { @@ -746,7 +714,7 @@ struct TD510 : SchemeModuleWidget { addText(newItem); if (!module) return; - int moduleId = module->id; + int64_t moduleId = module->id; int id = index(newItem); NVGcolor color = newItem->data->color; std::string text = newItem->data->text; @@ -773,7 +741,7 @@ struct TD510 : SchemeModuleWidget { } void removeTextWithHistory(TD5Text *oldItem) { - int moduleId = module->id; + int64_t moduleId = module->id; unsigned int id = index(oldItem); NVGcolor color = oldItem->data->color; std::string text = oldItem->data->text; @@ -801,8 +769,8 @@ struct TD510 : SchemeModuleWidget { )); } - TD510 *getModuleWidgetById(int moduleId) { - for (Widget *widget : APP->scene->rack->moduleContainer->children) { + TD510 *getModuleWidgetById(int64_t moduleId) { + for (Widget *widget : APP->scene->rack->getModuleContainer()->children) { TD510 *mw = dynamic_cast(widget); if (mw) { if (mw->module) { @@ -815,10 +783,32 @@ struct TD510 : SchemeModuleWidget { return NULL; } + void step() override { + TD_510 *tdm = dynamic_cast(module); + if (!tdm) + return; + if (tdm->lblDirty) { + + for(TD5Data *data : tdm->dataItems) { + TD5Text *item = new TD5Text(); + item->data = data; + item->box.pos = Vec(4, 15); + addClickHandler(item); + item->box.size.x = data->fontSize = clampFontSize(data->fontSize); + item->box.size.y = box.size.y - 30; + + item->box.pos.x = data->position; + addText(item); + } + tdm->lblDirty = false; + } + } + void onResize(const event::Resize &e) override { ModuleWidget::onResize(e); onResized(); } + void onResized() { for (TD5Text *text : textItems) { text->box.pos.x = text->data->position = clampPosition(text->data->position); diff --git a/src/TF1.cpp b/src/TF1.cpp old mode 100755 new mode 100644 index b1fa0de5..88feae18 --- a/src/TF1.cpp +++ b/src/TF1.cpp @@ -1,7 +1,6 @@ //SubTag W2 W6 #include "SubmarineFree.hpp" -#include "shared/torpedo.hpp" template struct TF : Module { @@ -36,12 +35,13 @@ struct TF : Module { LIGHT_BG_RED, LIGHT_BG_GREEN, LIGHT_BG_BLUE, + LIGHT_LEFT, + LIGHT_RIGHT, NUM_LIGHTS }; float prevValues[7] {NAN,NAN,NAN,NAN,NAN,NAN,NAN}; int isDirty = false; - Torpedo::PatchOutputPort outPort = Torpedo::PatchOutputPort(this, OUTPUT_TOR); float messages[2][7] = {{NAN,NAN,NAN,NAN,NAN,NAN,NAN},{NAN,NAN,NAN,NAN,NAN,NAN,NAN}}; TF() : Module() { config(hasParams * NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); @@ -54,11 +54,22 @@ struct TF : Module { configParam(PARAM_BG_BLUE, 0.0f, 1.0f, 0.0f, "Background blue", "%", 0.f, 100.f); configParam(PARAM_FONT_SIZE, 6.0f, 26.0f, 12.0f, "Font size", "pts"); } + configInput(INPUT_FG_RED, "Foreground Red"); + configInput(INPUT_FG_GREEN, "Foreground Green"); + configInput(INPUT_FG_BLUE, "Foreground Blue"); + configInput(INPUT_BG_RED, "Background Red"); + configInput(INPUT_BG_GREEN, "Background Green"); + configInput(INPUT_BG_BLUE, "Background Blue"); + configInput(INPUT_FONT_SIZE, "Text Size"); + configOutput(OUTPUT_TOR, "Deprecated"); + configLight(LIGHT_FG_RED, "Foreground Colour"); + configLight(LIGHT_BG_RED, "Background Colour"); + configLight(LIGHT_LEFT, "Module Link"); + configLight(LIGHT_RIGHT, "Module Link"); prevValues[0] = 0.1569f; prevValues[1] = 0.6902f; prevValues[2] = 0.9529f; prevValues[6] = 12.0f; - outPort.size(1); leftExpander.producerMessage = rightExpander.producerMessage = messages[0]; leftExpander.consumerMessage = rightExpander.consumerMessage = messages[1]; } @@ -85,9 +96,7 @@ struct TF : Module { json_object_set_new(rootJ, "bg", json_string(encodeColor(prevValues[3], prevValues[4], prevValues[5]).c_str())); if (hasParams || inputs[INPUT_FONT_SIZE].isConnected()) json_object_set_new(rootJ, "size", json_real(prevValues[6])); - outPort.send("SubmarineFree", "TDNotesColor", rootJ); } - outPort.process(); float *message = (float *)(leftExpander.producerMessage); if (hasParams || inputs[INPUT_FG_RED].isConnected() || inputs[INPUT_FG_GREEN].isConnected() || inputs[INPUT_FG_BLUE].isConnected()) { message[0] = prevValues[0]; @@ -113,6 +122,8 @@ struct TF : Module { } leftExpander.messageFlipRequested = true; rightExpander.messageFlipRequested = true; + lights[LIGHT_LEFT].setBrightness(leftExpander.module && ((leftExpander.module->model == modelTD202) || (leftExpander.module->model == modelTD316))); + lights[LIGHT_RIGHT].setBrightness(rightExpander.module && ((rightExpander.module->model == modelTD202) || (rightExpander.module->model == modelTD316))); } std::string encodeColor(float r, float g, float b) { std::string out; @@ -161,8 +172,11 @@ struct TF101 : SchemeModuleWidget { addChild(createLightCentered>(Vec(14.5, 55.5), module, TF::LIGHT_FG_RED)); addChild(createLightCentered>(Vec(14.5, 189.5), module, TF::LIGHT_BG_RED)); + + addChild(createLightCentered(Vec(3, 14), module, TF::LIGHT_LEFT)); + addChild(createLightCentered(Vec(87, 14), module, TF::LIGHT_RIGHT)); - addOutput(createOutputCentered(Vec(73.5,31.5), module, TF::OUTPUT_TOR)); + addOutput(createOutputCentered(Vec(73.5,31.5), module, TF::OUTPUT_TOR)); } void render(NVGcontext *vg, SchemeCanvasWidget *canvas) override { drawBase(vg, "TF-101"); @@ -178,7 +192,6 @@ struct TF101 : SchemeModuleWidget { nvgMoveTo(vg, 4, 315.5); nvgLineTo(vg, 86, 315.5); nvgStroke(vg); - drawText(vg, 59, 35, NVG_ALIGN_RIGHT | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "OUT"); drawText(vg, 55, 57, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "FOREGROUND"); drawText(vg, 55, 191, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "BACKGROUND"); drawText(vg, 55, 325, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "TEXT-SIZE"); @@ -205,10 +218,13 @@ struct TF102 : SchemeModuleWidget { addInput(createInputCentered(Vec(15,265), module, TF::INPUT_BG_BLUE)); addInput(createInputCentered(Vec(15,315), module, TF::INPUT_FONT_SIZE)); - addChild(createLightCentered>(Vec(15, 71), module, TF::LIGHT_FG_RED)); - addChild(createLightCentered>(Vec(15, 186), module, TF::LIGHT_BG_RED)); + addChild(createLightCentered>(Vec(15, 71), module, TF::LIGHT_FG_RED)); + addChild(createLightCentered>(Vec(15, 186), module, TF::LIGHT_BG_RED)); - addOutput(createOutputCentered(Vec(15,40), module, TF::OUTPUT_TOR)); + addChild(createLightCentered(Vec(3, 14), module, TF::LIGHT_LEFT)); + addChild(createLightCentered(Vec(27, 14), module, TF::LIGHT_RIGHT)); + + addOutput(createOutputCentered(Vec(15,40), module, TF::OUTPUT_TOR)); } void render(NVGcontext *vg, SchemeCanvasWidget *canvas) override { drawBase(vg, "TF-102"); @@ -224,7 +240,6 @@ struct TF102 : SchemeModuleWidget { nvgMoveTo(vg, 2, 285); nvgLineTo(vg, 28, 285); nvgStroke(vg); - drawText(vg, 15, 25, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "OUT"); drawText(vg, 15, 65, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "FORE"); drawText(vg, 15, 180, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "BACK"); drawText(vg, 15, 295, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "SIZE"); diff --git a/src/TM1.cpp b/src/TM1.cpp deleted file mode 100755 index 1cd975cf..00000000 --- a/src/TM1.cpp +++ /dev/null @@ -1,142 +0,0 @@ -//SubTag W2 - -#include "SubmarineFree.hpp" -#include "shared/torpedo.hpp" - -struct TM_105; - -namespace { - - struct TM_105InPort : Torpedo::RawInputPort { - TM_105 *tmModule; - TM_105InPort(TM_105 *module, unsigned int portNum) : RawInputPort((Module *)module, portNum) {tmModule = module;} - void received(std::string appId, std::string message) override; - void error(unsigned int errorType) override; - }; - - struct TM_Msg { - std::string appId; - std::string msg; - }; -} // end namespace - -struct TM_105 : Module { - enum ParamIds { - NUM_PARAMS - }; - enum InputIds { - INPUT_1, - INPUT_2, - INPUT_3, - INPUT_4, - INPUT_5, - NUM_INPUTS - }; - enum OutputIds { - OUTPUT_TOR, - NUM_OUTPUTS - }; - enum LightIds { - LIGHT_Q_1, - LIGHT_Q_2, - LIGHT_Q_3, - LIGHT_Q_4, - LIGHT_Q_5, - LIGHT_M_1, - LIGHT_M_2, - LIGHT_M_3, - LIGHT_M_4, - LIGHT_M_5, - LIGHT_E_1, - LIGHT_E_2, - LIGHT_E_3, - LIGHT_E_4, - LIGHT_E_5, - NUM_LIGHTS - }; - - std::vector queue; - unsigned int count = 0; - unsigned int index = 0; - TM_105InPort inPort1 = TM_105InPort(this, INPUT_1); - TM_105InPort inPort2 = TM_105InPort(this, INPUT_2); - TM_105InPort inPort3 = TM_105InPort(this, INPUT_3); - TM_105InPort inPort4 = TM_105InPort(this, INPUT_4); - TM_105InPort inPort5 = TM_105InPort(this, INPUT_5); - dsp::PulseGenerator msgPulses[5]; - dsp::PulseGenerator errPulses[5]; - Torpedo::RawOutputPort outPort = Torpedo::RawOutputPort(this, OUTPUT_TOR); - TM_105() : Module() { - config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); - for (unsigned int i = 0; i < 5; i++) { - queue.push_back(TM_Msg()); - } - } - void process(const ProcessArgs &args) override; -}; - -namespace { - void TM_105InPort::received(std::string appId, std::string msg) { - if (tmModule->count >= 5) { - return; - } - unsigned int newPos = (tmModule->index + tmModule->count) % 5; - tmModule->queue[newPos].appId.assign(appId); - tmModule->queue[newPos].msg.assign(msg); - tmModule->count++; - tmModule->msgPulses[_portNum - TM_105::INPUT_1].trigger(0.1f); - } - - void TM_105InPort::error(unsigned int errorType) { - tmModule->errPulses[_portNum - TM_105::INPUT_1].trigger(0.1f); - } -} // end namespace - -void TM_105::process(const ProcessArgs &args) { - inPort1.process(); - inPort2.process(); - inPort3.process(); - inPort4.process(); - inPort5.process(); - if (!outPort.isBusy()) { - if (count) { - unsigned int sendPos = (count + index) % 5; - outPort.send(queue[sendPos].appId, queue[sendPos].msg); - index++; - index %= 5; - count--; - } - } - for(unsigned int i = 0; i < 5; i++) { - lights[LIGHT_Q_1 + i].setBrightness(count > i); - lights[LIGHT_M_1 + i].setBrightness(msgPulses[i].process(args.sampleTime)); - lights[LIGHT_E_1 + i].setBrightness(errPulses[i].process(args.sampleTime)); - } - outPort.process(); -} - -struct TM105 : SchemeModuleWidget { - TM105(TM_105 *module) { - setModule(module); - this->box.size = Vec(30, 380); - addChild(new SchemePanel(this->box.size)); - for (unsigned int i = 0; i < 5; i++) { - addInput(createInputCentered(Vec(15,41.5 + 32 * i), module, TM_105::INPUT_1 + i)); - addChild(createLightCentered>(Vec(4, 54.5 + 32 * i), module, TM_105::LIGHT_M_1 + i)); - addChild(createLightCentered>(Vec(26, 54.5 + 32 * i), module, TM_105::LIGHT_E_1 + i)); - } - addChild(createLightCentered>(Vec(15, 261.5), module, TM_105::LIGHT_Q_1)); - addChild(createLightCentered>(Vec(15, 266.5), module, TM_105::LIGHT_Q_2)); - addChild(createLightCentered>(Vec(15, 271.5), module, TM_105::LIGHT_Q_3)); - addChild(createLightCentered>(Vec(15, 276.5), module, TM_105::LIGHT_Q_4)); - addChild(createLightCentered>(Vec(15, 281.5), module, TM_105::LIGHT_Q_5)); - addOutput(createOutputCentered(Vec(15,244.5), module, TM_105::OUTPUT_TOR)); - } - void render(NVGcontext *vg, SchemeCanvasWidget *canvas) override { - drawBase(vg, "TM-105"); - drawText(vg, 15, 27, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "IN"); - drawText(vg, 15, 227, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "OUT"); - } -}; - -Model *modelTM105 = createModel("TM-105"); diff --git a/src/VMX.cpp b/src/VMX.cpp old mode 100755 new mode 100644 index cdf6715a..aef3c96b --- a/src/VMX.cpp +++ b/src/VMX.cpp @@ -12,7 +12,7 @@ a₀⋅y₀ = b₀⋅x₀ + b₁⋅x₋₁ + b₂⋅x₋₂ - a₁⋅y₋₁ - a ωn = 13.5119 (undamped natural frequency) a₀ = 4 + 4⋅ζ⋅ωn⋅Td + ωn²⋅Td² -a₁ = -8 + 2⋅ωn²⋅Td +a₁ = -8 + 2⋅ωn²⋅Td² a₂ = 4 - 4⋅ζ⋅ωn⋅Td + ωn²⋅Td² b₀ = ωn²⋅Td² b₁ = 2⋅ωn²⋅Td² @@ -36,6 +36,8 @@ namespace { NUM_OUTPUTS }; enum LightIds { + LIGHT_LINK_LEFT, + LIGHT_LINK_RIGHT, NUM_LIGHTS }; const double zeta = 0.81272; @@ -90,27 +92,34 @@ namespace { return rescale(x, 0.0f, 1.0f, min, max); } - struct VM_LinearDisplay : LightWidget { + struct VM_LinearDisplay : Widget { float value = 0.0f; - void draw(const DrawArgs &args) override { - float zeroPoint = squareScale(0, box.size.y, 0); - float meter = squareScale(value, 0.0f, box.size.y); - - NVGpaint grad = nvgLinearGradient(args.vg, 0, zeroPoint - 10.0f, 0, zeroPoint + 10.0f, SUBLIGHTRED, nvgRGB(30,255,0)); - nvgFillPaint(args.vg, grad); - - nvgBeginPath(args.vg); - nvgRect(args.vg, 0, box.size.y - meter, box.size.x, meter); - nvgFill(args.vg); - Widget::draw(args); + void drawLayer(const DrawArgs &args, int layer) override { + if (layer == 1) { + float meter = squareScale(value, 0.0f, box.size.y); + + if (meter) { + float zeroPoint = squareScale(0, box.size.y, 0); + NVGpaint grad = nvgLinearGradient(args.vg, 0, zeroPoint - 10.0f, 0, zeroPoint + 10.0f, SUBLIGHTRED, nvgRGB(30,255,0)); + nvgFillPaint(args.vg, grad); + + nvgBeginPath(args.vg); + nvgRect(args.vg, 0, box.size.y - meter, box.size.x, meter); + nvgFill(args.vg); + } + } + Widget::drawLayer(args, layer); } }; - struct VM_NeedleCanvas : Widget { - + struct VM_NeedleDisplay : Widget { + float value = 0.0f; + VM_NeedleDisplay(float width, float height) : Widget() { + box.size = Vec(width, height); + } void drawText(NVGcontext *vg, float x, float y, int align, float size, NVGcolor col, const char *txt) { - nvgFontFaceId(vg, gScheme.font(vg)); + nvgFontFaceId(vg, gScheme.font()->handle); nvgFontSize(vg, size * 90 / SVG_DPI); nvgTextAlign(vg, align); nvgFillColor(vg, col); @@ -119,7 +128,7 @@ namespace { void drawText(NVGcontext *vg, float point, NVGcolor col, const char *txt) { float tick = squareScale(point, M_PI * 0.75, M_PI * 0.25); drawText(vg, box.size.x * 0.5 + cos(tick) * box.size.y * 0.75f, box.size.y - sin(tick) * box.size.y * 0.77f, - NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, 8, col, txt); + NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, box.size.y * 0.08889, col, txt); } void addTick(const DrawArgs &args, float point) { @@ -134,93 +143,94 @@ namespace { nvgFillColor(args.vg, nvgRGB(255,255,255)); nvgRect(args.vg, 0, 0, box.size.x, box.size.y); nvgFill(args.vg); - - // Change from black to red scale - float zeroPoint = squareScale(0.0f, M_PI * 0.75, M_PI * 0.25); - - // Red arc - nvgLineCap(args.vg, NVG_ROUND); - nvgStrokeColor(args.vg, SUBLIGHTRED); - nvgBeginPath(args.vg); - nvgArc(args.vg, - box.size.x * 0.5f, - box.size.y, - box.size.y * 0.9f, - -zeroPoint, - M_PI * -0.25f, - NVG_CW); - addTick(args, 1.0f); - addTick(args, 2.0f); - addTick(args, 3.0f); - nvgStroke(args.vg); - - // Black arc - nvgStrokeColor(args.vg, nvgRGB(0,0,0)); - nvgBeginPath(args.vg); - nvgArc(args.vg, - box.size.x * 0.5f, - box.size.y, - box.size.y * 0.9f, - M_PI * -0.75f, - -zeroPoint, - NVG_CW); - addTick(args, 0.0f); - addTick(args, -1.0f); - addTick(args, -2.0f); - addTick(args, -3.0f); - addTick(args, -4.0f); - addTick(args, -5.0f); - addTick(args, -6.0f); - addTick(args, -7.0f); - addTick(args, -8.0f); - addTick(args, -9.0f); - addTick(args, -10.0f); - addTick(args, -20.0f); - nvgStroke(args.vg); - - drawText(args.vg, box.size.x * 0.5, box.size.y * 0.7, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, 12, nvgRGB(0,0,0), "VU"); - drawText(args.vg, 10, 20, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, 10, nvgRGB(0,0,0), "-"); - drawText(args.vg, box.size.x - 10, 20, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, 10, SUBLIGHTRED, "+"); - drawText(args.vg, -27, nvgRGB(0,0,0), "20"); - drawText(args.vg, -10, nvgRGB(0,0,0), "10"); - drawText(args.vg, -7, nvgRGB(0,0,0), "7"); - drawText(args.vg, -5, nvgRGB(0,0,0), "5"); - drawText(args.vg, -3, nvgRGB(0,0,0), "3"); - drawText(args.vg, -1, nvgRGB(0,0,0), "1"); - drawText(args.vg, 0, nvgRGB(0,0,0), "0"); - drawText(args.vg, 1, SUBLIGHTRED, "1"); - drawText(args.vg, 2, SUBLIGHTRED, "2"); - drawText(args.vg, 3.3, SUBLIGHTRED, "3"); - Widget::draw(args); } - }; - - struct VM_NeedleDisplay : LightWidget { - float value = 0.0f; - FramebufferWidget *fb; - VM_NeedleDisplay(float width, float height) : LightWidget() { - box.size = Vec(width, height); - fb = new FramebufferWidget(); - VM_NeedleCanvas *canvas = new VM_NeedleCanvas(); - canvas->box.size = box.size; - fb->addChild(canvas); - addChild(fb); - } - void draw(const DrawArgs &args) override { - Widget::draw(args); - float meter = squareScale(value, M_PI * 0.75, M_PI * 0.25); - nvgStrokeColor(args.vg, nvgRGB(0,0,0)); - nvgBeginPath(args.vg); - nvgMoveTo(args.vg, box.size.x * 0.5f, box.size.y); - nvgLineTo(args.vg, box.size.x * 0.5f + cos(meter) * box.size.y * 0.9f, box.size.y - sin(meter) * box.size.y * 0.9f); - nvgStrokeWidth(args.vg, 1); - nvgStroke(args.vg); + void drawLayer(const DrawArgs &args, int layer) override { + if (layer == 1) { + // White backpanel + nvgBeginPath(args.vg); + NVGpaint grad = nvgRadialGradient(args.vg, box.size.x * 0.5f, box.size.y * 1.2f, box.size.y * 0.5f, box.size.y * 2, nvgRGBAf(1, 1, 1, 1), nvgRGBAf(1, 1, 1, 0)); + nvgFillPaint(args.vg, grad); + nvgRect(args.vg, 0, 0, box.size.x, box.size.y); + nvgFill(args.vg); + + // Change from black to red scale + float zeroPoint = squareScale(0.0f, M_PI * 0.75, M_PI * 0.25); + + // Red arc + nvgLineCap(args.vg, NVG_ROUND); + nvgStrokeColor(args.vg, SUBLIGHTRED); + nvgBeginPath(args.vg); + nvgArc(args.vg, + box.size.x * 0.5f, + box.size.y, + box.size.y * 0.9f, + -zeroPoint, + M_PI * -0.25f, + NVG_CW); + addTick(args, 1.0f); + addTick(args, 2.0f); + addTick(args, 3.0f); + nvgStroke(args.vg); + + // Black arc + nvgStrokeColor(args.vg, nvgRGB(0,0,0)); + nvgBeginPath(args.vg); + nvgArc(args.vg, + box.size.x * 0.5f, + box.size.y, + box.size.y * 0.9f, + M_PI * -0.75f, + -zeroPoint, + NVG_CW); + addTick(args, 0.0f); + addTick(args, -1.0f); + addTick(args, -2.0f); + addTick(args, -3.0f); + addTick(args, -4.0f); + addTick(args, -5.0f); + addTick(args, -6.0f); + addTick(args, -7.0f); + addTick(args, -8.0f); + addTick(args, -9.0f); + addTick(args, -10.0f); + addTick(args, -20.0f); + nvgStroke(args.vg); + + drawText(args.vg, box.size.x * 0.5, box.size.y * 0.7, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, 12, nvgRGB(0,0,0), "VU"); + drawText(args.vg, 10, box.size.y * 0.222, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, 10, nvgRGB(0,0,0), "-"); + drawText(args.vg, box.size.x - 10, box.size.y * 0.222, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, 10, SUBLIGHTRED, "+"); + drawText(args.vg, -27, nvgRGB(0,0,0), "20"); + drawText(args.vg, -10, nvgRGB(0,0,0), "10"); + drawText(args.vg, -7, nvgRGB(0,0,0), "7"); + drawText(args.vg, -5, nvgRGB(0,0,0), "5"); + drawText(args.vg, -3, nvgRGB(0,0,0), "3"); + drawText(args.vg, -1, nvgRGB(0,0,0), "1"); + drawText(args.vg, 0, nvgRGB(0,0,0), "0"); + drawText(args.vg, 1, SUBLIGHTRED, "1"); + drawText(args.vg, 2, SUBLIGHTRED, "2"); + drawText(args.vg, 3.3, SUBLIGHTRED, "3"); + + float meter = squareScale(value, M_PI * 0.75, M_PI * 0.25); + nvgStrokeColor(args.vg, nvgRGB(0,0,0)); + nvgBeginPath(args.vg); + nvgMoveTo(args.vg, box.size.x * 0.5f, box.size.y); + nvgLineTo(args.vg, box.size.x * 0.5f + cos(meter) * box.size.y * 0.9f, box.size.y - sin(meter) * box.size.y * 0.9f); + nvgStrokeWidth(args.vg, 1); + nvgStroke(args.vg); + } + Widget::drawLayer(args, layer); } }; + } struct VM_Base : Module { + unsigned int meterCount; + unsigned int inputCount = 0; + float load = 150; + float attenuation = 0; + float data[16]; VM_Base() : Module() { } Menu * addLoadMenu() { @@ -228,17 +238,17 @@ struct VM_Base : Module { Module * module = this; EventWidgetMenuItem *m = createMenuItem("150\xe2\x84\xa6"); m->clickHandler = [=]() { - APP->engine->setParam(module, PARAM_LOAD, 150); + APP->engine->setParamValue(module, PARAM_LOAD, 150); }; menu->addChild(m); m = createMenuItem("600\xe2\x84\xa6"); m->clickHandler = [=]() { - APP->engine->setParam(module, PARAM_LOAD, 600); + APP->engine->setParamValue(module, PARAM_LOAD, 600); }; menu->addChild(m); m = createMenuItem("1000\xe2\x84\xa6"); m->clickHandler = [=]() { - APP->engine->setParam(module, PARAM_LOAD, 1000); + APP->engine->setParamValue(module, PARAM_LOAD, 1000); }; menu->addChild(m); return menu; @@ -254,6 +264,70 @@ struct VM_Base : Module { }; menu->addChild(m); } + + void getLinkedData() { + bool left = false; + bool right = false; + + VM_Base *searchMod = this; + unsigned int dataOffset = 0; + for (unsigned int i = inputCount; i < meterCount; i++) { + data[i] = 0; + } + if (!inputCount) { // no inputs of our own, look to the left + bool found = false; + while (!found) { + if (searchMod->leftExpander.module) { + if ((searchMod->leftExpander.module->model == modelVM101) || + (searchMod->leftExpander.module->model == modelVM102) || + (searchMod->leftExpander.module->model == modelVM104) || + (searchMod->leftExpander.module->model == modelVM201) || + (searchMod->leftExpander.module->model == modelVM202) || + (searchMod->leftExpander.module->model == modelVM204)) { + searchMod = reinterpret_cast(searchMod->leftExpander.module); + dataOffset += searchMod->meterCount; + if (dataOffset >= 16) + break; + if (searchMod->inputCount) { + for(unsigned int i = 0; i < meterCount; i++) { + if (dataOffset >= searchMod->inputCount) + break; + data[i] = searchMod->data[dataOffset++]; + left = true; + } + load = searchMod->load; + attenuation = searchMod->attenuation; + break; + } + continue; + } + } + break; + } + } + else { + dataOffset = meterCount; + } + if (dataOffset < searchMod->inputCount && rightExpander.module) { + if ((rightExpander.module->model == modelVM101) || + (rightExpander.module->model == modelVM102) || + (rightExpander.module->model == modelVM104) || + (rightExpander.module->model == modelVM201) || + (rightExpander.module->model == modelVM202) || + (rightExpander.module->model == modelVM204)) { + searchMod = reinterpret_cast(rightExpander.module); + if (!searchMod->inputCount) + right = true; + } + } + if (load != params[PARAM_LOAD].getValue()) + params[PARAM_LOAD].setValue(load); + if (attenuation != params[PARAM_ATTENUATOR].getValue()) + params[PARAM_ATTENUATOR].setValue(attenuation); + + lights[LIGHT_LINK_LEFT].setBrightness(left); + lights[LIGHT_LINK_RIGHT].setBrightness(right); + } }; template @@ -264,9 +338,15 @@ struct VM_ : VM_Base { }; VM_() : VM_Base() { + meterCount = x; config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); configParam(PARAM_LOAD, 50.0f, 20000.0f, 600.0f, "Load Resistor", "\xe2\x84\xa6"); configParam(PARAM_ATTENUATOR, -2.0f, 4.0f, 0.0f, "Attenuator", "x", 2.0f); + for(unsigned int i = 0; i < x; i++) { + configInput(INPUT_1 + i, string::f("Signal %d", i + 1)); + } + configLight(LIGHT_LINK_LEFT, "Module Link"); + configLight(LIGHT_LINK_RIGHT, "Module Link"); } Coefficients c { { APP->engine->getSampleTime() } }; @@ -275,8 +355,8 @@ struct VM_ : VM_Base { c.Recalculate(APP->engine->getSampleTime()); } double calculate(double y_0) { - double vRef = 1 / std::sqrt(params[PARAM_LOAD].getValue() * 0.001); - double atten = params[PARAM_ATTENUATOR].getValue() * 6.0f; + double vRef = 1 / std::sqrt(load * 0.001); + double atten = attenuation * 6.0f; double sample = 20 * std::log10(y_0 * vRef) - atten; if (std::isnan(sample)) { sample = -20.0f; @@ -293,20 +373,62 @@ struct VM_xx1 : VM_<1> { Samples samples; void process(const ProcessArgs &args) override { - samples.process(&c, inputs[INPUT_1].getVoltage(0)); + inputs[INPUT_1].readVoltages(data); + inputCount = inputs[INPUT_1].getChannels(); + load = params[PARAM_LOAD].getValue(); + attenuation = params[PARAM_ATTENUATOR].getValue(); + + getLinkedData(); + + samples.process(&c, data[0]); } }; struct VM_102 : VM_<1> { - VM_102() : VM_<1>() { } + VM_102() : VM_<1>() { + meterCount = 2; + } Samples samples_1; Samples samples_2; void process(const ProcessArgs &args) override { - samples_1.process(&c, inputs[INPUT_1].getVoltage(0)); - samples_2.process(&c, inputs[INPUT_1].getVoltage(1)); + inputs[INPUT_1].readVoltages(data); + inputCount = inputs[INPUT_1].getChannels(); + load = params[PARAM_LOAD].getValue(); + attenuation = params[PARAM_ATTENUATOR].getValue(); + + getLinkedData(); + + samples_1.process(&c, data[0]); + samples_2.process(&c, data[1]); + } +}; + +struct VM_xx4 : VM_<1> { + + VM_xx4() : VM_<1>() { + meterCount = 4; + } + + Samples samples_1; + Samples samples_2; + Samples samples_3; + Samples samples_4; + + void process(const ProcessArgs &args) override { + inputs[INPUT_1].readVoltages(data); + inputCount = inputs[INPUT_1].getChannels(); + load = params[PARAM_LOAD].getValue(); + attenuation = params[PARAM_ATTENUATOR].getValue(); + + getLinkedData(); + + samples_1.process(&c, data[0]); + samples_2.process(&c, data[1]); + samples_3.process(&c, data[2]); + samples_4.process(&c, data[3]); } }; @@ -318,13 +440,22 @@ struct VM_202 : VM_<2> { Samples samples_2; void process(const ProcessArgs &args) override { - samples_1.process(&c, inputs[INPUT_1].getVoltage(0)); - if (inputs[INPUT_1 + 1].isConnected()) { - samples_2.process(&c, inputs[INPUT_1 + 1].getVoltage(0)); + inputs[INPUT_1].readVoltages(data); + inputCount = inputs[INPUT_1].getChannels(); + load = params[PARAM_LOAD].getValue(); + attenuation = params[PARAM_ATTENUATOR].getValue(); + if (!inputs[INPUT_1].isConnected()) { + data[0] = 0; } - else { - samples_2.process(&c, inputs[INPUT_1].getVoltage(1)); + if (inputs[INPUT_1 + 1].isConnected()) { + inputCount = 2; + data[1] = inputs[INPUT_1 + 1].getVoltage(0); } + + getLinkedData(); + + samples_1.process(&c, data[0]); + samples_2.process(&c, data[1]); } }; @@ -356,6 +487,8 @@ struct VM101 : VMxxx { addInput(createInputCentered(Vec(15,350), module, VM_xx1::INPUT_1)); addParam(createParamCentered>(Vec(15, 315), module, PARAM_ATTENUATOR)); + addChild(createLightCentered(Vec(3, 332), module, LIGHT_LINK_LEFT)); + addChild(createLightCentered(Vec(27, 332), module, LIGHT_LINK_RIGHT)); } void addTick(NVGcontext *vg, float point) { float tick = displayPos + squareScale(point, displayHeight, 0.0f); @@ -431,6 +564,8 @@ struct VM102 : VMxxx { addInput(createInputCentered(Vec(15,350), module, VM_102::INPUT_1)); addParam(createParamCentered>(Vec(15, 315), module, PARAM_ATTENUATOR)); + addChild(createLightCentered(Vec(3, 332), module, LIGHT_LINK_LEFT)); + addChild(createLightCentered(Vec(27, 332), module, LIGHT_LINK_RIGHT)); } void addTick(NVGcontext *vg, float point) { float tick = displayPos + squareScale(point, displayHeight, 0.0f); @@ -486,6 +621,85 @@ struct VM102 : VMxxx { } }; +struct VM104 : VMxxx { + const float displayHeight = 276.0f; + const float displayPos = 19.5f; + VM_LinearDisplay *display1; + VM_LinearDisplay *display2; + VM_LinearDisplay *display3; + VM_LinearDisplay *display4; + VM104(VM_xx4 *module) : VMxxx() { + setModule(module); + this->box.size = Vec(30, 380); + addChild(new SchemePanel(this->box.size)); + + display1 = new VM_LinearDisplay(); + display1->box.pos = Vec(2, displayPos); + display1->box.size = Vec(6, displayHeight); + addChild(display1); + + display2 = new VM_LinearDisplay(); + display2->box.pos = Vec(9, displayPos); + display2->box.size = Vec(6, displayHeight); + addChild(display2); + + display3 = new VM_LinearDisplay(); + display3->box.pos = Vec(16, displayPos); + display3->box.size = Vec(6, displayHeight); + addChild(display3); + + display4 = new VM_LinearDisplay(); + display4->box.pos = Vec(23, displayPos); + display4->box.size = Vec(6, displayHeight); + addChild(display4); + + addInput(createInputCentered(Vec(15,350), module, VM_102::INPUT_1)); + addParam(createParamCentered>(Vec(15, 315), module, PARAM_ATTENUATOR)); + addChild(createLightCentered(Vec(3, 332), module, LIGHT_LINK_LEFT)); + addChild(createLightCentered(Vec(27, 332), module, LIGHT_LINK_RIGHT)); + } + void addTick(NVGcontext *vg, float point) { + float tick = displayPos + squareScale(point, displayHeight, 0.0f); + nvgMoveTo(vg, 2, tick); + nvgLineTo(vg, 28, tick); + } + void render(NVGcontext *vg, SchemeCanvasWidget *canvas) override { + drawBase(vg, "VM-104"); + nvgStrokeWidth(vg, 1); + nvgBeginPath(vg); + nvgStrokeColor(vg, SUBLIGHTRED); + addTick(vg, 1); + addTick(vg, 2); + addTick(vg, 3); + nvgStroke(vg); + nvgBeginPath(vg); + nvgStrokeColor(vg, gScheme.getContrast(module)); + addTick(vg, 0); + addTick(vg, -1); + addTick(vg, -2); + addTick(vg, -3); + addTick(vg, -4); + addTick(vg, -5); + addTick(vg, -6); + addTick(vg, -7); + addTick(vg, -8); + addTick(vg, -9); + addTick(vg, -10); + addTick(vg, -20); + nvgStroke(vg); + } + void step() override { + if (module) { + VM_xx4 *vmModule = dynamic_cast(module); + display1->value = vmModule->calculate(vmModule->samples_1.y_0); + display2->value = vmModule->calculate(vmModule->samples_2.y_0); + display3->value = vmModule->calculate(vmModule->samples_3.y_0); + display4->value = vmModule->calculate(vmModule->samples_4.y_0); + } + SchemeModuleWidget::step(); + } +}; + struct VM201 : VMxxx { VM_NeedleDisplay *display; VM201(VM_xx1 *module) : VMxxx() { @@ -497,12 +711,14 @@ struct VM201 : VMxxx { display->box.pos = Vec(10, 20); addChild(display); - addInput(createInputCentered(Vec(20,330), module, VM_xx1::INPUT_1)); + addInput(createInputCentered(Vec(35,330), module, VM_xx1::INPUT_1)); addParam(createParamCentered>(Vec(115, 330), module, PARAM_ATTENUATOR)); + addChild(createLightCentered(Vec(3, 332), module, LIGHT_LINK_LEFT)); + addChild(createLightCentered(Vec(147, 332), module, LIGHT_LINK_RIGHT)); } void render(NVGcontext *vg, SchemeCanvasWidget *canvas) override { drawBase(vg, "VM-201"); - drawText(vg, 20, 355, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "INPUT"); + drawText(vg, 35, 355, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "INPUT"); drawText(vg, 115, 355, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "ATTENUATOR"); } void step() override { @@ -530,13 +746,15 @@ struct VM202 : VMxxx { display2->box.pos = Vec(10, 120); addChild(display2); - addInput(createInputCentered(Vec(20,330), module, VM_202::INPUT_1)); - addInput(createInputCentered(Vec(55,330), module, VM_202::INPUT_1 + 1)); + addInput(createInputCentered(Vec(35,330), module, VM_202::INPUT_1)); + addInput(createInputCentered(Vec(70,330), module, VM_202::INPUT_1 + 1)); addParam(createParamCentered>(Vec(115, 330), module, PARAM_ATTENUATOR)); + addChild(createLightCentered(Vec(3, 332), module, LIGHT_LINK_LEFT)); + addChild(createLightCentered(Vec(147, 332), module, LIGHT_LINK_RIGHT)); } void render(NVGcontext *vg, SchemeCanvasWidget *canvas) override { drawBase(vg, "VM-202"); - drawText(vg, 37.5f, 355, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "INPUT"); + drawText(vg, 52.5f, 355, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "INPUT"); drawText(vg, 115, 355, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "ATTENUATOR"); } void step() override { @@ -549,7 +767,57 @@ struct VM202 : VMxxx { } }; +struct VM204 : VMxxx { + VM_NeedleDisplay *display1; + VM_NeedleDisplay *display2; + VM_NeedleDisplay *display3; + VM_NeedleDisplay *display4; + VM204(VM_xx4 *module) : VMxxx() { + setModule(module); + this->box.size = Vec(120, 380); + addChild(new SchemePanel(this->box.size)); + + display1 = new VM_NeedleDisplay(100, 70); + display1->box.pos = Vec(10, 15); + addChild(display1); + + display2 = new VM_NeedleDisplay(100, 70); + display2->box.pos = Vec(10, 90); + addChild(display2); + + display3 = new VM_NeedleDisplay(100, 70); + display3->box.pos = Vec(10, 165); + addChild(display3); + + display4 = new VM_NeedleDisplay(100, 70); + display4->box.pos = Vec(10, 240); + addChild(display4); + + addInput(createInputCentered(Vec(35,330), module, VM_xx4::INPUT_1)); + addParam(createParamCentered>(Vec(85, 330), module, PARAM_ATTENUATOR)); + addChild(createLightCentered(Vec(3, 332), module, LIGHT_LINK_LEFT)); + addChild(createLightCentered(Vec(117, 332), module, LIGHT_LINK_RIGHT)); + } + void render(NVGcontext *vg, SchemeCanvasWidget *canvas) override { + drawBase(vg, "VM-204"); + drawText(vg, 35, 355, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "INPUT"); + drawText(vg, 85, 355, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "ATTENUATOR"); + } + void step() override { + if (module) { + VM_xx4 *vmModule = dynamic_cast(module); + display1->value = vmModule->calculate(vmModule->samples_1.y_0); + display2->value = vmModule->calculate(vmModule->samples_2.y_0); + display3->value = vmModule->calculate(vmModule->samples_3.y_0); + display4->value = vmModule->calculate(vmModule->samples_4.y_0); + } + SchemeModuleWidget::step(); + } +}; + Model *modelVM101 = createModel("VM-101"); Model *modelVM102 = createModel("VM-102"); +Model *modelVM104 = createModel("VM-104"); Model *modelVM201 = createModel("VM-201"); Model *modelVM202 = createModel("VM-202"); +Model *modelVM204 = createModel("VM-204"); diff --git a/src/WKX.cpp b/src/WKX.cpp old mode 100755 new mode 100644 index 6d17892f..9aa81fe5 --- a/src/WKX.cpp +++ b/src/WKX.cpp @@ -1,7 +1,6 @@ //SubTag W2 W10 #include "SubmarineFree.hpp" -#include "shared/torpedo.hpp" #include #include @@ -114,7 +113,7 @@ namespace { line.append(1,c); strings[i].erase(0,1); if (!std::isdigit(c) && (c != '/') && (c != '.')) { - WARN("SubmarineFree WK: Scala file format error in %s", string::filename(path).c_str()); + WARN("SubmarineFree WK: Scala file format error in %s", system::getFilename(path).c_str()); return; } if (c == '.') @@ -122,7 +121,7 @@ namespace { if (c == '/' && !ratio) ratio = line.size(); if (decimal && ratio) { - WARN("SubmarineFree WK: Scala file format error in %s", string::filename(path).c_str()); + WARN("SubmarineFree WK: Scala file format error in %s", system::getFilename(path).c_str()); return; } } @@ -131,13 +130,13 @@ namespace { float d = std::stof(line, nullptr); d -= (i-1) * 100.0; if ((d < -50.0) || (d > 50.0)) { - WARN("SubmarineFree WK: Scala file format error in %s", string::filename(path).c_str()); + WARN("SubmarineFree WK: Scala file format error in %s", system::getFilename(path).c_str()); return; } tuning.offsets[(i-1)%12] = d; } catch (std::exception &err) { - WARN("SubmarineFree WK: Scala file format error in %s", string::filename(path).c_str()); + WARN("SubmarineFree WK: Scala file format error in %s", system::getFilename(path).c_str()); return; } } @@ -149,20 +148,20 @@ namespace { int inum = std::stoi(num,nullptr); int idenom = std::stoi(denom, nullptr); if (!idenom) { - WARN("SubmarineFree WK: Scala file format error in %s", string::filename(path).c_str()); + WARN("SubmarineFree WK: Scala file format error in %s", system::getFilename(path).c_str()); return; } float r = (1.0f * inum / idenom); float d = 1200.0 * log2(r); d -= (i-1) * 100.0; if ((d < -50.0) || (d > 50.0)) { - WARN("SubmarineFree WK: Scala file format error in %s", string::filename(path).c_str()); + WARN("SubmarineFree WK: Scala file format error in %s", system::getFilename(path).c_str()); return; } tuning.offsets[(i-1)%12] = d; } catch (std::exception &err) { - WARN("SubmarineFree WK: Scala file format error in %s", string::filename(path).c_str()); + WARN("SubmarineFree WK: Scala file format error in %s", system::getFilename(path).c_str()); return; } } @@ -172,13 +171,13 @@ namespace { float d = 1200.0 * log2(inum); d -= (i-1) * 100.0; if ((d < -50.0) || (d > 50.0)) { - WARN("SubmarineFree WK: Scala file format error in %s", string::filename(path).c_str()); + WARN("SubmarineFree WK: Scala file format error in %s", system::getFilename(path).c_str()); return; } tuning.offsets[(i-1)%12] = d; } catch (std::exception &err) { - WARN("SubmarineFree WK: Scala file format error in %s", string::filename(path).c_str()); + WARN("SubmarineFree WK: Scala file format error in %s", system::getFilename(path).c_str()); return; } } @@ -194,20 +193,14 @@ namespace { } void WK_Tunings::loadTuningsFromScala(Plugin *pluginInstance) { - std::list dirList = system::getEntries(asset::plugin(pluginInstance, "Scala")); + std::vector dirList = system::getEntries(asset::plugin(pluginInstance, "Scala"), 0); for (auto entry : dirList) { if (system::isDirectory(entry)) continue; - if (string::lowercase(string::filenameExtension(entry)).compare("scl")) continue; + if (string::lowercase(system::getExtension(entry)).compare(".scl")) continue; loadScalaFile(entry); } } - struct WK101_InputPort : Torpedo::PatchInputPort { - WK_101 *wkModule; - WK101_InputPort(WK_101 *module, unsigned int portNum):PatchInputPort((Module *)module, portNum) { wkModule = module;}; - void received(std::string pluginName, std::string moduleName, json_t *rootJ) override; - }; - } // end namespace struct WK_101 : Module { @@ -237,19 +230,23 @@ struct WK_101 : Module { NUM_OUTPUTS }; enum LightIds { + LIGHT_EXT, NUM_LIGHTS }; - int toSend = 0; unsigned int light = PARAM_1; - Torpedo::PatchOutputPort outPort = Torpedo::PatchOutputPort(this, OUTPUT_TOR); - WK101_InputPort inPort = WK101_InputPort(this, INPUT_TOR); + float tunings[12]; WK_101() : Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); for (unsigned int i = 0; i < NUM_PARAMS; i++) { configParam(PARAM_1 + i, -50.0f, 50.0f, 0.0f, "Detune", " cents"); } - outPort.size(5); + configInput(INPUT_CV, "V/oct"); + configInput(INPUT_TOR, "Deprecated"); + configOutput(OUTPUT_CV, "Quantised V/oct"); + configOutput(OUTPUT_TOR, "Deprecated"); + configLight(LIGHT_EXT, "Module Link"); + configBypass(INPUT_CV, OUTPUT_CV); } void process(const ProcessArgs &args) override { @@ -257,53 +254,30 @@ struct WK_101 : Module { int note = (120 + quantized) % 12; outputs[OUTPUT_CV].setVoltage((params[PARAM_1 + note].getValue() / 1200.0f) + (quantized / 12.0f)); light = note; - if (toSend && !outPort.isBusy()) { - toSend = 0; - json_t *rootJ = json_array(); - for (int i = 0; i < 12; i++) - json_array_append_new(rootJ, json_real(params[PARAM_1 + i].getValue())); - outPort.send(std::string(TOSTRING(SLUG)), std::string("WK"), rootJ); + for (unsigned int i = 0; i < 12; i++) { + tunings[i] = params[PARAM_1 + i].getValue(); } - outPort.process(); - inPort.process(); + lights[LIGHT_EXT].setBrightness(rightExpander.module && (rightExpander.module->model == modelWK205)); } }; namespace { - void WK101_InputPort::received(std::string pluginName, std::string moduleName, json_t *rootJ) { - if (pluginName.compare(TOSTRING(SLUG))) return; - if (moduleName.compare("WK")) return; - float tunings[12]; - int size = json_array_size(rootJ); - if (!size) return; - if (size > 12) - size = 12; - for (int i = 0; i < size; i++) { - json_t *j1 = json_array_get(rootJ, i); - if (j1) - tunings[i] = json_number_value(j1); - } - for (int i = 0; i < 12; i++) - wkModule->params[WK_101::PARAM_1 + i].setValue(tunings[i]); - } - - struct WK_Display : LightWidget { - WK_101 *module; - int index; + struct WK_Display : Widget { + LightKnob *knob; char dspText[20]; - void draw(const DrawArgs &args) override { - if (!module) { - return; + void drawLayer(const DrawArgs &args, int layer) override { + if (knob && (layer == 1)) { + float val = knob->getParamQuantity()->getValue(); + sprintf(dspText, "%+05.2f", val); + nvgFontSize(args.vg, 14); + nvgFontFaceId(args.vg, gScheme.font()->handle); + nvgFillColor(args.vg, SUBLIGHTBLUE); + nvgTextAlign(args.vg, NVG_ALIGN_CENTER); + nvgText(args.vg, 30, 13, dspText, NULL); } - float val = APP->engine->getParam(module, WK_101::PARAM_1 + index); - sprintf(dspText, "%+05.2f", val); - nvgFontSize(args.vg, 14); - nvgFontFaceId(args.vg, gScheme.font()->handle); - nvgFillColor(args.vg, SUBLIGHTBLUE); - nvgTextAlign(args.vg, NVG_ALIGN_CENTER); - nvgText(args.vg, 30, 13, dspText, NULL); + Widget::drawLayer(args, layer); } }; @@ -316,53 +290,48 @@ namespace { } MedKnob::step(); } - void onChange(const event::Change &e) override { - MedKnob::onChange(e); - - if (module) { - module->toSend = true; - } - } }; } // end namespace struct WK101 : SchemeModuleWidget { + WK_Param *knobs[12]; WK101(WK_101 *module) { setModule(module); this->box.size = Vec(150, 380); addChild(new SchemePanel(this->box.size)); addInput(createInputCentered(Vec(16.5,41.5), module, WK_101::INPUT_CV)); - addOutput(createOutputCentered(Vec(55.5,41.5), module, WK_101::OUTPUT_CV)); - addInput(createInputCentered(Vec(94.5,41.5), module, WK_101::INPUT_TOR)); - addOutput(createOutputCentered(Vec(133.5,41.5), module, WK_101::OUTPUT_TOR)); + addOutput(createOutputCentered(Vec(133.5,41.5), module, WK_101::OUTPUT_CV)); + addInput(createInputCentered(Vec(94.5,41.5), module, WK_101::INPUT_TOR)); + addOutput(createOutputCentered(Vec(55.5,41.5), module, WK_101::OUTPUT_TOR)); + addChild(createLightCentered(Vec(147, 25), module, WK_101::LIGHT_EXT)); for (int i = 0; i < 5; i++) { + knobs[i] = createParamCentered(Vec(23 + 104 * (i%2),89 + 21 * i), module, WK_101::PARAM_1 + i); + knobs[i]->module = module; + knobs[i]->index = i; + addParam(knobs[i]); WK_Display *display = new WK_Display(); - display->module = module; - display->index = i; display->box.pos = Vec(45, 79 + 21 * i); display->box.size = Vec(60, 20); addChild(display); - WK_Param *widget = createParamCentered(Vec(23 + 104 * (i%2),89 + 21 * i), module, WK_101::PARAM_1 + i); - widget->module = module; - widget->index = i; - addParam(widget); + if (module) + display->knob = knobs[i]; } for (int i = 5; i < 12; i++) { + knobs[i] = createParamCentered(Vec(127 - 104 * (i%2),110 + 21 * i), module, WK_101::PARAM_1 + i); + knobs[i]->module = module; + knobs[i]->index = i; + addParam(knobs[i]); WK_Display *display = new WK_Display(); - display->module = module; - display->index = i; display->box.pos = Vec(45, 100 + 21 * i); display->box.size = Vec(60, 20); addChild(display); - WK_Param *widget = createParamCentered(Vec(127 - 104 * (i%2),110 + 21 * i), module, WK_101::PARAM_1 + i); - widget->module = module; - widget->index = i; - addParam(widget); + if (module) + display->knob = knobs[i]; } WK_Tunings::loadTunings(pluginInstance); } @@ -522,12 +491,9 @@ struct WK101 : SchemeModuleWidget { nvgRoundedRect(vg, 50, 332, 50, 17, 4); nvgFill(vg); - drawText(vg, 36, 25, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "V/OCT"); - drawText(vg, 114, 25, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "SYNC"); - drawText(vg, 16.5, 61, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "IN"); - drawText(vg, 55.5, 61, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "OUT"); - drawText(vg, 94.5, 61, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "IN"); - drawText(vg, 133.5, 61, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "OUT"); + drawText(vg, 75, 41.5, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, 8, gScheme.getContrast(module), "V/OCT"); + drawText(vg, 30, 41.5, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, 8, gScheme.getContrast(module), "IN"); + drawText(vg, 120, 41.5, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE, 8, gScheme.getContrast(module), "OUT"); } }; @@ -540,9 +506,8 @@ void WK101::appendContextMenu(Menu *menu) { EventWidgetMenuItem *m = createMenuItem(tunings[i].name.c_str()); m->clickHandler = [=]() { for (int j = 0; j < 12; j++) { - APP->engine->setParam(module, WK_101::PARAM_1 + j, tunings[i].offsets[j]); + knobs[j]->getParamQuantity()->setValue(tunings[i].offsets[j]); } - module->toSend = true; }; menu->addChild(m); } @@ -551,16 +516,6 @@ void WK101::appendContextMenu(Menu *menu) { struct WK_205; -namespace { - - struct WK205_InputPort : Torpedo::PatchInputPort { - WK_205 *wkModule; - WK205_InputPort(WK_205 *module, unsigned int portNum):PatchInputPort((Module *)module, portNum) { wkModule = module;}; - void received(std::string pluginName, std::string moduleName, json_t *rootJ) override; - }; - -} // end namespace - struct WK_205 : Module { static const int deviceCount = 5; enum ParamIds { @@ -584,13 +539,22 @@ struct WK_205 : Module { NUM_OUTPUTS }; enum LightIds { + LIGHT_EXT_LEFT, + LIGHT_EXT_RIGHT, NUM_LIGHTS }; float tunings[12]; - WK205_InputPort inPort = WK205_InputPort(this, INPUT_TOR); WK_205() : Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + for (unsigned int i = 0; i < 5; i++) { + configInput(INPUT_CV_1 + i, string::f("Signal %d", i + 1)); + configOutput(OUTPUT_CV_1 + i, string::f("Signal %d", i + 1)); + configBypass(INPUT_CV_1 + i, OUTPUT_CV_1 + i); + } + configInput(INPUT_TOR, "Deprecated"); + configLight(LIGHT_EXT_LEFT, "Module Link"); + configLight(LIGHT_EXT_RIGHT, "Module Link"); } void process(const ProcessArgs &args) override; json_t *dataToJson(void) override { @@ -613,41 +577,45 @@ struct WK_205 : Module { }; void WK_205::process(const ProcessArgs &args) { + bool light = false; + if (leftExpander.module) { + if (leftExpander.module->model == modelWK101) { + WK_101 *wk = dynamic_cast(leftExpander.module); + for (unsigned int i = 0; i < 12; i++) { + tunings[i] = wk->tunings[i]; + } + light = true; + } + if (leftExpander.module->model == modelWK205) { + WK_205 *wk = dynamic_cast(leftExpander.module); + for (unsigned int i = 0; i < 12; i++) { + tunings[i] = wk->tunings[i]; + } + light = true; + } + } + lights[LIGHT_EXT_LEFT].setBrightness(light); + lights[LIGHT_EXT_RIGHT].setBrightness(rightExpander.module && (rightExpander.module->model == modelWK205)); for (int i = 0; i < deviceCount; i++) { int quantized = floor((12.0f * inputs[INPUT_CV_1 + i].getVoltage()) + 0.5f); int note = (120 + quantized) % 12; outputs[OUTPUT_CV_1 + i].setVoltage((tunings[note] / 1200.0f) + (quantized / 12.0f)); } - inPort.process(); } -namespace { - void WK205_InputPort::received(std::string pluginName, std::string moduleName, json_t *rootJ) { - if (pluginName.compare(TOSTRING(SLUG))) return; - if (moduleName.compare("WK")) return; - int size = json_array_size(rootJ); - if (!size) return; - if (size > 12) - size = 12; - for (int i = 0; i < size; i++) { - json_t *j1 = json_array_get(rootJ, i); - if (j1) - wkModule->tunings[i] = json_number_value(j1); - } - } -} // end namespace - struct WK205 : SchemeModuleWidget { WK205(WK_205 *module) { setModule(module); this->box.size = Vec(30, 380); addChild(new SchemePanel(this->box.size)); - addInput(createInputCentered(Vec(15,31.5), module, WK_205::INPUT_TOR)); + addInput(createInputCentered(Vec(15,31.5), module, WK_205::INPUT_TOR)); for (int i = 0; i < WK_205::deviceCount; i++) { addInput(createInputCentered(Vec(15,75.5 + i * 60), module, WK_205::INPUT_CV_1 + i)); addOutput(createOutputCentered(Vec(15,104.5 + i * 60), module, WK_205::OUTPUT_CV_1 + i)); } + addChild(createLightCentered(Vec(3, 25), module, WK_205::LIGHT_EXT_LEFT)); + addChild(createLightCentered(Vec(27, 25), module, WK_205::LIGHT_EXT_RIGHT)); WK_Tunings::loadTunings(pluginInstance); } @@ -669,7 +637,6 @@ struct WK205 : SchemeModuleWidget { } void render(NVGcontext *vg, SchemeCanvasWidget *canvas) override { drawBase(vg, "WK-205"); - drawText(vg, 15, 52, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE, 8, gScheme.getContrast(module), "SYNC"); nvgStrokeColor(vg, gScheme.getContrast(module)); nvgStrokeWidth(vg, 1); nvgLineCap(vg, NVG_ROUND); diff --git a/src/WM1.cpp b/src/WM1.cpp old mode 100755 new mode 100644 index e027265d..e69de228 --- a/src/WM1.cpp +++ b/src/WM1.cpp @@ -1,6 +1,4 @@ //SubTag W10 WP AM -#include -#include #include #include "SubmarineFree.hpp" @@ -627,7 +625,7 @@ struct WM101 : SizeableModuleWidget, WM_Base { ModuleWidget *lastHover = NULL; bool highlightIsDirty = true; - int cableCount = 0; + int64_t cableCount = 0; Widget *lastCable = NULL; unsigned int newColorIndex = 0; @@ -675,7 +673,7 @@ struct WM101 : SizeableModuleWidget, WM_Base { backPanel = new BackPanel(); backPanel->box.pos = Vec(10, 15); - backPanel->box.size = Vec(box.size.x - 20, box.size.y - 30); + backPanel->box.size = Vec(130, box.size.y - 30); addChild(backPanel); scrollWidget = new ScrollWidget(); scrollWidget->box.pos = Vec(0, 21); @@ -719,7 +717,7 @@ struct WM101 : SizeableModuleWidget, WM_Base { deleteLabel = new EventWidgetLabel(); deleteLabel->box.pos = Vec(15, 195); - deleteLabel->box.size = Vec(box.size.x - 40, 19); + deleteLabel->box.size = Vec(110, 19); deleteConfirmPanel->addChild(deleteLabel); deleteOkButton = new EventWidgetButton(); @@ -755,7 +753,7 @@ struct WM101 : SizeableModuleWidget, WM_Base { billboardPanel = new BillboardPanel(); billboardPanel->box.pos = Vec(0, 15); - billboardPanel->box.size = Vec(box.size.x, box.size.y - 30); + billboardPanel->box.size = Vec(150, box.size.y - 30); billboardPanel->visible = false; billboardPanel->drawHandler = [=](const DrawArgs &args) { this->drawBillboard(args); @@ -789,7 +787,7 @@ struct WM101 : SizeableModuleWidget, WM_Base { varyCheck = new EventWidgetCheckBox(); varyCheck->label = "Variation"; varyCheck->box.pos = Vec(10, 5); - varyCheck->box.size = Vec(box.size.x - 40, 19); + varyCheck->box.size = Vec(110, 19); varyCheck->changeHandler = [=]() { this->varyCheckChanged(); }; settingsPanel->addChild(varyCheck); @@ -813,7 +811,7 @@ struct WM101 : SizeableModuleWidget, WM_Base { varyH = new EventWidgetSlider(); varyH->box.pos = Vec(20, 25); - varyH->box.size = Vec(box.size.x - 50, 19); + varyH->box.size = Vec(100, 19); varyH->value = 0.1f; varyH->textHandler = [](float value) -> std::string { return string::f("%.4g%s", value * 360.0, "\xC2\xB0"); @@ -841,7 +839,7 @@ struct WM101 : SizeableModuleWidget, WM_Base { varyS = new EventWidgetSlider(); varyS->box.pos = Vec(20, 45); - varyS->box.size = Vec(box.size.x - 50, 19); + varyS->box.size = Vec(100, 19); varyS->value = 0.1f; varyS->textHandler = percentageTextHandler; varyS->label = "Saturation"; @@ -867,7 +865,7 @@ struct WM101 : SizeableModuleWidget, WM_Base { varyL = new EventWidgetSlider(); varyL->box.pos = Vec(20, 65); - varyL->box.size = Vec(box.size.x - 50, 19); + varyL->box.size = Vec(100, 19); varyL->value = 0.1f; varyL->textHandler = percentageTextHandler; varyL->label = "Lightness"; @@ -894,13 +892,13 @@ struct WM101 : SizeableModuleWidget, WM_Base { EventWidgetLabel *highlightLabel = new EventWidgetLabel(); highlightLabel->label = "Highlighting"; highlightLabel->box.pos = Vec(10, 105); - highlightLabel->box.size = Vec(box.size.x - 40, 19); + highlightLabel->box.size = Vec(110, 19); settingsPanel->addChild(highlightLabel); highlightOff = new EventWidgetRadioButton(); highlightOff->label = "Off"; highlightOff->box.pos = Vec(10, 125); - highlightOff->box.size = Vec(box.size.x - 40, 19); + highlightOff->box.size = Vec(110, 19); highlightOff->selected = true; highlightOff->changeHandler = [=]() { this->highlightChanged(HIGHLIGHT_OFF); @@ -911,7 +909,7 @@ struct WM101 : SizeableModuleWidget, WM_Base { highlightLow = new EventWidgetRadioButton(); highlightLow->label = "When hovering"; highlightLow->box.pos = Vec(10, 145); - highlightLow->box.size = Vec(box.size.x - 40, 19); + highlightLow->box.size = Vec(110, 19); highlightLow->changeHandler = [=]() { this->highlightChanged(HIGHLIGHT_LOW); this->saveSettings(); @@ -921,7 +919,7 @@ struct WM101 : SizeableModuleWidget, WM_Base { highlightOn = new EventWidgetRadioButton(); highlightOn->label = "Always On"; highlightOn->box.pos = Vec(10, 165); - highlightOn->box.size = Vec(box.size.x - 40, 19); + highlightOn->box.size = Vec(110, 19); highlightOn->changeHandler = [=]() { this->highlightChanged(HIGHLIGHT_ON); this->saveSettings(); @@ -930,7 +928,7 @@ struct WM101 : SizeableModuleWidget, WM_Base { highlightSlider = new EventWidgetSlider(); highlightSlider->box.pos = Vec(10, 185); - highlightSlider->box.size = Vec(box.size.x - 40, 21); + highlightSlider->box.size = Vec(110, 21); highlightSlider->value = 0.1f; highlightSlider->textHandler = percentageTextHandler; highlightSlider->label = "Opacity"; @@ -959,14 +957,14 @@ struct WM101 : SizeableModuleWidget, WM_Base { redoCheck = new EventWidgetCheckBox(); redoCheck->label = "Redo colors?"; redoCheck->box.pos = Vec(10, 220); - redoCheck->box.size = Vec(box.size.x - 40, 19); + redoCheck->box.size = Vec(110, 19); redoCheck->changeHandler = [=]() { this->redoCheckChanged(); }; settingsPanel->addChild(redoCheck); billboard3d = new EventWidgetCheckBox(); billboard3d->label = "3D billboard?"; billboard3d->box.pos = Vec(10, 255); - billboard3d->box.size = Vec(box.size.x - 40, 19); + billboard3d->box.size = Vec(110, 19); billboard3d->selected = 1; billboard3d->changeHandler = [=]() { this->billboard3dChanged(); }; settingsPanel->addChild(billboard3d); @@ -1005,12 +1003,24 @@ struct WM101 : SizeableModuleWidget, WM_Base { blockingButton->clickHandler = [=]() { this->takeMasterSlot(); }; blockingPanel->addChild(blockingButton); - if (!module) + if (module) { + setInitialSize(module); + } + else { loadSettings(); + } } ~WM101() { this->_delete(); } + void setInitialSize(SizeableModule *module) { + if (module->loadedSize == 0) + return; + if (module->loadedSize == module->size) + return; + module->size = module->loadedSize; + Minimize(module->size < 16.0f); + } void onHoverKey(const event::HoverKey &e) override { ModuleWidget::onHoverKey(e); if (e.isConsumed()) @@ -1128,9 +1138,10 @@ struct WM101 : SizeableModuleWidget, WM_Base { if (!module) { return; } + if (!stabilized) { stabilized = true; - cableCount = APP->scene->rack->cableContainer->children.size(); + cableCount = APP->scene->rack->getCableContainer()->children.size(); } if (masterWireManager != this) { if (masterWireManager) { @@ -1142,11 +1153,12 @@ struct WM101 : SizeableModuleWidget, WM_Base { } takeMasterSlot(); } - int newSize = APP->scene->rack->cableContainer->children.size(); + int64_t newSize = APP->scene->rack->getCableContainer()->children.size(); + if (newSize < cableCount) { cableCount = newSize; if (cableCount) - lastCable = APP->scene->rack->cableContainer->children.back(); + lastCable = APP->scene->rack->getCableContainer()->children.back(); else lastCable = NULL; } @@ -1158,20 +1170,20 @@ struct WM101 : SizeableModuleWidget, WM_Base { APP->history->push(complex); cableCount = 0; } - std::list::reverse_iterator iterator = APP->scene->rack->cableContainer->children.rbegin(); - for (int i = 0; i < newSize - cableCount; i++) { + std::list::reverse_iterator iterator = APP->scene->rack->getCableContainer()->children.rbegin(); + for (int64_t i = 0; i < newSize - cableCount; i++) { colorCable(*iterator, complex); ++iterator; } cableCount = newSize; if (cableCount) - lastCable = APP->scene->rack->cableContainer->children.back(); + lastCable = APP->scene->rack->getCableContainer()->children.back(); else lastCable = NULL; highlightIsDirty = true; } - if (wirePanel->visible && APP->scene->rack->incompleteCable) { - colorCable(APP->scene->rack->incompleteCable,NULL); + if (wirePanel->visible && APP->scene->rack->getIncompleteCable()) { + colorCable(APP->scene->rack->getIncompleteCable(),NULL); } highlightWires(); SizeableModuleWidget::step(); @@ -1191,7 +1203,7 @@ struct WM101 : SizeableModuleWidget, WM_Base { } if (highlightIsDirty) { highlightIsDirty = false; - for (Widget *widget : APP->scene->rack->cableContainer->children) { + for (Widget *widget : APP->scene->rack->getCableContainer()->children) { CableWidget *cable = dynamic_cast(widget); if (focusedModuleWidget) { if (!cable->outputPort || !cable->inputPort) { @@ -1219,7 +1231,7 @@ struct WM101 : SizeableModuleWidget, WM_Base { } void colorCable(Widget *widget, history::ComplexAction *complex) { CableWidget *cable = dynamic_cast(widget); - if (cable->cable->id > -1 && !complex && redoCheck->selected && !wirePanel->visible) + if (cable->cable && cable->cable->id > -1 && !complex && redoCheck->selected && !wirePanel->visible) return; NVGcolor oldColor = cable->color; if (wirePanel->visible) { @@ -1235,7 +1247,7 @@ struct WM101 : SizeableModuleWidget, WM_Base { if (!complex) return; NVGcolor newColor = cable->color; - int id = cable->cable->id; + int64_t id = cable->cable->id; complex->push( new EventWidgetAction("Color Cable", [id, oldColor](){ @@ -1503,7 +1515,6 @@ struct WM101 : SizeableModuleWidget, WM_Base { } addColor(nvgRGB(0xff, 0xae, 0xc9), "", false); - addColor(nvgRGB(0xb7, 0x00, 0xb5), "", false); addColor(nvgRGB(0x80, 0x80, 0x80), "", false); addColor(nvgRGB(0xff, 0xff, 0xff), "", false); addColor(nvgRGB(0x10, 0x0f, 0x12), "", false); @@ -1816,7 +1827,7 @@ struct WM101 : SizeableModuleWidget, WM_Base { Menu *menu = createMenu(); if (forcePosition) { // put the name field under the mouse - menu->box.pos = APP->window->mousePos.minus(Vec(100, 12)); + menu->box.pos = APP->scene->rack->getMousePos().minus(Vec(100, 12)); } EventParamField *paramField = new EventParamField(); paramField->box.size.x = 100; @@ -1976,7 +1987,7 @@ struct WM101 : SizeableModuleWidget, WM_Base { // Append .vcv extension if no extension was given. std::string pathStr = pathC; - if (string::filenameExtension(string::filename(pathStr)) == "") { + if (system::getExtension(system::getFilename(pathStr)) == "") { pathStr += ".wmCollection"; } @@ -2498,6 +2509,7 @@ struct WM102 : SchemeModuleWidget, WM_Base { void render(NVGcontext *vg, SchemeCanvasWidget *canvas) override { if (!module) { drawBase(vg, "WM-102"); + drawEasterEgg(vg); return; } WM_102 *wm = dynamic_cast(module); @@ -2511,6 +2523,25 @@ struct WM102 : SchemeModuleWidget, WM_Base { drawBillboardBase(vg, renderBox, wm->colors, wm->labels, draw3d); nvgRestore(vg); } + void drawEasterEgg(NVGcontext *vg) { + Rect renderBox; + renderBox.pos = Vec(0, 15); + renderBox.size = Vec(box.size.x, box.size.y - 30); + nvgSave(vg); + nvgTranslate(vg, renderBox.pos.x, renderBox.pos.y); + std::vector colors; + colors.push_back(color::fromHexString("#c91847")); + colors.push_back(color::fromHexString("#0986ad")); + colors.push_back(color::fromHexString("#c9b70e")); + colors.push_back(color::fromHexString("#0c8e15")); + std::vector labels; + labels.push_back(""); + labels.push_back("Submarine"); + labels.push_back("WM-102"); + labels.push_back(""); + drawBillboardBase(vg, renderBox, colors, labels, true); + nvgRestore(vg); + } void appendContextMenu(Menu *menu) override { if(!module) return; @@ -2590,6 +2621,7 @@ struct WM102 : SchemeModuleWidget, WM_Base { btn->labels = labels; return btn; } + /* void fromJson(json_t *rootJ) override { ModuleWidget::fromJson(rootJ); if (!module) @@ -2614,6 +2646,7 @@ struct WM102 : SchemeModuleWidget, WM_Base { module->params[WM_102::PARAM_LOCKED].setValue(clamp((int)json_number_value(v1), 0, 1)); } } + */ }; Model *modelWM101 = createModel("WM-101"); diff --git a/src/XFX.cpp b/src/XFX.cpp index 576f0885..5aeb7ced 100644 --- a/src/XFX.cpp +++ b/src/XFX.cpp @@ -104,8 +104,8 @@ namespace { int cv; int link; void step() override { - if (paramQuantity) { - Module *module = paramQuantity->module; + if (module) { + //Module *module = paramQuantity->module; if (link) { setEnabled(!module->inputs[cv].isConnected() && (module->params[link].getValue() < 0.5f)); } @@ -209,9 +209,16 @@ struct XF_101 : XF { }; XF_101() : XF(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { - configParam(PARAM_CV_1, 0.0f, 1.0f, 0.0f, "CV is bipolar"); - configParam(PARAM_MODE_1, 0.0f, 2.0f, 0.0f, "Fade profile"); + configSwitch(PARAM_CV_1, 0.0f, 1.0f, 0.0f, "CV Mode", { "Unipolar", "Bipolar" }); + configSwitch(PARAM_MODE_1, 0.0f, 2.0f, 0.0f, "Fade Profile", { "Linear", "Logarithmic", "Automatic" }); configParam(PARAM_FADE_1, 0.0f, 10.0f, 5.0f, "A/B blend", "%", 0.f, 10.f ); + configInput(INPUT_A_1, "Signal A"); + configInput(INPUT_B_1, "Signal B"); + configInput(INPUT_CV_1, "CV"); + configOutput(OUTPUT_1, "Signal"); + configLight(LIGHT_LIN_1, "Linear"); + configLight(LIGHT_LOG_1, "Logarithmic"); + configLight(LIGHT_AUTO_1, "Auto / Inverted"); } void process(const ProcessArgs &args) override { @@ -304,10 +311,10 @@ struct XF_102 : XF { XF_Controls controls[(int)(deviceCount * 1.5f)]; XF_102() : XF(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { - configParam(PARAM_LINK_1, 0.0f, 1.0f, 0.0f, "Link faders"); + configSwitch(PARAM_LINK_1, 0.0f, 1.0f, 0.0f, "Link Faders", { "Unlinked", "Linked" }); for (int i = 0; i < deviceCount; i++) { - configParam(PARAM_CV_1 + i, 0.0f, 1.0f, 0.0f, string::f("Fader %d CV is bipolar", i + 1)); - configParam(PARAM_MODE_1 + i, 0.0f, 2.0f, 0.0f, string::f("Fader %d Fade profile", i + 1)); + configSwitch(PARAM_CV_1 + i, 0.0f, 1.0f, 0.0f, "CV Mode", { "Unipolar", "Bipolar" }); + configSwitch(PARAM_MODE_1 + i, 0.0f, 2.0f, 0.0f, "Fade Profile", { "Linear", "Logarithmic", "Automatic" }); configParam(PARAM_FADE_1 + i, 0.0f, 10.0f, 5.0f, string::f("Fader %d A/B blend", i + 1), "%", 0.f, 10.f); controls[i].a = INPUT_A_1 + i; controls[i].ar = 0; @@ -341,6 +348,20 @@ struct XF_102 : XF { controls[i + deviceCount].light3 = LIGHT_AUTO_1 + x * 2; controls[i + deviceCount].correlator = &correlators[x]; } + configInput(INPUT_A_1, "Signal A 1"); + configInput(INPUT_A_2, "Signal A 2"); + configInput(INPUT_B_1, "Signal B 1"); + configInput(INPUT_B_2, "Signal B 2"); + configInput(INPUT_CV_1, "CV 1"); + configInput(INPUT_CV_2, "CV 2"); + configOutput(OUTPUT_1, "Signal 1"); + configOutput(OUTPUT_2, "Signal 2"); + configLight(LIGHT_LIN_1, "Linear"); + configLight(LIGHT_LIN_2, "Linear"); + configLight(LIGHT_LOG_1, "Logarithmic"); + configLight(LIGHT_LOG_2, "Logarithmic"); + configLight(LIGHT_AUTO_1, "Auto / Inverted"); + configLight(LIGHT_AUTO_2, "Auto / Inverted"); } void process(const ProcessArgs &args) override { @@ -455,11 +476,11 @@ struct XF_104 : XF { XF_Controls controls[(int)(deviceCount * 1.5f)]; XF_104() : XF(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { - configParam(PARAM_LINK_1, 0.0f, 1.0f, 0.0f, "Link faders 1 & 2"); - configParam(PARAM_LINK_2, 0.0f, 1.0f, 0.0f, "Link faders 3 & 4"); + configSwitch(PARAM_LINK_1, 0.0f, 1.0f, 0.0f, "Link Faders 1 & 2", { "Not Linked", "Linked" }); + configSwitch(PARAM_LINK_2, 0.0f, 1.0f, 0.0f, "Link Faders 3 & 4", { "Not Linked", "Linked" }); for (int i = 0; i < deviceCount; i++) { - configParam(PARAM_CV_1 + i, 0.0f, 1.0f, 0.0f, string::f("Fader %d CV is bipolar", i + 1)); - configParam(PARAM_MODE_1 + i, 0.0f, 2.0f, 0.0f, string::f("Fader %d Fade profile", i + 1)); + configSwitch(PARAM_CV_1 + i, 0.0f, 1.0f, 0.0f, "CV Mode", { "Unipolar", "Bipolar" }); + configSwitch(PARAM_MODE_1 + i, 0.0f, 2.0f, 0.0f, "Fade Profile", { "Linear", "Logarithmic", "Automatic" }); configParam(PARAM_FADE_1 + i, 0.0f, 10.0f, 5.0f, string::f("Fader %d A/B blend", i + 1), "%", 0.f, 10.f); controls[i].a = INPUT_A_1 + i; controls[i].ar = 0; @@ -493,6 +514,34 @@ struct XF_104 : XF { controls[i + deviceCount].light3 = LIGHT_AUTO_1 + x * 2; controls[i + deviceCount].correlator = &correlators[x]; } + configInput(INPUT_A_1, "Signal A 1"); + configInput(INPUT_A_2, "Signal A 2"); + configInput(INPUT_A_3, "Signal A 3"); + configInput(INPUT_A_4, "Signal A 4"); + configInput(INPUT_B_1, "Signal B 1"); + configInput(INPUT_B_2, "Signal B 2"); + configInput(INPUT_B_3, "Signal B 3"); + configInput(INPUT_B_4, "Signal B 4"); + configInput(INPUT_CV_1, "CV 1"); + configInput(INPUT_CV_2, "CV 2"); + configInput(INPUT_CV_3, "CV 3"); + configInput(INPUT_CV_4, "CV 4"); + configOutput(OUTPUT_1, "Signal 1"); + configOutput(OUTPUT_2, "Signal 2"); + configOutput(OUTPUT_3, "Signal 3"); + configOutput(OUTPUT_4, "Signal 4"); + configLight(LIGHT_LIN_1, "Linear"); + configLight(LIGHT_LIN_2, "Linear"); + configLight(LIGHT_LIN_3, "Linear"); + configLight(LIGHT_LIN_4, "Linear"); + configLight(LIGHT_LOG_1, "Logarithmic"); + configLight(LIGHT_LOG_2, "Logarithmic"); + configLight(LIGHT_LOG_3, "Logarithmic"); + configLight(LIGHT_LOG_4, "Logarithmic"); + configLight(LIGHT_AUTO_1, "Auto / Inverted"); + configLight(LIGHT_AUTO_2, "Auto / Inverted"); + configLight(LIGHT_AUTO_3, "Auto / Inverted"); + configLight(LIGHT_AUTO_4, "Auto / Inverted"); } void process(const ProcessArgs &args) override { @@ -638,8 +687,8 @@ struct XF_201 : XF { XF_201() : XF(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { for (int i = 0; i < deviceCount; i++) { - configParam(PARAM_CV_1 + i, 0.0f, 1.0f, 0.0f, string::f("Fader %d CV is bipolar", i + 1)); - configParam(PARAM_MODE_1 + i, 0.0f, 2.0f, 0.0f, string::f("Fader %d Fade profile", i + 1)); + configSwitch(PARAM_CV_1 + i, 0.0f, 1.0f, 0.0f, "CV Mode", { "Unipolar", "Bipolar" }); + configSwitch(PARAM_MODE_1 + i, 0.0f, 2.0f, 0.0f, "Fade Profile", { "Linear", "Logarithmic", "Automatic" }); configParam(PARAM_FADE_1 + i, 0.0f, 10.0f, 5.0f, string::f("Fader %d A/B blend", i + 1), "%", 0.f, 10.f); controls[i].a = INPUT_A_1 + i; controls[i].ar = INPUT_AR_1 + i; @@ -656,6 +705,16 @@ struct XF_201 : XF { controls[i].light3 = LIGHT_AUTO_1 + i * 2; controls[i].correlator = &correlators[i]; } + configInput(INPUT_A_1, "Signal A Left"); + configInput(INPUT_AR_1, "Signal A Right"); + configInput(INPUT_B_1, "Signal B Left"); + configInput(INPUT_BR_1, "Signal B Right"); + configInput(INPUT_CV_1, "CV"); + configOutput(OUTPUT_1, "Signal Left"); + configOutput(OUTPUTR_1, "Signal Right"); + configLight(LIGHT_LIN_1, "Linear"); + configLight(LIGHT_LOG_1, "Logarithmic"); + configLight(LIGHT_AUTO_1, "Auto / Inverted"); } void process(const ProcessArgs &args) override { @@ -817,8 +876,8 @@ struct XF_202 : XF { XF_202() : XF(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { for (int i = 0; i < deviceCount; i++) { - configParam(PARAM_CV_1 + i, 0.0f, 1.0f, 0.0f, string::f("Fader %d CV is bipolar", i + 1)); - configParam(PARAM_MODE_1 + i, 0.0f, 2.0f, 0.0f, string::f("Fader %d Fade profile", i + 1)); + configSwitch(PARAM_CV_1 + i, 0.0f, 1.0f, 0.0f, "CV Mode", { "Unipolar", "Bipolar" }); + configSwitch(PARAM_MODE_1 + i, 0.0f, 2.0f, 0.0f, "Fade Profile", { "Linear", "Logarithmic", "Automatic" }); configParam(PARAM_FADE_1 + i, 0.0f, 10.0f, 5.0f, string::f("Fader %d A/B blend", i + 1), "%", 0.f, 10.f); controls[i].a = INPUT_A_1 + i; controls[i].ar = INPUT_AR_1 + i; @@ -835,6 +894,26 @@ struct XF_202 : XF { controls[i].light3 = LIGHT_AUTO_1 + i * 2; controls[i].correlator = &correlators[i]; } + configInput(INPUT_A_1, "Signal A 1 Left"); + configInput(INPUT_AR_1, "Signal A 1 Right"); + configInput(INPUT_B_1, "Signal B 1 Left"); + configInput(INPUT_BR_1, "Signal B 1 Right"); + configInput(INPUT_CV_1, "CV 1"); + configOutput(OUTPUT_1, "Signal 1 Left"); + configOutput(OUTPUTR_1, "Signal 1 Right"); + configLight(LIGHT_LIN_1, "Linear"); + configLight(LIGHT_LOG_1, "Logarithmic"); + configLight(LIGHT_AUTO_1, "Auto / Inverted"); + configInput(INPUT_A_2, "Signal A 1 Left"); + configInput(INPUT_AR_2, "Signal A 1 Right"); + configInput(INPUT_B_2, "Signal B 1 Left"); + configInput(INPUT_BR_2, "Signal B 1 Right"); + configInput(INPUT_CV_2, "CV 1"); + configOutput(OUTPUT_2, "Signal 1 Left"); + configOutput(OUTPUTR_2, "Signal 1 Right"); + configLight(LIGHT_LIN_2, "Linear"); + configLight(LIGHT_LOG_2, "Logarithmic"); + configLight(LIGHT_AUTO_2, "Auto / Inverted"); } void process(const ProcessArgs &args) override { diff --git a/src/XG1.cpp b/src/XG1.cpp old mode 100755 new mode 100644 index 4d798bc7..925a4b1f --- a/src/XG1.cpp +++ b/src/XG1.cpp @@ -22,6 +22,11 @@ struct XG_1 : DS_Module { XG_1() : DS_Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + for (int i = 0; i < x; i++) { + configInput(INPUT_A_1 + i, "Signal " + std::to_string(i + 1) + "A"); + configInput(INPUT_B_1 + i, "Signal " + std::to_string(i + 1) + "B"); + configOutput(OUTPUT_1 + i, "Signal " + std::to_string(i + 1)); + } } void process(const ProcessArgs &args) override { int setCount = 0; diff --git a/src/XG2.cpp b/src/XG2.cpp old mode 100755 new mode 100644 index efc22b0a..b707d332 --- a/src/XG2.cpp +++ b/src/XG2.cpp @@ -28,6 +28,16 @@ struct XG_2 : DS_Module { XG_2() : DS_Module() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + configInput(INPUT_A_1, "Signal 1A"); + configInput(INPUT_A_2, "Signal 2A"); + configInput(INPUT_B_1, "Signal 1B"); + configInput(INPUT_B_2, "Signal 2B"); + configInput(INPUT_C_1, "Signal 1C"); + configInput(INPUT_C_2, "Signal 2C"); + configInput(INPUT_D_1, "Signal 1D"); + configInput(INPUT_D_2, "Signal 2D"); + configOutput(OUTPUT_1, "Signal 1"); + configOutput(OUTPUT_2, "Signal 2"); } void process(const ProcessArgs &args) override { diff --git a/src/XXX.cpp b/src/XXX.cpp old mode 100755 new mode 100644 index fcc0dff0..45a8b064 --- a/src/XXX.cpp +++ b/src/XXX.cpp @@ -10,14 +10,14 @@ struct XX219 : SchemeModuleWidget { addChild(new SchemePanel(this->box.size)); } void render(NVGcontext *vg, SchemeCanvasWidget *canvas) override { - drawBackground(vg); + drawBackground(vg); drawLogo(vg, 0, 20, 1, -M_PI / 2.0f); nvgSave(vg); nvgTranslate(vg, 1, 377); nvgRotate(vg, -M_PI / 2.0f); drawText(vg, 0, 0, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, 12, gScheme.getAlternative(module), "submarine OBSOLETE"); nvgRestore(vg); - } + } void addMenuItem(Menu *menu, const char *label) { MenuLabel *ml = new MenuLabel(); ml->text = label; @@ -31,3 +31,65 @@ struct XX219 : SchemeModuleWidget { }; Model *modelXX219 = createModel("XX-219"); + +struct TM_105 : Module { + enum ParamIds { + NUM_PARAMS + }; + enum InputIds { + INPUT_1, + INPUT_2, + INPUT_3, + INPUT_4, + INPUT_5, + NUM_INPUTS + }; + enum OutputIds { + OUTPUT_TOR, + NUM_OUTPUTS + }; + enum LightIds { + NUM_LIGHTS + }; + + TM_105() : Module() { + config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + for (unsigned int i = 0; i < 5; i++) { + configInput(i, "Deprecated"); + } + configOutput(OUTPUT_TOR, "Deprecated"); + } +}; + +struct TM105 : SchemeModuleWidget { + TM105(TM_105 *module) { + setModule(module); + this->box.size = Vec(15, 380); + addChild(new SchemePanel(this->box.size)); + for (unsigned int i = 0; i < 5; i++) { + addInput(createInputCentered(Vec(7.5,41.5 + 32 * i), module, TM_105::INPUT_1 + i)); + } + addOutput(createOutputCentered(Vec(7.5,244.5), module, TM_105::OUTPUT_TOR)); + } + void render(NVGcontext *vg, SchemeCanvasWidget *canvas) override { + drawBackground(vg); + drawLogo(vg, 0, 20, 1, -M_PI / 2.0f); + nvgSave(vg); + nvgTranslate(vg, 1, 377); + nvgRotate(vg, -M_PI / 2.0f); + drawText(vg, 0, 0, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, 12, gScheme.getAlternative(module), "submarine OBSOLETE"); + nvgRestore(vg); + } + void addMenuItem(Menu *menu, const char *label) { + MenuLabel *ml = new MenuLabel(); + ml->text = label; + menu->addChild(ml); + } + void appendContextMenu(Menu *menu) override { + ModuleWidget::appendContextMenu(menu); + addMenuItem(menu, ""); + addMenuItem(menu, "This Module does Nothing"); + } +}; + +Model *modelTM105 = createModel("TM-105"); diff --git a/src/gates/CLK-DELAY b/src/gates/CLK-DELAY index 38ff08f8..ec287aa9 100755 --- a/src/gates/CLK-DELAY +++ b/src/gates/CLK-DELAY @@ -17,7 +17,7 @@ drawOutput(args.vg, 60); nvgStrokeWidth(args.vg, 2); nvgStroke(args.vg); - nvgFontFaceId(args.vg, gScheme.font(args.vg)); + nvgFontFaceId(args.vg, gScheme.font()->handle); nvgFontSize(args.vg, 8 * 90 / SVG_DPI); nvgFillColor(args.vg, SUBLIGHTBLUE); nvgTextAlign(args.vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); diff --git a/src/gates/D-TYPE-FLIPFLOP b/src/gates/D-TYPE-FLIPFLOP index e7726fda..55c870c3 100755 --- a/src/gates/D-TYPE-FLIPFLOP +++ b/src/gates/D-TYPE-FLIPFLOP @@ -15,7 +15,7 @@ drawOutput(args.vg, 60); nvgStrokeWidth(args.vg, 2); nvgStroke(args.vg); - nvgFontFaceId(args.vg, gScheme.font(args.vg)); + nvgFontFaceId(args.vg, gScheme.font()->handle); nvgFontSize(args.vg, 8 * 90 / SVG_DPI); nvgTextAlign(args.vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); nvgFillColor(args.vg, SUBLIGHTBLUE); diff --git a/src/gates/D-TYPE-LATCH b/src/gates/D-TYPE-LATCH index 662341ad..124e699e 100755 --- a/src/gates/D-TYPE-LATCH +++ b/src/gates/D-TYPE-LATCH @@ -16,7 +16,7 @@ drawOutput(args.vg, 60); nvgStrokeWidth(args.vg, 2); nvgStroke(args.vg); - nvgFontFaceId(args.vg, gScheme.font(args.vg)); + nvgFontFaceId(args.vg, gScheme.font()->handle); nvgFontSize(args.vg, 8 * 90 / SVG_DPI); nvgTextAlign(args.vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); nvgFillColor(args.vg, SUBLIGHTBLUE); diff --git a/src/gates/DELAY b/src/gates/DELAY index 57496326..689ba4a6 100755 --- a/src/gates/DELAY +++ b/src/gates/DELAY @@ -13,7 +13,7 @@ drawOutput(args.vg, 60); nvgStrokeWidth(args.vg, 2); nvgStroke(args.vg); - nvgFontFaceId(args.vg, gScheme.font(args.vg)); + nvgFontFaceId(args.vg, gScheme.font()->handle); nvgFontSize(args.vg, 8 * 90 / SVG_DPI); nvgFillColor(args.vg, SUBLIGHTBLUE); nvgTextAlign(args.vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); diff --git a/src/gates/LATCH b/src/gates/LATCH index 28abbeb8..857d91b2 100755 --- a/src/gates/LATCH +++ b/src/gates/LATCH @@ -17,7 +17,7 @@ drawOutput(args.vg, 60); nvgStrokeWidth(args.vg, 2); nvgStroke(args.vg); - nvgFontFaceId(args.vg, gScheme.font(args.vg)); + nvgFontFaceId(args.vg, gScheme.font()->handle); nvgFontSize(args.vg, 8 * 90 / SVG_DPI); nvgTextAlign(args.vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); nvgFillColor(args.vg, SUBLIGHTBLUE); diff --git a/src/gates/NC b/src/gates/NC index 78d79921..4bfd7f52 100755 --- a/src/gates/NC +++ b/src/gates/NC @@ -6,7 +6,7 @@ X X X X ZE , [](const Widget::DrawArgs &args, Vec size) { - nvgFontFaceId(args.vg, gScheme.font(args.vg)); + nvgFontFaceId(args.vg, gScheme.font()->handle); nvgFontSize(args.vg, 10 * 90 / SVG_DPI); nvgTextAlign(args.vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); nvgFillColor(args.vg, SUBLIGHTBLUE); diff --git a/src/gates/SR-FLIPFLOP b/src/gates/SR-FLIPFLOP index f1f2b1d5..38ad60d1 100755 --- a/src/gates/SR-FLIPFLOP +++ b/src/gates/SR-FLIPFLOP @@ -16,7 +16,7 @@ drawOutput(args.vg, 60); nvgStrokeWidth(args.vg, 2); nvgStroke(args.vg); - nvgFontFaceId(args.vg, gScheme.font(args.vg)); + nvgFontFaceId(args.vg, gScheme.font()->handle); nvgFontSize(args.vg, 8 * 90 / SVG_DPI); nvgTextAlign(args.vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); nvgFillColor(args.vg, SUBLIGHTBLUE); diff --git a/src/gates/SR-LATCH b/src/gates/SR-LATCH index e19a92d8..0b8e483e 100755 --- a/src/gates/SR-LATCH +++ b/src/gates/SR-LATCH @@ -19,7 +19,7 @@ drawOutput(args.vg, 60); nvgStrokeWidth(args.vg, 2); nvgStroke(args.vg); - nvgFontFaceId(args.vg, gScheme.font(args.vg)); + nvgFontFaceId(args.vg, gScheme.font()->handle); nvgFontSize(args.vg, 8 * 90 / SVG_DPI); nvgTextAlign(args.vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); nvgFillColor(args.vg, SUBLIGHTBLUE); diff --git a/src/shared/BulkKnob.cpp b/src/shared/BulkKnob.cpp deleted file mode 100644 index 6ac07543..00000000 --- a/src/shared/BulkKnob.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "../SubmarineFree.hpp" - -void BulkKnob::onHover(const event::Hover& e) { - math::Vec c = box.size.div(2); - float dist = e.pos.minus(c).norm(); - if (dist <= c.x) { - BulkParamWidget::onHover(e); - } -} - -void BulkKnob::onButton(const event::Button& e) { - math::Vec c = box.size.div(2); - float dist = e.pos.minus(c).norm(); - if (dist <= c.x) { - BulkParamWidget::onButton(e); - } -} - -void BulkKnob::onDragStart(const event::DragStart& e) { - if (e.button != GLFW_MOUSE_BUTTON_LEFT) - return; - - if (value) { - oldValue = *value; - if (snap) { - snapValue = *value; - } - } - - APP->window->cursorLock(); -} - -void BulkKnob::onDragEnd(const event::DragEnd& e) { - if (e.button != GLFW_MOUSE_BUTTON_LEFT) - return; - - APP->window->cursorUnlock(); - - if (value) { - float newValue = *value; - if (oldValue != newValue) { - int thisModuleId = module->id; - int thisParamId = paramId; - int thisOldValue = oldValue; - APP->history->push(new EventWidgetAction( - "move knob", - [=]() { - setBulkParamValue(thisModuleId, thisParamId, thisOldValue); - }, - [=]() { - setBulkParamValue(thisModuleId, thisParamId, newValue); - } - )); - } - } -} - -void BulkKnob::onDragMove(const event::DragMove& e) { - if (e.button != GLFW_MOUSE_BUTTON_LEFT) - return; - - if (value) { - float range = 2.0f; - if (std::isfinite(minValue) && std::isfinite(maxValue)) { - range = maxValue - minValue; - } - float delta = (horizontal ? e.mouseDelta.x : -e.mouseDelta.y); - delta *= 0.0015f; - delta *= speed; - delta *= range; - - // Drag slower if mod is held - int mods = APP->window->getMods(); - if ((mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { - delta /= 16.f; - } - // Drag even slower if mod+shift is held - if ((mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) { - delta /= 256.f; - } - - if (snap) { - snapValue += delta; - snapValue = math::clamp(snapValue, minValue, maxValue); - *value = std::round(snapValue); - } - else { - *value += delta; - } - } - - BulkParamWidget::onDragMove(e); -} - -void BulkKnob::reset() { - if (value) - oldValue = snapValue = *value = defaultValue; -} - -void BulkKnob::randomize() { - if (value && std::isfinite(minValue) && std::isfinite(maxValue)) { - *value = math::rescale(random::uniform(), 0.f, 1.f, minValue, maxValue); - if (snap) - *value = std::round(*value); - oldValue = snapValue = *value; - } -} diff --git a/src/shared/BulkParamWidget.cpp b/src/shared/BulkParamWidget.cpp deleted file mode 100644 index 39a949fd..00000000 --- a/src/shared/BulkParamWidget.cpp +++ /dev/null @@ -1,211 +0,0 @@ -#include "../SubmarineFree.hpp" -#include "settings.hpp" - -void BulkParamTooltip::step() { - if (bulkParamWidget->value) { - // Quantity string - text = bulkParamWidget->getString(); - // Param description - std::string description = bulkParamWidget->description; - if (!description.empty()) - text += "\n" + description; - } - Tooltip::step(); - // Position at bottom-right of parameter - box.pos = bulkParamWidget->getAbsoluteOffset(bulkParamWidget->box.size).round(); - // Fit inside parent (copied from Tooltip.cpp) - assert(parent); - box = box.nudge(parent->box.zeroPos()); -} - -std::string BulkParamWidget::getString() { - std::string s; - if (!label.empty()) - s += label + ": "; - s += getDisplayValueString() + unit; - return s; -} - -float BulkParamWidget::getDisplayValue() { - if (!value) - return .0f; - float v = *value; - if (displayBase == 0.f) { - // Linear - // v is unchanged - } - else if (displayBase < 0.f) { - // Logarithmic - v = std::log(v) / std::log(-displayBase); - } - else { - // Exponential - v = std::pow(displayBase, v); - } - return v * displayMultiplier + displayOffset; -} - -void BulkParamWidget::setDisplayValue(float displayValue) { - if (!value) - return; - float v = displayValue - displayOffset; - if (displayMultiplier == 0.f) - v = 0.f; - else - v /= displayMultiplier; - if (displayBase == 0.f) { - // Linear - // v is unchanged - } - else if (displayBase < 0.f) { - // Logarithmic - v = std::pow(-displayBase, v); - } - else { - // Exponential - v = std::log(v) / std::log(displayBase); - } - *value = v; -} - -std::string BulkParamWidget::getDisplayValueString() { - return string::f("%.*g", 5, math::normalizeZero(getDisplayValue())); -} - -void BulkParamWidget::setDisplayValueString(std::string s) { - float v = 0.f; - char suffix[2]; - int n = std::sscanf(s.c_str(), "%f%1s", &v, suffix); - if (n >= 2) { - // Parse SI prefixes - switch (suffix[0]) { - case 'n': v *= 1e-9f; break; - case 'u': v *= 1e-6f; break; - case 'm': v *= 1e-3f; break; - case 'k': v *= 1e3f; break; - case 'M': v *= 1e6f; break; - case 'G': v *= 1e9f; break; - default: break; - } - } - if (n >= 1) - setDisplayValue(v); -} - -void BulkParamWidget::onButton(const event::Button& e) { - OpaqueWidget::onButton(e); - - // Touch parameter - if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT && (e.mods & RACK_MOD_MASK) == 0) { - e.consume(this); - } - - // Right click to open context menu - if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && (e.mods & RACK_MOD_MASK) == 0) { - createContextMenu(); - e.consume(this); - } -} - -void BulkParamWidget::onDoubleClick(const event::DoubleClick& e) { - resetAction(); -} - -void BulkParamWidget::onEnter(const event::Enter& e) { - if (settings::paramTooltip && !tooltip && value) { - BulkParamTooltip* bulkParamTooltip = new BulkParamTooltip; - bulkParamTooltip->bulkParamWidget = this; - APP->scene->addChild(bulkParamTooltip); - tooltip = bulkParamTooltip; - } -} - -void BulkParamWidget::onLeave(const event::Leave& e) { - if (tooltip) { - APP->scene->removeChild(tooltip); - delete tooltip; - tooltip = NULL; - } -} - -void BulkParamWidget::fromJson(json_t* rootJ) { - json_t* valueJ = json_object_get(rootJ, "value"); - if (valueJ) { - if (value) - *value = json_number_value(valueJ); - } -} - -void BulkParamWidget::createContextMenu() { - ui::Menu* menu = createMenu(); - - MenuLabel* menuLabel = new MenuLabel; - menuLabel->text = getString(); - menu->addChild(menuLabel); - - EventParamField *paramField = new EventParamField; - paramField->box.size.x = 100; - paramField->text = getDisplayValueString(); - paramField->selectAll(); - paramField->changeHandler = [=](std::string text) { - float oldValue = *value; - setDisplayValueString(text); - float newValue = *value; - - if (oldValue != newValue) { - int thisModuleId = module->id; - int thisParamId = paramId; - APP->history->push(new EventWidgetAction( - "change parameter", - [=]() { - setBulkParamValue(thisModuleId, thisParamId, oldValue); - }, - [=]() { - setBulkParamValue(thisModuleId, thisParamId, newValue); - } - )); - } - }; - menu->addChild(paramField); - - - EventWidgetMenuItem *resetItem = new EventWidgetMenuItem; - resetItem->text = "Initialize"; - resetItem->rightText = "Double-click"; - resetItem->clickHandler = [=]() { - this->resetAction(); - }; - menu->addChild(resetItem); - if (contextMenuCallback) { - contextMenuCallback(menu); - } -} - -void BulkParamWidget::resetAction() { - if (value) { - float oldValue = *value; - reset(); - float newValue = *value; - if (oldValue != newValue) { - int thisModuleId = module->id; - int thisParamId = paramId; - APP->history->push(new EventWidgetAction( - "reset parameter", - [=]() { - setBulkParamValue(thisModuleId, thisParamId, oldValue); - }, - [=]() { - setBulkParamValue(thisModuleId, thisParamId, newValue); - } - )); - } - } -} - -void BulkParamWidget::setBulkParamValue(int thisModuleId, int thisParamId, float thisValue) { - SchemeModuleWidget *smw = dynamic_cast(APP->scene->rack->getModule(thisModuleId)); - if (smw) { - float *value = smw->getBulkParam(thisParamId); - if (value) *value = thisValue; - } -} diff --git a/src/shared/DS.cpp b/src/shared/DS.cpp index de3be160..58185c47 100755 --- a/src/shared/DS.cpp +++ b/src/shared/DS.cpp @@ -1,5 +1,10 @@ #include "DS.hpp" +namespace SubmarineDS { + float globalVL = 0.0f; + float globalVH = 10.0f; +} + float DS_Module::midpoint() { return (voltage0 * 0.5f + voltage1 * 0.5f); } @@ -93,6 +98,8 @@ void DS_Module::appendContextMenu(Menu *menu) { void DS_MenuItem::onAction(const event::Action &e) { module->voltage0 = vl; module->voltage1 = vh; + SubmarineDS::globalVL = vl; + SubmarineDS::globalVH = vh; } void DS_MenuItem::step() { diff --git a/src/shared/DS.hpp b/src/shared/DS.hpp index 1231de94..cf2cdc71 100755 --- a/src/shared/DS.hpp +++ b/src/shared/DS.hpp @@ -1,8 +1,13 @@ #include "../SubmarineFree.hpp" +namespace SubmarineDS { + extern float globalVL; + extern float globalVH; +} + struct DS_Module : Module { - float voltage0 = 0.0f; - float voltage1 = 10.0f; + float voltage0 = SubmarineDS::globalVL; + float voltage1 = SubmarineDS::globalVH; float midpoint(); float output(int); DS_Module() {} diff --git a/src/shared/EventWidgets.cpp b/src/shared/EventWidgets.cpp index b92dca1b..e0a7373d 100755 --- a/src/shared/EventWidgets.cpp +++ b/src/shared/EventWidgets.cpp @@ -1,4 +1,3 @@ -#include #include "../SubmarineFree.hpp" void EventWidgetAction::undo() { @@ -116,7 +115,7 @@ void EventWidgetSlider::onDoubleClick(const event::DoubleClick &e) { } void EventWidgetSlider::onEnter(const event::Enter &e) { - if (settings::paramTooltip && !tooltip) { + if (settings::tooltips && !tooltip) { tooltip = new EventWidgetSliderTooltip(); tooltip->slider = this; APP->scene->addChild(tooltip); @@ -260,7 +259,7 @@ void EventWidgetMenuItem::step() { void EventParamField::step() { // Keep selected - APP->event->setSelected(this); + APP->event->setSelectedWidget(this); TextField::step(); } diff --git a/src/shared/ExtensionLight.cpp b/src/shared/ExtensionLight.cpp new file mode 100644 index 00000000..f986c2ca --- /dev/null +++ b/src/shared/ExtensionLight.cpp @@ -0,0 +1,51 @@ +/************************************************************** +* +* The graphical styles and images encoded in this source file +* are copyright © 2018 David O'Rourke +* +**************************************************************/ + +#include "../SubmarineFree.hpp" + +ExtensionLight::ExtensionLight() { + box.size.x = 4; + box.size.y = 4; +} + +void ExtensionLight::drawBackground(const widget::Widget::DrawArgs& args) { + getShape(args); + if (bgColor.a > 0.0) { + nvgFillColor(args.vg, bgColor); + nvgFill(args.vg); + } + + if (borderColor.a > 0.0) { + nvgStrokeWidth(args.vg, 0.5); + nvgStrokeColor(args.vg, borderColor); + nvgStroke(args.vg); + } +} + +void ExtensionLight::drawLight(const widget::Widget::DrawArgs& args) { + if (color.a > 0.0) { + getShape(args); + nvgFillColor(args.vg, color); + nvgFill(args.vg); + } +} + +void LeftLight::getShape(const widget::Widget::DrawArgs &args) { + nvgBeginPath(args.vg); + nvgMoveTo(args.vg, 0, box.size.y / 2); + nvgLineTo(args.vg, box.size.x, box.size.y); + nvgLineTo(args.vg, box.size.x, 0); + nvgClosePath(args.vg); +} + +void RightLight::getShape(const widget::Widget::DrawArgs &args) { + nvgBeginPath(args.vg); + nvgMoveTo(args.vg, box.size.x, box.size.y / 2); + nvgLineTo(args.vg, 0, box.size.y); + nvgLineTo(args.vg, 0, 0); + nvgClosePath(args.vg); +} diff --git a/src/shared/LightButton.cpp b/src/shared/LightButton.cpp index b233dd18..d6bdc557 100755 --- a/src/shared/LightButton.cpp +++ b/src/shared/LightButton.cpp @@ -11,11 +11,6 @@ LightButton::LightButton() { box.size.x = 16.0f; box.size.y = 16.0f; - light = new LightButtonLight(); - light->box.pos = Vec(0,0); - light->box.size = box.size; - light->button = this; - addChild(light); } void LightButton::draw(const DrawArgs &args) { @@ -45,21 +40,37 @@ void LightButton::draw(const DrawArgs &args) { nvgFill(args.vg); nvgStroke(args.vg); } + float value = 0.0f; + if (getParamQuantity()) { + value = getParamQuantity()->getValue(); + } + if (value < 0.5f) { + drawLight(args, false); + } nvgRestore(args.vg); Widget::draw(args); } -void LightButtonLight::draw(const DrawArgs &args) { - float value = 0.0f; - if (button->paramQuantity) { - value = button->paramQuantity->getValue(); +void LightButton::drawLayer(const DrawArgs &args, int layer) { + if (layer == 1) { + float value = 0.0f; + if (getParamQuantity()) { + value = getParamQuantity()->getValue(); + } + if (value > 0.5f) { + drawLight(args, true); + drawHalo(args); + } + } + Widget::drawLayer(args, layer); +} +void LightButton::drawLight(const DrawArgs &args, bool enabled) { Rect lightbox = Rect(Vec(box.size.x / 4.0f, box.size.y / 4.0f), Vec(box.size.x / 2.0f, box.size.y / 4.0f)); - NVGcolor lcol = (value > 0.5f)?button->color:nvgRGB(0x4a,0x4a,0x4a); + NVGcolor lcol = (enabled)?color:nvgRGB(0x4a,0x4a,0x4a); - nvgSave(args.vg); // Light { nvgBeginPath(args.vg); @@ -75,21 +86,33 @@ void LightButtonLight::draw(const DrawArgs &args) { } nvgFill(args.vg); } +} +void LightButton::drawHalo(const DrawArgs &args) { // Halo - if (!gScheme.isFlat) { - float lradius = mm2px(0.544); - float oradius = lradius + 15.0; - nvgBeginPath(args.vg); - nvgRect(args.vg, box.size.x / 2.0 - oradius, box.size.y * 0.375f - oradius, 2 * oradius, 2 * oradius); - NVGpaint paint; - NVGcolor icol = color::mult(lcol, 0.08); - NVGcolor ocol = nvgRGB(0, 0, 0); - paint = nvgRadialGradient(args.vg, box.size.x / 2.0, box.size.y * 0.375f, lradius, oradius, icol, ocol); - nvgFillPaint(args.vg, paint); - nvgGlobalCompositeOperation(args.vg, NVG_LIGHTER); - nvgFill(args.vg); - } - nvgRestore(args.vg); + // Don't draw halo if rendering in a framebuffer, e.g. screenshots or Module Browser + if (args.fb) + return; + const float halo = settings::haloBrightness; + if (halo == 0.f) + return; + + // If light is off, rendering the halo gives no effect. + if (color.r == 0.f && color.g == 0.f && color.b == 0.f) + return; + + nvgSave(args.vg); + float lradius = mm2px(0.544); + float oradius = lradius + 15.0; + nvgBeginPath(args.vg); + nvgRect(args.vg, box.size.x / 2.0 - oradius, box.size.y * 0.375f - oradius, 2 * oradius, 2 * oradius); + NVGpaint paint; + NVGcolor icol = color::mult(color, halo); + NVGcolor ocol = nvgRGB(0, 0, 0); + paint = nvgRadialGradient(args.vg, box.size.x / 2.0, box.size.y * 0.375f, lradius, oradius, icol, ocol); + nvgFillPaint(args.vg, paint); + nvgGlobalCompositeBlendFunc(args.vg, NVG_ONE_MINUS_DST_COLOR, NVG_ONE); + nvgFill(args.vg); + nvgRestore(args.vg); } diff --git a/src/shared/LightKnob.cpp b/src/shared/LightKnob.cpp index 1c546847..4de8d82c 100755 --- a/src/shared/LightKnob.cpp +++ b/src/shared/LightKnob.cpp @@ -8,20 +8,18 @@ #include "../SubmarineFree.hpp" #include "color.hpp" -void BaseLightKnob::setEnabled(int val) { +void LightKnob::setEnabled(int val) { enabled = val; } -void BaseLightKnob::setRadius(int r) { +void LightKnob::setRadius(int r) { Widget *w = dynamic_cast(this); radius = r; w->box.size.x = r * 2; w->box.size.y = r * 2; - light->box.size.x = r * 2; - light->box.size.y = r * 2; } -void BaseLightKnob::doDraw(const rack::widget::Widget::DrawArgs &args) { +void LightKnob::draw(const DrawArgs &args) { nvgSave(args.vg); // Shadow @@ -39,7 +37,7 @@ void BaseLightKnob::doDraw(const rack::widget::Widget::DrawArgs &args) { nvgBeginPath(args.vg); nvgCircle(args.vg, radius, radius, radius); nvgTranslate(args.vg, radius, radius); - nvgRotate(args.vg, M_PI / -15); + nvgRotate(args.vg, M_PI * 0.35f); nvgScale(args.vg, 40, 1); NVGpaint paint; paint = nvgRadialGradient(args.vg, 0, 0, 0, radius * 0.2, nvgRGB(0x7a,0x7a,0x7a), nvgRGB(10,10,10)); @@ -52,57 +50,108 @@ void BaseLightKnob::doDraw(const rack::widget::Widget::DrawArgs &args) { nvgFillColor(args.vg, nvgRGB(10,10,10)); nvgFill(args.vg); } + + if (!enabled) { + drawLight(args); + } + + nvgRestore(args.vg); + Knob::draw(args); } -void LightKnobLight::draw(const DrawArgs &args) { - NVGcolor lcol = knob->enabled?knob->color:nvgRGB(0x4a,0x4a,0x4a); - float value = knob->getBLKValue(); - float minValue = knob->getBLKMinValue(); - float maxValue = knob->getBLKMaxValue(); +void LightKnob::drawLayer(const DrawArgs& args, int layer) { + if (layer == 1) { + if (enabled) { + drawLight(args); + drawHalo(args); + } + + } + Widget::drawLayer(args, layer); +} + +void LightKnob::drawLight(const DrawArgs &args) { + NVGcolor lcol = enabled?color:nvgRGB(0x4a, 0x4a, 0x4a); float angle; + float value = 0.0f; + float minValue = -1.0f; + float maxValue = 1.0f; + if (getParamQuantity()) { + value = getParamQuantity()->getValue(); + minValue = getParamQuantity()->getMinValue(); + maxValue = getParamQuantity()->getMaxValue(); + } if (std::isfinite(minValue) && std::isfinite(maxValue)) { - angle = rescale(value, minValue, maxValue, knob->minAngle, knob->maxAngle); + angle = rescale(value, minValue, maxValue, minAngle, maxAngle); } else { - angle = rescale(value, -1.0, 1.0, knob->minAngle, knob->maxAngle); + angle = rescale(value, -1.0, 1.0, minAngle, maxAngle); angle = fmodf(angle, 2*M_PI); } - float cx = (1.0f + sinf(angle) * 0.7f) * knob->radius; - float cy = (1.0f - cosf(angle) * 0.7f) * knob->radius; - float lradius = mm2px(0.544); - float oradius = lradius + 15.0; - + // Light { nvgSave(args.vg); nvgBeginPath(args.vg); - nvgTranslate(args.vg, knob->radius, knob->radius); + nvgTranslate(args.vg, radius, radius); nvgRotate(args.vg, angle); - nvgRect(args.vg, knob->radius * -0.05, knob->radius * -0.9, knob->radius * 0.1, knob->radius * 0.4); + nvgRect(args.vg, radius * -0.05, radius * -0.9, radius * 0.1, radius * 0.4); if (gScheme.isFlat) { nvgFillColor(args.vg, lcol); } else { NVGpaint paint; NVGcolor ocol = color::mult(lcol, 0.1); - paint = nvgRadialGradient(args.vg, 0, knob->radius * -0.7, knob->radius * 0.05, knob->radius * 0.2, lcol, ocol); + paint = nvgRadialGradient(args.vg, 0, radius * -0.7, radius * 0.05, radius * 0.2, lcol, ocol); nvgFillPaint(args.vg, paint); } nvgFill(args.vg); nvgRestore(args.vg); } +} + +void LightKnob::drawHalo(const DrawArgs &args) { + // Don't draw halo if rendering in a framebuffer, e.g. screenshots or Module Browser + if (args.fb) + return; - // Halo - if (!gScheme.isFlat) { + const float halo = settings::haloBrightness; + if (halo == 0.f) + return; + + // If light is off, rendering the halo gives no effect. + if (color.r == 0.f && color.g == 0.f && color.b == 0.f) + return; + + // Halo + float angle; + float value = 0.0f; + float minValue = -1.0f; + float maxValue = 1.0f; + if (getParamQuantity()) { + value = getParamQuantity()->getValue(); + minValue = getParamQuantity()->getMinValue(); + maxValue = getParamQuantity()->getMaxValue(); + } + if (std::isfinite(minValue) && std::isfinite(maxValue)) { + angle = rescale(value, minValue, maxValue, minAngle, maxAngle); + } + else { + angle = rescale(value, -1.0, 1.0, minAngle, maxAngle); + angle = fmodf(angle, 2*M_PI); + } + float cx = (1.0f + sinf(angle) * 0.7f) * radius; + float cy = (1.0f - cosf(angle) * 0.7f) * radius; + float lradius = mm2px(0.544); + float oradius = lradius + 15.0; nvgBeginPath(args.vg); nvgRect(args.vg, cx - oradius, cy - oradius, 2 * oradius, 2 * oradius); NVGpaint paint; - NVGcolor icol = color::mult(lcol, 0.08); + NVGcolor icol = color::mult(color, halo); NVGcolor ocol = nvgRGB(0, 0, 0); paint = nvgRadialGradient(args.vg, cx, cy, lradius, oradius, icol, ocol); nvgFillPaint(args.vg, paint); - nvgGlobalCompositeOperation(args.vg, NVG_LIGHTER); + nvgGlobalCompositeBlendFunc(args.vg, NVG_ONE_MINUS_DST_COLOR, NVG_ONE); nvgFill(args.vg); - } } diff --git a/src/shared/MouseTransformWidget.cpp b/src/shared/MouseTransformWidget.cpp index 26a8e46b..aef32f2c 100644 --- a/src/shared/MouseTransformWidget.cpp +++ b/src/shared/MouseTransformWidget.cpp @@ -57,6 +57,17 @@ void MouseTransformWidget::draw(const DrawArgs &args) { Widget::draw(txCtx); }; +void MouseTransformWidget::drawLayer(const DrawArgs &args, int layer) { + DrawArgs txCtx = args; + if (hasInverse) { + nvgTransformPoint(&txCtx.clipBox.pos.x, &txCtx.clipBox.pos.y, inverse, txCtx.clipBox.pos.x, txCtx.clipBox.pos.y); + } + + // No need to save the state because that is done in the parent + nvgTransform(txCtx.vg, transform[0], transform[1], transform[2], transform[3], transform[4], transform[5]); + Widget::drawLayer(txCtx, layer); +}; + void MouseTransformWidget::onButton(const event::Button &e) { event::Button e2 = e; if (hasInverse) { diff --git a/src/shared/Port.cpp b/src/shared/Port.cpp index b085a92c..6b161657 100755 --- a/src/shared/Port.cpp +++ b/src/shared/Port.cpp @@ -77,7 +77,7 @@ void SilverPort::draw(const DrawArgs &args) { nvgCircle(args.vg, radius, radius, 8.0); nvgPathWinding(args.vg, NVG_HOLE); nvgStrokeWidth(args.vg, 0.80645); - if (type == app::PortWidget::OUTPUT) { + if (type == engine::Port::OUTPUT) { if (gScheme.isFlat) { nvgFillColor(args.vg, color::mult(col, nvgRGB(0x80, 0x80, 0x80))); } diff --git a/src/shared/ResizeHandle.cpp b/src/shared/ResizeHandle.cpp index f52f078d..08983651 100644 --- a/src/shared/ResizeHandle.cpp +++ b/src/shared/ResizeHandle.cpp @@ -8,14 +8,14 @@ #include "../SubmarineFree.hpp" ResizeHandle::ResizeHandle() { - box.size = Vec(8, 12); + box.size = Vec(8, 10); } void ResizeHandle::onDragStart(const event::DragStart& e) { if (e.button != GLFW_MOUSE_BUTTON_LEFT) return; - dragPos = APP->scene->rack->mousePos; + dragPos = APP->scene->rack->getMousePos(); ModuleWidget* mw = getAncestorOfType(); assert(mw); originalBox = mw->box; @@ -26,7 +26,7 @@ void ResizeHandle::onDragMove(const event::DragMove& e) { ModuleWidget *mw = sp->getAncestorOfType(); assert(sp); - Vec newDragPos = APP->scene->rack->mousePos; + Vec newDragPos = APP->scene->rack->getMousePos(); float deltaX = newDragPos.x - dragPos.x; Rect newBox = originalBox; diff --git a/src/shared/Scheme.cpp b/src/shared/Scheme.cpp index 2becb914..cfe340a3 100755 --- a/src/shared/Scheme.cpp +++ b/src/shared/Scheme.cpp @@ -81,21 +81,10 @@ void Scheme::setColors() { } std::shared_ptr Scheme::font() { - if (!_fontLoaded) { - _fontLoaded = true; - _font = APP->window->loadFont(asset::system("res/fonts/DejaVuSans.ttf")); - } + std::shared_ptr _font = APP->window->loadFont(asset::system("res/fonts/DejaVuSans.ttf")); return _font; } -int Scheme::font(NVGcontext *vg) { - int ret = nvgFindFont(vg, "subDejaVu"); - if (ret != -1) { - return ret; - } - return nvgCreateFont(vg, "subDejaVu", asset::system("res/fonts/DejaVuSans.ttf").c_str()); -} - Scheme gScheme; SchemePanel::SchemePanel() { @@ -151,10 +140,13 @@ void SchemePanel::resize(ModuleWidget *mw, Rect newBox) { canvas->box.size = newBox.size; rightHandle->box.pos.x = newBox.size.x - 10; mw->setSize(newBox.size); + if (resizeHandler) + resizeHandler(); dirty = true; } void SchemeCanvasWidget::draw(const DrawArgs &args) { + SchemeModuleWidget *smw = dynamic_cast(parent->parent); nvgSave(args.vg); smw->render(args.vg, this); @@ -182,6 +174,8 @@ void SchemeModuleWidget::drawBackground(NVGcontext *vg) { nvgBeginPath(vg); nvgMoveTo(vg, 0, 0); nvgLineTo(vg, box.size.x, 0); + nvgLineTo(vg, box.size.x -1, 1); + nvgLineTo(vg, 1, box.size.y - 1); nvgLineTo(vg, 0, box.size.y); nvgClosePath(vg); nvgFillColor(vg, gScheme.getHighlight(module)); @@ -190,6 +184,8 @@ void SchemeModuleWidget::drawBackground(NVGcontext *vg) { nvgMoveTo(vg, box.size.x, 0); nvgLineTo(vg, box.size.x, box.size.y); nvgLineTo(vg, 0, box.size.y); + nvgLineTo(vg, 1, box.size.y - 1); + nvgLineTo(vg, box.size.x - 1, 1); nvgClosePath(vg); nvgFillColor(vg, gScheme.getShadow(module)); nvgFill(vg); @@ -270,7 +266,7 @@ void SchemeModuleWidget::drawLogo(NVGcontext *vg, float left, float top, float s } void SchemeModuleWidget::drawText(NVGcontext *vg, float x, float y, int align, float size, NVGcolor col, const char *txt) { - nvgFontFaceId(vg, gScheme.font(vg)); + nvgFontFaceId(vg, gScheme.font()->handle); nvgFontSize(vg, size * 90 / SVG_DPI); nvgTextAlign(vg, align); nvgFillColor(vg, col); diff --git a/src/shared/SizeableModuleWidget.cpp b/src/shared/SizeableModuleWidget.cpp index dc8f5b58..9829f6e0 100755 --- a/src/shared/SizeableModuleWidget.cpp +++ b/src/shared/SizeableModuleWidget.cpp @@ -1,4 +1,3 @@ -#include #include "../SubmarineFree.hpp" json_t *SizeableModule::dataToJson() { @@ -9,16 +8,17 @@ json_t *SizeableModule::dataToJson() { void SizeableModule::dataFromJson(json_t *rootJ) { json_t *widthJ = json_object_get(rootJ, "width"); - if (widthJ) - size = json_number_value(widthJ); + if (widthJ) { + loadedSize = json_number_value(widthJ); + } } SizeableModuleWidget::SizeableModuleWidget(SizeableModule *sm, float size) { sizeableModule = sm; + fullSize = size; if (sm) { sm->size = size; } - fullSize = size; this->box.size = Vec(size, 380); panel = new SchemePanel(this->box.size); addChild(panel); @@ -38,7 +38,7 @@ void SizeableModuleWidget::Minimize(bool minimize) { box.size.x = minimize?15:fullSize; ShiftOthers(box.size.x - oldSize); Resize(); - unsigned int id = module->id; + int64_t id = module->id; float fs = fullSize; if (!stabilized) return; @@ -68,7 +68,7 @@ void SizeableModuleWidget::ShiftOthers(float delta) { return; if (delta == 0.0f) return; - for (Widget *w : APP->scene->rack->moduleContainer->children) { + for (Widget *w : APP->scene->rack->getModuleContainer()->children) { if (this == w) continue; if (this->box.pos.x > w->box.pos.x) @@ -78,7 +78,7 @@ void SizeableModuleWidget::ShiftOthers(float delta) { w->box.pos.x += delta; } } - +/* void SizeableModuleWidget::fromJson(json_t *rootJ) { ModuleWidget::fromJson(rootJ); if (!sizeableModule) @@ -89,6 +89,7 @@ void SizeableModuleWidget::fromJson(json_t *rootJ) { Minimize(sizeableModule->size < 16.0f); APP->scene->rack->requestModulePos(this, box.pos); } +*/ void SizeableModuleWidget::onResized() { } diff --git a/src/shared/SubLightSlider.cpp b/src/shared/SubLightSlider.cpp index 96e53020..01905b3b 100755 --- a/src/shared/SubLightSlider.cpp +++ b/src/shared/SubLightSlider.cpp @@ -8,7 +8,7 @@ #include "../SubmarineFree.hpp" #include "color.hpp" void SubLightSlider::draw(const DrawArgs &args) { - float offset = rescale(paramQuantity->getValue(), paramQuantity->getMinValue(), paramQuantity->getMaxValue(), 0, box.size.y - 12); + float offset = rescale(getParamQuantity()->getValue(), getParamQuantity()->getMinValue(), getParamQuantity()->getMaxValue(), 0, box.size.y - 12); NVGcolor lcol = enabled?color:nvgRGB(0x4a,0x4a,0x4a); nvgFillColor(args.vg, nvgRGB(0, 0, 0)); diff --git a/src/shared/SubSwitch.cpp b/src/shared/SubSwitch.cpp index 9c2a78f8..be60d616 100755 --- a/src/shared/SubSwitch.cpp +++ b/src/shared/SubSwitch.cpp @@ -12,10 +12,10 @@ void SubSwitch2::draw(const DrawArgs &args) { float value = 0.0f; float minValue = 0.0f; float maxValue = 1.0f; - if (paramQuantity) { - value = paramQuantity->getValue(); - minValue = paramQuantity->getMinValue(); - maxValue = paramQuantity->getMaxValue(); + if (getParamQuantity()) { + value = getParamQuantity()->getValue(); + minValue = getParamQuantity()->getMinValue(); + maxValue = getParamQuantity()->getMaxValue(); } float cx = 7.0f + (box.size.x - 14.0f) * value / (maxValue - minValue); diff --git a/src/shared/SubTooltip.cpp b/src/shared/SubTooltip.cpp index be0be9d9..7bc5b62b 100755 --- a/src/shared/SubTooltip.cpp +++ b/src/shared/SubTooltip.cpp @@ -1,32 +1,6 @@ -#include #include "../SubmarineFree.hpp" void SubTooltip::step() { if (stepLambda != NULL) stepLambda(); - //Tooltip::step(); } - -void TooltipKnob::onEnter(const event::Enter &e) { - if (settings::paramTooltip && !tooltip) { - SubTooltip *stt = new SubTooltip(); - tooltip = stt; - stt->stepLambda = [=]() { - tooltip->text = ""; - if (this->getText != NULL) - tooltip->text = this->getText(); - stt->Tooltip::step(); - tooltip->box.pos = this->getAbsoluteOffset(this->box.size).round(); - }; - APP->scene->addChild(tooltip); - } -} - -void TooltipKnob::onLeave(const event::Leave &e) { - if (tooltip) { - APP->scene->removeChild(tooltip); - delete tooltip; - tooltip = NULL; - } -} - diff --git a/src/shared/TextDisplay.cpp b/src/shared/TextDisplay.cpp index 7931b18a..b8d76c33 100644 --- a/src/shared/TextDisplay.cpp +++ b/src/shared/TextDisplay.cpp @@ -1,37 +1,47 @@ #include "../SubmarineFree.hpp" -#include "window.hpp" +#include "window/Window.hpp" int SubText::getTextPosition(Vec mousePos) { - 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 = APP->window->loadFont("res/fonts/ShareTechMono-Regular.ttf"); + if (font && font->handle >= 0) { + 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; + } + return 0; } void SubText::draw(const DrawArgs &args) { - nvgScissor(args.vg, 0, 0, box.size.x, box.size.y); //Background nvgBeginPath(args.vg); nvgRoundedRect(args.vg, 0, 0, box.size.x, box.size.y, 5.0); nvgFillColor(args.vg, bgColor); nvgFill(args.vg); +} - //Text - if (font->handle >= 0) { - bndSetFont(font->handle); - - NVGcolor highlightColor = color; - highlightColor.a = 0.5; - int begin = std::min(cursor, selection); - int end = (this == APP->event->selectedWidget) ? std::max(cursor, selection) : -1; - bndIconLabelCaret(args.vg, textOffset.x, textOffset.y, - box.size.x - 2*textOffset.x, box.size.y - 2*textOffset.y, - -1, color, fontSize, text.c_str(), highlightColor, begin, end); +void SubText::drawLayer(const DrawArgs &args, int layer) { + if (layer == 1) { + //Text + nvgScissor(args.vg, 0, 0, box.size.x, box.size.y); + std::shared_ptr font = APP->window->loadFont(asset::system("res/fonts/ShareTechMono-Regular.ttf")); + if (font && font->handle >= 0) { + bndSetFont(font->handle); + + NVGcolor highlightColor = color; + highlightColor.a = 0.5; + int begin = std::min(cursor, selection); + int end = (this == APP->event->selectedWidget) ? std::max(cursor, selection) : -1; + bndIconLabelCaret(args.vg, textOffset.x, textOffset.y, + box.size.x - 2*textOffset.x, box.size.y - 2*textOffset.y, + -1, color, fontSize, text.c_str(), highlightColor, begin, end); + bndSetFont(APP->window->uiFont->handle); + } + nvgResetScissor(args.vg); } - nvgResetScissor(args.vg); - bndSetFont(APP->window->uiFont->handle); + Widget::drawLayer(args, layer); } void SubText::appendContextMenu(Menu *menu) { @@ -149,4 +159,11 @@ void SubText::backgroundMenu(Menu *menu) { menu->addChild(createBackgroundMenuItem("Black", nvgRGB(0, 0, 0))); menu->addChild(createBackgroundMenuItem("White", nvgRGB(0xff, 0xff, 0xff))); } + +void SubText::onChange(const ChangeEvent &e) { + if (changeHandler) { + changeHandler(); + } + LedDisplayTextField::onChange(e); +} diff --git a/src/shared/components.hpp b/src/shared/components.hpp index 7c8387be..b99b5caf 100755 --- a/src/shared/components.hpp +++ b/src/shared/components.hpp @@ -19,6 +19,16 @@ // Ports ////////////////// +struct DeprecatedPort : PortWidget { + DeprecatedPort() { + box.size.x = 0; + box.size.y = 0; + } + void draw(const DrawArgs &args) override { + Widget::draw(args); + } +}; + struct SilverPort : PortWidget { NVGcolor col = nvgRGB(0xf0, 0xf0, 0xf0); SilverPort() { @@ -36,9 +46,9 @@ struct BluePort : SilverPort { BluePort() { col = SUBLIGHTBLUE; } }; -struct BlackPort : SilverPort { - BlackPort() { col = nvgRGB(0x40, 0x40, 0x40); } -}; +//struct BlackPort : SilverPort { + //BlackPort() { col = nvgRGB(0x40, 0x40, 0x40); } +//}; ////////////////// // Switches @@ -83,172 +93,37 @@ struct SubSwitchHorz : k { // Buttons ////////////////// -struct LightButtonLight; - struct LightButton : app::Switch { NVGcolor color = SUBLIGHTBLUE; - LightButtonLight *light; LightButton(); void draw(const DrawArgs &args) override; -}; - -struct LightButtonLight : LightWidget { - LightButton *button; - void draw(const DrawArgs &args) override; -}; - -////////////////// -// BulkParams -////////////////// - -struct BulkParamWidget : widget::OpaqueWidget { - Module *module; - int paramId; - float *value = NULL; - float minValue = .0f; - float maxValue = 1.0f; - float defaultValue = .0f; - ui::Tooltip* tooltip = NULL; - std::string description; - std::string label; - std::string unit; - /** Set to 0 for linear, positive for exponential, negative for logarithmic. */ - float displayBase = 0.f; - float displayMultiplier = 1.f; - float displayOffset = 0.f; - - void onButton(const event::Button& e) override; - void onDoubleClick(const event::DoubleClick& e) override; - void onEnter(const event::Enter& e) override; - void onLeave(const event::Leave& e) override; - - /** For legacy patch loading */ - void fromJson(json_t* rootJ); - void createContextMenu(); - void resetAction(); - virtual void reset() {} - virtual void randomize() {} - - std::function contextMenuCallback; - - std::string getString(); - float getDisplayValue(); - void setDisplayValue(float displayValue); - std::string getDisplayValueString(); - void setDisplayValueString(std::string s); - - static void setBulkParamValue(int thisModuleId, int thisParamId, float thisValue); -}; - -struct BulkParamTooltip : ui::Tooltip { - BulkParamWidget* bulkParamWidget; - - void step() override; + void drawLayer(const DrawArgs &args, int layer) override; + void drawLight(const DrawArgs &args, bool enabled); + void drawHalo(const DrawArgs &args); }; ////////////////// // Knobs ////////////////// -struct BulkKnob : BulkParamWidget { - /** Multiplier for mouse movement to adjust knob value */ - float speed = 1.0; - float oldValue = .0f; - bool smooth = true; - /** Enable snapping at integer values */ - bool snap = false; - float snapValue = NAN; - /** Drag horizontally instead of vertically */ - bool horizontal = false; - - void onHover(const event::Hover& e) override; - void onButton(const event::Button& e) override; - void onDragStart(const event::DragStart& e) override; - void onDragEnd(const event::DragEnd& e) override; - void onDragMove(const event::DragMove& e) override; - void reset() override; - void randomize() override; -}; - -struct LightKnobLight; -struct BaseLightKnob -{ +struct LightKnob : Knob { /** Angles in radians */ float minAngle = -0.83*M_PI; float maxAngle = 0.83*M_PI; /** Radii in standard units */ float radius = 19.0; int enabled = 1; - LightKnobLight *light; NVGcolor color = SUBLIGHTBLUE; - virtual void doDraw(const rack::widget::Widget::DrawArgs &args); void setEnabled(int val); void setRadius(int r); - virtual float getBLKValue() { return 0.0f; } - virtual float getBLKMinValue() { return -1.0f; } - virtual float getBLKMaxValue() { return 1.0f; } -}; - -struct LightKnobLight : LightWidget { - BaseLightKnob *knob; - void draw(const DrawArgs &args) override; -}; - -struct LightKnob : BaseLightKnob, Knob { LightKnob() { smooth = false; - light = new LightKnobLight(); - light->box.pos = Vec(0,0); - light->box.size = Vec(radius * 2, radius * 2); - light->knob = this; - addChild(light); - } - float getBLKValue() override { - if (paramQuantity) - return paramQuantity->getValue(); - return BaseLightKnob::getBLKValue(); - } - float getBLKMinValue() override { - if (paramQuantity) - return paramQuantity->getMinValue(); - return BaseLightKnob::getBLKMinValue(); - } - float getBLKMaxValue() override { - if (paramQuantity) - return paramQuantity->getMaxValue(); - return BaseLightKnob::getBLKMaxValue(); - } - void draw(const DrawArgs &args) override { - doDraw(args); - Knob::draw(args); - } -}; - -struct BulkLightKnob : BaseLightKnob, BulkKnob { - BulkLightKnob() { - smooth = false; - light = new LightKnobLight(); - light->box.pos = Vec(0,0); - light->box.size = Vec(radius * 2, radius * 2); - light->knob = this; - addChild(light); - } - float getBLKValue() override { - if (value) - return *value; - return BaseLightKnob::getBLKValue(); - } - float getBLKMinValue() override { - return minValue; - } - float getBLKMaxValue() override { - return maxValue; - } - void draw(const DrawArgs &args) override { - doDraw(args); - BulkKnob::draw(args); } + void draw(const DrawArgs &args) override; + void drawLayer(const DrawArgs &args, int layer) override; + void drawLight(const DrawArgs &args); + void drawHalo(const DrawArgs &args); }; template @@ -319,6 +194,21 @@ struct BlueRedLight : GrayModuleLightWidget { } }; +struct ExtensionLight : BlueLight { + ExtensionLight(); + virtual void getShape(const widget::Widget::DrawArgs& args) {} + void drawBackground(const widget::Widget::DrawArgs& args) override; + void drawLight(const widget::Widget::DrawArgs& args) override; +}; + +struct LeftLight : ExtensionLight { + void getShape(const widget::Widget::DrawArgs &args) override; +}; + +struct RightLight : ExtensionLight { + void getShape(const widget::Widget::DrawArgs &args) override; +}; + ////////////////// // Scheme ////////////////// @@ -333,11 +223,8 @@ struct Scheme { void setColors(); void save(); std::shared_ptr font(); - int font(NVGcontext *vg); bool isFlat = false; int scheme = Blue; - std::shared_ptr _font = NULL; - bool _fontLoaded = false; NVGcolor getBackground(Module *module) { return module?background:_background; } NVGcolor getAlternative(Module *module) { return module?alternative:_alternative; } NVGcolor getContrast(Module *module) { return module?contrast:_contrast; } @@ -392,6 +279,7 @@ struct SchemePanel : FramebufferWidget { void step() override; void resize(Rect newBox, Rect oldBox); void resize(ModuleWidget *mw, Rect newBox); + std::function resizeHandler; }; struct SchemeCanvasWidget : Widget { @@ -410,7 +298,6 @@ struct SchemeModuleWidget : app::ModuleWidget { void drawText(NVGcontext *vg, float x, float y, int align, float size, NVGcolor col, const char *txt); void drawBase(NVGcontext *vg, const char *txt); virtual void render(NVGcontext *vg, SchemeCanvasWidget *canvas); - virtual float* getBulkParam(int id) { return NULL; } }; ////////////////// @@ -427,11 +314,14 @@ struct SubText : LedDisplayTextField { } int getTextPosition(Vec mousePos) override; void draw(const DrawArgs &args) override; + void drawLayer(const DrawArgs &args, int layer) override; + void onChange(const ChangeEvent &e) override; void appendContextMenu(Menu *menu); MenuItem *createForegroundMenuItem(std::string label, NVGcolor color); MenuItem *createBackgroundMenuItem(std::string label, NVGcolor color); virtual void foregroundMenu(Menu *menu); virtual void backgroundMenu(Menu *menu); + std::function changeHandler; }; ////////////////// @@ -450,6 +340,7 @@ struct MouseTransformWidget:Widget { void rotate(float angle); void scale(Vec s); void draw(const DrawArgs &args) override; + void drawLayer(const DrawArgs &args, int layer) override; void onButton(const event::Button &e) override; void onHover(const event::Hover &e) override; void onHoverKey(const event::HoverKey &e) override; @@ -554,6 +445,7 @@ struct EventParamField : ui::TextField { struct SizeableModule : Module { float size = 0; + float loadedSize = 0; json_t *dataToJson() override; void dataFromJson(json_t *rootJ) override; }; @@ -567,7 +459,7 @@ struct SizeableModuleWidget : SchemeModuleWidget { void Resize(); void Minimize(bool minimize); void ShiftOthers(float delta); - void fromJson(json_t *rootJ) override; +// void dataFromJson(json_t *rootJ) override; virtual void onResized(); }; @@ -586,9 +478,3 @@ struct SubTooltip : ui::Tooltip { void step() override; }; -struct TooltipKnob : Knob -{ - std::function getText; - void onEnter(const event::Enter &e) override; - void onLeave(const event::Leave &e) override; -}; diff --git a/src/shared/torpedo.cpp b/src/shared/torpedo.cpp deleted file mode 100755 index f68254af..00000000 --- a/src/shared/torpedo.cpp +++ /dev/null @@ -1,406 +0,0 @@ -#include "rack.hpp" -#include "torpedo.hpp" -using namespace Torpedo; - -void BasePort::addCheckSum(unsigned int byte, unsigned int counter) { - _checksum += ((byte & 0xff) << ((counter % 4) * 8)); - _checksum &= 0xffffffff; -} - -void BasePort::raiseError(unsigned int errorType) { - _state = STATE_QUIESCENT; - _checksum = 0; - switch (errorType) { - case ERROR_STATE: - if (dbg) DEBUG("Torpedo Error: STATE"); - break; - case ERROR_COUNTER: - if (dbg) DEBUG("Torpedo Error: COUNTER"); - break; - case ERROR_LENGTH: - if (dbg) DEBUG("Torpedo Error: LENGTH"); - break; - case ERROR_CHECKSUM: - if (dbg) DEBUG("Torpedo Error: CHECKSUM"); - break; - } - error(errorType); -} - -void RawOutputPort::abort(void) { - _state = STATE_ABORTING; - _message.clear(); - _counter = 0; -} - -void RawOutputPort::completed(void) { - if (dbg) DEBUG("Torpedo Completed:"); -} - -void RawOutputPort::process(void) { - unsigned int channels = hiSpeed?16:1; - _module->outputs[_portNum].setChannels(channels); - for (unsigned int channel = 0; channel < channels; channel++) { - int portValue = 0; - switch (_state) { - case STATE_HEADER: - switch (_counter) { - case 0: - _checksum = 0; - portValue = 0x1000 | (_appId.length()?_appId[0]:0); - _counter++; - break; - case 1: - case 2: - case 3: - portValue = 0x1000 | (_counter * 0x100) | ((_appId.length() > _counter)?_appId[_counter]:0); - _counter++; - break; - case 4: - case 5: - case 6: - case 7: - portValue = 0x1000 | (_counter * 0x100) | (_message.length() >> (8 * (_counter - 4)) & 0xff); - _counter++; - break; - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - portValue = 0x1000 | (_counter * 0x100); - _counter++; - break; - case 15: - portValue = 0x1000 | (_counter * 0x100); - _counter = 0; - _state = STATE_BODY; - } - addCheckSum(portValue & 0xff, _counter + 3); - break; - case STATE_BODY: - portValue = 0x2000 | ((_counter % 0x10) * 0x100) | _message[_counter]; - addCheckSum(portValue & 0xff, _counter); - _counter++; - if (_counter == _message.length()) { - _counter = 0; - _state = STATE_TRAILER; - } - break; - case STATE_TRAILER: - switch (_counter) { - case 0: - case 1: - case 2: - portValue = 0x3000 | (_counter * 0x100) | (_checksum & 0xff); - _checksum >>= 8; - _counter++; - break; - case 3: - portValue = 0x3000 | (_counter * 0x100) | (_checksum & 0xff); - _counter = 0; - _state = STATE_QUIESCENT; - completed(); - break; - } - break; - case STATE_ABORTING: - portValue = 0x3f00; - _counter = 0; - if (_message.length() > 0) { - _state = STATE_HEADER; - } - else { - _state = STATE_QUIESCENT; - } - break; - case STATE_QUIESCENT: - portValue = 0; - break; - } - _module->outputs[_portNum].setVoltage(1.0f * portValue, channel); - } -} - -void RawOutputPort::send(std::string appId, std::string message) { - _appId.assign(appId); - send(message); -} - -void RawOutputPort::send(std::string message) { - if (!_module->outputs[_portNum].isConnected()) return; - if (!message.length()) { - raiseError(ERROR_LENGTH); - return; - } - if (dbg) DEBUG("Torpedo Send:%s %s", _appId.c_str(), message.c_str()); - switch (_state) { - case STATE_HEADER: - case STATE_BODY: - case STATE_TRAILER: - abort(); - break; - case STATE_ABORTING: - break; - case STATE_QUIESCENT: - _state = STATE_HEADER; - break; - } - _message.assign(message); - _counter = 0; -} - -void RawInputPort::process(void) { - if (!_module->inputs[_portNum].isConnected()) { - _state = STATE_QUIESCENT; - _checksum = 0; - return; - } - unsigned int channels = _module->inputs[_portNum].getChannels(); - for (unsigned int channel = 0; channel < channels; channel++) { - unsigned int data = (unsigned int)(_module->inputs[_portNum].getVoltage(channel)); - if ((data & 0xff00) == 0x3f00) { - _state = STATE_QUIESCENT; - _checksum = 0; - return; - } - unsigned int state = data >> 12; - unsigned int counter = (data & 0x0f00) >> 8; - data &= 0xff; - switch (_state) { - case STATE_QUIESCENT: - if (!state) { - return; - } - addCheckSum(data, counter); - if (state == 1) { - _counter = 0; - _message.clear(); - _state = STATE_HEADER; - if (counter != _counter) { - raiseError(ERROR_COUNTER); - return; - } - _appId.clear(); - _appId.push_back(data); - _length = 0; - continue; - } - raiseError(ERROR_STATE); - return; - case STATE_HEADER: - addCheckSum(data, counter); - if (state != _state) { - raiseError(ERROR_STATE); - return; - } - _counter++; - if (counter != _counter) { - raiseError(ERROR_COUNTER); - return; - } - switch (counter) { - case 0: - case 1: - case 2: - case 3: - _appId.push_back(data); - break; - case 4: - case 5: - case 6: - case 7: - _length >>= 8; - _length += (data << 24); - break; - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - break; - case 15: - _state = STATE_BODY; - _message.reserve(_length); - _counter = 0; - break; - } - break; - case STATE_BODY: - addCheckSum(data, counter); - if (state != _state) { - raiseError(ERROR_STATE); - return; - } - if (counter != _counter++) { - raiseError(ERROR_COUNTER); - return; - } - _counter %= 16; - _message.push_back(data); - if (_message.length() >= _length) { - _state = STATE_TRAILER; - _counter = 0; - continue; - } - break; - case STATE_TRAILER: - if (state != _state) { - raiseError(ERROR_STATE); - return; - } - if (counter != _counter) { - raiseError(ERROR_COUNTER); - return; - } - if (_message.length() != _length) { - raiseError(ERROR_LENGTH); - return; - } - if (data != (_checksum & 0xff)) { - raiseError(ERROR_CHECKSUM); - return; - } - _checksum >>= 8; - _counter++; - if (_counter == 4) { - _state = STATE_QUIESCENT; - _checksum = 0; - received(_appId, _message); - } - continue; - } - } -} - -void RawInputPort::received(std::string appId, std::string message) { - if (dbg) DEBUG("Torpedo Received:%s %s", appId.c_str(), message.c_str()); -} - -void TextInputPort::received(std::string appId, std::string message) { - if (!appId.compare("TEXT")) - received(message); -} - -void QueuedOutputPort::abort() { - RawOutputPort::abort(); - for (auto i : _queue) delete i; - _queue.clear(); -} - -void QueuedOutputPort::process() { - if (!RawOutputPort::isBusy()) { - if (_queue.size()) { - std::string *s = _queue.front(); - _queue.erase(_queue.begin()); - RawOutputPort::send(std::string(*s)); - delete s; - } - } - RawOutputPort::process(); -} - -void QueuedOutputPort::send(std::string message) { - if (QueuedOutputPort::isBusy()) { - if (_queue.size() >= _size) { - if (!_replace) - return; - std::string *s = _queue.back(); - _queue.pop_back(); - delete s; - if (dbg) DEBUG("Torpedo Replaced:"); - } - { - std::string *s = new std::string(message); - _queue.push_back(s); - if (dbg) DEBUG("Torpedo Queued:"); - } - return; - } - RawOutputPort::send(message); -} - -void QueuedOutputPort::size(unsigned int s) { - if (s < 1) { - return; - } - _size = s; -} - -void MessageOutputPort::send(std::string pluginName, std::string moduleName, std::string message) { - json_t *rootJ = json_object(); - json_object_set_new(rootJ, "pluginInstance", json_string(pluginName.c_str())); - json_object_set_new(rootJ, "module", json_string(moduleName.c_str())); - json_object_set_new(rootJ, "message", json_string(message.c_str())); - char *msg = json_dumps(rootJ, 0); - json_decref(rootJ); - QueuedOutputPort::send(std::string(msg)); - free(msg); -} - -void MessageInputPort::received(std::string appId, std::string message) { - if (dbg) DEBUG("Torpedo Received: %s", message.c_str()); - std::string pluginName; - std::string moduleName; - std::string messageText; - - if (appId.compare("MESG")) - return; - json_error_t error; - json_t *rootJ = json_loads(message.c_str(), 0, &error); - if (!rootJ) { - DEBUG("Torpedo MESG Error: %s", error.text); - return; - } - json_t *jp = json_object_get(rootJ, "pluginInstance"); - if (json_is_string(jp)) - pluginName.assign(json_string_value(jp)); - json_t *jm = json_object_get(rootJ, "module"); - if (json_is_string(jm)) - moduleName.assign(json_string_value(jm)); - json_t *jt = json_object_get(rootJ, "message"); - if (json_is_string(jt)) - messageText.assign(json_string_value(jt)); - json_decref(rootJ); - received(pluginName, moduleName, messageText); -} - -void PatchOutputPort::send(std::string pluginName, std::string moduleName, json_t *rootJ) { - json_t *wrapper = json_object(); - json_object_set_new(wrapper, "pluginInstance", json_string(pluginName.c_str())); - json_object_set_new(wrapper, "module", json_string(moduleName.c_str())); - json_object_set_new(wrapper, "patch", rootJ); - char *msg = json_dumps(wrapper, 0); - json_decref(wrapper); - QueuedOutputPort::send(std::string(msg)); - free(msg); -} - -void PatchInputPort::received(std::string appId, std::string message) { - if (dbg) DEBUG("Torpedo Received: %s", message.c_str()); - std::string pluginName; - std::string moduleName; - - if (appId.compare("PTCH")) - return; - json_error_t error; - json_t *rootJ = json_loads(message.c_str(), 0, &error); - if (!rootJ) { - DEBUG("Torpedo MESG Error: %s", error.text); - return; - } - json_t *jp = json_object_get(rootJ, "pluginInstance"); - if (json_is_string(jp)) - pluginName.assign(json_string_value(jp)); - json_t *jm = json_object_get(rootJ, "module"); - if (json_is_string(jm)) - moduleName.assign(json_string_value(jm)); - json_t *jt = json_object_get(rootJ, "patch"); - if (jt) - received(pluginName, moduleName, jt); - json_decref(rootJ); -} diff --git a/src/shared/torpedo.hpp b/src/shared/torpedo.hpp deleted file mode 100755 index 6b4fa21a..00000000 --- a/src/shared/torpedo.hpp +++ /dev/null @@ -1,157 +0,0 @@ -#pragma once -#include "deque" -using namespace rack; - -namespace Torpedo { - // - // Basic shared functionality - // - - struct BasePort { - enum States { - STATE_QUIESCENT, - STATE_HEADER, - STATE_BODY, - STATE_TRAILER, - STATE_ABORTING - }; - - enum Errors { - ERROR_STATE, - ERROR_COUNTER, - ERROR_LENGTH, - ERROR_CHECKSUM - }; - - unsigned int _checksum = 0; - Module *_module; - unsigned int _portNum; - unsigned int _state = STATE_QUIESCENT; - - bool dbg = false; - bool hiSpeed = true; - - BasePort(Module *module, unsigned int portNum) { - _module = module; - _portNum = portNum; - } - void addCheckSum(unsigned int byte, unsigned int counter); - virtual int isBusy(void) { - return (_state != STATE_QUIESCENT); - } - void raiseError(unsigned int errorType); - virtual void error(unsigned int errorType) {}; - - }; - - // - // Raw output port functionality. Encapsulating layers 2-5 of the OSI model - // - - struct RawOutputPort : BasePort { - std::string _appId; - unsigned int _counter; - std::string _message; - - RawOutputPort(Module *module, unsigned int portNum) : BasePort(module, portNum) {} - - virtual void abort(); - virtual void appId(std::string app) { _appId.assign(app); } - virtual void completed(); - virtual void process(); - virtual void send(std::string appId, std::string message); - virtual void send(std::string message); - }; - - // - // Raw input port functionality. Encapsulating layers 2-5 of the OSI model - // - - struct RawInputPort : BasePort { - std::string _appId; - unsigned int _counter; - unsigned int _length; - std::string _message; - - RawInputPort(Module *module, unsigned int portNum) : BasePort(module, portNum) {} - - void process(); - virtual void received(std::string appId, std::string message); - }; - - // - // Basic text sending. - // - - struct TextInputPort : RawInputPort { - TextInputPort(Module *module, unsigned int portNum) : RawInputPort(module, portNum) {} - - void received(std::string appId, std::string message) override; - virtual void received(std::string message) {} - }; - - struct TextOutputPort : RawOutputPort { - TextOutputPort(Module *module, unsigned int portNum) : RawOutputPort(module, portNum) {_appId.assign("TEXT");} - }; - - // - // Queued sending. - // - - struct QueuedOutputPort : RawOutputPort { - std::vector _queue; - unsigned int _replace = 0; - unsigned int _size = 0; - - QueuedOutputPort(Module *module, unsigned int portNum) : RawOutputPort(module, portNum) {} - virtual ~QueuedOutputPort() { for (auto i : _queue) delete i; } - - void abort() override; - int isBusy() override { return (_state != STATE_QUIESCENT) || _queue.size(); } - virtual int isFul() { return _queue.size() >= _size; } - void process() override; - void replace(unsigned int rep) { _replace = rep; } - void send(std::string message) override; - void size(unsigned int s); - }; - - // - // Addressed Messages. - // - - struct MessageOutputPort : QueuedOutputPort { - MessageOutputPort(Module *module, unsigned int portNum) : QueuedOutputPort(module, portNum) {_appId.assign("MESG");} - - virtual void send(std::string pluginName, std::string moduleName, std::string message); - private: - using QueuedOutputPort::send; - }; - - struct MessageInputPort : RawInputPort { - MessageInputPort(Module *module, unsigned int portNum) : RawInputPort(module, portNum) {} - - void received(std::string appId, std::string message) override; - virtual void received(std::string pluginName, std::string moduleName, std::string message) {} - }; - - // - // Device Patches. - // - - struct PatchOutputPort : QueuedOutputPort { - PatchOutputPort(Module *module, unsigned int portNum) : QueuedOutputPort(module, portNum) {_appId.assign("PTCH");} - - virtual void send(std::string pluginName, std::string moduleName, json_t *rootJ); - private: - using QueuedOutputPort::send; - }; - - struct PatchInputPort : RawInputPort { - PatchInputPort(Module *module, unsigned int portNum) : RawInputPort(module, portNum) {} - - void received(std::string appId, std::string message) override; - virtual void received(std::string pluginName, std::string moduleName, json_t *rootJ) {} - }; - -} -