diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..aafd6f5d --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +github: falkTX +liberapay: falkTX +patreon: falkTX +custom: "https://paypal.me/falkTX" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 134af71b..5429fcf0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,26 +1,31 @@ name: build -on: - push: +on: [push, pull_request] env: - CACHE_VERSION: 31 + CACHE_VERSION: 4 CARDINAL_UNDER_WINE: 1 - DEBIAN_FRONTEND: noninteractive - HOMEBREW_NO_AUTO_UPDATE: 1 - LIBGL_ALWAYS_SOFTWARE: 'true' - WITH_LTO: 'false' + CIBUILD: true + EMSCRIPTEN_VERSION: 3.1.27 + LIBGL_ALWAYS_SOFTWARE: true + PAWPAW_SKIP_LTO: 1 + PAWPAW_SKIP_GLIB: 1 + PAWPAW_SKIP_LV2: 1 + PAWPAW_SKIP_SAMPLERATE: 1 jobs: - linux-arm64: + linux: + strategy: + matrix: + target: [aarch64, armhf, i386, riscv64, x86_64] runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - - name: Set up cache + - name: Set up build cache id: cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: | ~/PawPawBuilds @@ -31,295 +36,98 @@ jobs: src/Rack/dep/jansson-2.12 src/Rack/dep/libarchive-3.4.3 src/Rack/dep/libsamplerate-0.1.9 - src/Rack/dep/speexdsp-SpeexDSP-1.2rc3 src/Rack/dep/zstd-1.4.5 - key: linux-arm64-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} + key: linux-${{ matrix.target }}-v${{ env.CACHE_VERSION }} - name: Fix GitHub's mess run: | - sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo rm /etc/apt/sources.list.d/*.list sudo apt-get update -qq - sudo apt-get install -yqq --allow-downgrades libpcre2-8-0/focal libpcre2-16-0/focal libpcre2-32-0/focal libpcre2-posix2/focal - - name: Set up dependencies + sudo apt-get purge -yqq git-man libclang* libgbm* libllvm* libmono* libnginx* moby* mono* nginx* perl php* libgdiplus libpcre2-posix3 libselinux1-dev libzip4 + sudo apt-get install -yqq --allow-downgrades autoconf/focal automake/focal build-essential/focal git/focal libgd3/focal libglib2.0-0/focal libglib2.0-dev/focal libpcre2-8-0/focal libpcre2-16-0/focal libpcre2-32-0/focal libpcre2-posix2/focal pkg-config/focal + sudo apt-get clean + - name: Setup dependencies (aarch64) + if: ${{ matrix.target == 'aarch64' }} + shell: bash run: | sudo dpkg --add-architecture arm64 sudo sed -i "s/deb http/deb [arch=amd64] http/" /etc/apt/sources.list + sudo sed -i "s/deb mirror/deb [arch=amd64] mirror/" /etc/apt/sources.list echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports focal main restricted universe multiverse" | sudo tee /etc/apt/sources.list.d/ports-arm64.list echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports focal-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/ports-arm64.list echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports focal-backports main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/ports-arm64.list sudo apt-get update -qq - sudo apt-get install -yqq g++-aarch64-linux-gnu libdbus-1-dev:arm64 libgl1-mesa-dev:arm64 libglib2.0-dev:arm64 libx11-dev:arm64 libxcursor-dev:arm64 libxext-dev:arm64 libxrandr-dev:arm64 qemu-user-static - - name: Set up ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: ccache-linux-arm64-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} - - name: Build extra dependencies - env: - PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig - run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi - export PATH="/usr/lib/ccache:${PATH}" - ./deps/PawPaw/bootstrap-cardinal.sh linux-aarch64 && ./deps/PawPaw/.cleanup.sh linux-aarch64 - - name: Build linux arm64 cross-compiled - run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi - export PATH="/usr/lib/ccache:${PATH}" - pushd deps/PawPaw; source local.env linux-aarch64; popd - make features - make CIBUILD=true NOOPT=true WITH_LTO=${{ env.WITH_LTO }} -j $(nproc) - make unzipfx - - name: Set sha8 (non-release) - if: startsWith(github.ref, 'refs/tags/') != true - id: slug1 - run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" - - name: Set sha8 (release) - if: startsWith(github.ref, 'refs/tags/') - id: slug2 - run: echo "::set-output name=sha8::$(echo ${{ github.ref_name }})" - - name: Set sha8 - id: slug - run: echo "::set-output name=sha8::$(echo ${{ steps.slug1.outputs.sha8 || steps.slug2.outputs.sha8 }})" - - name: Pack binaries - run: | - tar -c -h --hard-dereference -z -f ${{ github.event.repository.name }}-linux-arm64-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}.tar.gz -C bin $(ls bin | grep -e lv2 -e vst) ../CardinalJACK ../CardinalNative - - uses: actions/upload-artifact@v2 - with: - name: ${{ github.event.repository.name }}-linux-arm64-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} - path: | - *.tar.gz - - uses: softprops/action-gh-release@v1 - if: startsWith(github.ref, 'refs/tags/') - with: - tag_name: ${{ github.ref_name }} - name: ${{ github.ref_name }} - draft: false - prerelease: false - files: | - *.tar.gz - - linux-armhf: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - - name: Set up cache - id: cache - uses: actions/cache@v2 - with: - path: | - ~/PawPawBuilds - src/Rack/dep/bin - src/Rack/dep/include - src/Rack/dep/lib - src/Rack/dep/share - src/Rack/dep/jansson-2.12 - src/Rack/dep/libarchive-3.4.3 - src/Rack/dep/libsamplerate-0.1.9 - src/Rack/dep/speexdsp-SpeexDSP-1.2rc3 - src/Rack/dep/zstd-1.4.5 - key: linux-armhf-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} - - name: Fix GitHub's mess - run: | - sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list - sudo apt-get update -qq - sudo apt-get install -yqq --allow-downgrades libpcre2-8-0/focal libpcre2-16-0/focal libpcre2-32-0/focal libpcre2-posix2/focal - - name: Set up dependencies + sudo apt-get install -yqq g++-aarch64-linux-gnu libasound2-dev:arm64 libdbus-1-dev:arm64 libgl1-mesa-dev:arm64 libglib2.0-dev:arm64 libsdl2-dev:arm64 libx11-dev:arm64 libxcursor-dev:arm64 libxext-dev:arm64 libxrandr-dev:arm64 gperf meson qemu-user-static + sudo apt-get clean + - name: Setup dependencies (armhf) + if: ${{ matrix.target == 'armhf' }} + shell: bash run: | sudo dpkg --add-architecture armhf sudo sed -i "s/deb http/deb [arch=amd64] http/" /etc/apt/sources.list + sudo sed -i "s/deb mirror/deb [arch=amd64] mirror/" /etc/apt/sources.list echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports focal main restricted universe multiverse" | sudo tee /etc/apt/sources.list.d/ports-armhf.list echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports focal-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/ports-armhf.list echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports focal-backports main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/ports-armhf.list sudo apt-get update -qq - sudo apt-get install -yqq g++-arm-linux-gnueabihf libdbus-1-dev:armhf libgl1-mesa-dev:armhf libglib2.0-dev:armhf libx11-dev:armhf libxcursor-dev:armhf libxext-dev:armhf libxrandr-dev:armhf qemu-user-static - - name: Set up ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: ccache-linux-armhf-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} - - name: Build extra dependencies - env: - PKG_CONFIG_PATH: /usr/lib/arm-linux-gnueabihf/pkgconfig - run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi - export PATH="/usr/lib/ccache:${PATH}" - ./deps/PawPaw/bootstrap-cardinal.sh linux-armhf && ./deps/PawPaw/.cleanup.sh linux-armhf - - name: Build linux armhf cross-compiled - run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi - export PATH="/usr/lib/ccache:${PATH}" - pushd deps/PawPaw; source local.env linux-armhf; popd - make features - make CIBUILD=true NOOPT=true WITH_LTO=${{ env.WITH_LTO }} -j $(nproc) - make unzipfx - - name: Set sha8 (non-release) - if: startsWith(github.ref, 'refs/tags/') != true - id: slug1 - run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" - - name: Set sha8 (release) - if: startsWith(github.ref, 'refs/tags/') - id: slug2 - run: echo "::set-output name=sha8::$(echo ${{ github.ref_name }})" - - name: Set sha8 - id: slug - run: echo "::set-output name=sha8::$(echo ${{ steps.slug1.outputs.sha8 || steps.slug2.outputs.sha8 }})" - - name: Pack binaries - run: | - tar -c -h --hard-dereference -z -f ${{ github.event.repository.name }}-linux-armhf-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}.tar.gz -C bin $(ls bin | grep -e lv2 -e vst) ../CardinalJACK ../CardinalNative - - uses: actions/upload-artifact@v2 - with: - name: ${{ github.event.repository.name }}-linux-armhf-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} - path: | - *.tar.gz - - uses: softprops/action-gh-release@v1 - if: startsWith(github.ref, 'refs/tags/') - with: - tag_name: ${{ github.ref_name }} - name: ${{ github.ref_name }} - draft: false - prerelease: false - files: | - *.tar.gz - - linux-i686: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - - name: Set up cache - id: cache - uses: actions/cache@v2 - with: - path: | - ~/PawPawBuilds - src/Rack/dep/bin - src/Rack/dep/include - src/Rack/dep/lib - src/Rack/dep/share - src/Rack/dep/jansson-2.12 - src/Rack/dep/libarchive-3.4.3 - src/Rack/dep/libsamplerate-0.1.9 - src/Rack/dep/speexdsp-SpeexDSP-1.2rc3 - src/Rack/dep/zstd-1.4.5 - key: linux-i686-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} - - name: Fix GitHub's mess - run: | - sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list - sudo apt-get update -qq - sudo apt-get install -yqq --allow-downgrades libpcre2-8-0/focal libpcre2-16-0/focal libpcre2-32-0/focal libpcre2-posix2/focal - - name: Set up dependencies + sudo apt-get install -yqq g++-arm-linux-gnueabihf libasound2-dev:armhf libdbus-1-dev:armhf libgl1-mesa-dev:armhf libglib2.0-dev:armhf libsdl2-dev:armhf libx11-dev:armhf libxcursor-dev:armhf libxext-dev:armhf libxrandr-dev:armhf gperf meson qemu-user-static + sudo apt-get clean + - name: Setup dependencies (i386) + if: ${{ matrix.target == 'i386' }} + shell: bash run: | sudo dpkg --add-architecture i386 sudo apt-get update -qq - sudo apt-get install -yqq g++-multilib libdbus-1-dev:i386 libgl1-mesa-dev:i386 libglib2.0-dev:i386 libx11-dev:i386 libxcursor-dev:i386 libxext-dev:i386 libxrandr-dev:i386 - - name: Set up ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: ccache-linux-i686-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} - - name: Build extra dependencies - env: - PKG_CONFIG_PATH: /usr/lib/i386-linux-gnu/pkgconfig - run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi - export PATH="/usr/lib/ccache:${PATH}" - ./deps/PawPaw/bootstrap-cardinal.sh linux-i686 && ./deps/PawPaw/.cleanup.sh linux-i686 - - name: Build linux i686 - run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi - export PATH="/usr/lib/ccache:${PATH}" - pushd deps/PawPaw; source local.env linux-i686; popd - make features - make CIBUILD=true NOOPT=true WITH_LTO=${{ env.WITH_LTO }} -j $(nproc) - make unzipfx - - name: Set sha8 (non-release) - if: startsWith(github.ref, 'refs/tags/') != true - id: slug1 - run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" - - name: Set sha8 (release) - if: startsWith(github.ref, 'refs/tags/') - id: slug2 - run: echo "::set-output name=sha8::$(echo ${{ github.ref_name }})" - - name: Set sha8 - id: slug - run: echo "::set-output name=sha8::$(echo ${{ steps.slug1.outputs.sha8 || steps.slug2.outputs.sha8 }})" - - name: Pack binaries + sudo apt-get install -yqq g++-i686-linux-gnu libasound2-dev:i386 libdbus-1-dev:i386 libgl1-mesa-dev:i386 libglib2.0-dev:i386 libsdl2-dev:i386 libx11-dev:i386 libxcursor-dev:i386 libxext-dev:i386 libxrandr-dev:i386 gperf meson + sudo apt-get clean + - name: Setup dependencies (riscv64) + if: ${{ matrix.target == 'riscv64' }} + shell: bash run: | - tar -c -h --hard-dereference -z -f ${{ github.event.repository.name }}-linux-i686-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}.tar.gz -C bin $(ls bin | grep -e lv2 -e vst) ../CardinalJACK ../CardinalNative - - uses: actions/upload-artifact@v2 - with: - name: ${{ github.event.repository.name }}-linux-i686-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} - path: | - *.tar.gz - - uses: softprops/action-gh-release@v1 - if: startsWith(github.ref, 'refs/tags/') - with: - tag_name: ${{ github.ref_name }} - name: ${{ github.ref_name }} - draft: false - prerelease: false - files: | - *.tar.gz - - linux-x86_64: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - - name: Set up cache - id: cache - uses: actions/cache@v2 - with: - path: | - ~/PawPawBuilds - src/Rack/dep/bin - src/Rack/dep/include - src/Rack/dep/lib - src/Rack/dep/share - src/Rack/dep/jansson-2.12 - src/Rack/dep/libarchive-3.4.3 - src/Rack/dep/libsamplerate-0.1.9 - src/Rack/dep/speexdsp-SpeexDSP-1.2rc3 - src/Rack/dep/zstd-1.4.5 - key: linux-x86_64-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} - - name: Set up dependencies + sudo dpkg --add-architecture riscv64 + sudo sed -i "s/deb http/deb [arch=amd64] http/" /etc/apt/sources.list + sudo sed -i "s/deb mirror/deb [arch=amd64] mirror/" /etc/apt/sources.list + echo "deb [arch=riscv64] http://ports.ubuntu.com/ubuntu-ports focal main restricted universe multiverse" | sudo tee /etc/apt/sources.list.d/ports-riscv64.list + echo "deb [arch=riscv64] http://ports.ubuntu.com/ubuntu-ports focal-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/ports-riscv64.list + echo "deb [arch=riscv64] http://ports.ubuntu.com/ubuntu-ports focal-backports main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/ports-riscv64.list + sudo apt-get update -qq + sudo apt-get install -yqq g++-riscv64-linux-gnu libasound2-dev:riscv64 libdbus-1-dev:riscv64 libgl1-mesa-dev:riscv64 libglapi-mesa:riscv64 libglvnd0:riscv64 libglib2.0-dev:riscv64 libsdl2-dev:riscv64 libx11-dev:riscv64 libxcursor-dev:riscv64 libxext-dev:riscv64 libxrandr-dev:riscv64 gperf meson qemu-user-static + sudo apt-get clean + - name: Setup dependencies (x86_64) + if: ${{ matrix.target == 'x86_64' }} + shell: bash run: | sudo apt-get update -qq - sudo apt-get install -yqq libdbus-1-dev libgl1-mesa-dev libglib2.0-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev + sudo apt-get install -yqq libasound2-dev libdbus-1-dev libgl1-mesa-dev libglib2.0-dev libsdl2-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev gperf meson + sudo apt-get clean - name: Set up ccache uses: hendrikmuhs/ccache-action@v1.2 with: - key: ccache-linux-x86_64-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} + key: ccache-linux-${{ matrix.target }}-v${{ env.CACHE_VERSION }} - name: Build extra dependencies + env: + PKG_CONFIG_PATH: /usr/lib/${{ matrix.target }}-linux-gnu/pkgconfig run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi - export PATH="/usr/lib/ccache:${PATH}" - ./deps/PawPaw/bootstrap-cardinal.sh linux && ./deps/PawPaw/.cleanup.sh linux - - name: Build linux x86_64 + ./deps/PawPaw/bootstrap-cardinal.sh linux-${{ matrix.target }} && ./deps/PawPaw/.cleanup.sh linux-${{ matrix.target }} + - name: Build linux run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi export PATH="/usr/lib/ccache:${PATH}" - pushd deps/PawPaw; source local.env linux; popd + source deps/PawPaw/local.env linux-${{ matrix.target }} + export PKG_CONFIG_PATH+=:/usr/lib/${{ matrix.target }}-linux-gnu/pkgconfig make features - make CIBUILD=true NOOPT=true WITH_LTO=${{ env.WITH_LTO }} -j $(nproc) + make HAVE_PULSEAUDIO=false NOOPT=true -j $(nproc) make unzipfx - name: Set sha8 (non-release) if: startsWith(github.ref, 'refs/tags/') != true - id: slug1 - run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" + run: echo "SHA8=$(echo ${{ github.sha }} | cut -c1-8)" >> $GITHUB_ENV - name: Set sha8 (release) if: startsWith(github.ref, 'refs/tags/') - id: slug2 - run: echo "::set-output name=sha8::$(echo ${{ github.ref_name }})" - - name: Set sha8 - id: slug - run: echo "::set-output name=sha8::$(echo ${{ steps.slug1.outputs.sha8 || steps.slug2.outputs.sha8 }})" + run: echo "SHA8=$(echo ${{ github.ref_name }})" >> $GITHUB_ENV - name: Pack binaries run: | - tar -c -h --hard-dereference -z -f ${{ github.event.repository.name }}-linux-x86_64-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}.tar.gz -C bin $(ls bin | grep -e lv2 -e vst) ../CardinalJACK ../CardinalNative - - uses: actions/upload-artifact@v2 + tar -c -h --hard-dereference -z -f ${{ github.event.repository.name }}-linux-${{ matrix.target }}-${{ github.event.pull_request.number || env.SHA8 }}.tar.gz -C bin $(ls bin | grep -e lv2 -e vst -e clap) ../CardinalJACK ../CardinalNative ../LICENSE ../README.md ../docs + - uses: actions/upload-artifact@v3 with: - name: ${{ github.event.repository.name }}-linux-x86_64-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} + name: ${{ github.event.repository.name }}-linux-${{ matrix.target }}-${{ github.event.pull_request.number || env.SHA8 }} path: | *.tar.gz - uses: softprops/action-gh-release@v1 @@ -335,71 +143,47 @@ jobs: linux-x86_64-debug: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - name: Set up dependencies run: | sudo apt-get update -qq - sudo apt-get install -yqq libdbus-1-dev libgl1-mesa-dev liblo-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev + sudo apt-get install -yqq libasound2-dev libdbus-1-dev libgl1-mesa-dev liblo-dev libsdl2-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev gperf meson + sudo apt-get clean - name: Build linux x86_64 (debug) env: LDFLAGS: -static-libgcc -static-libstdc++ run: | make features - make DEBUG=true -j $(nproc) + # multiple jobs for building carla, deps and plugins + make DEBUG=true carla deps dgl plugins resources -j $(nproc) + # single job for final build stage, otherwise we might get killed due to OOM + make DEBUG=true HAVE_PULSEAUDIO=false clap lv2 vst2 vst3 -j 1 - name: Set sha8 id: slug - run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" + run: echo "SHA8=$(echo ${{ github.sha }} | cut -c1-8)" >> $GITHUB_ENV - name: Pack binaries run: | - tar -c -h --hard-dereference -z -f ${{ github.event.repository.name }}-linux-x86_64-debug-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}.tar.gz -C bin $(ls bin | grep -e lv2 -e vst) - - uses: actions/upload-artifact@v2 + tar -c -h --hard-dereference -z -f ${{ github.event.repository.name }}-linux-x86_64-debug-${{ github.event.pull_request.number || env.SHA8 }}.tar.gz -C bin $(ls bin | grep -e lv2 -e vst -e clap) ../LICENSE ../README.md ../docs + - uses: actions/upload-artifact@v3 with: - name: ${{ github.event.repository.name }}-linux-x86_64-debug-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} + name: ${{ github.event.repository.name }}-linux-x86_64-debug-${{ github.event.pull_request.number || env.SHA8 }} path: | *.tar.gz - linux-x86_64-headless: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - - name: Set up dependencies - run: | - sudo apt-get update -qq - sudo apt-get remove -yqq libcairo2-dev libx11-dev libx11-dev libxext-dev - sudo apt-get install -yqq liblo-dev - - name: Build linux x86_64 (headless) - run: | - make HEADLESS=true features - make HEADLESS=true -j $(nproc) - - linux-x86_64-sysdeps: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - - name: Set up dependencies - run: | - sudo apt-get update -qq - sudo apt-get install -yqq libdbus-1-dev libgl1-mesa-dev liblo-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev libarchive-dev libjansson-dev libsamplerate0-dev libsndfile1-dev libspeexdsp-dev - - name: Build linux x86_64 (sysdeps) - run: | - make features - make SYSDEPS=true -j $(nproc) - - macos-intel: + macos: + strategy: + matrix: + target: [universal-10.15] runs-on: macos-11 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - name: Set up cache id: cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: | ~/PawPawBuilds @@ -410,142 +194,53 @@ jobs: src/Rack/dep/jansson-2.12 src/Rack/dep/libarchive-3.4.3 src/Rack/dep/libsamplerate-0.1.9 - src/Rack/dep/speexdsp-SpeexDSP-1.2rc3 src/Rack/dep/zstd-1.4.5 - key: macos-intel-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} - - name: Set up ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: ccache-macos-intel-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} - - name: Build extra dependencies + key: macos-${{ matrix.target }}-v${{ env.CACHE_VERSION }} + - name: Setup dependencies run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi - export PATH="/usr/local/opt/ccache/libexec:${PATH}" - ./deps/PawPaw/bootstrap-cardinal.sh macos && ./deps/PawPaw/.cleanup.sh macos - - name: Build macOS intel (base) + brew install autoconf automake meson + - name: Build extra dependencies run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi export PATH="/usr/local/opt/ccache/libexec:${PATH}" - pushd deps/PawPaw; source local.env macos; popd - make features - make CIBUILD=true NOOPT=true WITH_LTO=${{ env.WITH_LTO }} -j $(sysctl -n hw.logicalcpu) - - name: Build macOS intel (AU using juce) - env: - MACOSX_DEPLOYMENT_TARGET: '10.8' - run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi - pushd deps/PawPaw; source local.env macos; popd - git clone --depth=1 -b 6.1.6 https://github.com/juce-framework/JUCE.git jucewrapper/JUCE - sed -i -e 's/kAudioUnitProperty_SupportsMPE/kAudioUnitProperty_ignore_SupportsMPE/' jucewrapper/JUCE/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h - mkdir -p jucewrapper/build - pushd jucewrapper/build; cmake -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_OSX_DEPLOYMENT_TARGET=10.8 -DCMAKE_OSX_SYSROOT="macosx" -DCMAKE_BUILD_TYPE=Release .. && make VERBOSE=1 -j $(sysctl -n hw.logicalcpu); popd - mv jucewrapper/build/*_artefacts/Release/AU/*.component bin/ - - name: Build macOS intel (packaging) - env: - MACOS_ARCHS: 'x86_64' - run: | - pushd deps/PawPaw; source local.env macos; popd - ./utils/create-macos-installer.sh - - name: Set sha8 (non-release) - if: startsWith(github.ref, 'refs/tags/') != true - id: slug1 - run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" - - name: Set sha8 (release) - if: startsWith(github.ref, 'refs/tags/') - id: slug2 - run: echo "::set-output name=sha8::$(echo ${{ github.ref_name }})" - - name: Set sha8 - id: slug - run: echo "::set-output name=sha8::$(echo ${{ steps.slug1.outputs.sha8 || steps.slug2.outputs.sha8 }})" - - name: Rename macOS bundle - run: | - mv ${{ github.event.repository.name }}-macOS.pkg ${{ github.event.repository.name }}-macOS-intel-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}.pkg - - uses: actions/upload-artifact@v2 - with: - name: ${{ github.event.repository.name }}-macOS-intel-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} - path: | - ${{ github.event.repository.name }}-*.pkg - - uses: softprops/action-gh-release@v1 - if: startsWith(github.ref, 'refs/tags/') - with: - tag_name: ${{ github.ref_name }} - name: ${{ github.ref_name }} - draft: false - prerelease: false - files: | - ${{ github.event.repository.name }}-*.pkg - - macos-universal: - runs-on: macos-11 - steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - - name: Set up cache - id: cache - uses: actions/cache@v2 - with: - path: | - ~/PawPawBuilds - src/Rack/dep/bin - src/Rack/dep/include - src/Rack/dep/lib - src/Rack/dep/share - src/Rack/dep/jansson-2.12 - src/Rack/dep/libarchive-3.4.3 - src/Rack/dep/libsamplerate-0.1.9 - src/Rack/dep/speexdsp-SpeexDSP-1.2rc3 - src/Rack/dep/zstd-1.4.5 - key: macos-universal-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} + ./deps/PawPaw/bootstrap-cardinal.sh macos-${{ matrix.target }} && ./deps/PawPaw/.cleanup.sh macos-${{ matrix.target }} - name: Set up ccache + if: steps.cache.outputs.cache-hit == 'true' uses: hendrikmuhs/ccache-action@v1.2 with: - key: ccache-macos-universal-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} - - name: Build extra dependencies - run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi - export PATH="/usr/local/opt/ccache/libexec:${PATH}" - ./deps/PawPaw/bootstrap-cardinal.sh macos-universal && ./deps/PawPaw/.cleanup.sh macos-universal - - name: Build macOS universal (base) + key: ccache-macos-${{ matrix.target }}-v${{ env.CACHE_VERSION }} + - name: Build macOS (base) + if: steps.cache.outputs.cache-hit == 'true' run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi export PATH="/usr/local/opt/ccache/libexec:${PATH}" - pushd deps/PawPaw; source local.env macos-universal; popd + source deps/PawPaw/local.env macos-${{ matrix.target }} make features - make CIBUILD=true NOOPT=true WITH_LTO=${{ env.WITH_LTO }} -j $(sysctl -n hw.logicalcpu) - - name: Build macOS universal (AU using juce) - env: - MACOSX_DEPLOYMENT_TARGET: '10.12' + make NOOPT=true -j $(sysctl -n hw.logicalcpu) + - name: Build macOS (AU using juce) + if: steps.cache.outputs.cache-hit == 'true' run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi - pushd deps/PawPaw; source local.env macos-universal; popd - git clone --depth=1 -b 6.1.6 https://github.com/juce-framework/JUCE.git jucewrapper/JUCE + export PATH="/usr/local/opt/ccache/libexec:${PATH}" + source deps/PawPaw/local.env macos-${{ matrix.target }} mkdir -p jucewrapper/build - pushd jucewrapper/build; cmake -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' -DCMAKE_OSX_DEPLOYMENT_TARGET=10.12 -DCMAKE_OSX_SYSROOT="macosx" -DCMAKE_BUILD_TYPE=Release .. && make VERBOSE=1 -j $(sysctl -n hw.logicalcpu); popd + pushd jucewrapper/build; cmake -DCMAKE_BUILD_TYPE=Release .. && make VERBOSE=1 -j $(sysctl -n hw.logicalcpu); popd mv jucewrapper/build/*_artefacts/Release/AU/*.component bin/ - - name: Build macOS universal (packaging) - env: - MACOS_ARCHS: 'arm64,x86_64' + - name: Build macOS (packaging) + if: steps.cache.outputs.cache-hit == 'true' run: | - pushd deps/PawPaw; source local.env macos-universal; popd + source deps/PawPaw/local.env macos-${{ matrix.target }} ./utils/create-macos-installer.sh - name: Set sha8 (non-release) if: startsWith(github.ref, 'refs/tags/') != true - id: slug1 - run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" + run: echo "SHA8=$(echo ${{ github.sha }} | cut -c1-8)" >> $GITHUB_ENV - name: Set sha8 (release) if: startsWith(github.ref, 'refs/tags/') - id: slug2 - run: echo "::set-output name=sha8::$(echo ${{ github.ref_name }})" - - name: Set sha8 - id: slug - run: echo "::set-output name=sha8::$(echo ${{ steps.slug1.outputs.sha8 || steps.slug2.outputs.sha8 }})" + run: echo "SHA8=$(echo ${{ github.ref_name }})" >> $GITHUB_ENV - name: Rename macOS bundle + if: steps.cache.outputs.cache-hit == 'true' run: | - mv ${{ github.event.repository.name }}-macOS.pkg ${{ github.event.repository.name }}-macOS-universal-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}.pkg - - uses: actions/upload-artifact@v2 + mv ${{ github.event.repository.name }}-macOS.pkg ${{ github.event.repository.name }}-macOS-${{ matrix.target }}-${{ github.event.pull_request.number || env.SHA8 }}.pkg + - uses: actions/upload-artifact@v3 with: - name: ${{ github.event.repository.name }}-macOS-universal-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} + name: ${{ github.event.repository.name }}-macOS-${{ matrix.target }}-${{ github.event.pull_request.number || env.SHA8 }} path: | ${{ github.event.repository.name }}-*.pkg - uses: softprops/action-gh-release@v1 @@ -558,132 +253,71 @@ jobs: files: | ${{ github.event.repository.name }}-*.pkg - modduo: + modaudio: + strategy: + matrix: + include: + - name: modduo + target: modduo-static + extraflags: MODDUO=true + - name: modduox + target: modduox-static + - name: moddwarf + target: moddwarf runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - name: Set up cache - uses: actions/cache@v2 + uses: actions/cache@v3 id: mpb-cache with: path: | ~/mod-workdir - key: modduo-static-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} + key: ${{ matrix.target }}-v${{ env.CACHE_VERSION }} - name: Set up dependencies run: | sudo apt-get update -qq sudo apt-get install -yqq acl bc curl cvs git mercurial rsync subversion wget bison bzip2 flex gawk gperf gzip help2man nano perl patch tar texinfo unzip automake binutils build-essential cpio libtool libncurses-dev pkg-config python libtool-bin liblo-dev qemu-user-static sudo apt-get install -yqq pandoc texlive-latex-recommended texlive-latex-extra + sudo apt-get clean - name: Bootstrap toolchain if: steps.mpb-cache.outputs.cache-hit != 'true' run: | git clone --depth=1 https://github.com/moddevices/mod-plugin-builder.git deps/mod-plugin-builder sed -i "s/CT_LOG_PROGRESS_BAR=y/CT_LOG_PROGRESS_BAR=n/" deps/mod-plugin-builder/toolchain/*.config - $(pwd)/deps/mod-plugin-builder/bootstrap.sh modduo-static minimal && $(pwd)/deps/mod-plugin-builder/.clean-install.sh modduo-static - - name: Build for modduo + $(pwd)/deps/mod-plugin-builder/bootstrap.sh ${{ matrix.target }} minimal && $(pwd)/deps/mod-plugin-builder/.clean-install.sh ${{ matrix.target }} + - name: Build for modaudio + if: steps.mpb-cache.outputs.cache-hit == 'true' run: | - make modduo HEADLESS=true WITH_LTO=${{ env.WITH_LTO }} MODDUO=true -j $(nproc) + make HEADLESS=true ${{ matrix.name }}-features + make HEADLESS=true ${{ matrix.extraflags }} ${{ matrix.name }} -j $(nproc) - name: Set sha8 id: slug - run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" + run: echo "SHA8=$(echo ${{ github.sha }} | cut -c1-8)" >> $GITHUB_ENV - name: Pack binaries + if: steps.mpb-cache.outputs.cache-hit == 'true' run: | - tar -c -h --hard-dereference -z -f ${{ github.event.repository.name }}-modduo-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}.tar.gz -C bin $(ls bin | grep lv2) - - uses: actions/upload-artifact@v2 + tar -c -h --hard-dereference -z -f ${{ github.event.repository.name }}-${{ matrix.name }}-${{ github.event.pull_request.number || env.SHA8 }}.tar.gz -C bin $(ls bin | grep lv2) + - uses: actions/upload-artifact@v3 with: - name: ${{ github.event.repository.name }}-modduo-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} - path: | - *.tar.gz - - modduox: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - - name: Set up cache - uses: actions/cache@v2 - id: mpb-cache - with: - path: | - ~/mod-workdir - key: modduox-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} - - name: Set up dependencies - run: | - sudo apt-get update -qq - sudo apt-get install -yqq acl bc curl cvs git mercurial rsync subversion wget bison bzip2 flex gawk gperf gzip help2man nano perl patch tar texinfo unzip automake binutils build-essential cpio libtool libncurses-dev pkg-config python libtool-bin liblo-dev qemu-user-static - sudo apt-get install -yqq pandoc texlive-latex-recommended texlive-latex-extra - - name: Bootstrap toolchain - if: steps.mpb-cache.outputs.cache-hit != 'true' - run: | - git clone --depth=1 https://github.com/moddevices/mod-plugin-builder.git deps/mod-plugin-builder - sed -i "s/CT_LOG_PROGRESS_BAR=y/CT_LOG_PROGRESS_BAR=n/" deps/mod-plugin-builder/toolchain/*.config - $(pwd)/deps/mod-plugin-builder/bootstrap.sh modduox-static minimal && $(pwd)/deps/mod-plugin-builder/.clean-install.sh modduox-static - - name: Build for modduox - run: | - make modduox HEADLESS=true WITH_LTO=${{ env.WITH_LTO }} -j $(nproc) - - name: Set sha8 - id: slug - run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" - - name: Pack binaries - run: | - tar -c -h --hard-dereference -z -f ${{ github.event.repository.name }}-modduox-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}.tar.gz -C bin $(ls bin | grep lv2) - - uses: actions/upload-artifact@v2 - with: - name: ${{ github.event.repository.name }}-modduox-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} - path: | - *.tar.gz - - moddwarf: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - - name: Set up cache - uses: actions/cache@v2 - id: mpb-cache - with: - path: | - ~/mod-workdir - key: moddwarf-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} - - name: Set up dependencies - run: | - sudo apt-get update -qq - sudo apt-get install -yqq acl bc curl cvs git mercurial rsync subversion wget bison bzip2 flex gawk gperf gzip help2man nano perl patch tar texinfo unzip automake binutils build-essential cpio libtool libncurses-dev pkg-config python libtool-bin liblo-dev qemu-user-static - sudo apt-get install -yqq pandoc texlive-latex-recommended texlive-latex-extra - - name: Bootstrap toolchain - if: steps.mpb-cache.outputs.cache-hit != 'true' - run: | - git clone --depth=1 https://github.com/moddevices/mod-plugin-builder.git deps/mod-plugin-builder - sed -i "s/CT_LOG_PROGRESS_BAR=y/CT_LOG_PROGRESS_BAR=n/" deps/mod-plugin-builder/toolchain/*.config - $(pwd)/deps/mod-plugin-builder/bootstrap.sh moddwarf minimal && $(pwd)/deps/mod-plugin-builder/.clean-install.sh moddwarf - - name: Build for moddwarf - run: | - make moddwarf HEADLESS=true WITH_LTO=${{ env.WITH_LTO }} -j $(nproc) - - name: Set sha8 - id: slug - run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" - - name: Pack binaries - run: | - tar -c -h --hard-dereference -z -f ${{ github.event.repository.name }}-moddwarf-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}.tar.gz -C bin $(ls bin | grep lv2) - - uses: actions/upload-artifact@v2 - with: - name: ${{ github.event.repository.name }}-moddwarf-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} + name: ${{ github.event.repository.name }}-${{ matrix.name }}-${{ github.event.pull_request.number || env.SHA8 }} path: | *.tar.gz wasm: - runs-on: ubuntu-20.04 + strategy: + matrix: + target: [simd, nosimd] + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - name: Set up cache id: cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: | ~/PawPawBuilds @@ -694,107 +328,67 @@ jobs: src/Rack/dep/jansson-2.12 src/Rack/dep/libarchive-3.4.3 src/Rack/dep/libsamplerate-0.1.9 - src/Rack/dep/speexdsp-SpeexDSP-1.2rc3 src/Rack/dep/zstd-1.4.5 - key: wasm-v${{ env.CACHE_VERSION }} + key: wasm-${{ matrix.target }}-v${{ env.CACHE_VERSION }} - name: Set up dependencies run: | - [ -e ~/PawPawBuilds/emsdk ] || git clone https://github.com/emscripten-core/emsdk.git ~/PawPawBuilds/emsdk - cd ~/PawPawBuilds/emsdk && ./emsdk install latest && ./emsdk activate latest + sudo apt-get update -qq + sudo apt-get install -yqq brotli gperf meson + sudo apt-get clean + [ -e ~/PawPawBuilds/emsdk ] || git clone https://github.com/emscripten-core/emsdk.git ~/PawPawBuilds/emsdk + cd ~/PawPawBuilds/emsdk && ./emsdk install ${{ env.EMSCRIPTEN_VERSION }} && ./emsdk activate ${{ env.EMSCRIPTEN_VERSION }} - name: Build extra dependencies run: | + ${{ matrix.target == 'nosimd' }} && export PAWPAW_NOSIMD=1 source ~/PawPawBuilds/emsdk/emsdk_env.sh ./deps/PawPaw/bootstrap-cardinal.sh wasm && ./deps/PawPaw/.cleanup.sh wasm - name: Build wasm cross-compiled + if: steps.cache.outputs.cache-hit == 'true' run: | + ${{ matrix.target == 'nosimd' }} && export PAWPAW_NOSIMD=1 source ~/PawPawBuilds/emsdk/emsdk_env.sh - pushd deps/PawPaw; source local.env wasm; popd + source deps/PawPaw/local.env wasm + # FIXME send patch upstream, assuming this works.. + sed -i -e 's/defined(__riscv)/defined(__riscv) || defined(__EMSCRIPTEN__)/' plugins/surgext/surge/src/common/globals.h make features - make CIBUILD=true NOOPT=true USE_GLES2=true -j $(nproc) - - name: Set sha8 (non-release) - if: startsWith(github.ref, 'refs/tags/') != true - id: slug1 - run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" - - name: Set sha8 (release) - if: startsWith(github.ref, 'refs/tags/') - id: slug2 - run: echo "::set-output name=sha8::$(echo ${{ github.ref_name }})" - - name: Set sha8 - id: slug - run: echo "::set-output name=sha8::$(echo ${{ steps.slug1.outputs.sha8 || steps.slug2.outputs.sha8 }})" - - name: Pack binaries - run: | - cd bin; zip -r -9 ../${{ github.event.repository.name }}-wasm-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}.zip $(ls *.html *.data *.js *.wasm) - - uses: actions/upload-artifact@v2 - with: - name: ${{ github.event.repository.name }}-wasm-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} - path: | - *.zip - - uses: softprops/action-gh-release@v1 - if: startsWith(github.ref, 'refs/tags/') - with: - tag_name: ${{ github.ref_name }} - name: ${{ github.ref_name }} - draft: false - prerelease: false - files: | - *.zip - - wasm-mini: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - - name: Set up cache - id: cache - uses: actions/cache@v2 - with: - path: | - ~/emsdk - src/Rack/dep/bin - src/Rack/dep/include - src/Rack/dep/lib - src/Rack/dep/share - src/Rack/dep/jansson-2.12 - src/Rack/dep/libarchive-3.4.3 - src/Rack/dep/libsamplerate-0.1.9 - src/Rack/dep/speexdsp-SpeexDSP-1.2rc3 - src/Rack/dep/zstd-1.4.5 - key: wasm-mini-v${{ env.CACHE_VERSION }} - - name: Set up dependencies + make HAVE_LIBLO=false NOOPT=true NOSIMD=${{ matrix.target == 'nosimd' }} -j $(nproc) + - name: Build modgui + if: steps.cache.outputs.cache-hit == 'true' run: | - [ -e ~/emsdk ] || git clone https://github.com/emscripten-core/emsdk.git ~/emsdk - cd ~/emsdk && ./emsdk install latest && ./emsdk activate latest - - name: Build wasm-mini cross-compiled - env: - AR: emar - CC: emcc - CXX: em++ - NM: emnm - RANLIB: emranlib - STRIP: emstrip - run: | - source ~/emsdk/emsdk_env.sh - make features - make CIBUILD=true NOPLUGINS=true STATIC_BUILD=true USE_GLES2=true -j $(nproc) + ${{ matrix.target == 'nosimd' }} && export PAWPAW_NOSIMD=1 + source ~/PawPawBuilds/emsdk/emsdk_env.sh + source deps/PawPaw/local.env wasm + make HAVE_LIBLO=false NOOPT=true NOSIMD=${{ matrix.target == 'nosimd' }} -j $(nproc) -C src/CardinalMiniSep modgui + - name: Make wasm versioned and compress + if: steps.cache.outputs.cache-hit == 'true' + run: | + ${{ matrix.target == 'nosimd' }} && export SUFFIX="-nosimd" + VERSION=$(cat Makefile | awk 'sub("VERSION = ","")') + cd bin + sed -i "s/CardinalMini\./CardinalMini-v${VERSION}\./g" *.html *.js + sed -i "s/CardinalNative\./CardinalNative-v${VERSION}\./g" *.html *.js + sed -i "s/CardinalMini-nosimd\./CardinalMini-nosimd-v${VERSION}\./g" *.html *.js + sed -i "s/CardinalNative-nosimd\./CardinalNative-nosimd-v${VERSION}\./g" *.html *.js + mv CardinalMini.data CardinalMini${SUFFIX}-v${VERSION}.data + mv CardinalMini.js CardinalMini${SUFFIX}-v${VERSION}.js + mv CardinalMini.wasm CardinalMini${SUFFIX}-v${VERSION}.wasm + mv CardinalNative.data CardinalNative${SUFFIX}-v${VERSION}.data + mv CardinalNative.js CardinalNative${SUFFIX}-v${VERSION}.js + mv CardinalNative.wasm CardinalNative${SUFFIX}-v${VERSION}.wasm + brotli -k -q 11 *.data *.html *.js *.wasm - name: Set sha8 (non-release) if: startsWith(github.ref, 'refs/tags/') != true - id: slug1 - run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" + run: echo "SHA8=$(echo ${{ github.sha }} | cut -c1-8)" >> $GITHUB_ENV - name: Set sha8 (release) if: startsWith(github.ref, 'refs/tags/') - id: slug2 - run: echo "::set-output name=sha8::$(echo ${{ github.ref_name }})" - - name: Set sha8 - id: slug - run: echo "::set-output name=sha8::$(echo ${{ steps.slug1.outputs.sha8 || steps.slug2.outputs.sha8 }})" + run: echo "SHA8=$(echo ${{ github.ref_name }})" >> $GITHUB_ENV - name: Pack binaries + if: steps.cache.outputs.cache-hit == 'true' run: | - cd bin; zip -r -9 ../${{ github.event.repository.name }}-wasm-mini-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}.zip $(ls *.html *.data *.js *.wasm) - - uses: actions/upload-artifact@v2 + cd bin; zip -r -9 ../${{ github.event.repository.name }}-wasm-${{ matrix.target }}-${{ github.event.pull_request.number || env.SHA8 }}.zip $(ls *.br *.html *.data *.js *.wasm) CardinalMini.lv2/modgui + - uses: actions/upload-artifact@v3 with: - name: ${{ github.event.repository.name }}-wasm-mini-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} + name: ${{ github.event.repository.name }}-wasm-${{ matrix.target }}-${{ github.event.pull_request.number || env.SHA8 }} path: | *.zip - uses: softprops/action-gh-release@v1 @@ -807,15 +401,18 @@ jobs: files: | *.zip - win32: - runs-on: ubuntu-20.04 + windows: + strategy: + matrix: + target: [win32, win64] + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - name: Set up cache id: cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: | ~/PawPawBuilds @@ -826,68 +423,72 @@ jobs: src/Rack/dep/jansson-2.12 src/Rack/dep/libarchive-3.4.3 src/Rack/dep/libsamplerate-0.1.9 - src/Rack/dep/speexdsp-SpeexDSP-1.2rc3 src/Rack/dep/zstd-1.4.5 - key: win32-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} + key: ${{ matrix.target }}-v${{ env.CACHE_VERSION }} - name: Fix GitHub's mess run: | sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo dpkg --add-architecture i386 sudo apt-get update -qq - sudo apt-get install -yqq --allow-downgrades libgd3/focal libpcre2-8-0/focal libpcre2-16-0/focal libpcre2-32-0/focal libpcre2-posix2/focal - sudo apt-get purge -yqq libmono* moby* mono* php* libgdiplus libpcre2-posix3 libzip4 + sudo apt-get install -yqq --allow-downgrades libc6:i386 libgcc-s1:i386 libstdc++6:i386 + sudo apt-get clean - name: Set up dependencies + if: ${{ matrix.target == 'win32' }} run: | - sudo dpkg --add-architecture i386 - sudo apt-get update -qq - sudo apt-get install -yqq binutils-mingw-w64-i686 g++-mingw-w64-i686 mingw-w64 wine-stable:i386 qttools5-dev qttools5-dev-tools xvfb + sudo apt-get install -yqq binutils-mingw-w64-i686 g++-mingw-w64-i686 mingw-w64 wine-stable:i386 gperf meson qttools5-dev qttools5-dev-tools xvfb + sudo apt-get clean + - name: Set up dependencies + if: ${{ matrix.target == 'win64' }} + run: | + sudo apt-get install -yqq binutils-mingw-w64-x86-64 g++-mingw-w64-x86-64 mingw-w64 wine-stable gperf meson qttools5-dev qttools5-dev-tools xvfb + sudo apt-get clean - name: Set up ccache uses: hendrikmuhs/ccache-action@v1.2 with: - key: ccache-win32-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} + key: ccache-${{ matrix.target }}-v${{ env.CACHE_VERSION }} - name: Build extra dependencies run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi - export PATH="/usr/lib/ccache:${PATH}" - ./deps/PawPaw/bootstrap-cardinal.sh win32 && ./deps/PawPaw/.cleanup.sh win32 - - name: Build win32 cross-compiled (base) + ./deps/PawPaw/bootstrap-cardinal.sh ${{ matrix.target }} && ./deps/PawPaw/.cleanup.sh ${{ matrix.target }} + - name: Build cross-compiled (base) + if: steps.cache.outputs.cache-hit == 'true' run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi export PATH="/usr/lib/ccache:${PATH}" - pushd deps/PawPaw; source local.env win32; popd + source deps/PawPaw/local.env ${{ matrix.target }} make features - make CIBUILD=true NOOPT=true WITH_LTO=${{ env.WITH_LTO }} -j $(nproc) - - name: Build win64 cross-compiled (carla) + make NOOPT=true -j $(nproc) + - name: Build cross-compiled (carla) + if: steps.cache.outputs.cache-hit == 'true' run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi export PATH="/usr/lib/ccache:${PATH}" - pushd deps/PawPaw; source local.env win32; popd - make -C carla CARLA_BACKEND_NAMESPACE=Cardinal EXTERNAL_PLUGINS=true HAVE_FLUIDSYNTH=false HAVE_ZYN_DEPS=false HAVE_ZYN_UI_DEPS=false HAVE_PYQT=true HAVE_QT5=true HAVE_QT5PKG=true STATIC_PLUGIN_TARGET=true USING_CUSTOM_DPF=true CUSTOM_DPF_PATH=$(pwd)/dpf -j $(nproc) + source deps/PawPaw/local.env ${{ matrix.target }} + make carla-win32 -j $(nproc) make -C carla EMBED_TARGET=true TESTING=true dist make -C carla EMBED_TARGET=true TESTING=true dist - - name: Build win64 cross-compiled (packaging) + - name: Build cross-compiled (packaging) + if: steps.cache.outputs.cache-hit == 'true' run: | - pushd deps/PawPaw; source local.env win32; popd - xvfb-run ./utils/create-windows-installer.sh 32 + source deps/PawPaw/local.env ${{ matrix.target }} + xvfb-run ./utils/create-windows-installer.sh ${{ matrix.target }} + make unzipfx - name: Set sha8 (non-release) if: startsWith(github.ref, 'refs/tags/') != true - id: slug1 - run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" + run: echo "SHA8=$(echo ${{ github.sha }} | cut -c1-8)" >> $GITHUB_ENV - name: Set sha8 (release) if: startsWith(github.ref, 'refs/tags/') - id: slug2 - run: echo "::set-output name=sha8::$(echo ${{ github.ref_name }})" - - name: Set sha8 - id: slug - run: echo "::set-output name=sha8::$(echo ${{ steps.slug1.outputs.sha8 || steps.slug2.outputs.sha8 }})" + run: echo "SHA8=$(echo ${{ github.ref_name }})" >> $GITHUB_ENV - name: Pack binaries + if: steps.cache.outputs.cache-hit == 'true' run: | - cd bin; zip -r -9 ../${{ github.event.repository.name }}-win32-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}.zip $(ls | grep -e lv2 -e vst) - - uses: actions/upload-artifact@v2 + pushd bin + zip -r -9 ../${{ github.event.repository.name }}-${{ matrix.target }}-${{ github.event.pull_request.number || env.SHA8 }}.zip $(ls | grep -e lv2 -e vst -e clap) + popd + zip -u -9 ${{ github.event.repository.name }}-${{ matrix.target }}-${{ github.event.pull_request.number || env.SHA8 }}.zip LICENSE README.md docs/*.* CardinalJACK.exe CardinalNative.exe + - uses: actions/upload-artifact@v3 with: - name: ${{ github.event.repository.name }}-win32-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} + name: ${{ github.event.repository.name }}-${{ matrix.target }}-${{ github.event.pull_request.number || env.SHA8 }} path: | - *.exe - *.zip + Cardinal-*.exe + Cardinal-*.zip - uses: softprops/action-gh-release@v1 if: startsWith(github.ref, 'refs/tags/') with: @@ -896,129 +497,82 @@ jobs: draft: false prerelease: false files: | - *.exe - *.zip + Cardinal-*.exe + Cardinal-*.zip - win64: + headless: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - - name: Set up cache - id: cache - uses: actions/cache@v2 - with: - path: | - ~/PawPawBuilds - src/Rack/dep/bin - src/Rack/dep/include - src/Rack/dep/lib - src/Rack/dep/share - src/Rack/dep/jansson-2.12 - src/Rack/dep/libarchive-3.4.3 - src/Rack/dep/libsamplerate-0.1.9 - src/Rack/dep/speexdsp-SpeexDSP-1.2rc3 - src/Rack/dep/zstd-1.4.5 - key: win64-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} - - name: Fix GitHub's mess - run: | - sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list - sudo apt-get update -qq - sudo apt-get install -yqq --allow-downgrades libgd3/focal libpcre2-8-0/focal libpcre2-16-0/focal libpcre2-32-0/focal libpcre2-posix2/focal - sudo apt-get purge -yqq libmono* moby* mono* php* libgdiplus libpcre2-posix3 libzip4 - name: Set up dependencies run: | - sudo dpkg --add-architecture i386 sudo apt-get update -qq - sudo apt-get install -yqq binutils-mingw-w64-x86-64 g++-mingw-w64-x86-64 mingw-w64 wine-stable qttools5-dev qttools5-dev-tools xvfb - - name: Set up ccache - uses: hendrikmuhs/ccache-action@v1.2 + sudo apt-get remove -yqq libcairo2-dev libx11-dev libx11-dev libxext-dev + sudo apt-get install -yqq liblo-dev + sudo apt-get clean + - name: Build linux (headless) + run: | + make HEADLESS=true features + make HEADLESS=true -j $(nproc) + + lto: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 with: - key: ccache-win64-v${{ env.CACHE_VERSION }}-${{ env.WITH_LTO }} - - name: Build extra dependencies + submodules: recursive + - name: Set up dependencies run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi - export PATH="/usr/lib/ccache:${PATH}" - ./deps/PawPaw/bootstrap-cardinal.sh win64 && ./deps/PawPaw/.cleanup.sh win64 - - name: Build win64 cross-compiled (base) + sudo apt-get update -qq + sudo apt-get install -yqq libasound2-dev libdbus-1-dev libgl1-mesa-dev liblo-dev libsdl2-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev + sudo apt-get clean + - name: Build linux (LTO) run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi - export PATH="/usr/lib/ccache:${PATH}" - pushd deps/PawPaw; source local.env win64; popd make features - make CIBUILD=true NOOPT=true WITH_LTO=${{ env.WITH_LTO }} -j $(nproc) - - name: Build win64 cross-compiled (carla) - run: | - if [ "${{ env.WITH_LTO }}" != "true" ]; then export PAWPAW_SKIP_LTO=1; fi - export PATH="/usr/lib/ccache:${PATH}" - pushd deps/PawPaw; source local.env win64; popd - make -C carla CARLA_BACKEND_NAMESPACE=Cardinal EXTERNAL_PLUGINS=true HAVE_FLUIDSYNTH=false HAVE_ZYN_DEPS=false HAVE_ZYN_UI_DEPS=false HAVE_PYQT=true HAVE_QT5=true HAVE_QT5PKG=true STATIC_PLUGIN_TARGET=true USING_CUSTOM_DPF=true CUSTOM_DPF_PATH=$(pwd)/dpf all win32r -j $(nproc) - make -C carla EMBED_TARGET=true TESTING=true dist - make -C carla EMBED_TARGET=true TESTING=true dist - - name: Build win64 cross-compiled (packaging) + make WITH_LTO=true -j $(nproc) native + + sysdeps: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - name: Set up dependencies run: | - pushd deps/PawPaw; source local.env win64; popd - xvfb-run ./utils/create-windows-installer.sh 64 - - name: Set sha8 (non-release) - if: startsWith(github.ref, 'refs/tags/') != true - id: slug1 - run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" - - name: Set sha8 (release) - if: startsWith(github.ref, 'refs/tags/') - id: slug2 - run: echo "::set-output name=sha8::$(echo ${{ github.ref_name }})" - - name: Set sha8 - id: slug - run: echo "::set-output name=sha8::$(echo ${{ steps.slug1.outputs.sha8 || steps.slug2.outputs.sha8 }})" - - name: Pack binaries + sudo apt-get update -qq + sudo apt-get install -yqq libdbus-1-dev libgl1-mesa-dev liblo-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev libarchive-dev libfftw3-dev libjansson-dev libsamplerate0-dev libsndfile1-dev libspeexdsp-dev + sudo apt-get clean + - name: Build linux (sysdeps) run: | - cd bin; zip -r -9 ../${{ github.event.repository.name }}-win64-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}.zip $(ls | grep -e lv2 -e vst) - - uses: actions/upload-artifact@v2 - with: - name: ${{ github.event.repository.name }}-win64-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} - path: | - *.exe - *.zip - - uses: softprops/action-gh-release@v1 - if: startsWith(github.ref, 'refs/tags/') - with: - tag_name: ${{ github.ref_name }} - name: ${{ github.ref_name }} - draft: false - prerelease: false - files: | - *.exe - *.zip + make features + make SYSDEPS=true -j $(nproc) source-tarball: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - name: Set up dependencies run: | sudo apt-get update -qq sudo apt-get install -yqq liblo-dev + sudo apt-get clean - name: Create source tarball run: | make HEADLESS=true tarball make HEADLESS=true tarball+deps - name: Set sha8 (non-release) if: startsWith(github.ref, 'refs/tags/') != true - id: slug1 - run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" + run: echo "SHA8=$(echo ${{ github.sha }} | cut -c1-8)" >> $GITHUB_ENV - name: Set sha8 (release) if: startsWith(github.ref, 'refs/tags/') - id: slug2 - run: echo "::set-output name=sha8::$(echo ${{ github.ref_name }})" - - name: Set sha8 - id: slug - run: echo "::set-output name=sha8::$(echo ${{ steps.slug1.outputs.sha8 || steps.slug2.outputs.sha8 }})" - - uses: actions/upload-artifact@v2 + run: echo "SHA8=$(echo ${{ github.ref_name }})" >> $GITHUB_ENV + - uses: actions/upload-artifact@v3 with: - name: ${{ github.event.repository.name }}-source-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} + name: ${{ github.event.repository.name }}-source-${{ github.event.pull_request.number || env.SHA8 }} path: | /home/runner/cardinal*.tar.xz /home/runner/*/cardinal*.tar.xz @@ -1038,12 +592,12 @@ jobs: plugin-validation: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - name: Set up cache id: cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: | src/Rack/dep/bin @@ -1053,7 +607,6 @@ jobs: src/Rack/dep/jansson-2.12 src/Rack/dep/libarchive-3.4.3 src/Rack/dep/libsamplerate-0.1.9 - src/Rack/dep/speexdsp-SpeexDSP-1.2rc3 src/Rack/dep/zstd-1.4.5 key: pluginval-v${{ env.CACHE_VERSION }} - name: Set up dependencies @@ -1066,19 +619,27 @@ jobs: sudo apt-get install -yqq libdbus-1-dev libgl1-mesa-dev liblo-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev # runtime testing sudo apt-get install -yqq carla-git lilv-utils lv2-dev lv2lint kxstudio-lv2-extensions mod-lv2-extensions valgrind xvfb - - name: Set up ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: ccache-pluginval-v${{ env.CACHE_VERSION }} - - name: Build Cardinal + sudo apt-get clean + # multiple jobs for building carla, deps and plugins + - name: Build Cardinal (carla, deps and plugins) env: CFLAGS: -g - CXXFLAGS: -g -DDPF_ABORT_ON_ERROR -DDPF_RUNTIME_TESTING + CXXFLAGS: -g -DDPF_ABORT_ON_ERROR -DDPF_RUNTIME_TESTING -Wno-pmf-conversions LDFLAGS: -static-libgcc -static-libstdc++ run: | - export PATH="/usr/lib/ccache:${PATH}" make features - make NOOPT=true SKIP_STRIPPING=true -j $(nproc) + make NOOPT=true SKIP_STRIPPING=true carla deps dgl plugins resources -j $(nproc) + # single job for final build stage, otherwise we might get killed due to OOM + - name: Build Cardinal (final build stage) + env: + CFLAGS: -g + CXXFLAGS: -g -DDPF_ABORT_ON_ERROR -DDPF_RUNTIME_TESTING -Wno-pmf-conversions + LDFLAGS: -static-libgcc -static-libstdc++ + run: | + make features + make NOOPT=true SKIP_STRIPPING=true -j 1 -C src jack + make NOOPT=true -j 1 + ./dpf/utils/generate-ttl.sh - name: Run Cardinal self-tests run: | # --exit-on-first-error=yes @@ -1087,23 +648,24 @@ jobs: --error-exitcode=255 \ --leak-check=no \ --track-origins=yes \ + --keep-debuginfo=yes \ --suppressions=./dpf/utils/valgrind-dpf.supp \ ./bin/Cardinal selftest - name: Validate LV2 ttl syntax run: | lv2_validate \ - /usr/lib/lv2/mod.lv2/*.ttl \ /usr/lib/lv2/kx-meta/*.ttl \ /usr/lib/lv2/kx-control-input-port-change-request.lv2/*.ttl \ /usr/lib/lv2/kx-programs.lv2/*.ttl \ + /usr/lib/lv2/mod.lv2/*.ttl \ + /usr/lib/lv2/modgui.lv2/*.ttl \ ./bin/*.lv2/*.ttl - name: Validate LV2 metadata and binaries run: | export LV2_PATH=/tmp/lv2-path mkdir ${LV2_PATH} - cp -r bin/CardinalFX.lv2 bin/CardinalSynth.lv2 \ - /usr/lib/lv2/{atom,buf-size,core,data-access,kx-control-input-port-change-request,kx-programs,instance-access,midi,mod,parameters,port-groups,port-props,options,patch,presets,resize-port,state,time,ui,units,urid,worker}.lv2 \ - ${LV2_PATH} + mv bin/CardinalFX.lv2 bin/CardinalSynth.lv2 ${LV2_PATH} + cp -r /usr/lib/lv2/{atom,buf-size,core,data-access,kx-control-input-port-change-request,kx-programs,instance-access,midi,mod,modgui,parameters,port-groups,port-props,options,patch,presets,resize-port,state,time,ui,units,urid,worker}.lv2 ${LV2_PATH} xvfb-run lv2lint -s lv2_generate_ttl -l ld-linux-x86-64.so.2 -M nopack $(lv2ls) - name: Test LV2 plugin run: | @@ -1114,8 +676,9 @@ jobs: --error-exitcode=255 \ --leak-check=no \ --track-origins=yes \ + --keep-debuginfo=yes \ --suppressions=./dpf/utils/valgrind-dpf.supp \ - /usr/lib/carla/carla-bridge-native lv2 "" ${p} 1>/dev/null; \ + /usr/lib/carla/carla-bridge-native lv2 "" ${p}; \ done - name: Test VST2 plugin run: | @@ -1125,8 +688,9 @@ jobs: --error-exitcode=255 \ --leak-check=no \ --track-origins=yes \ + --keep-debuginfo=yes \ --suppressions=./dpf/utils/valgrind-dpf.supp \ - /usr/lib/carla/carla-bridge-native vst2 ./${p} "" 1>/dev/null; \ + /usr/lib/carla/carla-bridge-native vst2 ./${p} ""; \ done - name: Test VST3 plugin run: | @@ -1136,6 +700,7 @@ jobs: --error-exitcode=255 \ --leak-check=no \ --track-origins=yes \ + --keep-debuginfo=yes \ --suppressions=./dpf/utils/valgrind-dpf.supp \ - /usr/lib/carla/carla-bridge-native vst3 ./bin/${p} "" 1>/dev/null; \ + /usr/lib/carla/carla-bridge-native vst3 ./bin/${p} ""; \ done diff --git a/.github/workflows/irc.yml b/.github/workflows/irc.yml index 108c326b..3be06fea 100644 --- a/.github/workflows/irc.yml +++ b/.github/workflows/irc.yml @@ -1,6 +1,6 @@ name: irc -on: [push] +on: [push, pull_request] jobs: notification: @@ -8,13 +8,14 @@ jobs: name: IRC notification steps: - name: Format message - id: message run: | - message="${{ github.actor }} pushed $(echo '${{ github.event.commits[0].message }}' | head -n 1) ${{ github.event.commits[0].url }}" - echo ::set-output name=message::"${message}" + echo commitmessage=$(echo "${{ github.event.commits[0].message }}" | head -n 1) >> $GITHUB_ENV + - name: Format message + run: | + echo message="${{ github.actor }} pushed ${{ env.commitmessage }} ${{ github.event.commits[0].url }}" >> $GITHUB_ENV - name: IRC notification uses: Gottox/irc-message-action@v2 with: channel: '#cardinal' nickname: github-event-bot - message: ${{ steps.message.outputs.message }} + message: ${{ env.message }} diff --git a/.gitignore b/.gitignore index 4b7839a5..d30193b6 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,8 @@ compile_commands.json /bin/ /build/ +/build-headless/ +/deps/surge-build/ /documentation.pdf /jucewrapper/build/ /jucewrapper/JUCE/ diff --git a/.gitmodules b/.gitmodules index 6dc1aa03..7c83b4c4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,12 +4,6 @@ [submodule "dpf"] path = dpf url = https://github.com/DISTRHO/DPF.git -[submodule "plugins/Cardinal/mingw-std-threads"] - path = include/mingw-std-threads - url = https://github.com/meganz/mingw-std-threads.git -[submodule "plugins/Cardinal/sse2neon"] - path = include/sse2neon - url = https://github.com/DLTcollab/sse2neon.git [submodule "plugins/Befaco"] path = plugins/Befaco url = https://github.com/VCVRack/Befaco.git @@ -209,6 +203,36 @@ [submodule "plugins/myth-modules"] path = plugins/myth-modules url = https://github.com/Ahineya/vcv-myth-plugin.git +[submodule "plugins/alefsbits"] + path = plugins/alefsbits + url = https://github.com/alefnull/alefsbits.git +[submodule "plugins/h4n4-modules"] + path = plugins/h4n4-modules + url = https://github.com/hannakoppelaar/h4n4-modules.git +[submodule "plugins/dBiz"] + path = plugins/dBiz + url = https://github.com/dBiz/dBiz.git +[submodule "include/simde"] + path = include/simde + url = https://github.com/simd-everywhere/simde.git +[submodule "plugins/RebelTech"] + path = plugins/RebelTech + url = https://github.com/hemmer/rebel-tech-vcv.git +[submodule "plugins/stoermelder-packone"] + path = plugins/stoermelder-packone + url = https://github.com/stoermelder/vcvrack-packone.git +[submodule "plugins/surgext"] + path = plugins/surgext + url = https://github.com/surge-synthesizer/surge-rack.git +[submodule "plugins/Sapphire"] + path = plugins/Sapphire + url = https://github.com/cosinekitty/sapphire.git +[submodule "plugins/Cardinal/src/AIDA-X/RTNeural"] + path = plugins/Cardinal/src/AIDA-X/RTNeural + url = https://github.com/jatinchowdhury18/RTNeural.git +[submodule "plugins/EnigmaCurry"] + path = plugins/EnigmaCurry + url = https://github.com/EnigmaCurry/EnigmaCurry-vcv-pack.git [submodule "plugins/StarlingVia"] path = plugins/StarlingVia url = https://github.com/starlingcode/Via-for-Rack.git diff --git a/Makefile b/Makefile index b2b722f5..e2c3a6ba 100644 --- a/Makefile +++ b/Makefile @@ -4,16 +4,19 @@ # Created by falkTX # +ROOT = . +include $(ROOT)/Makefile.base.mk + +# ----------------------------------------------------------------------------- +# Set version + # also set in: -# jucewrapper/CMakeList.txt `project` +# jucewrapper/CMakeLists.txt `project` # src/CardinalCommon.cpp `CARDINAL_VERSION` # src/CardinalPlugin.cpp `getVersion` -VERSION = 22.09 - -# -------------------------------------------------------------- -# Import base definitions - -include dpf/Makefile.base.mk +# utils/macOS/Info_{JACK,Native}.plist +# jucewrapper/CMakeLists.txt src/CardinalCommon.cpp src/CardinalPlugin.cpp utils/macOS/Info_{JACK,Native}.plist +VERSION = 23.10 # -------------------------------------------------------------- # Build targets @@ -26,20 +29,6 @@ all: cardinal carla deps dgl plugins gen resources PREFIX ?= /usr/local DESTDIR ?= -ifeq ($(BSD),true) -SYSDEPS ?= true -else -SYSDEPS ?= false -endif - -ifeq ($(LINUX),true) -VST3_SUPPORTED = true -else ifeq ($(MACOS),true) -VST3_SUPPORTED = true -else ifeq ($(WINDOWS),true) -VST3_SUPPORTED = true -endif - # -------------------------------------------------------------- # Carla config @@ -56,32 +45,21 @@ ifneq ($(DEBUG),true) CARLA_EXTRA_ARGS += EXTERNAL_PLUGINS=true endif -# -------------------------------------------------------------- -# DGL config - -DGL_EXTRA_ARGS = \ - DISTRHO_NAMESPACE=CardinalDISTRHO \ - DGL_NAMESPACE=CardinalDGL \ - NVG_DISABLE_SKIPPING_WHITESPACE=true \ - NVG_FONT_TEXTURE_FLAGS=NVG_IMAGE_NEAREST \ - USE_NANOVG_FBO=true \ - WINDOWS_ICON_ID=401 - # -------------------------------------------------------------- # Check for required system-wide dependencies ifeq ($(SYSDEPS),true) -ifneq ($(shell pkg-config --exists jansson && echo true),true) +ifneq ($(shell $(PKG_CONFIG) --exists jansson && echo true),true) $(error jansson dependency not installed/available) endif -ifneq ($(shell pkg-config --exists libarchive && echo true),true) +ifneq ($(shell $(PKG_CONFIG) --exists libarchive && echo true),true) $(error libarchive dependency not installed/available) endif -ifneq ($(shell pkg-config --exists samplerate && echo true),true) +ifneq ($(shell $(PKG_CONFIG) --exists samplerate && echo true),true) $(error samplerate dependency not installed/available) endif -ifneq ($(shell pkg-config --exists speexdsp && echo true),true) +ifneq ($(shell $(PKG_CONFIG) --exists speexdsp && echo true),true) $(error speexdsp dependency not installed/available) endif @@ -89,7 +67,7 @@ endif ifeq ($(HEADLESS),true) -ifneq ($(shell pkg-config --exists liblo && echo true),true) +ifneq ($(shell $(PKG_CONFIG) --exists liblo && echo true),true) $(error liblo dependency not installed/available) endif @@ -119,6 +97,8 @@ endif else +CARLA_EXTRA_ARGS += HAVE_DBUS=false +CARLA_EXTRA_ARGS += HAVE_DGL=false CARLA_EXTRA_ARGS += HAVE_OPENGL=false CARLA_EXTRA_ARGS += HAVE_X11=false CARLA_EXTRA_ARGS += HAVE_XCURSOR=false @@ -140,8 +120,7 @@ endif # -------------------------------------------------------------- # MOD builds -EXTRA_MOD_FLAGS = -I../include/single-precision -fsingle-precision-constant - +EXTRA_MOD_FLAGS = -I../include/single-precision -fsingle-precision-constant -Wno-attributes ifeq ($(MODDUO),true) EXTRA_MOD_FLAGS += -mno-unaligned-access endif @@ -149,51 +128,9 @@ ifeq ($(WITH_LTO),true) EXTRA_MOD_FLAGS += -ffat-lto-objects endif -MOD_WORKDIR ?= $(HOME)/mod-workdir -MOD_ENVIRONMENT = \ - AR=${1}/host/usr/bin/${2}-gcc-ar \ - CC=${1}/host/usr/bin/${2}-gcc \ - CPP=${1}/host/usr/bin/${2}-cpp \ - CXX=${1}/host/usr/bin/${2}-g++ \ - LD=${1}/host/usr/bin/${2}-ld \ - PKG_CONFIG=${1}/host/usr/bin/pkg-config \ - STRIP=${1}/host/usr/bin/${2}-strip \ - CFLAGS="-I${1}/staging/usr/include $(EXTRA_MOD_FLAGS)" \ - CPPFLAGS= \ - CXXFLAGS="-I${1}/staging/usr/include $(EXTRA_MOD_FLAGS) -Wno-attributes" \ - LDFLAGS="-L${1}/staging/usr/lib $(EXTRA_MOD_FLAGS)" \ - EXE_WRAPPER="qemu-${3}-static -L ${1}/target" \ - HEADLESS=true \ - MOD_BUILD=true \ - NOOPT=true \ - STATIC_BUILD=true - -modduo: - $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduo-static,arm-mod-linux-gnueabihf.static,arm) - -modduox: - $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduox-static,aarch64-mod-linux-gnueabi.static,aarch64) - -moddwarf: - $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/moddwarf,aarch64-mod-linux-gnu,aarch64) - -publish: - tar -C bin -cz $(subst bin/,,$(wildcard bin/*.lv2)) | base64 | curl -F 'package=@-' http://192.168.51.1/sdk/install && echo - -ifneq (,$(findstring modduo-,$(MAKECMDGOALS))) -$(MAKECMDGOALS): - $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduo-static,arm-mod-linux-gnueabihf.static,arm) $(subst modduo-,,$(MAKECMDGOALS)) -endif - -ifneq (,$(findstring modduox-,$(MAKECMDGOALS))) -$(MAKECMDGOALS): - $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduox-static,aarch64-mod-linux-gnueabi.static,aarch64) $(subst modduox-,,$(MAKECMDGOALS)) -endif - -ifneq (,$(findstring moddwarf-,$(MAKECMDGOALS))) -$(MAKECMDGOALS): - $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/moddwarf,aarch64-mod-linux-gnu,aarch64) $(subst moddwarf-,,$(MAKECMDGOALS)) -endif +MOD_ENVIRONMENT += HEADLESS=true +MOD_ENVIRONMENT += MOD_BUILD=true +MOD_ENVIRONMENT += STATIC_BUILD=true # -------------------------------------------------------------- # Individual targets @@ -210,9 +147,35 @@ ifneq ($(STATIC_BUILD),true) USING_CUSTOM_DPF=true endif +carla-win32: +ifneq ($(STATIC_BUILD),true) + $(MAKE) all -C carla $(CARLA_EXTRA_ARGS) \ + CAN_GENERATE_LV2_TTL=false \ + CUSTOM_DPF_PATH=$(CURDIR)/dpf \ + DGL_NAMESPACE=CardinalDGL \ + HAVE_FRONTEND=true \ + HAVE_PYQT=true \ + HAVE_QT5=true \ + HAVE_QT5PKG=true \ + STATIC_PLUGIN_TARGET=true \ + USING_CUSTOM_DPF=true +ifeq ($(CPU_X86_64),true) + $(MAKE) win32r -C carla $(CARLA_EXTRA_ARGS) \ + CAN_GENERATE_LV2_TTL=false \ + CUSTOM_DPF_PATH=$(CURDIR)/dpf \ + DGL_NAMESPACE=CardinalDGL \ + HAVE_FRONTEND=true \ + HAVE_PYQT=true \ + HAVE_QT5=true \ + HAVE_QT5PKG=true \ + STATIC_PLUGIN_TARGET=true \ + USING_CUSTOM_DPF=true +endif +endif + deps: ifeq ($(SYSDEPS),true) - $(MAKE) quickjs -C deps + $(MAKE) quickjs surge -C deps else $(MAKE) all -C deps endif @@ -222,7 +185,7 @@ endif dgl: ifneq ($(HEADLESS),true) - $(MAKE) -C dpf/dgl opengl $(DGL_EXTRA_ARGS) + $(MAKE) opengl -C dpf/dgl $(DGL_EXTRA_ARGS) endif plugins: deps @@ -241,27 +204,51 @@ else gen: endif +# -------------------------------------------------------------- +# extra rules, for quick testing + +jack: carla deps dgl plugins resources + $(MAKE) jack -C src $(CARLA_EXTRA_ARGS) + +native: carla deps dgl plugins resources + $(MAKE) native -C src $(CARLA_EXTRA_ARGS) + +mini: carla deps dgl plugins resources + $(MAKE) mini -C src $(CARLA_EXTRA_ARGS) + +clap: carla deps dgl plugins resources + $(MAKE) clap -C src $(CARLA_EXTRA_ARGS) + +lv2: carla deps dgl plugins resources + $(MAKE) lv2 -C src $(CARLA_EXTRA_ARGS) + +vst2: carla deps dgl plugins resources + $(MAKE) vst2 -C src $(CARLA_EXTRA_ARGS) + +vst3: carla deps dgl plugins resources + $(MAKE) vst3 -C src $(CARLA_EXTRA_ARGS) + # -------------------------------------------------------------- # Packaging standalone for CI unzipfx: deps/unzipfx/unzipfx2cat$(APP_EXT) CardinalJACK.zip CardinalNative.zip - cat deps/unzipfx/unzipfx2cat$(APP_EXT) CardinalJACK.zip > CardinalJACK - cat deps/unzipfx/unzipfx2cat$(APP_EXT) CardinalNative.zip > CardinalNative - chmod +x CardinalJACK CardinalNative + cat deps/unzipfx/unzipfx2cat$(APP_EXT) CardinalJACK.zip > CardinalJACK$(APP_EXT) + cat deps/unzipfx/unzipfx2cat$(APP_EXT) CardinalNative.zip > CardinalNative$(APP_EXT) + chmod +x CardinalJACK$(APP_EXT) CardinalNative$(APP_EXT) -CardinalJACK.zip: bin/Cardinal bin/CardinalFX.lv2/resources +CardinalJACK.zip: bin/Cardinal$(APP_EXT) bin/CardinalFX.lv2/resources mkdir -p build/unzipfx-jack - ln -sf ../../bin/Cardinal build/unzipfx-jack/Cardinal - ln -s ../../bin/CardinalFX.lv2/resources build/unzipfx-jack/resources + ln -sf ../../bin/Cardinal$(APP_EXT) build/unzipfx-jack/Cardinal$(APP_EXT) + ln -sf ../../bin/CardinalFX.lv2/resources build/unzipfx-jack/resources cd build/unzipfx-jack && \ - zip -r -9 ../../$@ Cardinal resources + zip -r -9 ../../$@ Cardinal$(APP_EXT) resources -CardinalNative.zip: bin/CardinalNative bin/CardinalFX.lv2/resources +CardinalNative.zip: bin/CardinalNative$(APP_EXT) bin/CardinalFX.lv2/resources mkdir -p build/unzipfx-native - ln -sf ../../bin/CardinalNative build/unzipfx-native/Cardinal - ln -s ../../bin/CardinalFX.lv2/resources build/unzipfx-native/resources + ln -sf ../../bin/CardinalNative$(APP_EXT) build/unzipfx-native/Cardinal$(APP_EXT) + ln -sf ../../bin/CardinalFX.lv2/resources build/unzipfx-native/resources cd build/unzipfx-native && \ - zip -r -9 ../../$@ Cardinal resources + zip -r -9 ../../$@ Cardinal$(APP_EXT) resources deps/unzipfx/unzipfx2cat: make -C deps/unzipfx -f Makefile.linux @@ -280,7 +267,10 @@ clean: $(MAKE) clean -C dpf/utils/lv2-ttl-generator $(MAKE) clean -C plugins $(MAKE) clean -C src - rm -rf bin build + rm -rf bin build build-headless dpf/utils/lv2_ttl_generator.d + # FIXME + rm -f src/Rack/BaconMusic/default-skin.json + rm -f src/Rack/SurgeXTRack/default-skin.json # -------------------------------------------------------------- # Install step @@ -289,32 +279,39 @@ install: install -d $(DESTDIR)$(PREFIX)/bin install -d $(DESTDIR)$(PREFIX)/lib/lv2/Cardinal.lv2 install -d $(DESTDIR)$(PREFIX)/lib/lv2/CardinalFX.lv2 + install -d $(DESTDIR)$(PREFIX)/lib/lv2/CardinalMini.lv2 install -d $(DESTDIR)$(PREFIX)/lib/lv2/CardinalSynth.lv2 + install -d $(DESTDIR)$(PREFIX)/lib/clap/Cardinal.clap install -d $(DESTDIR)$(PREFIX)/lib/vst/Cardinal.vst -ifeq ($(VST3_SUPPORTED),true) - install -d $(DESTDIR)$(PREFIX)/lib/vst3/Cardinal.vst3/Contents - install -d $(DESTDIR)$(PREFIX)/lib/vst3/CardinalFX.vst3/Contents - install -d $(DESTDIR)$(PREFIX)/lib/vst3/CardinalSynth.vst3/Contents +ifneq ($(VST3_BINARY_DIR),) + install -d $(DESTDIR)$(PREFIX)/lib/vst3/Cardinal.vst3/$(VST3_BINARY_DIR) + install -d $(DESTDIR)$(PREFIX)/lib/vst3/CardinalFX.vst3/$(VST3_BINARY_DIR) + install -d $(DESTDIR)$(PREFIX)/lib/vst3/CardinalSynth.vst3/$(VST3_BINARY_DIR) endif install -d $(DESTDIR)$(PREFIX)/share/cardinal install -d $(DESTDIR)$(PREFIX)/share/doc/cardinal/docs install -m 644 bin/Cardinal.lv2/*.* $(DESTDIR)$(PREFIX)/lib/lv2/Cardinal.lv2/ install -m 644 bin/CardinalFX.lv2/*.* $(DESTDIR)$(PREFIX)/lib/lv2/CardinalFX.lv2/ + install -m 644 bin/CardinalMini.lv2/*.* $(DESTDIR)$(PREFIX)/lib/lv2/CardinalMini.lv2/ install -m 644 bin/CardinalSynth.lv2/*.* $(DESTDIR)$(PREFIX)/lib/lv2/CardinalSynth.lv2/ + install -m 644 bin/Cardinal.clap/*.* $(DESTDIR)$(PREFIX)/lib/clap/Cardinal.clap/ install -m 644 bin/Cardinal.vst/*.* $(DESTDIR)$(PREFIX)/lib/vst/Cardinal.vst/ -ifeq ($(VST3_SUPPORTED),true) - cp -rL bin/Cardinal.vst3/Contents/*-* $(DESTDIR)$(PREFIX)/lib/vst3/Cardinal.vst3/Contents/ - cp -rL bin/CardinalFX.vst3/Contents/*-* $(DESTDIR)$(PREFIX)/lib/vst3/CardinalFX.vst3/Contents/ - cp -rL bin/CardinalSynth.vst3/Contents/*-* $(DESTDIR)$(PREFIX)/lib/vst3/CardinalSynth.vst3/Contents/ +ifneq ($(VST3_BINARY_DIR),) + install -m 644 bin/Cardinal.vst3/$(VST3_BINARY_DIR)/* $(DESTDIR)$(PREFIX)/lib/vst3/Cardinal.vst3/$(VST3_BINARY_DIR)/ + install -m 644 bin/CardinalFX.vst3/$(VST3_BINARY_DIR)/* $(DESTDIR)$(PREFIX)/lib/vst3/CardinalFX.vst3/$(VST3_BINARY_DIR)/ + install -m 644 bin/CardinalSynth.vst3/$(VST3_BINARY_DIR)/* $(DESTDIR)$(PREFIX)/lib/vst3/CardinalSynth.vst3/$(VST3_BINARY_DIR)/ endif - install -m 755 bin/Cardinal$(APP_EXT) $(DESTDIR)$(PREFIX)/bin/ + install -m 755 bin/Cardinal$(APP_EXT) $(DESTDIR)$(PREFIX)/bin/ + install -m 755 bin/CardinalMini$(APP_EXT) $(DESTDIR)$(PREFIX)/bin/ + install -m 755 bin/CardinalNative$(APP_EXT) $(DESTDIR)$(PREFIX)/bin/ + cp -rL bin/Cardinal.lv2/resources/* $(DESTDIR)$(PREFIX)/share/cardinal/ - install -m 644 README.md $(DESTDIR)$(PREFIX)/share/doc/cardinal/ + install -m 644 README.md $(DESTDIR)$(PREFIX)/share/doc/cardinal/ install -m 644 docs/*.md docs/*.png $(DESTDIR)$(PREFIX)/share/doc/cardinal/docs/ # -------------------------------------------------------------- @@ -330,7 +327,6 @@ TAR_ARGS = \ --exclude="*.kdev*" \ --exclude=".travis*" \ --exclude=".vscode*" \ - --exclude="carla/source/modules/juce_*" \ --exclude="carla/source/native-plugins/external/zynaddsubfx*" \ --exclude="src/Rack/dep/osdialog/osdialog_*" \ --exclude="src/Rack/icon.*" \ @@ -365,7 +361,10 @@ TAR_ARGS = \ --exclude=plugins/BogaudioModules/res-src \ --exclude=plugins/Cardinal/orig \ --exclude=plugins/GrandeModular/res-src \ - --exclude=src/MOD \ + --exclude=plugins/surgext/surge/libs/JUCE \ + --exclude=plugins/surgext/surge/resources/data/patches_3rdparty \ + --exclude=plugins/surgext/surge/resources/data/patches_factory \ + --exclude=plugins/surgext/surge/resources/data/wavetables_3rdparty \ --exclude=src/Rack/adapters \ --exclude=src/Rack/dep/filesystem/cmake \ --exclude=src/Rack/dep/filesystem/examples \ @@ -400,10 +399,13 @@ TAR_ARGS = \ --exclude=src/Rack/src/app/AudioDisplay.cpp \ --exclude=src/Rack/src/app/MenuBar.cpp \ --exclude=src/Rack/src/app/MidiDisplay.cpp \ + --exclude=src/Rack/src/app/ModuleWidget.cpp \ --exclude=src/Rack/src/app/Scene.cpp \ --exclude=src/Rack/src/app/TipWindow.cpp \ + --exclude=src/Rack/src/dsp/minblep.cpp \ --exclude=src/Rack/src/engine/Engine.cpp \ --exclude=src/Rack/src/plugin/Model.cpp \ + --exclude=src/Rack/src/widget/OpenGlWidget.cpp \ --exclude=src/Rack/src/window/Window.cpp \ --exclude=src/Rack/res/Core \ --exclude=src/Rack/res/icon.png \ diff --git a/Makefile.base.mk b/Makefile.base.mk new file mode 100644 index 00000000..c4cbcffb --- /dev/null +++ b/Makefile.base.mk @@ -0,0 +1,209 @@ +#!/usr/bin/make -f +# Makefile for Cardinal # +# --------------------- # +# Created by falkTX +# + +ifeq ($(ROOT),) +$(error invalid usage) +endif + +ifeq ($(NOSIMD),true) +ifneq (,$(findstring -msse,$(CXXFLAGS))) +$(error NOSIMD build requested but -msse compiler flag is present in CXXFLAGS) +endif +endif + +# ----------------------------------------------------------------------------- +# Import base definitions + +export DISTRHO_NAMESPACE = CardinalDISTRHO +export DGL_NAMESPACE = CardinalDGL +export NVG_DISABLE_SKIPPING_WHITESPACE = true +export NVG_FONT_TEXTURE_FLAGS = NVG_IMAGE_NEAREST +export USE_NANOVG_FBO = true +export WASM_EXCEPTIONS = true +export WINDOWS_ICON_ID = 401 +export X11_WINDOW_ICON_NAME = gCardinalX11Icon +export X11_WINDOW_ICON_SIZE = 18950 +include $(ROOT)/dpf/Makefile.base.mk + +DGL_EXTRA_ARGS = \ + DISTRHO_NAMESPACE=$(DISTRHO_NAMESPACE) \ + DGL_NAMESPACE=$(DGL_NAMESPACE) \ + NVG_DISABLE_SKIPPING_WHITESPACE=$(NVG_DISABLE_SKIPPING_WHITESPACE) \ + NVG_FONT_TEXTURE_FLAGS=$(NVG_FONT_TEXTURE_FLAGS) \ + USE_NANOVG_FBO=$(USE_NANOVG_FBO) \ + WASM_EXCEPTIONS=$(WASM_EXCEPTIONS) \ + WINDOWS_ICON_ID=$(WINDOWS_ICON_ID) \ + X11_WINDOW_ICON_NAME=$(X11_WINDOW_ICON_NAME) \ + X11_WINDOW_ICON_SIZE=$(X11_WINDOW_ICON_SIZE) + +# ----------------------------------------------------------------------------- +# Build config + +ifeq ($(BSD),true) +SYSDEPS ?= true +else +SYSDEPS ?= false +endif + +ifeq ($(SYSDEPS),true) +RACK_DEP_PATH = $(abspath $(ROOT)/deps/sysroot) +else +RACK_DEP_PATH = $(abspath $(ROOT)/src/Rack/dep) +endif + +# ----------------------------------------------------------------------------- +# Custom build flags + +BASE_FLAGS += -I$(abspath $(ROOT)/include) +BASE_FLAGS += -I$(abspath $(ROOT)/include/simd-compat) +BASE_FLAGS += -I$(RACK_DEP_PATH)/include + +ifeq ($(MOD_BUILD),true) +BASE_FLAGS += -DSIMDE_ENABLE_OPENMP -fopenmp +LINK_FLAGS += -fopenmp +endif + +ifeq ($(NOSIMD),true) +BASE_FLAGS += -DCARDINAL_NOSIMD +endif + +ifeq ($(SYSDEPS),true) +BASE_FLAGS += -DCARDINAL_SYSDEPS +BASE_FLAGS += $(shell $(PKG_CONFIG) --cflags jansson libarchive samplerate speexdsp) +else +BASE_FLAGS += -DZSTDLIB_VISIBILITY= +endif + +ifeq ($(BSD)$(HAIKU),true) +BASE_FLAGS += -DCLOCK_MONOTONIC_RAW=CLOCK_MONOTONIC +endif + +ifeq ($(HAIKU)$(WASM),true) +BASE_FLAGS += -I$(abspath $(ROOT)/include/linux-compat) +else +BASE_FLAGS += -pthread +endif + +ifeq ($(WINDOWS),true) +BASE_FLAGS += -D_USE_MATH_DEFINES +BASE_FLAGS += -DWIN32_LEAN_AND_MEAN +BASE_FLAGS += -D_WIN32_WINNT=0x0600 +BASE_FLAGS += -I$(abspath $(ROOT)/include/mingw-compat) +endif + +# make sure these flags always end up last +BUILD_C_FLAGS += -fno-finite-math-only -fno-strict-aliasing +BUILD_CXX_FLAGS += -fno-finite-math-only -fno-strict-aliasing + +# ----------------------------------------------------------------------------- +# simde flags + +BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/dep/simde) +BASE_FLAGS += -DSIMDE_ACCURACY_PREFERENCE=0 +BASE_FLAGS += -DSIMDE_FAST_CONVERSION_RANGE +BASE_FLAGS += -DSIMDE_FAST_MATH +BASE_FLAGS += -DSIMDE_FAST_NANS +BASE_FLAGS += -DSIMDE_FAST_ROUND_MODE +BASE_FLAGS += -DSIMDE_FAST_ROUND_TIES + +# unwanted +BASE_FLAGS += -DSIMDE_X86_SSE4_1_H +BASE_FLAGS += -DSIMDE_X86_SSE4_2_H + +# ----------------------------------------------------------------------------- +# Rack build flags + +ifeq ($(BUILDING_RACK),true) + +# Rack code is not tested for this flag, unset it +BUILD_CXX_FLAGS += -U_GLIBCXX_ASSERTIONS -Wp,-U_GLIBCXX_ASSERTIONS + +# Ignore bad behaviour from Rack API +BUILD_CXX_FLAGS += -Wno-format-security + +# Ignore warnings from simde +ifeq ($(MOD_BUILD),true) +BUILD_CXX_FLAGS += -Wno-overflow +endif + +# lots of warnings from VCV side +BASE_FLAGS += -Wno-unused-parameter +BASE_FLAGS += -Wno-unused-variable + +ifeq ($(CPU_ARM_OR_ARM64)$(CPU_RISCV64),true) +BASE_FLAGS += -Wno-attributes +endif + +ifeq ($(MACOS),true) +BASE_FLAGS += -DARCH_MAC +else ifeq ($(WINDOWS),true) +BASE_FLAGS += -DARCH_WIN +else +BASE_FLAGS += -DARCH_LIN +endif + +ifeq ($(DEBUG),true) +BASE_FLAGS += -UDEBUG +endif + +ifeq ($(HEADLESS),true) +BASE_FLAGS += -DHEADLESS +endif + +ifeq ($(USE_GLES2),true) +BASE_FLAGS += -DNANOVG_GLES2_FORCED +else ifeq ($(USE_GLES3),true) +BASE_FLAGS += -DNANOVG_GLES3_FORCED +endif + +# needed for enabling SSE in pffft +ifeq ($(CPU_I386),true) +ifneq ($(NOSIMD),true) +BASE_FLAGS += -Di386 +endif +endif + +# SIMD must always be enabled, even in debug builds +ifneq ($(NOSIMD),true) +ifeq ($(DEBUG),true) + +ifeq ($(WASM),true) +BASE_FLAGS += -msse -msse2 -msse3 -msimd128 +else ifeq ($(CPU_ARM32),true) +BASE_FLAGS += -mfpu=neon-vfpv4 -mfloat-abi=hard +else ifeq ($(CPU_I386_OR_X86_64),true) +BASE_FLAGS += -msse -msse2 -mfpmath=sse +endif + +endif +endif + +BASE_FLAGS += -I$(abspath $(ROOT)/dpf/dgl/src/nanovg) +BASE_FLAGS += -I$(abspath $(ROOT)/dpf/distrho) + +BASE_FLAGS += -I$(abspath $(ROOT)/src) +BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/include) +BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/include/dsp) +BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/dep/filesystem/include) +BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/dep/fuzzysearchdatabase/src) +BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/dep/glfw/include) +BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/dep/nanosvg/src) +BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/dep/oui-blendish) +BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/dep/pffft) +BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/dep/tinyexpr) + +BUILD_C_FLAGS += -std=gnu11 + +ifneq ($(MACOS),true) +BUILD_CXX_FLAGS += -faligned-new -Wno-abi +ifeq ($(MOD_BUILD),true) +BUILD_CXX_FLAGS += -std=gnu++17 +endif +endif + +endif + +# ----------------------------------------------------------------------------- diff --git a/README.md b/README.md index d7cb1d7b..8224ac1c 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,13 @@ *Cardinal, the Rack!* Cardinal is a free and open-source virtual modular synthesizer plugin, -available as JACK standalone and AU, LV2, VST2 and VST3 audio plugin for FreeBSD, Linux, macOS and Windows. +available in AudioUnit/CLAP/LV2/VST2/VST3 plugin formats and as a standalone app for FreeBSD, Linux, macOS, Windows and the Web. It is based on the popular [VCV Rack](https://vcvrack.com/) but with a focus on being a fully self-contained plugin version. More specifically, this is a [DPF-based](https://github.com/DISTRHO/DPF/) plugin wrapper around [VCV Rack](https://github.com/VCVRack/Rack/), using its code directly instead of forking the project, -with the target of having a **proper, self-contained, fully free and open-source plugin version of Rack**. +with the target of having a **self-contained, fully free and open-source plugin version of Rack**. See the [why section](#Why) below for the reasons Cardinal exists, also for frequently asked questions check this [FAQ document](docs/FAQ.md). @@ -25,14 +25,16 @@ All VCV branding has been removed (to the best of our knowledge) in order to avo Cardinal should be considered stable, if you spot any bugs please report them. Currently the following should be noted: -- Windows 32bit builds do not work well [#80](https://github.com/DISTRHO/Cardinal/issues/80) +- CLAP support is a work-in-progress [DPF#383](https://github.com/DISTRHO/DPF/issues/383) +- VST3 plugin hosting (inside Carla or Ildaeil modules) mostly works but is considered experimental +- Windows 32bit builds still have a few problematic modules [#80](https://github.com/DISTRHO/Cardinal/issues/80) ### Stable release Cardinal releases have official builds for Linux, macOS and Windows. You can find these under https://github.com/DISTRHO/Cardinal/releases. -There are Linux builds for various architectures (armhf, arm64, i686 and x86_64), macOS "universal" (arm64 + intel) and Windows 32 and 64bit builds. +There are Linux builds for various architectures (armhf, arm64, i686, riscv64 and x86_64), macOS "universal" (arm64 + intel) and Windows 32 and 64bit builds. Both macOS and Windows builds have an installer. Install instructions are available [here](https://github.com/DISTRHO/Cardinal/wiki/Install). @@ -62,9 +64,10 @@ All variants have MIDI input and output support. ### Main -This variant provides 8 audio inputs and outputs and 10 CV inputs and outputs. +This variant provides 8 audio inputs and outputs and 10 CV inputs and outputs. -NOTE: Due to AU and VST2 formats not supporting CV ports, this variant is not available for those formats. +NOTE: Due to AU and VST2 formats not supporting CV ports, this variant is not available for those formats. +NOTE: This variant is not available in CLAP yet, to be added in a later release ### Synth @@ -76,6 +79,19 @@ Plugin type is set as "instrument". This variant provides 2 audio inputs and outputs, but no CV ports. Plugin type is set as regular "effect". +### Mini + +This is a special variant with a very small, hand-picked module selection and limited IO (2 audio ports plus 5 CV). +It only exists as LV2 and Standalone plugin. + +For now the list of selected modules is quite small, intentionally. We will add a few more as the need appears. +All included modules support polyphony, reducing confusion for new users not yet used to mono vs poly approach in Rack/Cardinal. + +The main reason for this variant to exist is being able to support DSP/UI separation, which is only possible with more simple modules. +The DSP/UI separation means we can run the DSP on a different machine than the UI. +This is particularly interesting for running Cardinal on embed systems, being controlled remotely via a web browser or a native desktop application. +Such setup is already in use in [Cardinal Mini for MOD Audio](https://forum.mod.audio/t/distrho-cardinal-mini/9262/). + ## Screenshots @@ -103,77 +119,85 @@ But a couple of modules background's have their colors flipped, because damn we At the moment the following 3rd-party modules are provided: -- 21kHz -- 8Mode -- Aaron Static -- AlgoritmArte -- Amalgamated Harmonics -- Animated Circuits -- Arable Instruments -- Aria Salvatrice -- AS -- Audible Instruments -- Autinn -- Axioma -- Bacon Music -- Befaco -- Bidoo -- Bogaudio -- Catro/Modulo -- cf -- ChowDSP -- DrumKit -- E-Series -- ExpertSleepers Encoders -- Extratone -- Fehler Fabrik -- forsitan modulare -- Fundamental -- Glue the Giant -- GoodSheperd -- Grande -- Hampton Harmonics -- HetrickCV -- ihtsyn -- Impromptu -- JW-Modules -- kocmoc -- LifeFormModular -- Lilac Loop -- Little Utils -- Lomas Modules -- Lyrae Modules -- Meander -- MindMeld -- ML Modules -- Mockba Modular -- Mog -- mscHack -- MSM -- Myth -- Nonlinear Circuits -- Orbits -- Parable Instruments -- Path Set -- PinkTrombone -- Prism -- rackwindows -- repelzen -- Sonus Modular -- Starling Via -- stocaudio -- unless_modules -- Valley -- Voxglitch -- WhatTheRack -- ZetaCarinae -- ZZC +- [21kHz](https://github.com/netboy3/21kHz-rack-plugins) +- [8Mode](https://github.com/8Mode/8Mode-VCV_Modules) +- [Aaron Static](https://github.com/aaronstatic/AaronStatic_modules) +- [alef's bits](https://github.com/alefnull/alefsbits) +- [AlgoritmArte](https://github.com/algoritmarte/AlgoritmarteVCVPlugin) +- [Amalgamated Harmonics](https://github.com/jhoar/AmalgamatedHarmonics) +- [Animated Circuits](https://github.com/AnimatedCircuits/RackModules) +- [Arable Instruments](https://github.com/adbrant/ArableInstruments) +- [Aria Salvatrice](https://aria.dog/modules/) +- [AS](https://github.com/AScustomWorks/AS) +- [Audible Instruments](https://vcvrack.com/AudibleInstruments) +- [Autinn](https://github.com/NikolaiVChr/Autinn) +- [Axioma](https://github.com/kauewerner/Axioma) +- [Bacon Music](https://github.com/baconpaul/BaconPlugs) +- [Befaco](https://github.com/VCVRack/Befaco) +- [Bidoo](https://github.com/sebastien-bouffier/Bidoo) +- [Bogaudio](https://github.com/bogaudio/BogaudioModules) +- [Catro/Modulo](https://github.com/catronomix/catro-modulo) +- [cf](https://github.com/cfoulc/cf) +- [ChowDSP](https://github.com/jatinchowdhury18/ChowDSP-VCV) +- [dBiz](https://github.com/dBiz/dBiz) +- [DrumKit](https://svmodular.com/plugin/vcv/drumkit.html) +- [EnigmaCurry](https://github.com/EnigmaCurry/EnigmaCurry-vcv-pack) +- [E-Series](https://github.com/VCVRack/ESeries) +- [ExpertSleepers Encoders](https://expert-sleepers.co.uk/vcvrack_encoders.html) +- [Extratone](http://extratone.xyz/modules) +- [Fehler Fabrik](https://github.com/RCameron93/FehlerFabrik) +- [forsitan modulare](https://github.com/gosub/forsitan-modulare) +- [Fundamental](https://github.com/VCVRack/Fundamental) +- [Glue the Giant](https://github.com/gluethegiant/gtg-rack) +- [GoodSheperd](https://github.com/jensschulze/GoodSheperd) +- [Grande](https://github.com/dbgrande/GrandeModular) +- [H4N4 Modules](https://github.com/hannakoppelaar/h4n4-modules) +- [Hampton Harmonics](https://gitlab.com/hampton-harmonics/hampton-harmonics-modules) +- [HetrickCV](https://github.com/mhetrick/hetrickcv) +- [ihtsyn](https://github.com/nysthi/ihtsyn) +- [Impromptu](https://github.com/MarcBoule/ImpromptuModular) +- [JW-Modules](https://github.com/jeremywen/JW-Modules) +- [kocmoc](https://github.com/janne808/kocmoc-rack-modules) +- [LifeFormModular](https://github.com/TimeControlledOrganism/LifeFormModular) +- [Lilac Loop](https://grough.github.io/lilac-loop-vcv) +- [Little Utils](https://github.com/mgunyho/Little-Utils) +- [Lomas Modules](https://github.com/LomasModules/LomasModules) +- [Lyrae Modules](https://github.com/VegaDeftwing/LyraeModules) +- [Meander](https://github.com/knchaffin/Meander) +- [MindMeld](https://github.com/MarcBoule/MindMeldModular) +- [ML Modules](https://github.com/martin-lueders/ML_modules) +- [Mockba Modular](https://github.com/MockbaTheBorg/MockbaModular) +- [Mog](https://github.com/JustMog/Mog-VCV) +- [mscHack](https://github.com/mschack/VCV-Rack-Plugins) +- [MSM](https://github.com/netboy3/MSM-vcvrack-plugin) +- [Myth](https://github.com/Ahineya/vcv-myth-plugin) +- [Nonlinear Circuits](https://github.com/mhetrick/nonlinearcircuits) +- [Orbits](https://github.com/RareBreeds/Orbits) +- [Parable Instruments](https://github.com/adbrant/ArableInstruments) +- [Path Set](https://github.com/patheros/PathSetModules) +- [PinkTrombone](https://github.com/VegaDeftwing/PinkTromboneVCV) +- [Prism](https://github.com/SteveRussell33/Prism) +- [rackwindows](https://github.com/n0jo/rackwindows) +- [RebelTech](https://github.com/hemmer/rebel-tech-vcv) +- [repelzen](https://github.com/wiqid/repelzen) +- [Sapphire](https://github.com/cosinekitty/sapphire) +- [Sonus Modular](https://gitlab.com/sonusdept/sonusmodular) +- [stocaudio](https://github.com/aptrn/stocaudio-modules) +- [Starling Via](https://github.com/starlingcode/Via-for-Rack) +- [Stoermelder Pack-One](https://github.com/stoermelder/vcvrack-packone) +- [Surge XT](https://github.com/surge-synthesizer/surge-rack) +- [unless_modules](https://gitlab.com/unlessgames/unless_modules) +- [Valley](https://github.com/ValleyAudio/ValleyRackFree) +- [Voxglitch](https://github.com/clone45/voxglitch) +- [WhatTheRack](https://github.com/korfuri/WhatTheRack) +- [ZetaCarinae](https://github.com/mhampton/ZetaCarinaeModules) +- [ZZC](https://github.com/zezic/ZZC) Additionally Cardinal provides its own modules for DAW/Host automation, time position, audio to CV pitch conversion and internal plugin hosting. ### Adding modules -Install new modules on a Cardinal build is not possible, but we can add new modules to the build. +Installing new modules on a Cardinal build is not possible, but we can integrate existing open-source modules to be part of Cardinal. Details on this are available [here](https://github.com/DISTRHO/Cardinal/discussions/28). Also check [this wiki page](https://github.com/DISTRHO/Cardinal/wiki/Possible-modules-to-include) where we discuss possible modules to include. @@ -223,7 +247,6 @@ Other relevant reasons include: - LV2 plugin version from the start - Proper dark mode support - - Proper optimized build (because all code is compiled to a single file, we can use LTO over the whole thing) - Real CV ports to and from the plugin - Removing online access from the plugin and included modules (no phone-home here!) - Works as a test case for [DPF](https://github.com/DISTRHO/DPF/) and [Carla](https://github.com/falkTX/Carla/) @@ -250,4 +273,4 @@ An overview of the included code and linked submodules can be seen [here](docs/L ## Community chat Currently we are all on #cardinal IRC room in irc.libera.chat server. -Come join us in your favorite IRC client or through a Matrix bridge. +Come join us in your favorite IRC client. diff --git a/carla b/carla index 963f194b..41f07e11 160000 --- a/carla +++ b/carla @@ -1 +1 @@ -Subproject commit 963f194b0ed93829188ffda23320b1dc848f07d8 +Subproject commit 41f07e119252b8b14627bec8345cb7304485a815 diff --git a/deps/Makefile b/deps/Makefile index 28e4f39b..4d32cd28 100644 --- a/deps/Makefile +++ b/deps/Makefile @@ -4,76 +4,27 @@ # Created by falkTX # -# -------------------------------------------------------------- -# Import base definitions - -DISTRHO_NAMESPACE = CardinalDISTRHO -DGL_NAMESPACE = CardinalDGL -USE_NANOVG_FBO = true -WASM_EXCEPTIONS = true -include ../dpf/Makefile.base.mk - -# -------------------------------------------------------------- -# Build config - -ifeq ($(BSD),true) -SYSDEPS ?= true -else -SYSDEPS ?= false -endif - -ifeq ($(SYSDEPS),true) -DEP_PATH = $(abspath sysroot) -else -DEP_PATH = $(abspath ../src/Rack/dep) -endif - -# -------------------------------------------------------------- -# custom build flags - -BASE_FLAGS += -I../include -BASE_FLAGS += -I../include/simd-compat - -ifeq ($(HEADLESS),true) -ifeq ($(WITH_LTO),true) -BASE_FLAGS += -ffat-lto-objects -endif -endif - -ifneq ($(SYSDEPS),true) -BASE_FLAGS += -DZSTDLIB_VISIBILITY= -endif - -ifneq ($(HAIKU),true) -ifneq ($(WASM),true) -BASE_FLAGS += -pthread -endif -endif - -ifeq ($(WINDOWS),true) -BASE_FLAGS += -D_USE_MATH_DEFINES -BASE_FLAGS += -DWIN32_LEAN_AND_MEAN -BASE_FLAGS += -I../include/mingw-compat -BASE_FLAGS += -I../include/mingw-std-threads -endif - -BUILD_C_FLAGS += -fno-finite-math-only -fno-strict-aliasing -BUILD_CXX_FLAGS += -fno-finite-math-only -fno-strict-aliasing - -# Rack code is not tested for this flag, unset it -BUILD_CXX_FLAGS += -U_GLIBCXX_ASSERTIONS -Wp,-U_GLIBCXX_ASSERTIONS +ROOT = .. +include $(ROOT)/Makefile.base.mk # -------------------------------------------------------------- # override VCV arch.mk stuff so we can build more architectures ifeq ($(CPU_ARM32),true) ARCH_NAME = arm -MACHINE = i686-the-rack +MACHINE = arm64 else ifeq ($(CPU_ARM64),true) ARCH_NAME = arm64 -MACHINE = x86_64-the-rack +MACHINE = arm64 +else ifeq ($(CPU_I386),true) +ARCH_NAME = i686 +MACHINE = x86_64 +else ifeq ($(CPU_RISCV64),true) +ARCH_NAME = riscv64 +MACHINE = arm64 else ifeq ($(WASM),true) -MACHINE = i686-wasm +ARCH_NAME = wasm +MACHINE = x86_64 else MACHINE = $(TARGET_MACHINE) endif @@ -105,7 +56,7 @@ SPACE += CMAKE = cmake CMAKE += -DCMAKE_INSTALL_LIBDIR=lib -CMAKE += -DCMAKE_INSTALL_PREFIX='$(DEP_PATH)' +CMAKE += -DCMAKE_INSTALL_PREFIX='$(RACK_DEP_PATH)' CMAKE += -DBUILD_SHARED_LIBS=OFF # make sure debug/release matches @@ -145,6 +96,27 @@ ifeq ($(shell uname -s),Darwin) CMAKE += -DCMAKE_CROSSCOMPILING=ON CMAKE += -DCMAKE_SYSTEM_NAME=Generic endif +CMAKE += -DCMAKE_SKIP_COMPATIBILITY_TESTS=1 +CMAKE += -DCMAKE_SIZEOF_CHAR=1 +CMAKE += -DCMAKE_SIZEOF_UNSIGNED_SHORT=2 +CMAKE += -DCMAKE_SIZEOF_SHORT=2 +CMAKE += -DCMAKE_SIZEOF_INT=4 +CMAKE += -DCMAKE_SIZEOF_UNSIGNED_LONG=4 +CMAKE += -DCMAKE_SIZEOF_UNSIGNED_INT=4 +CMAKE += -DCMAKE_SIZEOF_LONG=4 +CMAKE += -DCMAKE_SIZEOF_VOID_P=4 +CMAKE += -DCMAKE_SIZEOF_FLOAT=4 +CMAKE += -DCMAKE_SIZEOF_DOUBLE=8 +CMAKE += -DCMAKE_C_SIZEOF_DATA_PTR=4 +CMAKE += -DCMAKE_CXX_SIZEOF_DATA_PTR=4 +CMAKE += -DCMAKE_HAVE_LIMITS_H=1 +CMAKE += -DCMAKE_HAVE_UNISTD_H=1 +CMAKE += -DCMAKE_HAVE_PTHREAD_H=1 +CMAKE += -DCMAKE_HAVE_SYS_PRCTL_H=1 +CMAKE += -DCMAKE_WORDS_BIGENDIAN=0 +CMAKE += -DCMAKE_DL_LIBS='' +CMAKE += -DCMAKE_C_BYTE_ORDER=LITTLE_ENDIAN +CMAKE += -DCMAKE_CXX_BYTE_ORDER=LITTLE_ENDIAN endif # fix cross-compilation for windows @@ -158,7 +130,7 @@ endif # Fix up configure CONFIGURE = ./configure -CONFIGURE += --prefix="$(DEP_PATH)" +CONFIGURE += --prefix="$(RACK_DEP_PATH)" CONFIGURE += --host=$(TARGET_MACHINE) CONFIGURE += --enable-static CONFIGURE += --disable-shared @@ -167,6 +139,7 @@ CONFIGURE += --disable-alsa # NOTE speex fails to build when neon is enabled, so we disable that CONFIGURE += --disable-neon # NOTE libsamplerate fails with invalid host, so we force ac_cv_host +CONFIGURE += ac_cv_build=$(TARGET_MACHINE) CONFIGURE += ac_cv_host=$(TARGET_MACHINE) # -------------------------------------------------------------- @@ -200,58 +173,54 @@ DEP_MAKE2 += CONFIGURE="$(ENV) $(CONFIGURE)" # -------------------------------------------------------------- # Rack internal dependencies target -$(DEP_PATH)/lib/%.a: - $(DEP_MAKE2) -C $(DEP_PATH) lib/$*.a +$(RACK_DEP_PATH)/lib/%.a: + $(DEP_MAKE2) -C $(RACK_DEP_PATH) lib/$*.a -$(DEP_PATH)/jansson-2.12: - $(DEP_MAKE2) -C $(DEP_PATH) jansson-2.12 +$(RACK_DEP_PATH)/jansson-2.12: + $(DEP_MAKE2) -C $(RACK_DEP_PATH) jansson-2.12 # libarchive: skip shared lib and ensure libzstd is enabled -$(DEP_PATH)/lib/libarchive.a: $(DEP_PATH)/lib/libzstd.a $(DEP_PATH)/libarchive-3.4.3/.stamp-patched +$(RACK_DEP_PATH)/lib/libarchive.a: $(RACK_DEP_PATH)/lib/libzstd.a $(RACK_DEP_PATH)/libarchive-3.4.3/.stamp-patched -$(DEP_PATH)/lib/libarchive_static.a: $(DEP_PATH)/lib/libzstd.a $(DEP_PATH)/libarchive-3.4.3/.stamp-patched +$(RACK_DEP_PATH)/lib/libarchive_static.a: $(RACK_DEP_PATH)/lib/libzstd.a $(RACK_DEP_PATH)/libarchive-3.4.3/.stamp-patched -$(DEP_PATH)/libarchive-3.4.3/.stamp-patched: - $(DEP_MAKE2) -C $(DEP_PATH) libarchive-3.4.3 - sed -i -e "618,625d" $(DEP_PATH)/libarchive-3.4.3/CMakeLists.txt - awk 'NR==616{print " SET(HAVE_LIBZSTD 1)"}1' $(DEP_PATH)/libarchive-3.4.3/CMakeLists.txt > $(DEP_PATH)/libarchive-3.4.3/CMakeLists.txt2 - mv $(DEP_PATH)/libarchive-3.4.3/CMakeLists.txt2 $(DEP_PATH)/libarchive-3.4.3/CMakeLists.txt - sed -i -e "238,243d" $(DEP_PATH)/libarchive-3.4.3/libarchive/CMakeLists.txt - sed -i -e "s/TARGETS archive archive_static/TARGETS archive_static/" $(DEP_PATH)/libarchive-3.4.3/libarchive/CMakeLists.txt +$(RACK_DEP_PATH)/libarchive-3.4.3/.stamp-patched: + $(DEP_MAKE2) -C $(RACK_DEP_PATH) libarchive-3.4.3 + sed -i -e "618,625d" $(RACK_DEP_PATH)/libarchive-3.4.3/CMakeLists.txt + awk 'NR==616{print " SET(HAVE_LIBZSTD 1)"}1' $(RACK_DEP_PATH)/libarchive-3.4.3/CMakeLists.txt > $(RACK_DEP_PATH)/libarchive-3.4.3/CMakeLists.txt2 + mv $(RACK_DEP_PATH)/libarchive-3.4.3/CMakeLists.txt2 $(RACK_DEP_PATH)/libarchive-3.4.3/CMakeLists.txt + sed -i -e "238,243d" $(RACK_DEP_PATH)/libarchive-3.4.3/libarchive/CMakeLists.txt + sed -i -e "s/TARGETS archive archive_static/TARGETS archive_static/" $(RACK_DEP_PATH)/libarchive-3.4.3/libarchive/CMakeLists.txt touch $@ # libsamplerate: skip tests, fails to build in some systems and are not needed or wanted anyway -$(DEP_PATH)/lib/libsamplerate.a: $(DEP_PATH)/libsamplerate-0.1.9/.stamp-patched +$(RACK_DEP_PATH)/lib/libsamplerate.a: $(RACK_DEP_PATH)/libsamplerate-0.1.9/.stamp-patched -$(DEP_PATH)/libsamplerate-0.1.9/.stamp-patched: - $(DEP_MAKE2) -C $(DEP_PATH) libsamplerate-0.1.9 - sed -i -e "s/src doc examples tests/src/" $(DEP_PATH)/libsamplerate-0.1.9/Makefile.in +$(RACK_DEP_PATH)/libsamplerate-0.1.9/.stamp-patched: + $(DEP_MAKE2) -C $(RACK_DEP_PATH) libsamplerate-0.1.9 + sed -i -e "s/src doc examples tests/src/" $(RACK_DEP_PATH)/libsamplerate-0.1.9/Makefile.in touch $@ # libspeexdsp: hide symbols -$(DEP_PATH)/lib/libspeexdsp.a: $(DEP_PATH)/speexdsp-SpeexDSP-1.2rc3/.stamp-patched - -$(DEP_PATH)/speexdsp-SpeexDSP-1.2rc3/.stamp-patched: - $(DEP_MAKE2) -C $(DEP_PATH) speexdsp-SpeexDSP-1.2rc3 \ - WGET="wget -c http://downloads.xiph.org/releases/speex/speexdsp-1.2rc3.tar.gz && mv speexdsp-1.2rc3.tar.gz speexdsp-SpeexDSP-1.2rc3.tgz #" \ - SHA256SUM="true" \ - UNTAR="mkdir -p speexdsp-SpeexDSP-1.2rc3 && tar -x --strip-components=1 --directory=$(DEP_PATH)/speexdsp-SpeexDSP-1.2rc3 -f" - sed -i -e "s/#pragma GCC visibility push/#error we dont want this/" $(DEP_PATH)/speexdsp-SpeexDSP-1.2rc3/configure +$(RACK_DEP_PATH)/lib/libspeexdsp.a: $(RACK_DEP_PATH)/speexdsp/.stamp-patched + +$(RACK_DEP_PATH)/speexdsp/.stamp-patched: + sed -i -e 's/__attribute__((visibility("default")))//' $(RACK_DEP_PATH)/speexdsp/configure.ac touch $@ # custom zstd build for only building static libs -$(DEP_PATH)/lib/libzstd.a: $(DEP_PATH)/zstd-1.4.5/.stamp-patched - cd $(DEP_PATH)/zstd-1.4.5/build/cmake && $(CMAKE) -DZSTD_BUILD_STATIC=ON -DZSTD_BUILD_PROGRAMS=OFF -DZSTD_BUILD_SHARED=OFF -DZSTD_MULTITHREAD_SUPPORT=OFF . - $(DEP_MAKE2) -C $(DEP_PATH)/zstd-1.4.5/build/cmake - $(DEP_MAKE2) -C $(DEP_PATH)/zstd-1.4.5/build/cmake install +$(RACK_DEP_PATH)/lib/libzstd.a: $(RACK_DEP_PATH)/zstd-1.4.5/.stamp-patched + cd $(RACK_DEP_PATH)/zstd-1.4.5/build/cmake && $(CMAKE) -DZSTD_BUILD_STATIC=ON -DZSTD_BUILD_PROGRAMS=OFF -DZSTD_BUILD_SHARED=OFF -DZSTD_MULTITHREAD_SUPPORT=OFF . + $(DEP_MAKE2) -C $(RACK_DEP_PATH)/zstd-1.4.5/build/cmake + $(DEP_MAKE2) -C $(RACK_DEP_PATH)/zstd-1.4.5/build/cmake install # zstd cmake is borked, see https://github.com/facebook/zstd/issues/1401 # zstd also fails to build on old systems, patch that too -$(DEP_PATH)/zstd-1.4.5/.stamp-patched: - $(DEP_MAKE2) -C $(DEP_PATH) zstd-1.4.5 - sed -i -e "56,66d" $(DEP_PATH)/zstd-1.4.5/build/cmake/CMakeModules/AddZstdCompilationFlags.cmake - sed -i -e "146,175d" $(DEP_PATH)/zstd-1.4.5/programs/util.c - sed -i -e "142,144d" $(DEP_PATH)/zstd-1.4.5/programs/util.c +$(RACK_DEP_PATH)/zstd-1.4.5/.stamp-patched: + $(DEP_MAKE2) -C $(RACK_DEP_PATH) zstd-1.4.5 + sed -i -e "56,66d" $(RACK_DEP_PATH)/zstd-1.4.5/build/cmake/CMakeModules/AddZstdCompilationFlags.cmake + sed -i -e "146,175d" $(RACK_DEP_PATH)/zstd-1.4.5/programs/util.c + sed -i -e "142,144d" $(RACK_DEP_PATH)/zstd-1.4.5/programs/util.c touch $@ # -------------------------------------------------------------- @@ -272,53 +241,123 @@ else ifeq ($(MACOS),true) QUICKJS_MAKE_FLAGS += CONFIG_DARWIN=y endif -$(DEP_PATH)/lib/libquickjs.a: +$(RACK_DEP_PATH)/lib/libquickjs.a: $(DEP_MAKE) $(QUICKJS_MAKE_FLAGS) -C $(CURDIR)/QuickJS - install -d $(DEP_PATH)/include - install -d $(DEP_PATH)/lib + install -d $(RACK_DEP_PATH)/include + install -d $(RACK_DEP_PATH)/lib install -m644 $(CURDIR)/QuickJS/libquickjs.a $@ - install -m644 $(CURDIR)/QuickJS/quickjs.h $(DEP_PATH)/include/quickjs.h + install -m644 $(CURDIR)/QuickJS/quickjs.h $(RACK_DEP_PATH)/include/quickjs.h + +# -------------------------------------------------------------- +# SurgeXT target + +SURGE_DEP_PATH = $(abspath surge-build) +SURGE_SRC_PATH = $(abspath ../plugins/surgext/surge) +SURGE_NAMES = HysteresisProcessing Patch SolverType Tunings Wavetable clouds ghc plaits stmlib + +SURGE_CXX_FLAGS = $(filter-out -fsingle-precision-constant,$(filter-out -std=gnu++11,$(BUILD_CXX_FLAGS))) +SURGE_CXX_FLAGS += $(foreach n,$(SURGE_NAMES),-D$(n)=surgext$(n)) + +# fix build with gcc13 +SURGE_CXX_FLAGS += -include cstdint + +# fix JUCE build https://github.com/juce-framework/JUCE/issues/374 +ifeq ($(CPU_I386),true) +SURGE_CXX_FLAGS += -D__sigemptyset=sigemptyset +endif + +# use custom JUCE from DISTRHO and Carla +SURGE_CXX_FLAGS += -I$(abspath ../carla/source/modules) + +# SIMD must always be enabled, even in debug builds +ifeq ($(NOSIMD),true) +SURGE_CXX_FLAGS += -DCARDINAL_NOSIMD +else ifeq ($(DEBUG),true) +ifeq ($(WASM),true) +SURGE_CXX_FLAGS += -msse -msse2 -msse3 -msimd128 +else ifeq ($(CPU_ARM32),true) +SURGE_CXX_FLAGS += -mfpu=neon-vfpv4 -mfloat-abi=hard +else ifeq ($(CPU_I386_OR_X86_64),true) +SURGE_CXX_FLAGS += -msse -msse2 -mfpmath=sse +endif +endif + +# possibly use fftw? +# ifeq ($(shell $(PKG_CONFIG) --exists fftw3 fftw3f && echo true),true) +# SURGE_CXX_FLAGS += -DJUCE_DSP_USE_STATIC_FFTW=1 +# endif + +# JUCE_USE_CURL +SURGE_ENV = env \ + AR=$(AR) \ + CC=$(CC) \ + CXX=$(CXX) \ + CFLAGS='$(BUILD_C_FLAGS) -w' \ + CXXFLAGS='$(SURGE_CXX_FLAGS) -w' \ + LDFLAGS='$(LINK_FLAGS)' + +SURGE_LIB = $(SURGE_DEP_PATH)/src/common/libsurge-common.a + +$(SURGE_LIB): $(SURGE_DEP_PATH)/Makefile + $(DEP_MAKE) -C $(SURGE_DEP_PATH) surge-common + +$(SURGE_DEP_PATH)/Makefile: $(SURGE_SRC_PATH)/CMakeLists.txt + mkdir -p $(SURGE_DEP_PATH) + cd $(SURGE_DEP_PATH) && \ + $(SURGE_ENV) $(CMAKE) \ + -DSURGE_COMPILE_BLOCK_SIZE=8 \ + -DSURGE_SKIP_AIRWINDOWS=TRUE \ + -DSURGE_SKIP_JUCE_FOR_RACK=TRUE \ + -DSURGE_SKIP_LUA=TRUE \ + -DSURGE_SKIP_ODDSOUND_MTS=TRUE \ + -DSURGE_JUCE_PATH=$(abspath ../carla/source) \ + -DSURGE_SIMDE_PATH=$(abspath ../src/Rack/dep/simde) \ + $(SURGE_SRC_PATH) # -------------------------------------------------------------- # Build targets -TARGETS += $(DEP_PATH)/lib/libjansson.a -TARGETS += $(DEP_PATH)/lib/libquickjs.a -TARGETS += $(DEP_PATH)/lib/libsamplerate.a -TARGETS += $(DEP_PATH)/lib/libspeexdsp.a +ifneq ($(NOPLUGINS),true) +TARGETS += $(SURGE_LIB) +endif + +TARGETS += $(RACK_DEP_PATH)/lib/libjansson.a +TARGETS += $(RACK_DEP_PATH)/lib/libquickjs.a +TARGETS += $(RACK_DEP_PATH)/lib/libsamplerate.a +TARGETS += $(RACK_DEP_PATH)/lib/libspeexdsp.a ifeq ($(WINDOWS),true) -TARGETS += $(DEP_PATH)/lib/libarchive_static.a +TARGETS += $(RACK_DEP_PATH)/lib/libarchive_static.a else -TARGETS += $(DEP_PATH)/lib/libarchive.a +TARGETS += $(RACK_DEP_PATH)/lib/libarchive.a endif -TARGETS += $(DEP_PATH)/lib/libzstd.a +TARGETS += $(RACK_DEP_PATH)/lib/libzstd.a all: $(TARGETS) clean: $(DEP_MAKE) $(QUICKJS_MAKE_FLAGS) -C $(CURDIR)/QuickJS clean rm -f $(TARGETS) - rm -f $(DEP_PATH)/*.tgz - rm -f $(DEP_PATH)/*.tar.gz - rm -rf $(DEP_PATH)/bin - rm -rf $(DEP_PATH)/include - rm -rf $(DEP_PATH)/lib - rm -rf $(DEP_PATH)/share - rm -rf $(DEP_PATH)/jansson-2.12 - rm -rf $(DEP_PATH)/libarchive-3.4.3 - rm -rf $(DEP_PATH)/libsamplerate-0.1.9 - rm -rf $(DEP_PATH)/speexdsp-SpeexDSP-1.2rc3 - rm -rf $(DEP_PATH)/zstd-1.4.5 + rm -f $(RACK_DEP_PATH)/*.tgz + rm -f $(RACK_DEP_PATH)/*.tar.gz + rm -rf $(RACK_DEP_PATH)/bin + rm -rf $(RACK_DEP_PATH)/include + rm -rf $(RACK_DEP_PATH)/lib + rm -rf $(RACK_DEP_PATH)/share + rm -rf $(RACK_DEP_PATH)/jansson-2.12 + rm -rf $(RACK_DEP_PATH)/libarchive-3.4.3 + rm -rf $(RACK_DEP_PATH)/libsamplerate-0.1.9 + rm -rf $(RACK_DEP_PATH)/zstd-1.4.5 + rm -rf $(SURGE_DEP_PATH) download: \ - $(DEP_PATH)/jansson-2.12 \ - $(DEP_PATH)/libarchive-3.4.3/.stamp-patched \ - $(DEP_PATH)/libsamplerate-0.1.9/.stamp-patched \ - $(DEP_PATH)/speexdsp-SpeexDSP-1.2rc3/.stamp-patched \ - $(DEP_PATH)/zstd-1.4.5/.stamp-patched + $(RACK_DEP_PATH)/jansson-2.12 \ + $(RACK_DEP_PATH)/libarchive-3.4.3/.stamp-patched \ + $(RACK_DEP_PATH)/libsamplerate-0.1.9/.stamp-patched \ + $(RACK_DEP_PATH)/zstd-1.4.5/.stamp-patched -quickjs: $(DEP_PATH)/lib/libquickjs.a +quickjs: $(RACK_DEP_PATH)/lib/libquickjs.a +surge: $(SURGE_LIB) # -------------------------------------------------------------- diff --git a/deps/PawPaw b/deps/PawPaw index 4f7f9eb6..6a3c6a65 160000 --- a/deps/PawPaw +++ b/deps/PawPaw @@ -1 +1 @@ -Subproject commit 4f7f9eb6ff1677606a85fe701bbb535f8fe7086c +Subproject commit 6a3c6a65a89abe221858c3f7635140074506bfc3 diff --git a/deps/unzipfx/Makefile.win32 b/deps/unzipfx/Makefile.win32 index 24c096b5..91d19a5e 100644 --- a/deps/unzipfx/Makefile.win32 +++ b/deps/unzipfx/Makefile.win32 @@ -21,7 +21,7 @@ all: unzipfx2cat.exe unzipfx2cat.exe: $(OBJ) $(CC) $^ $(LINK_FLAGS) -o $@ -icon.o: ../../../resources/ico/carla.rc +icon.o: ../../utils/distrho.rc $(WINDRES) -i $< -o $@ -O coff clean: diff --git a/docs/BUILDING.md b/docs/BUILDING.md index cbcbcbef..127bf9bf 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -22,7 +22,7 @@ Use them as `make SOMEOPTION=SOMEVALUE` syntax. You can specify as many options Developer related options: * `DEBUG=true` build non-stripped debug binaries (terrible performance, only useful for developers) -* `NOPLUGINS=true` build only the Cardinal Core plugins (not recommended, only useful for developers) +* `NOSIMD=true` build without SIMD (not recommended, only useful for developers) Packaging related options: @@ -51,7 +51,7 @@ Dependencies for using system libraries: ``` # common -sudo pkg install -A dbus libglvnd liblo libsndfile libX11 libXcursor libXext libXrandr python3 +sudo pkg install -A cmake dbus fftw libglvnd liblo libsndfile libX11 libXcursor libXext libXrandr python3 # system libraries sudo pkg install -A libarchive libsamplerate jansson speexdsp ``` @@ -67,7 +67,7 @@ Dependencies for using system libraries, that is, with `SYSDEPS=true`: ``` # common -sudo pacman -S dbus file libgl liblo libsndfile libx11 libxcursor libxext libxrandr python3 +sudo pacman -S cmake dbus file fftw libgl liblo libsndfile libx11 libxcursor libxext libxrandr python3 # system libraries sudo pacman -S libarchive libsamplerate jansson speexdsp ``` @@ -76,9 +76,9 @@ Dependencies for vendored libraries: ``` # common -sudo pacman -S dbus file libgl liblo libsndfile libx11 libxcursor libxext libxrandr python3 +sudo pacman -S cmake dbus file fftw libgl liblo libsndfile libx11 libxcursor libxext libxrandr python3 # nedeed by vendored libraries -sudo pacman -S cmake wget +sudo pacman -S wget ``` ### Debian @@ -87,7 +87,7 @@ Dependencies for using system libraries, that is, with `SYSDEPS=true`: ``` # common -sudo apt install libdbus-1-dev libgl1-mesa-dev liblo-dev libmagic-dev libsndfile1-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev python3 +sudo apt install cmake libdbus-1-dev libgl1-mesa-dev liblo-dev libfftw3-dev libmagic-dev libsndfile1-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev python3 # system libraries sudo apt install libarchive-dev libjansson-dev libsamplerate0-dev libspeexdsp-dev ``` @@ -96,9 +96,9 @@ Dependencies for vendored libraries: ``` # common -sudo apt install libdbus-1-dev libgl1-mesa-dev liblo-dev libmagic-dev libsndfile1-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev python3 +sudo apt install cmake libdbus-1-dev libgl1-mesa-dev liblo-dev libfftw3-dev libmagic-dev libsndfile1-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev python3 # nedeed by vendored libraries -sudo apt install cmake wget +sudo apt install wget ``` ## macOS @@ -115,20 +115,50 @@ export CXXFLAGS="${CFLAGS}" # make etc.. ``` +## Web assembly + +Cardinal uses emscripten for its web version, see the official instructions on installing emscripten [here](https://emscripten.org/docs/getting_started/downloads.html). +Once installed, setup the build by importing the emscripten environment and setup the default build tools to point to them, like so: + +``` +source /path/to/emsdk/emsdk_env.sh +export AR=emar +export CC=emcc +export CXX=em++ +export NM=emnm +export RANLIB=emranlib +export STRIP=emstrip +``` + +Then for the actual build we just need to force graphics rendering to use GLES2 instead of the default "desktop" OpenGL mode, like so: + +``` +make USE_GLES2=true # add any other relevant options.. +``` + +You can place the generated files on a webserver, or run `emrun bin/CardinalNative.html` for an easy way to test it. + +Please note the web build only contains CardinalNative, no other variants will be built. +This is expected and intentional. + ## Windows Cardinal does not support msvc, using mingw is required. -You can either cross-compile Cardinal for Windows from Linux, or install and use msys2 natively on a Windows system. +It also requires a file-system with support for symbolic links, which Windows cannot do. +For these reasons it is only possible to build Cardinal for Windows from a Linux, macOS or any regular POSIX system. ### Cross-compile For cross-compilation, first install the relevant mingw packages. On Ubuntu these are `binutils-mingw-w64-x86-64 g++-mingw-w64-x86-64 mingw-w64`. -Then build with `CC` and `CXX` pointing to the mingw compiler, like so: +Then build with `AR`, `CC` and `CXX` pointing to the mingw compiler tools, like so: ``` +export AR=x86_64-w64-mingw32-gcc export CC=x86_64-w64-mingw32-gcc export CXX=x86_64-w64-mingw32-g++ +export EXE_WRAPPER=wine # for running generated windows binaries +export PKG_CONFIG=false # ignore pkg-config from base system # make etc.. ``` diff --git a/docs/CARDINAL-MODULES.md b/docs/CARDINAL-MODULES.md index 04a0b5c9..26124c6a 100644 --- a/docs/CARDINAL-MODULES.md +++ b/docs/CARDINAL-MODULES.md @@ -4,6 +4,22 @@ This file contains documentation for the DISTRHO Cardinal modules. ## Main modules +### AIDA-X + +![screenshot](Module_AIDA-X.png) + +[AIDA-X](https://github.com/AidaDSP/AIDA-X) is an Amp Model Player leveraging AI and machine learning, with a target of providing high fidelity simulations of guitar amplifiers. +It is also possible to run entire signal chains consisting of any combination of amp, cab, dist, drive, fuzz, boost and eq. + +The module loads AIDA-X files that have been trained to match a desired sound output. +Right-click on the module and select "Load model file..." to load an AIDA-X model file from disk. + +A quick model pack can be downloaded from [AIDA DSP's Google Drive folder](https://drive.google.com/drive/folders/18MwNhuo9fjK8hlne6SAdhpGtL4bWsVz-). + +Check out the [MOD Forum's Neural Modelling section](https://forum.mod.audio/c/neural/62) for an online place for discussion, sharing and all things related to Amp Models. + +This module is a port of the [AIDA-X audio plugin](https://github.com/AidaDSP/AIDA-X), also available separately. + ### Audio File ![screenshot](Module_AudioFile.png) diff --git a/docs/DIFFERENCES.md b/docs/DIFFERENCES.md index cbf1bb33..024b81d8 100644 --- a/docs/DIFFERENCES.md +++ b/docs/DIFFERENCES.md @@ -20,26 +20,28 @@ Bellow follows a list of features comparing the official plugin to Cardinal. | Contains internal modules | Core only | Everything is internal | | | Loads external modules | Yes | No | | | Supports closed-source modules | Yes | No | | -| Supports physical devices | Yes | No | Audio + MIDI only through the DAW/Host or via JACK in standalone | -| Plugin in AU format | No | Yes | | +| Supports physical devices | Yes | No (*) | CardinalNative binary provides native audio+midi as standalone | +| Plugin in AU format | Yes | Yes | | | Plugin in LV2 format | No | Yes | | | Plugin in VST2 format | Yes | Yes | | -| Plugin in VST3 format | No | Yes | | -| Plugin in CLAP format | No | WIP | | +| Plugin in VST3 format | Yes | Yes | | +| Plugin in CLAP format | Yes | Yes | | | Plugin inside itself | No, will crash | Yes | Technical limitations prevent Rack Pro from loading inside itself | +| Module processing order | Same as insertion order | Based on cable connections | In Cardinal module processing order changes automatically depending on cable connections | | Multi-threaded engine | Yes | No, uses host audio thread | Intentional in Cardinal, for removing jitter | -| Supports ARM systems | No | Yes | This means Apple M1 too, yes | +| Supports ARM systems | WIP | Yes | This means Apple M1 too, yes | | Supports BSD systems | No | Yes | Available as FreeBSD port | +| Supports RISC-V systems | No | Yes | | | Synth plugin variant | 16 ins, 16 outs | 2 ins, 2 outs | | | FX plugin variant | 16 ins, 16 outs | 2 ins, 2 outs | | | Raw-CV plugin variant | Unsupported | 8 audio IO + 10 CV IO | Available in JACK, LV2 and VST3 formats, not possible in AU and VST2 | -| Arbitrary parameter automation | Yes | No | Unsupported in Cardinal, tricky to do for many plugin formats at once | +| Arbitrary parameter automation | Yes | No (*) | Static 24 automatable params, use Host Params/Map modules to map them to module parameters | | Integrated plugin host | No, Host payed separately | Yes, using Carla or Ildaeil | | | Host sync/timing | Using MIDI signals | Using dedicated module | | | Linux/X11 event handling | Runs on 2nd thread | Runs on main/GUI thread | | | v1 module compatibility | No | No, but with less restrictions | Module widgets can load resources at any point | | Online phone-home | Yes | No | Online access is strictly forbidden in Cardinal | -| Proper dark theme | No, only room brightness | Yes | All dark panel variants have explicit permission when required | +| Proper dark theme | WIP | Yes | All dark panel variants have explicit permission when required | | Proper Linux headless mode | No, always requires X11 | Yes | | Additionally, Cardinal contains the following built-in modules not present in the official plugin or standalone: @@ -48,6 +50,7 @@ Additionally, Cardinal contains the following built-in modules not present in th * Mog (never updated to v2) * mscHack (never updated to v2) * rackwindows + * AIDA-X * Audio File * Audio to CV Pitch converter * Carla Plugin Host diff --git a/docs/Docs_Remote-Control-1.png b/docs/Docs_Remote-Control-1.png new file mode 100644 index 00000000..7fc7a457 Binary files /dev/null and b/docs/Docs_Remote-Control-1.png differ diff --git a/docs/Docs_Remote-Control-2.png b/docs/Docs_Remote-Control-2.png new file mode 100644 index 00000000..8cbdfa0b Binary files /dev/null and b/docs/Docs_Remote-Control-2.png differ diff --git a/docs/FAQ.md b/docs/FAQ.md index abdceff8..17d19dae 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -43,10 +43,16 @@ where we discuss possible modules to include. ## Changes are lost on restart -This is intentional. -Cardinal is meant to be a self-contained plugin, and as such it does not save any files whatsoever. -This includes user preferences (like list of favourites) or last used project. -As a plugin, the state will be saved together with the host/DAW project. +This is intentional. Unlike VCV Rack, Cardinal does not automatically save. + +Also, different variants (main vs FX vs Synth) use different files for saving their settings, so there might be some confusion arising from that. +But on the other hand this allows you to have a different template and other defaults per variant, which is quite handy. + +## Scaling/High-DPI not working properly, how to fix it? + +Cardinal, using [DPF](https://github.com/DISTRHO/DPF), will try to automatically detect the system scaling and adjust to that. +On cases where that does not work you can set `DPF_SCALE_FACTOR` environment variable to a value of your choosing in order to force a custom scale factor. +Note that this applies to all DPF-based plugins and not just Cardinal. ## On BSD/Linux/X11 the menu item "Save As/Export..." does nothing diff --git a/docs/LICENSES.md b/docs/LICENSES.md index 70e6d9c0..318f82da 100644 --- a/docs/LICENSES.md +++ b/docs/LICENSES.md @@ -16,6 +16,7 @@ Bellow follows a list of all code licenses used in Cardinal and linked submodule | 21kHz | MIT | | | 8Mode | BSD-3-Clause | | | Aaron Static | MIT | | +| alef's bits | GPL-3.0-or-later | | | AlgoritmArte | GPL-3.0-or-later | | | Amalgamated Harmonics | BSD-3-Clause | | | Animated Circuits | GPL-3.0-or-later | | @@ -32,7 +33,9 @@ Bellow follows a list of all code licenses used in Cardinal and linked submodule | Catro/Modulo | BSD-3-Clause | | | cf | BSD-3-Clause | | | ChowDSP | GPL-3.0-or-later | | +| dBiz | GPL-3.0-or-later | | | DrumKit | CC0-1.0 | | +| EnigmaCurry | GPL-3.0-or-later | | | E-Series | GPL-3.0-or-later | | | ExpertSleepers Encoders | MIT | | | Extratone | GPL-3.0-or-later | | @@ -42,6 +45,7 @@ Bellow follows a list of all code licenses used in Cardinal and linked submodule | Glue the Giant | GPL-3.0-or-later | | | GoodSheperd | GPL-3.0-or-later | | | Grande | GPL-3.0-or-later | | +| H4N4 Modules | GPL-3.0-or-later | | | Hampton Harmonics | MIT | | | HetrickCV | CC0-1.0 | | | ihtsyn | GPL-3.0-or-later | | @@ -69,9 +73,13 @@ Bellow follows a list of all code licenses used in Cardinal and linked submodule | Prism | BSD-3-Clause | | | Rackwindows | MIT | | | repelzen | GPL-3.0-or-later | | +| RebelTech | GPL-2.0-or-later | | +| Sapphire | GPL-3.0-or-later | | | Sonus Modular | GPL-3.0-or-later | | | Starling Via | MIT | | | stocaudio | GPL-3.0-or-later | | +| Stoermelder Pack-One | GPL-3.0-or-later | | +| Surge XT | GPL-3.0-or-later | | | unless_modules | GPL-3.0-or-later | | | Valley | GPL-3.0-or-later | | | Voxglitch | GPL-3.0-or-later | | @@ -99,6 +107,7 @@ Below is a list of artwork licenses from plugins | 8Mode | BSD-3-Clause | No artwork specific license provided | | AaronStatic/* | MIT | No artwork specific license provided | | AaronStatic/fonts/PixelOperator.ttf | CC0-1.0 | | +| alefsbits/* | GPL-3.0-or-later | No artwork specific license provided | | Algoritmarte/* | GPL-3.0-or-later | No artwork specific license provided | | Algoritmarte/LEDSliderGreenHandle.svg | CC-BY-NC-4.0 | | | AmalgamatedHarmonics/* | BSD-3-Clause | No artwork specific license provided | @@ -122,8 +131,15 @@ Below is a list of artwork licenses from plugins | BaconPlugs/* | GPL-3.0-or-later | No artwork specific license provided | | BaconPlugs/midi/* | CC-BY-SA-3.0-DE | | | BaconPlugs/midi/beeth/* | ??? | Unused in Cardinal, taken from http://www.jsbach.net/ | -| BaconPlugs/1f953.svg | CC-BY-4.0 | | +| BaconPlugs/FiraMono-Regular.ttf | OFL-1.1-RFN | | +| BaconPlugs/Monitorica-Bd.ttf | CC-BY-SA-4.0 | | | BaconPlugs/Keypunch029.json | OFL-1.1 | | +| BaconPlugs/1f953.svg | CC-BY-4.0 | | +| BaconPlugs/1f60d.svg | CC-BY-4.0 | | +| BaconPlugs/HelpActive.svg | CC0-1.0 | | +| BaconPlugs/HelpActiveSmall.svg | CC0-1.0 | | +| BaconPlugs/SABROG-*.svg | CC0-1.0 | | +| BaconPlugs/sabrog-*.svg | CC0-1.0 | | | Bidoo/* | CC-BY-NC-ND-4.0 | [Special permission granted for runtime dark mode](https://github.com/sebastien-bouffier/Bidoo/issues/191) | | Befaco/components/* | CC-BY-NC-4.0 | | | Befaco/fonts/Segment7Standard.otf | OFL-1.1-RFN | | @@ -141,8 +157,15 @@ Below is a list of artwork licenses from plugins | cf/VT323-Regular.ttf | OFL-1.1-no-RFN | | | ChowDSP/* | GPL-3.0-or-later | Same license as source code | | ChowDSP/fonts/RobotoCondensed-*.ttf | Apache-2.0 | | +| dBiz/* | CC-BY-NC-ND-4.0 | | +| dBiz/DejaVuSansMono.ttf | Bitstream-Vera | | +| dBiz/ShareTechMono-Regular.ttf | OFL-1.1 | | | DrumKit/* | CC0-1.0 | | | DrumKit/component/NovaMono.ttf | OFL-1.1-RFN | | +| EnigmaCurry/res/fonts/dseg/* | OFL-1.1-RFN | | +| EnigmaCurry/res/fonts/Fantasque/* | OFL-1.1 | | +| EnigmaCurry/res/fonts/manrope/* | OFL-1.1 | | +| EnigmaCurry/res/*.svg | CC0-1.0 | | | E-Series/* | Custom | Copyright © Synthesis Technology, [used and distributed with permission](LICENSE-PERMISSIONS.md#eseries-paul-schreiber--synthtech) | | ExpertSleepers-Encoders/* | MIT | [Same license as source code](https://github.com/expertsleepersltd/vcvrack-encoders/issues/3) | | Extratone/* | GPL-3.0-or-later | [Same license as source code](https://github.com/EaterOfSheep/Extratone/issues/7) | @@ -153,6 +176,7 @@ Below is a list of artwork licenses from plugins | GlueTheGiant/fonts/DSEG7-* | OFL-1.1-RFN | | | GoodSheperd/* | GPL-3.0-or-later | No artwork specific license provided | | GrandeModular/* | CC-BY-NC-ND-4.0 | | +| h4n4-modules/* | GPL-3.0-or-later | No artwork specific license provided | | HamptonHarmonics/* | MIT | No artwork specific license provided | | HamptonHarmonics/PixelOperator.ttf | CC0-1.0 | | | HetrickCV/* | CC0-1.0 | | @@ -201,9 +225,16 @@ Below is a list of artwork licenses from plugins | Prism/RobotoCondensed-Regular.ttf | Apache-2.0 | | | Rackwindows/* | MIT | [Same license as source code](https://github.com/n0jo/rackwindows/issues/15) | | repelzen/* | CC-BY-SA-4.0 | | +| RebelTech/* | CC-BY-NC-4.0 | | +| Sapphire/* | GPL-3.0-or-later | No artwork specific license provided | | sonusmodular/* | GPL-3.0-or-later | [Same license as source code](https://gitlab.com/sonusdept/sonusmodular/-/issues/14) | | StarlingVia/* | MIT | No artwork specific license provided | | stocaudio/* | GPL-3.0-or-later | No artwork specific license provided | +| stoermelder-packone/* | GPL-3.0-or-later | No artwork specific license provided | +| stoermelder-packone/fonts/RedkostComic.otf | OFL-1.1-RFN | | +| surgext/* | GPL-3.0-or-later | | +| surgext/xt/* | CC-BY-NC-SA-4.0 | | +| surgext/xt/fonts/quicksand/* | OFL-1.1-RFN | | | unless_modules/* | CC-BY-NC-ND-4.0 | | | unless_modules/font/CuteFont-Regular.ttf| OFL-1.1 | | | unless_modules/font/Terminus.ttf | GPL-2.0-or-later | [Starting from v4.32, font license is OFL-1.1](https://files.ax86.net/terminus-ttf/#license) | diff --git a/docs/Module_AIDA-X.png b/docs/Module_AIDA-X.png new file mode 100644 index 00000000..c8572c0c Binary files /dev/null and b/docs/Module_AIDA-X.png differ diff --git a/docs/OSC-REMOTE-CONTROL.md b/docs/OSC-REMOTE-CONTROL.md new file mode 100644 index 00000000..68673175 --- /dev/null +++ b/docs/OSC-REMOTE-CONTROL.md @@ -0,0 +1,63 @@ +# OSC Remote Control + +OSC (Open Sound Control) is a protocol commonly used for remote control over the network. +Starting with version 23.09, Cardinal allows remote control of the entire patch/project and individual parameters through OSC. + +Please note **OSC Remote Control is not available when using Cardinal as a plugin**, only in standalone. + +## Activating remote control + +Make sure you are using version 23.09 or later of Cardinal, start up the standalone (both Native and JACK variants will work) and under "Engine" menu click on "Enable OSC remote control". + +![screenshot](Docs_Remote-Control-1.png "Screenshot") + +This will ask you for which network port to use, Cardinal will default to 2228. +Valid range is typically between 1025 and 32767. +If unsure just stick the default value. + +![screenshot](Docs_Remote-Control-2.png "Screenshot") + +Depending on the OS security features you might be asked to allow network usage at this point. +If all went well opening the "Engine" menu again should show a checkmark, indicating that OSC remote control is enabled. + +For the moment there is no error dialog or information in case things go wrong. +If you are unable to connect, make sure your OS network firewall settings allows opening port 2228. + +## TouchOSC example setup + +A TouchOSC compatible file is available [here](https://github.com/DISTRHO/Cardinal/raw/main/patches/touchosc/24-direct-fader-params.tosc). + +It maps Cardinal's 24 parameters into 3 pages of sliders, 8 per page, each with a different color. +Inside Cardinal the Host Parameters and Host Parameters Map modules can be used as a way to control module knobs and other controls with it. + +## Available messages + +The following OSC messages are available: + +#### /hello + +Sending a `/hello` message will make Cardinal reply back with another hello, using `/resp` path and "hello" message. +Useful when testing if the connection works. + +#### /host-param i:port f:value + +Sending a `/host-param` message will set a port value of the "Host Params" module. +The port index starts from 0. + +There is no reply back from Cardinal. + +#### /param h:moduleId i:paramId f:value + +Sending a `/param` message will change the parameter value of any loaded module. +(TODO: describe a way to find the module and param id) + +There is no reply back from Cardinal. + +NOTE: the first argument must of be int64 type, as regular 32-bit integer is not enough to fit the whole range of values used inside Cardinal/Rack. + +#### /load b:patch-blob + +Sending a `/load` message will load the patch file contained in the message. +Patch contents must be in compressed format, not plain-text json. + +Cardinal replies back indicating either success or failure, using `/resp` path and "load" message. diff --git a/dpf b/dpf index 5ddaeefc..6876fd08 160000 --- a/dpf +++ b/dpf @@ -1 +1 @@ -Subproject commit 5ddaeefc47bd215c630b372304461a62f3464924 +Subproject commit 6876fd08ec9f0d1926158a4b60ed68ce9d33c6d4 diff --git a/include/OpenGL/gl.h b/include/OpenGL/gl.h new file mode 100644 index 00000000..da651aea --- /dev/null +++ b/include/OpenGL/gl.h @@ -0,0 +1,39 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the LICENSE file. + */ + +#pragma once + +#ifdef HEADLESS +# define GL_COLOR_BUFFER_BIT 0 +# define GL_DEPTH_BUFFER_BIT 0 +# define GL_STENCIL_BUFFER_BIT 0 +# define GL_PROJECTION 0 +# define GL_TRIANGLES 0 +static inline void glBegin(int) {} +static inline void glEnd() {} +static inline void glColor3f(float, float, float) {} +static inline void glVertex3f(float, float, float) {} +static inline void glClear(int) {} +static inline void glClearColor(double, double, double, double) {} +static inline void glLoadIdentity() {} +static inline void glMatrixMode(int) {} +static inline void glOrtho(double, double, double, double, double, double) {} +static inline void glViewport(double, double, double, double) {} +typedef unsigned int GLuint; +#else +# include_next +#endif diff --git a/include/common.hpp b/include/common.hpp index 4de06be9..f5ccbfc5 100644 --- a/include/common.hpp +++ b/include/common.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -97,3 +97,11 @@ void async_dialog_message(const char* message, std::function action); // opens a text input dialog, message and text can be null // action is always triggered on close (newText can be null), must be freed if not null void async_dialog_text_input(const char* message, const char* text, std::function action); + +// Cardinal specific config dir (might be equal to userDir) +namespace rack { +namespace asset { +extern std::string configDir; +std::string config(std::string filename = ""); +} +} diff --git a/include/engine/Port.hpp b/include/engine/Port.hpp index 12eb1364..9993a4ae 100644 --- a/include/engine/Port.hpp +++ b/include/engine/Port.hpp @@ -33,11 +33,7 @@ #include /** NOTE alignas is required in some systems in order to allow SSE usage. */ -#ifndef ARCH_MAC -#define SIMD_ALIGN alignas(32) -#else -#define SIMD_ALIGN -#endif +#define SIMD_ALIGN alignas(16) namespace rack { @@ -82,40 +78,40 @@ struct Port { }; /** Sets the voltage of the given channel. */ - void setVoltage(float voltage, int channel = 0) { + void setVoltage(float voltage, int channel = 0) noexcept { voltages[channel] = voltage; } /** Returns the voltage of the given channel. Because of proper bookkeeping, all channels higher than the input port's number of channels should be 0V. */ - float getVoltage(int channel = 0) { + float getVoltage(int channel = 0) const noexcept { return voltages[channel]; } /** Returns the given channel's voltage if the port is polyphonic, otherwise returns the first voltage (channel 0). */ - float getPolyVoltage(int channel) { + float getPolyVoltage(int channel) const noexcept { return isMonophonic() ? getVoltage(0) : getVoltage(channel); } /** Returns the voltage if a cable is connected, otherwise returns the given normal voltage. */ - float getNormalVoltage(float normalVoltage, int channel = 0) { + float getNormalVoltage(float normalVoltage, int channel = 0) const noexcept { return isConnected() ? getVoltage(channel) : normalVoltage; } - float getNormalPolyVoltage(float normalVoltage, int channel) { + float getNormalPolyVoltage(float normalVoltage, int channel) const noexcept { return isConnected() ? getPolyVoltage(channel) : normalVoltage; } /** Returns a pointer to the array of voltages beginning with firstChannel. The pointer can be used for reading and writing. */ - float* getVoltages(int firstChannel = 0) { + float* getVoltages(int firstChannel = 0) noexcept { return &voltages[firstChannel]; } /** Copies the port's voltages to an array of size at least `channels`. */ - void readVoltages(float* v) { + void readVoltages(float* v) const noexcept { for (int c = 0; c < channels; c++) { v[c] = voltages[c]; } @@ -131,14 +127,14 @@ struct Port { } /** Sets all voltages to 0. */ - void clearVoltages() { + void clearVoltages() noexcept { for (int c = 0; c < channels; c++) { voltages[c] = 0.f; } } /** Returns the sum of all voltages. */ - float getVoltageSum() { + float getVoltageSum() const noexcept { float sum = 0.f; for (int c = 0; c < channels; c++) { sum += voltages[c]; @@ -149,7 +145,7 @@ struct Port { /** Returns the root-mean-square of all voltages. Uses sqrt() which is slow, so use a custom approximation if calling frequently. */ - float getVoltageRMS() { + float getVoltageRMS() const { if (channels == 0) { return 0.f; } @@ -166,22 +162,22 @@ struct Port { } template - T getVoltageSimd(int firstChannel) { + T getVoltageSimd(int firstChannel) const noexcept { return T::load(&voltages[firstChannel]); } template - T getPolyVoltageSimd(int firstChannel) { + T getPolyVoltageSimd(int firstChannel) const noexcept { return isMonophonic() ? getVoltage(0) : getVoltageSimd(firstChannel); } template - T getNormalVoltageSimd(T normalVoltage, int firstChannel) { + T getNormalVoltageSimd(T normalVoltage, int firstChannel) const noexcept { return isConnected() ? getVoltageSimd(firstChannel) : normalVoltage; } template - T getNormalPolyVoltageSimd(T normalVoltage, int firstChannel) { + T getNormalPolyVoltageSimd(T normalVoltage, int firstChannel) const noexcept { return isConnected() ? getPolyVoltageSimd(firstChannel) : normalVoltage; } @@ -195,13 +191,15 @@ struct Port { If disconnected, this does nothing (`channels` remains 0). If 0 is given, `channels` is set to 1 but all voltages are cleared. */ - void setChannels(int channels) { + void setChannels(int channels) noexcept { // If disconnected, keep the number of channels at 0. if (this->channels == 0) { return; } // Set higher channel voltages to 0 for (int c = channels; c < this->channels; c++) { + if (c >= PORT_MAX_CHANNELS) + __builtin_unreachable(); voltages[c] = 0.f; } // Don't allow caller to set port as disconnected @@ -214,29 +212,29 @@ struct Port { /** Returns the number of channels. If the port is disconnected, it has 0 channels. */ - int getChannels() { + int getChannels() const noexcept { return channels; } /** Returns whether a cable is connected to the Port. You can use this for skipping code that generates output voltages. */ - bool isConnected() { + bool isConnected() const noexcept { return channels > 0; } /** Returns whether the cable exists and has 1 channel. */ - bool isMonophonic() { + bool isMonophonic() const noexcept { return channels == 1; } /** Returns whether the cable exists and has more than 1 channel. */ - bool isPolyphonic() { + bool isPolyphonic() const noexcept { return channels > 1; } /** Use getNormalVoltage() instead. */ - DEPRECATED float normalize(float normalVoltage) { + DEPRECATED float normalize(float normalVoltage) const noexcept { return getNormalVoltage(normalVoltage); } }; diff --git a/include/helpers.hpp b/include/helpers.hpp index 7126f3f5..8ffbe7f5 100644 --- a/include/helpers.hpp +++ b/include/helpers.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -36,6 +36,12 @@ namespace rack { +#ifndef HEADLESS +namespace asset { +void updateForcingBlackSilverScrewMode(std::string slug); +} +#endif + struct CardinalPluginModelHelper : plugin::Model { virtual app::ModuleWidget* createModuleWidgetFromEngineLoad(engine::Module* m) = 0; virtual void removeCachedModuleWidget(engine::Module* m) = 0; @@ -47,6 +53,11 @@ struct CardinalPluginModel : CardinalPluginModelHelper std::unordered_map widgets; std::unordered_map widgetNeedsDeletion; + CardinalPluginModel(const std::string slug) + { + this->slug = slug; + } + engine::Module* createModule() override { engine::Module* const m = new TModule; @@ -67,6 +78,9 @@ struct CardinalPluginModel : CardinalPluginModelHelper } tm = dynamic_cast(m); } + #ifndef HEADLESS + asset::updateForcingBlackSilverScrewMode(slug); + #endif app::ModuleWidget* const tmw = new TModuleWidget(tm); DISTRHO_CUSTOM_SAFE_ASSERT_RETURN(m != nullptr ? m->model->name.c_str() : "null", tmw->module == m, nullptr); tmw->setModel(this); @@ -81,6 +95,9 @@ struct CardinalPluginModel : CardinalPluginModelHelper TModule* const tm = dynamic_cast(m); DISTRHO_SAFE_ASSERT_RETURN(tm != nullptr, nullptr); + #ifndef HEADLESS + asset::updateForcingBlackSilverScrewMode(slug); + #endif TModuleWidget* const tmw = new TModuleWidget(tm); DISTRHO_SAFE_ASSERT_RETURN(tmw->module == m, nullptr); tmw->setModel(this); @@ -107,11 +124,9 @@ struct CardinalPluginModel : CardinalPluginModelHelper }; template -CardinalPluginModel* createModel(std::string slug) +CardinalPluginModel* createModel(const std::string slug) { - CardinalPluginModel* const o = new CardinalPluginModel(); - o->slug = slug; - return o; + return new CardinalPluginModel(slug); } } diff --git a/include/linux-compat/execinfo.h b/include/linux-compat/execinfo.h index c569c92e..3057f462 100644 --- a/include/linux-compat/execinfo.h +++ b/include/linux-compat/execinfo.h @@ -17,19 +17,25 @@ #pragma once -#define pthread_setname_np(...) +#include -int pthread_getcpuclockid(pthread_t, clockid_t* const clock_id) +static inline +int pthread_getcpuclockid_custom(pthread_t, clockid_t* const clock_id) { *clock_id = CLOCK_REALTIME; return 0; } -static int backtrace(void**, int) +#define pthread_getcpuclockid pthread_getcpuclockid_custom +#define pthread_setname_np(...) + +static inline +int backtrace(void**, int) { return 0; } +static inline char** backtrace_symbols(void* const*, int) { return nullptr; diff --git a/include/mingw-compat/cstdio b/include/mingw-compat/cstdio deleted file mode 100644 index bdcb7e84..00000000 --- a/include/mingw-compat/cstdio +++ /dev/null @@ -1,58 +0,0 @@ -/* - * DISTRHO Cardinal Plugin - * Copyright (C) 2021 Filipe Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 3 of - * the License, or any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * For a full copy of the GNU General Public License see the LICENSE file. - */ - -#pragma once - -/* On mingw stdio functions like printf are not inline, and thus get defined every time they are used. - * Its also does `#undef printf` which invalidates our macros :( - * We go through a few steps to ensure unique symbol names. - */ -#ifdef STDIO_OVERRIDE - -// helper macros -# define STDIO_OVERRIDE_HELPER(NS, SEP, FN) NS ## SEP ## FN -# define STDIO_OVERRIDE_MACRO(NS, FN) STDIO_OVERRIDE_HELPER(NS, _, FN) - -// step 1: prefix the needed stdio functions -# define printf STDIO_OVERRIDE_MACRO(STDIO_OVERRIDE, printf) - -// step 2: inlude which will use our prefixed names -# include - -// step 3: undef and define dummy functions required for (it uses `using ::printf` syntax) -# undef printf -static inline void printf() {} - -// step 4: we can safely include now -# include_next - -// step 5: define the same macros as in step 1 -# define printf STDIO_OVERRIDE_MACRO(STDIO_OVERRIDE, printf) - -// step 6: place the macro prefixed names in std namespace -/* -namespace std { - using ::printf; -} -*/ - -#else // STDIO_OVERRIDE - -// if STDIO_OVERRIDE is not defined, we have nothing to do -# include_next - -#endif // STDIO_OVERRIDE diff --git a/include/mingw-compat/mutex b/include/mingw-compat/mutex index 7b828929..ae24f4f1 100644 --- a/include/mingw-compat/mutex +++ b/include/mingw-compat/mutex @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,8 +17,8 @@ #pragma once #include_next -#include "mingw.mutex.h" +// fix macro pollution from Windows headers #undef IN #undef OUT #undef far diff --git a/include/mingw-compat/thread b/include/mingw-compat/thread index 2d5cb43f..24fb7d2d 100644 --- a/include/mingw-compat/thread +++ b/include/mingw-compat/thread @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,8 +17,8 @@ #pragma once #include_next -#include "mingw.thread.h" +// fix macro pollution from Windows headers #undef IN #undef OUT #undef far diff --git a/include/mingw-std-threads b/include/mingw-std-threads deleted file mode 160000 index f6365f90..00000000 --- a/include/mingw-std-threads +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f6365f900fb9b1cd6014c8d1cf13ceacf8faf3de diff --git a/include/rack.hpp b/include/simd-compat/emmintrin.h similarity index 57% rename from include/rack.hpp rename to include/simd-compat/emmintrin.h index 3ca4cc64..1fc6dc07 100644 --- a/include/rack.hpp +++ b/include/simd-compat/emmintrin.h @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,19 +17,10 @@ #pragma once -#include_next - -#ifdef BUILDING_PLUGIN_MODULES -namespace rack { -namespace app { -struct CardinalModuleWidget : ModuleWidget { - CardinalModuleWidget() : ModuleWidget() {} - DEPRECATED CardinalModuleWidget(engine::Module* module) : ModuleWidget() { - setModule(module); - } - void onButton(const ButtonEvent& e) override; -}; -} -} -# define ModuleWidget CardinalModuleWidget +#if (defined(__i386__) || defined(__x86_64__) || defined(__EMSCRIPTEN__)) && !defined(CARDINAL_NOSIMD) +# include_next +#else +# define SIMDE_ENABLE_NATIVE_ALIASES +# include "simde/x86/sse.h" +# undef SIMDE_ENABLE_NATIVE_ALIASES #endif diff --git a/include/simd-compat/immintrin.h b/include/simd-compat/immintrin.h new file mode 100644 index 00000000..3490cb80 --- /dev/null +++ b/include/simd-compat/immintrin.h @@ -0,0 +1,27 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the LICENSE file. + */ + +#pragma once + +#if (defined(__i386__) || defined(__x86_64__) || defined(__EMSCRIPTEN__)) && !defined(CARDINAL_NOSIMD) +# include_next +#else +# define SIMDE_ENABLE_NATIVE_ALIASES +# include "../simde/simde/x86/sse.h" +# include "../simde/simde/x86/sse2.h" +# undef SIMDE_ENABLE_NATIVE_ALIASES +#endif diff --git a/include/simd-compat/mmintrin.h b/include/simd-compat/mmintrin.h index ce019805..3ca24af5 100644 --- a/include/simd-compat/mmintrin.h +++ b/include/simd-compat/mmintrin.h @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,10 +17,12 @@ #pragma once -#if defined(__i386__) || defined(__x86_64__) +#if (defined(__i386__) || defined(__x86_64__)) && !defined(CARDINAL_NOSIMD) # include_next -#elif defined(__EMSCRIPTEN__) +#elif defined(__EMSCRIPTEN__) && !defined(CARDINAL_NOSIMD) # include #else -# include "../sse2neon/sse2neon.h" +# define SIMDE_ENABLE_NATIVE_ALIASES +# include "../simde/simde/x86/mmx.h" +# undef SIMDE_ENABLE_NATIVE_ALIASES #endif diff --git a/include/simd-compat/pmmintrin.h b/include/simd-compat/pmmintrin.h index 45fa3fb1..8ba6b36d 100644 --- a/include/simd-compat/pmmintrin.h +++ b/include/simd-compat/pmmintrin.h @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,19 +17,43 @@ #pragma once -#if defined(__i386__) || defined(__x86_64__) +#if (defined(__i386__) || defined(__x86_64__)) && !defined(CARDINAL_NOSIMD) # include_next -#elif defined(__EMSCRIPTEN__) +// bring in extra SSE3 support via simde +# define SIMDE_X86_SSE2_NATIVE +# define SIMDE_X86_SSE3_ENABLE_NATIVE_ALIASES + +// make sure to not include windows.h here +# ifdef _WIN32 +# define _WIN32_WAS_DEFINED +# undef _WIN32 +# endif + +// assume SSE3 only on macOS +# ifndef ARCH_MAC +# include "simde/x86/sse3.h" +# endif + +# ifdef _WIN32_WAS_DEFINED +# define _WIN32 +# undef _WIN32_WAS_DEFINED +# endif + +# undef SIMDE_X86_SSE2_NATIVE +# undef SIMDE_X86_SSE3_ENABLE_NATIVE_ALIASES + +#elif defined(__EMSCRIPTEN__) && !defined(CARDINAL_NOSIMD) # include_next -static inline -__m64 _mm_set1_pi16(short w) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_mm_set1_pi16(short w) { return __extension__ (__m64){ static_cast(w), static_cast(w) }; } -#else +/* +#elif defined(__ARM_NEON) # include "../sse2neon/sse2neon.h" static inline @@ -43,5 +67,12 @@ __m64 _mm_set1_pi16(short w) { return vreinterpret_s64_s16(vdup_n_s16(w)); } +*/ +#else +# define SIMDE_ENABLE_NATIVE_ALIASES +# include "simde/x86/sse.h" +# include "simde/x86/sse2.h" +# include "simde/x86/sse3.h" +# undef SIMDE_ENABLE_NATIVE_ALIASES #endif diff --git a/include/simd-compat/xmmintrin.h b/include/simd-compat/xmmintrin.h new file mode 100644 index 00000000..35008937 --- /dev/null +++ b/include/simd-compat/xmmintrin.h @@ -0,0 +1,26 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the LICENSE file. + */ + +#pragma once + +#if (defined(__i386__) || defined(__x86_64__) || defined(__EMSCRIPTEN__)) && !defined(CARDINAL_NOSIMD) +# include_next +#else +# define SIMDE_ENABLE_NATIVE_ALIASES +# include "simde/x86/avx.h" +# undef SIMDE_ENABLE_NATIVE_ALIASES +#endif diff --git a/include/simd/Vector.hpp b/include/simd/Vector.hpp index 7dd77ada..091af1b1 100644 --- a/include/simd/Vector.hpp +++ b/include/simd/Vector.hpp @@ -31,11 +31,7 @@ #include /** NOTE alignas is required in some systems in order to allow SSE usage. */ -#ifndef ARCH_MAC -#define SIMD_ALIGN alignas(32) -#else -#define SIMD_ALIGN -#endif +#define SIMD_ALIGN alignas(16) namespace rack { @@ -359,12 +355,12 @@ inline Vector operator~(const Vector& a) { /** `a << b` */ inline Vector operator<<(const Vector& a, const int& b) { - return Vector(_mm_slli_epi32(a.v, b)); + return Vector(_mm_sll_epi32(a.v, _mm_cvtsi32_si128(b))); } /** `a >> b` */ inline Vector operator>>(const Vector& a, const int& b) { - return Vector(_mm_srli_epi32(a.v, b)); + return Vector(_mm_srl_epi32(a.v, _mm_cvtsi32_si128(b))); } diff --git a/include/single-precision/algorithm b/include/single-precision/algorithm index 12cdd75b..0142c17b 100644 --- a/include/single-precision/algorithm +++ b/include/single-precision/algorithm @@ -26,6 +26,11 @@ float max(const float a, const double b) { return std::max(a, static_cast(b)); } +static inline +float min(const float a, const double b) { + return std::min(a, static_cast(b)); +} + static inline std::complex operator*(const std::complex& a, const float b) { return static_cast>(a) * b; diff --git a/include/sse2neon b/include/sse2neon deleted file mode 160000 index 1dfa4011..00000000 --- a/include/sse2neon +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1dfa40113a03a682dc79ba42235c5b0d1c50aaf2 diff --git a/jucewrapper/CMakeLists.txt b/jucewrapper/CMakeLists.txt index 099ff1d0..6239e257 100644 --- a/jucewrapper/CMakeLists.txt +++ b/jucewrapper/CMakeLists.txt @@ -1,7 +1,13 @@ cmake_minimum_required(VERSION 3.15) -project(Cardinal VERSION 22.09) +project(Cardinal VERSION 23.10) -add_subdirectory(JUCE) +include(FetchContent) +FetchContent_Declare(JUCE + GIT_REPOSITORY https://github.com/DISTRHO/JUCE.git + GIT_TAG v6.1.6 + GIT_SHALLOW TRUE +) +FetchContent_MakeAvailable(JUCE) # Config @@ -37,9 +43,6 @@ set_property(TARGET lilv PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../ca add_library(rtmempool STATIC IMPORTED) set_property(TARGET rtmempool PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../carla/build/modules/${CMAKE_BUILD_TYPE}/rtmempool.a") -add_library(sfzero STATIC IMPORTED) -set_property(TARGET sfzero PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../carla/build/modules/${CMAKE_BUILD_TYPE}/sfzero.a") - add_library(water STATIC IMPORTED) set_property(TARGET water PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../carla/build/modules/${CMAKE_BUILD_TYPE}/water.a") @@ -89,6 +92,30 @@ set_property(TARGET libspeexdsp PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR add_library(libzstd STATIC IMPORTED) set_property(TARGET libzstd PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../src/Rack/dep/lib/libzstd.a") +set(SURGE_DEP_PATH "${PROJECT_SOURCE_DIR}/../deps/surge-build") + +add_library(surgedep01 STATIC IMPORTED) +add_library(surgedep02 STATIC IMPORTED) +add_library(surgedep03 STATIC IMPORTED) +add_library(surgedep04 STATIC IMPORTED) +add_library(surgedep05 STATIC IMPORTED) +add_library(surgedep06 STATIC IMPORTED) +add_library(surgedep07 STATIC IMPORTED) +#add_library(surgedep08 STATIC IMPORTED) +add_library(surgedep09 STATIC IMPORTED) +add_library(surgedep10 STATIC IMPORTED) + +set_property(TARGET surgedep01 PROPERTY IMPORTED_LOCATION "${SURGE_DEP_PATH}/src/common/libsurge-common.a") +set_property(TARGET surgedep02 PROPERTY IMPORTED_LOCATION "${SURGE_DEP_PATH}/src/common/libjuce_dsp_rack_sub.a") +set_property(TARGET surgedep03 PROPERTY IMPORTED_LOCATION "${SURGE_DEP_PATH}/libs/airwindows/libairwindows.a") +set_property(TARGET surgedep04 PROPERTY IMPORTED_LOCATION "${SURGE_DEP_PATH}/libs/eurorack/libeurorack.a") +set_property(TARGET surgedep05 PROPERTY IMPORTED_LOCATION "${SURGE_DEP_PATH}/libs/fmt/libfmt.a") +set_property(TARGET surgedep06 PROPERTY IMPORTED_LOCATION "${SURGE_DEP_PATH}/libs/sqlite-3.23.3/libsqlite.a") +set_property(TARGET surgedep07 PROPERTY IMPORTED_LOCATION "${SURGE_DEP_PATH}/libs/sst/sst-plugininfra/libsst-plugininfra.a") +#set_property(TARGET surgedep08 PROPERTY IMPORTED_LOCATION "${SURGE_DEP_PATH}/libs/sst/sst-plugininfra/libs/filesystem/libfilesystem.a") +set_property(TARGET surgedep09 PROPERTY IMPORTED_LOCATION "${SURGE_DEP_PATH}/libs/sst/sst-plugininfra/libs/strnatcmp/libstrnatcmp.a") +set_property(TARGET surgedep10 PROPERTY IMPORTED_LOCATION "${SURGE_DEP_PATH}/libs/sst/sst-plugininfra/libs/tinyxml/libtinyxml.a") + # dependencies find_package(PkgConfig REQUIRED) @@ -139,6 +166,7 @@ target_sources(Cardinal target_include_directories(Cardinal PRIVATE ../dpf/distrho + ../dpf/dgl/src/pugl-upstream/include ../src/Cardinal) target_compile_definitions(Cardinal @@ -155,9 +183,9 @@ target_compile_definitions(Cardinal JUCE_USE_OGGVORBIS=0 JUCE_USE_XINERAMA=0 JUCE_VST3_CAN_REPLACE_VST2=0 - JUCE_ALSA=1 + JUCE_ALSA=0 JUCE_DIRECTSOUND=0 - JUCE_JACK=1 + JUCE_JACK=0 JUCE_WASAPI=0 JUCE_WEB_BROWSER=0) @@ -176,11 +204,20 @@ target_link_libraries(Cardinal jackbridge lilv rtmempool - sfzero water ysfx zita_resampler dgl + surgedep01 + surgedep02 + surgedep03 + surgedep04 + surgedep05 + surgedep06 + surgedep07 + #surgedep08 + surgedep09 + surgedep10 libaubio libarchive libjansson @@ -203,7 +240,6 @@ target_link_libraries(Cardinal -lmagic PUBLIC juce::juce_recommended_config_flags - juce::juce_recommended_lto_flags juce::juce_recommended_warning_flags) #]] @@ -232,6 +268,7 @@ target_sources(CardinalFX target_include_directories(CardinalFX PRIVATE ../dpf/distrho + ../dpf/dgl/src/pugl-upstream/include ../src/CardinalFX) target_compile_definitions(CardinalFX @@ -248,9 +285,9 @@ target_compile_definitions(CardinalFX JUCE_USE_OGGVORBIS=0 JUCE_USE_XINERAMA=0 JUCE_VST3_CAN_REPLACE_VST2=0 - JUCE_ALSA=1 + JUCE_ALSA=0 JUCE_DIRECTSOUND=0 - JUCE_JACK=1 + JUCE_JACK=0 JUCE_WASAPI=0 JUCE_WEB_BROWSER=0) @@ -269,11 +306,121 @@ target_link_libraries(CardinalFX jackbridge lilv rtmempool - sfzero water ysfx zita_resampler dgl + surgedep01 + surgedep02 + surgedep03 + surgedep04 + surgedep05 + surgedep06 + surgedep07 + #surgedep08 + surgedep09 + surgedep10 + libaubio + libarchive + libjansson + libquickjs + libsamplerate + libspeexdsp + libzstd + ${STATIC_LIBS_END} + ${GL_LIBRARIES} + ${DBUS_LIBRARIES} + -L${LIBLO_LIBRARY_DIRS} + ${FFTW3F_LIBRARIES} + ${LIBLO_LIBRARIES} + ${SNDFILE_LIBRARIES} + ${X11_LIBRARIES} + ${XCURSOR_LIBRARIES} + ${XEXT_LIBRARIES} + ${XRANDR_LIBRARIES} + ${EXTRA_LIBS} + -lmagic + PUBLIC + juce::juce_recommended_config_flags + juce::juce_recommended_warning_flags) + +# MIDI variant + +juce_add_plugin(CardinalMIDI + AU_MAIN_TYPE kAudioUnitType_MIDIProcessor + COMPANY_COPYRIGHT "GPL-3.0-or-later" + COMPANY_NAME "DISTRHO" + COMPANY_WEBSITE "https://github.com/DISTRHO/Cardinal" + DESCRIPTION "Virtual modular synthesizer plugin" + EDITOR_WANTS_KEYBOARD_FOCUS FALSE + FORMATS ${PLUGIN_FORMATS} + IS_MIDI_EFFECT TRUE + IS_SYNTH FALSE + NEEDS_MIDI_INPUT TRUE + NEEDS_MIDI_OUTPUT TRUE + PLUGIN_CODE DcnM + PLUGIN_MANUFACTURER_CODE Dstr + PRODUCT_NAME "CardinalMIDI") + +target_sources(CardinalMIDI + PRIVATE + CardinalWrapper.cpp) + +target_include_directories(CardinalMIDI + PRIVATE + ../dpf/distrho + ../dpf/dgl/src/pugl-upstream/include + ../src/CardinalFX) + +target_compile_definitions(CardinalMIDI + PUBLIC + DISTRHO_NAMESPACE=CardinalDISTRHO + DGL_NAMESPACE=CardinalDGL + JucePlugin_PreferredChannelConfigurations=2,2 + JUCE_CHECK_MEMORY_LEAKS=0 + JUCE_DISABLE_NATIVE_FILECHOOSERS=1 + JUCE_DISPLAY_SPLASH_SCREEN=0 + JUCE_MODAL_LOOPS_PERMITTED=0 + JUCE_USE_CURL=0 + JUCE_USE_FLAC=0 + JUCE_USE_OGGVORBIS=0 + JUCE_USE_XINERAMA=0 + JUCE_VST3_CAN_REPLACE_VST2=0 + JUCE_ALSA=0 + JUCE_DIRECTSOUND=0 + JUCE_JACK=0 + JUCE_WASAPI=0 + JUCE_WEB_BROWSER=0) + +target_link_libraries(CardinalMIDI + PRIVATE + juce::juce_audio_utils + ${STATIC_LIBS_START} + sPlugins + sCardinalFX + sRack + carla_host_plugin + carla_engine_plugin + carla_plugin + native_plugins + audio_decoder + jackbridge + lilv + rtmempool + water + ysfx + zita_resampler + dgl + surgedep01 + surgedep02 + surgedep03 + surgedep04 + surgedep05 + surgedep06 + surgedep07 + #surgedep08 + surgedep09 + surgedep10 libaubio libarchive libjansson @@ -296,7 +443,6 @@ target_link_libraries(CardinalFX -lmagic PUBLIC juce::juce_recommended_config_flags - juce::juce_recommended_lto_flags juce::juce_recommended_warning_flags) # Synth variant @@ -324,6 +470,7 @@ target_sources(CardinalSynth target_include_directories(CardinalSynth PRIVATE ../dpf/distrho + ../dpf/dgl/src/pugl-upstream/include ../src/CardinalSynth) target_compile_definitions(CardinalSynth @@ -340,9 +487,9 @@ target_compile_definitions(CardinalSynth JUCE_USE_OGGVORBIS=0 JUCE_USE_XINERAMA=0 JUCE_VST3_CAN_REPLACE_VST2=0 - JUCE_ALSA=1 + JUCE_ALSA=0 JUCE_DIRECTSOUND=0 - JUCE_JACK=1 + JUCE_JACK=0 JUCE_WASAPI=0 JUCE_WEB_BROWSER=0) @@ -361,11 +508,20 @@ target_link_libraries(CardinalSynth jackbridge lilv rtmempool - sfzero water ysfx zita_resampler dgl + surgedep01 + surgedep02 + surgedep03 + surgedep04 + surgedep05 + surgedep06 + surgedep07 + #surgedep08 + surgedep09 + surgedep10 libaubio libarchive libjansson @@ -388,5 +544,4 @@ target_link_libraries(CardinalSynth -lmagic PUBLIC juce::juce_recommended_config_flags - juce::juce_recommended_lto_flags juce::juce_recommended_warning_flags) diff --git a/jucewrapper/CardinalWrapper.cpp b/jucewrapper/CardinalWrapper.cpp index a4fd7e1f..562c6f34 100644 --- a/jucewrapper/CardinalWrapper.cpp +++ b/jucewrapper/CardinalWrapper.cpp @@ -18,7 +18,7 @@ #include #include -#if MAC_OS_X_VERSION_MAX_ALLOWED > 101200 +#if MAC_OS_X_VERSION_MAX_ALLOWED > 101500 #error unwanted macOS version, too new #endif @@ -270,11 +270,11 @@ class CardinalWrapperProcessor : public juce::AudioProcessor { if (const double sampleRate = getSampleRate()) if (sampleRate > 0.0) - plugin.setSampleRate(sampleRate); + plugin.setSampleRate(sampleRate, true); if (const int samplesPerBlock = getBlockSize()) if (samplesPerBlock > 0) - plugin.setBufferSize(static_cast(samplesPerBlock)); + plugin.setBufferSize(static_cast(samplesPerBlock), true); if (parameterCount != 0) { @@ -313,8 +313,8 @@ class CardinalWrapperProcessor : public juce::AudioProcessor DISTRHO_SAFE_ASSERT_RETURN(samplesPerBlock > 0,); plugin.deactivateIfNeeded(); - plugin.setSampleRate(sampleRate); - plugin.setBufferSize(static_cast(samplesPerBlock)); + plugin.setSampleRate(sampleRate, true); + plugin.setBufferSize(static_cast(samplesPerBlock), true); plugin.activate(); } diff --git a/lv2export/Makefile b/lv2export/Makefile index 53ef3a1c..9e0fe7c7 100644 --- a/lv2export/Makefile +++ b/lv2export/Makefile @@ -59,7 +59,6 @@ ifeq ($(WINDOWS),true) BASE_FLAGS += -D_USE_MATH_DEFINES BASE_FLAGS += -DWIN32_LEAN_AND_MEAN BASE_FLAGS += -I../include/mingw-compat -BASE_FLAGS += -I../include/mingw-std-threads endif # -------------------------------------------------------------- diff --git a/lv2export/export.cpp b/lv2export/export.cpp index c058ea9c..41fa1794 100644 --- a/lv2export/export.cpp +++ b/lv2export/export.cpp @@ -15,25 +15,7 @@ * For a full copy of the GNU General Public License see the LICENSE file. */ -#ifndef PLUGIN_BRAND -# error PLUGIN_BRAND undefined -#endif - -#ifndef PLUGIN_LABEL -# error PLUGIN_LABEL undefined -#endif - -#ifndef PLUGIN_MODEL -# error PLUGIN_MODEL undefined -#endif - -#ifndef PLUGIN_CV_INPUTS -# error PLUGIN_CV_INPUTS undefined -#endif - -#ifndef PLUGIN_CV_OUTPUTS -# error PLUGIN_CV_OUTPUTS undefined -#endif +#include "lv2plugin.hpp" #include diff --git a/lv2export/lv2plugin.cpp b/lv2export/lv2plugin.cpp index e15e4b64..e2e2d524 100644 --- a/lv2export/lv2plugin.cpp +++ b/lv2export/lv2plugin.cpp @@ -15,26 +15,7 @@ * For a full copy of the GNU General Public License see the LICENSE file. */ -#ifndef PLUGIN_MODEL -# error PLUGIN_MODEL undefined -#endif - -#ifndef PLUGIN_CV_INPUTS -# error PLUGIN_CV_INPUTS undefined -#endif - -#ifndef PLUGIN_CV_OUTPUTS -# error PLUGIN_CV_OUTPUTS undefined -#endif - -enum PortType { - Audio = 0, - Bi = 1, - Uni = 2, -}; - -static constexpr const int kCvInputs[] = PLUGIN_CV_INPUTS; -static constexpr const int kCvOutputs[] = PLUGIN_CV_OUTPUTS; +#include "lv2plugin.hpp" #include "src/lv2/buf-size.h" #include "src/lv2/options.h" @@ -185,21 +166,19 @@ static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, cons // ----------------------------------------------------------------------- -#define instancePtr ((PluginLv2*)instance) - static void lv2_connect_port(LV2_Handle instance, uint32_t port, void* dataLocation) { - instancePtr->lv2_connect_port(port, dataLocation); + static_cast(instance)->lv2_connect_port(port, dataLocation); } static void lv2_run(LV2_Handle instance, uint32_t sampleCount) { - instancePtr->lv2_run(sampleCount); + static_cast(instance)->lv2_run(sampleCount); } static void lv2_cleanup(LV2_Handle instance) { - delete instancePtr; + delete static_cast(instance); } // ----------------------------------------------------------------------- @@ -209,8 +188,6 @@ static const void* lv2_extension_data(const char* uri) return nullptr; } -#undef instancePtr - // ----------------------------------------------------------------------- static const LV2_Descriptor sLv2Descriptor = { diff --git a/include/mingw-compat/stdio.h b/lv2export/lv2plugin.hpp similarity index 51% rename from include/mingw-compat/stdio.h rename to lv2export/lv2plugin.hpp index ea67f0dc..25fc44df 100644 --- a/include/mingw-compat/stdio.h +++ b/lv2export/lv2plugin.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,19 +17,31 @@ #pragma once -/* On mingw stdio functions like printf are not inline, and thus get defined every time they are used. - * We go through a few steps to ensure unique symbol names. - */ -#ifdef STDIO_OVERRIDE +#ifndef PLUGIN_BRAND +# error PLUGIN_BRAND undefined +#endif + +#ifndef PLUGIN_LABEL +# error PLUGIN_LABEL undefined +#endif + +#ifndef PLUGIN_MODEL +# error PLUGIN_MODEL undefined +#endif -// helper macros -# define STDIO_OVERRIDE_HELPER(NS, SEP, FN) NS ## SEP ## FN -# define STDIO_OVERRIDE_MACRO(NS, FN) STDIO_OVERRIDE_HELPER(NS, _, FN) +#ifndef PLUGIN_CV_INPUTS +# error PLUGIN_CV_INPUTS undefined +#endif -// prefix the needed stdio functions -# define printf STDIO_OVERRIDE_MACRO(STDIO_OVERRIDE, printf) +#ifndef PLUGIN_CV_OUTPUTS +# error PLUGIN_CV_OUTPUTS undefined +#endif -#endif // STDIO_OVERRIDE +enum PortType { + Audio = 0, + Bi = 1, + Uni = 2, +}; -// now just include the real stdio.h -#include_next +static constexpr const PortType kCvInputs[] = PLUGIN_CV_INPUTS; +static constexpr const PortType kCvOutputs[] = PLUGIN_CV_OUTPUTS; diff --git a/lv2export/plugins/aubileinstruments-macro-osc-2.cpp b/lv2export/plugins/aubileinstruments-macro-osc-2.cpp index 5e6d73ea..d6afeb74 100644 --- a/lv2export/plugins/aubileinstruments-macro-osc-2.cpp +++ b/lv2export/plugins/aubileinstruments-macro-osc-2.cpp @@ -55,8 +55,8 @@ #define PLUGIN_BRAND "AudibleInstruments" #define PLUGIN_LABEL "Macro Osc 2" #define PLUGIN_MODEL modelPlaits -#define PLUGIN_CV_INPUTS {1,1,1,1,1,1,1,1} -#define PLUGIN_CV_OUTPUTS {0,0} +#define PLUGIN_CV_INPUTS {Bi,Bi,Bi,Bi,Bi,Bi,Bi,Bi} +#define PLUGIN_CV_OUTPUTS {Audio,Audio} #define PLUGIN_LV2_CATEGORY "lv2:GeneratorPlugin" #include "lv2plugin.cpp" diff --git a/lv2export/plugins/aubileinstruments-macro-osc.cpp b/lv2export/plugins/aubileinstruments-macro-osc.cpp index ed913e04..e196b267 100644 --- a/lv2export/plugins/aubileinstruments-macro-osc.cpp +++ b/lv2export/plugins/aubileinstruments-macro-osc.cpp @@ -35,8 +35,8 @@ #define PLUGIN_BRAND "AudibleInstruments" #define PLUGIN_LABEL "Macro Osc" #define PLUGIN_MODEL modelBraids -#define PLUGIN_CV_INPUTS {1,1,1,1,1} -#define PLUGIN_CV_OUTPUTS {0} +#define PLUGIN_CV_INPUTS {Bi,Bi,Bi,Bi,Bi} +#define PLUGIN_CV_OUTPUTS {Audio} #define PLUGIN_LV2_CATEGORY "lv2:GeneratorPlugin" #include "lv2plugin.cpp" diff --git a/lv2export/plugins/msm-phaser.cpp b/lv2export/plugins/msm-phaser.cpp index 8e93f863..08287a9b 100644 --- a/lv2export/plugins/msm-phaser.cpp +++ b/lv2export/plugins/msm-phaser.cpp @@ -20,8 +20,8 @@ #define PLUGIN_BRAND "MSM" #define PLUGIN_LABEL "Phaser" #define PLUGIN_MODEL modelPhaserModule -#define PLUGIN_CV_INPUTS {1,1,1,0} -#define PLUGIN_CV_OUTPUTS {0} +#define PLUGIN_CV_INPUTS {Bi,Bi,Bi,Audio} +#define PLUGIN_CV_OUTPUTS {Audio} #define PLUGIN_LV2_CATEGORY "lv2:DistortionPlugin" #include "lv2plugin.cpp" diff --git a/lv2export/plugins/rackwindows-mv.cpp b/lv2export/plugins/rackwindows-mv.cpp index a7991cef..85401301 100644 --- a/lv2export/plugins/rackwindows-mv.cpp +++ b/lv2export/plugins/rackwindows-mv.cpp @@ -20,8 +20,8 @@ #define PLUGIN_BRAND "Rackwindows" #define PLUGIN_LABEL "MV" #define PLUGIN_MODEL modelMv -#define PLUGIN_CV_INPUTS {1,1,1,1,0,0} -#define PLUGIN_CV_OUTPUTS {0,0} +#define PLUGIN_CV_INPUTS {Bi,Bi,Bi,Bi,Audio,Audio} +#define PLUGIN_CV_OUTPUTS {Audio,Audio} #define PLUGIN_LV2_CATEGORY "lv2:ReverbPlugin" #include "lv2plugin.cpp" diff --git a/lv2export/plugins/rackwindows-vibrato.cpp b/lv2export/plugins/rackwindows-vibrato.cpp index a4bdd9ee..96d88a38 100644 --- a/lv2export/plugins/rackwindows-vibrato.cpp +++ b/lv2export/plugins/rackwindows-vibrato.cpp @@ -20,8 +20,8 @@ #define PLUGIN_BRAND "Rackwindows" #define PLUGIN_LABEL "Vibrato" #define PLUGIN_MODEL modelVibrato -#define PLUGIN_CV_INPUTS {1,1,1,1,1,0} -#define PLUGIN_CV_OUTPUTS {1,0,1} +#define PLUGIN_CV_INPUTS {Bi,Bi,Bi,Bi,Bi,Audio} +#define PLUGIN_CV_OUTPUTS {Bi,Audio,Bi} #define PLUGIN_LV2_CATEGORY "lv2:DynamicsPlugin" #include "lv2plugin.cpp" diff --git a/lv2export/plugins/valleyaudio-plateau.cpp b/lv2export/plugins/valleyaudio-plateau.cpp index 9f4cc03d..554bc963 100644 --- a/lv2export/plugins/valleyaudio-plateau.cpp +++ b/lv2export/plugins/valleyaudio-plateau.cpp @@ -23,8 +23,8 @@ #define PLUGIN_BRAND "Valley Audio" #define PLUGIN_LABEL "Plateau" #define PLUGIN_MODEL modelPlateau -#define PLUGIN_CV_INPUTS {0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} -#define PLUGIN_CV_OUTPUTS {0,0} +#define PLUGIN_CV_INPUTS {Audio,Audio,Bi,Bi,Bi,Bi,Bi,Bi,Bi,Bi,Bi,Bi,Bi,Bi,Bi,Bi,Bi} +#define PLUGIN_CV_OUTPUTS {Audio,Audio} #define PLUGIN_LV2_CATEGORY "lv2:ReverbPlugin" #include "lv2plugin.cpp" diff --git a/patches/examples/DRMR_-_Interverb.vcv b/patches/examples/DRMR_-_Interverb.vcv index a1ffb51a..27e1c8e8 100644 --- a/patches/examples/DRMR_-_Interverb.vcv +++ b/patches/examples/DRMR_-_Interverb.vcv @@ -1,6 +1,5 @@ { - "version": "2.0", - "zoom": 1.0, + "version": "2.1.2", "modules": [ { "id": 1184757612963547, @@ -462,27 +461,6 @@ 0 ] }, - { - "id": 8996849652715896, - "plugin": "Cardinal", - "model": "Carla", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - }, - { - "value": 1.0, - "id": 1 - } - ], - "data": "\n\n\n \n false\n false\n false\n true\n 200\n 4000\n \n \n \n \n \n \n \n \n \n\n \n \n\n", - "pos": [ - 123, - 1 - ] - }, { "id": 644714212872810, "plugin": "Cardinal", @@ -492,7 +470,7 @@ "data": { "filepath": "", "lang": "None", - "etext": " \n ^ ^ ,_, \n (O,O) (.,.) \n ( ) ( ) \n--------\"-\"---dwb--\"-\"---dwb- \n\nversatile 4 voice polyphonic synth with a bit\nof reverb\n\nParam1: pulse width modulation\nParam2: filter frequency\nParam3: filter resonance\n\n\n /^--^\\ /^--^\\ /^--^\\ \n \\____/ \\____/ \\____/ \n / \\ / \\ / \\ \n | | | | | | \n \\__ __/ \\__ __/ \\__ __/ \n|^|^|^|^\\ \\^|^|^|^/ /^|^|^|^|^\\ \\^|^|^|^|^|^|^|^|^|\n| | | | |\\ \\| | |/ /| | | | | |\\ \\| | | | | | | | |\n#########/ /#####\\ \\###########/ /#################\n| | | | |\\/ | | | \\/| | | | | |\\/ | | | | | | | | |\n|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|\n\n\n\n\n\n\n", + "etext": " \n ^ ^ ,_, \n (O,O) (.,.) \n ( ) ( ) \n--------\"-\"---dwb--\"-\"---dwb- \n\nversatile 4 voice polyphonic synth with a bit\nof reverb\n\nParam1: pulse width modulation\nParam2: filter frequency\nParam3: filter resonance\n\n\n /^--^\\ /^--^\\ /^--^\\ \n \\____/ \\____/ \\____/ \n / \\ / \\ / \\ \n | | | | | | \n \\__ __/ \\__ __/ \\__ __/ \n|^|^|^|^\\ \\^|^|^|^/ /^|^|^|^|^\\ \\^|^|^|^|^|^|^|^|^|\n| | | | |\\ \\| | |/ /| | | | | |\\ \\| | | | | | | | |\n#########/ /#####\\ \\###########/ /#################\n| | | | |\\/ | | | \\/| | | | | |\\/ | | | | | | | | |\n|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|\n\n\n\n\n\n\n\n", "width": 27 }, "pos": [ @@ -527,6 +505,7 @@ "version": "2.0", "params": [], "data": { + "pwRange": 0.0, "smooth": true, "channels": 4, "polyMode": 0, @@ -546,6 +525,9 @@ "model": "HostParameters", "version": "2.0", "params": [], + "data": { + "smooth": true + }, "pos": [ 32, 2 diff --git a/patches/examples/JTB_-_Waves.vcv b/patches/examples/JTB_-_Waves.vcv new file mode 100644 index 00000000..8633c286 --- /dev/null +++ b/patches/examples/JTB_-_Waves.vcv @@ -0,0 +1,6384 @@ +{ + "version": "2.1.2", + "zoom": 0.82074141502380371, + "gridOffset": [ + -44.997005462646484, + -0.079142682254314423 + ], + "modules": [ + { + "id": 3538881790933672, + "plugin": "MindMeldModular", + "model": "PatchMasterBlank", + "version": "2.0", + "params": [], + "leftModuleId": 8631911439676095, + "rightModuleId": 7579603213780856, + "data": { + "facePlate": 0 + }, + "pos": [ + 65, + 0 + ] + }, + { + "id": 2859633263682263, + "plugin": "MindMeldModular", + "model": "PatchMaster", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.40481904149055481, + "id": 1 + }, + { + "value": 0.29517701268196106, + "id": 2 + }, + { + "value": 0.81927722692489624, + "id": 3 + }, + { + "value": 0.28915113210678101, + "id": 4 + }, + { + "value": 0.32771065831184387, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + } + ], + "rightModuleId": 359762865999381, + "data": { + "miscSettings": 65793, + "miscSettings2": 1, + "tileInfos": [ + 180, + 179, + 179, + 179, + 179, + 179, + 51, + 51, + 155, + 155, + 155, + 155, + 155, + 155, + 155, + 155 + ], + "tileNames": [ + "Reset", + "Melody Clock", + "Note Chance", + "Glide", + "MainDist", + "Rev+Dlay", + "No name", + "No name", + "Control", + "No name", + "No name", + "No name", + "No name", + "No name", + "No name", + "No name" + ], + "maps": [ + { + "moduleId": 3492788997026115, + "paramId": 12, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": 3492788997026115, + "paramId": 2, + "rangeMax": 0.7439998984336853, + "rangeMin": 0.42600008845329285 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": 2528905409371299, + "paramId": 0, + "rangeMax": 0.0, + "rangeMin": 1.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": 7545907193641280, + "paramId": 0, + "rangeMax": 0.14999982714653015, + "rangeMin": 0.0 + }, + { + "moduleId": 7545907193641280, + "paramId": 2, + "rangeMax": 0.14999990165233612, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": 8500492434533465, + "paramId": 0, + "rangeMax": 0.85000193119049072, + "rangeMin": 0.40299832820892334 + }, + { + "moduleId": 8500492434533465, + "paramId": 2, + "rangeMax": 0.47900623083114624, + "rangeMin": 0.73800313472747803 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": 1629089543055674, + "paramId": 9, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": 7411284708330475, + "paramId": 9, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + } + ], + "radioLits": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "tileOrders": [ + 8, + 0, + 1, + 2, + 3, + 4, + 5, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ], + "tileSettings": [ + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "pos": [ + 10, + 0 + ] + }, + { + "id": 3492788997026115, + "plugin": "ImpromptuModular", + "model": "Clocked", + "version": "2.0", + "params": [ + { + "value": 87.0, + "id": 0 + }, + { + "value": -9.0, + "id": 1 + }, + { + "value": 4.0, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.5, + "id": 8 + }, + { + "value": 0.5, + "id": 9 + }, + { + "value": 0.84217530488967896, + "id": 10 + }, + { + "value": 0.5, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + } + ], + "rightModuleId": 6206908039426907, + "data": { + "panelTheme": 1, + "panelContrast": 220.0, + "running": true, + "displayDelayNoteMode": true, + "bpmDetectionMode": false, + "resetOnStartStop": 0, + "ppqn": 4, + "resetClockOutputsHigh": false, + "momentaryRunInput": true, + "forceCvOnBpmOut": false, + "clockMaster": false + }, + "pos": [ + 34, + 2 + ] + }, + { + "id": 2528905409371299, + "plugin": "AudibleInstruments", + "model": "Branches", + "version": "2.0", + "params": [ + { + "value": 0.70482301712036133, + "id": 0 + }, + { + "value": 0.5, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + } + ], + "leftModuleId": 3147629330555360, + "rightModuleId": 8858399717280256, + "data": { + "modes": [ + false, + false + ] + }, + "pos": [ + 83, + 2 + ] + }, + { + "id": 8858399717280256, + "plugin": "Bogaudio", + "model": "Bogaudio-SampleHold", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + } + ], + "leftModuleId": 2528905409371299, + "rightModuleId": 1929072526365403, + "data": { + "poly_input": 0, + "noise_type": 0, + "range_offset": 1.0, + "range_scale": 5.0, + "smoothing_ms": 0.0 + }, + "pos": [ + 89, + 2 + ] + }, + { + "id": 7649815730956881, + "plugin": "Bogaudio", + "model": "Bogaudio-Slew", + "version": "2.0", + "params": [ + { + "value": 0.46746960282325745, + "id": 0 + }, + { + "value": 0.26987949013710022, + "id": 1 + }, + { + "value": 0.43912151455879211, + "id": 2 + }, + { + "value": 0.34457814693450928, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + } + ], + "leftModuleId": 1163775849135581, + "rightModuleId": 2364063745493562, + "data": {}, + "pos": [ + 16, + 1 + ] + }, + { + "id": 8078887273046425, + "plugin": "Bogaudio", + "model": "Bogaudio-Slew", + "version": "2.0", + "params": [ + { + "value": 0.38072267174720764, + "id": 0 + }, + { + "value": 0.15421679615974426, + "id": 1 + }, + { + "value": 0.51261603832244873, + "id": 2 + }, + { + "value": 0.34457814693450928, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + } + ], + "leftModuleId": 1232093242356119, + "rightModuleId": 7744264450943662, + "data": {}, + "pos": [ + 58, + 1 + ] + }, + { + "id": 1232093242356119, + "plugin": "Bogaudio", + "model": "Bogaudio-Slew", + "version": "2.0", + "params": [ + { + "value": 0.43012022972106934, + "id": 0 + }, + { + "value": -0.46987923979759216, + "id": 1 + }, + { + "value": 0.50538665056228638, + "id": 2 + }, + { + "value": 0.34457814693450928, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + } + ], + "leftModuleId": 1772638206753921, + "rightModuleId": 8078887273046425, + "data": {}, + "pos": [ + 55, + 1 + ] + }, + { + "id": 1929072526365403, + "plugin": "Bogaudio", + "model": "Bogaudio-DGate", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 1.0, + "id": 1 + }, + { + "value": 1.0, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + } + ], + "leftModuleId": 8858399717280256, + "rightModuleId": 931699531175066, + "data": { + "triggerOnLoad": true, + "shouldTriggerOnLoad": true + }, + "pos": [ + 92, + 2 + ] + }, + { + "id": 931699531175066, + "plugin": "Bogaudio", + "model": "Bogaudio-PolyMult", + "version": "2.0", + "params": [ + { + "value": 3.0, + "id": 0 + } + ], + "leftModuleId": 1929072526365403, + "rightModuleId": 5599750386095483, + "data": {}, + "pos": [ + 95, + 2 + ] + }, + { + "id": 6206908039426907, + "plugin": "Bogaudio", + "model": "Bogaudio-AddrSeq", + "version": "2.0", + "params": [ + { + "value": 4.1457595825195312, + "id": 0 + }, + { + "value": 1.0, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.22168663144111633, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.1012047752737999, + "id": 5 + }, + { + "value": 0.13975897431373596, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + } + ], + "leftModuleId": 3492788997026115, + "rightModuleId": 3623085877119332, + "data": { + "poly_input": 0, + "select_on_clock": false, + "triggered_select": false, + "reverse_on_negative_clock": false, + "wrap_select_at_steps": false, + "range_offset": 0.0, + "range_scale": 1.0 + }, + "pos": [ + 54, + 2 + ] + }, + { + "id": 3623085877119332, + "plugin": "ImpromptuModular", + "model": "Chord-Key", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + } + ], + "leftModuleId": 6206908039426907, + "rightModuleId": 3147629330555360, + "data": { + "panelTheme": 1, + "panelContrast": 220.0, + "octs": [ + 3, + 3, + 4, + -1, + 3, + 3, + 4, + -1, + 3, + 4, + 4, + -1, + 3, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1, + 4, + 4, + 4, + -1 + ], + "keys": [ + 7, + 10, + 2, + 0, + 0, + 3, + 7, + 0, + 2, + 5, + 9, + 0, + 10, + 2, + 5, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0, + 0, + 4, + 7, + 0 + ], + "mergeOutputs": 0, + "keypressEmitGate": 1, + "autostepPaste": 0 + }, + "pos": [ + 60, + 2 + ] + }, + { + "id": 7579603213780856, + "plugin": "SurgeXTRack", + "model": "SurgeXTOSCSine", + "version": "2.0", + "params": [ + { + "value": -1.0, + "id": 0 + }, + { + "value": 0.004999999888241291, + "id": 1 + }, + { + "value": 0.62857121229171753, + "id": 2 + }, + { + "value": 0.99500000476837158, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 1.0, + "id": 5 + }, + { + "value": 0.10000000149011612, + "id": 6 + }, + { + "value": 0.004999999888241291, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 0.0, + "id": 20 + }, + { + "value": 0.0, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 0.0, + "id": 24 + }, + { + "value": 0.0, + "id": 25 + }, + { + "value": 0.0, + "id": 26 + }, + { + "value": 0.0, + "id": 27 + }, + { + "value": 0.0, + "id": 28 + }, + { + "value": 0.0, + "id": 29 + }, + { + "value": 0.0, + "id": 30 + }, + { + "value": 0.0, + "id": 31 + }, + { + "value": 0.0, + "id": 32 + }, + { + "value": 0.0, + "id": 33 + }, + { + "value": 0.0, + "id": 34 + }, + { + "value": 0.0, + "id": 35 + }, + { + "value": 0.0, + "id": 36 + }, + { + "value": 0.0, + "id": 37 + }, + { + "value": 0.0, + "id": 38 + }, + { + "value": 0.0, + "id": 39 + }, + { + "value": 0.0, + "id": 40 + }, + { + "value": 0.0, + "id": 41 + }, + { + "value": 0.0, + "id": 42 + }, + { + "value": 0.0, + "id": 43 + }, + { + "value": 0.0, + "id": 44 + }, + { + "value": 0.0, + "id": 45 + }, + { + "value": 0.0, + "id": 46 + }, + { + "value": 0.0, + "id": 47 + }, + { + "value": 1.0, + "id": 48 + }, + { + "value": 0.0, + "id": 49 + }, + { + "value": 1.0, + "id": 50 + } + ], + "leftModuleId": 3538881790933672, + "rightModuleId": 3272418169313056, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Dec 20 2022 09:19:54", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + }, + "modulespecific": { + "halfbandM": 6, + "halfbandSteep": true, + "doDCBlock": true + } + }, + "pos": [ + 66, + 0 + ] + }, + { + "id": 3272418169313056, + "plugin": "SurgeXTRack", + "model": "SurgeXTFXTreeMonster", + "version": "2.0", + "params": [ + { + "value": 0.75, + "id": 0 + }, + { + "value": 0.5, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 1.0, + "id": 3 + }, + { + "value": 0.40000000596046448, + "id": 4 + }, + { + "value": 0.24543231725692749, + "id": 5 + }, + { + "value": 0.20671668648719788, + "id": 6 + }, + { + "value": 1.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 0.0, + "id": 20 + }, + { + "value": 0.0, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 0.0, + "id": 24 + }, + { + "value": 0.0, + "id": 25 + }, + { + "value": 0.0, + "id": 26 + }, + { + "value": 0.0, + "id": 27 + }, + { + "value": 0.0, + "id": 28 + }, + { + "value": 0.0, + "id": 29 + }, + { + "value": 0.0, + "id": 30 + }, + { + "value": 0.0, + "id": 31 + }, + { + "value": 0.0, + "id": 32 + }, + { + "value": 0.0, + "id": 33 + }, + { + "value": 0.0, + "id": 34 + }, + { + "value": 0.0, + "id": 35 + }, + { + "value": 0.0, + "id": 36 + }, + { + "value": 0.0, + "id": 37 + }, + { + "value": 0.0, + "id": 38 + }, + { + "value": 0.0, + "id": 39 + }, + { + "value": 0.0, + "id": 40 + }, + { + "value": 0.0, + "id": 41 + }, + { + "value": 0.0, + "id": 42 + }, + { + "value": 0.0, + "id": 43 + }, + { + "value": 0.0, + "id": 44 + }, + { + "value": 0.0, + "id": 45 + }, + { + "value": 0.0, + "id": 46 + }, + { + "value": 0.0, + "id": 47 + }, + { + "value": 0.0, + "id": 48 + }, + { + "value": 0.0, + "id": 49 + }, + { + "value": 0.0, + "id": 50 + }, + { + "value": 0.0, + "id": 51 + }, + { + "value": 0.0, + "id": 52 + }, + { + "value": 0.0, + "id": 53 + }, + { + "value": 0.0, + "id": 54 + }, + { + "value": 0.0, + "id": 55 + }, + { + "value": 0.0, + "id": 56 + }, + { + "value": 0.0, + "id": 57 + }, + { + "value": 0.0, + "id": 58 + }, + { + "value": 0.0, + "id": 59 + }, + { + "value": 1.0, + "id": 60 + }, + { + "value": 1.0, + "id": 61 + } + ], + "leftModuleId": 7579603213780856, + "rightModuleId": 2120522391757438, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Dec 20 2022 09:19:54", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + }, + "modulespecific": { + "loadedPreset": 0, + "presetName": "Init", + "presetIsDirty": true, + "polyphonicMode": true + } + }, + "pos": [ + 78, + 0 + ] + }, + { + "id": 2120522391757438, + "plugin": "SurgeXTRack", + "model": "SurgeXTVCF", + "version": "2.0", + "params": [ + { + "value": 0.23058414459228516, + "id": 0 + }, + { + "value": 0.82925224304199219, + "id": 1 + }, + { + "value": 2.0, + "id": 2 + }, + { + "value": 1.0, + "id": 3 + }, + { + "value": 1.5194351673126221, + "id": 4 + }, + { + "value": 1.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 0.0, + "id": 20 + }, + { + "value": 0.0, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 0.0, + "id": 24 + }, + { + "value": 28.0, + "id": 25 + }, + { + "value": 3.0, + "id": 26 + } + ], + "leftModuleId": 3272418169313056, + "rightModuleId": 1202888979525309, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Dec 20 2022 09:19:54", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + } + }, + "pos": [ + 90, + 0 + ] + }, + { + "id": 1202888979525309, + "plugin": "SurgeXTRack", + "model": "SurgeXTFXDistortion", + "version": "2.0", + "params": [ + { + "value": 0.63885778188705444, + "id": 0 + }, + { + "value": 0.48576384782791138, + "id": 1 + }, + { + "value": 0.38892880082130432, + "id": 2 + }, + { + "value": 0.53337103128433228, + "id": 3 + }, + { + "value": 0.87157571315765381, + "id": 4 + }, + { + "value": 0.84071719646453857, + "id": 5 + }, + { + "value": 0.56428641080856323, + "id": 6 + }, + { + "value": 0.25704637169837952, + "id": 7 + }, + { + "value": 0.40625, + "id": 8 + }, + { + "value": 0.5343744158744812, + "id": 9 + }, + { + "value": 0.5, + "id": 10 + }, + { + "value": 0.14642857015132904, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 1.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 0.0, + "id": 20 + }, + { + "value": 0.0, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 0.0, + "id": 24 + }, + { + "value": 0.0, + "id": 25 + }, + { + "value": 0.0, + "id": 26 + }, + { + "value": 0.0, + "id": 27 + }, + { + "value": 0.0, + "id": 28 + }, + { + "value": 0.0, + "id": 29 + }, + { + "value": 0.0, + "id": 30 + }, + { + "value": 0.0, + "id": 31 + }, + { + "value": 0.0, + "id": 32 + }, + { + "value": 0.0, + "id": 33 + }, + { + "value": 0.0, + "id": 34 + }, + { + "value": 0.0, + "id": 35 + }, + { + "value": 0.0, + "id": 36 + }, + { + "value": 0.0, + "id": 37 + }, + { + "value": 0.0, + "id": 38 + }, + { + "value": 0.0, + "id": 39 + }, + { + "value": 1.0, + "id": 40 + }, + { + "value": 0.0, + "id": 41 + }, + { + "value": 0.0, + "id": 42 + }, + { + "value": 0.0, + "id": 43 + }, + { + "value": 0.0, + "id": 44 + }, + { + "value": 0.0, + "id": 45 + }, + { + "value": 0.0, + "id": 46 + }, + { + "value": 0.0, + "id": 47 + }, + { + "value": 1.0, + "id": 48 + }, + { + "value": 0.0, + "id": 49 + }, + { + "value": 0.0, + "id": 50 + }, + { + "value": 0.0, + "id": 51 + }, + { + "value": 0.0, + "id": 52 + }, + { + "value": 0.0, + "id": 53 + }, + { + "value": 0.0, + "id": 54 + }, + { + "value": 0.0, + "id": 55 + }, + { + "value": 0.0, + "id": 56 + }, + { + "value": 0.0, + "id": 57 + }, + { + "value": 0.0, + "id": 58 + }, + { + "value": 0.0, + "id": 59 + }, + { + "value": 0.0, + "id": 60 + }, + { + "value": 1.0, + "id": 61 + } + ], + "leftModuleId": 2120522391757438, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Dec 20 2022 09:19:54", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + }, + "modulespecific": { + "loadedPreset": 0, + "presetName": "Init", + "presetIsDirty": true, + "polyphonicMode": false + } + }, + "pos": [ + 102, + 0 + ] + }, + { + "id": 1163775849135581, + "plugin": "SurgeXTRack", + "model": "SurgeXTOSCClassic", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.25957661867141724, + "id": 1 + }, + { + "value": 0.52571725845336914, + "id": 2 + }, + { + "value": 0.62986081838607788, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.10000000149011612, + "id": 6 + }, + { + "value": 0.004999999888241291, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 0.0, + "id": 20 + }, + { + "value": 0.0, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 0.0, + "id": 24 + }, + { + "value": 0.0, + "id": 25 + }, + { + "value": 0.0, + "id": 26 + }, + { + "value": 0.0, + "id": 27 + }, + { + "value": 0.0, + "id": 28 + }, + { + "value": 0.0, + "id": 29 + }, + { + "value": 0.0, + "id": 30 + }, + { + "value": 0.0, + "id": 31 + }, + { + "value": 0.0, + "id": 32 + }, + { + "value": 0.0, + "id": 33 + }, + { + "value": 0.0, + "id": 34 + }, + { + "value": 0.0, + "id": 35 + }, + { + "value": 0.0, + "id": 36 + }, + { + "value": 0.0, + "id": 37 + }, + { + "value": 0.0, + "id": 38 + }, + { + "value": 0.0, + "id": 39 + }, + { + "value": 0.0, + "id": 40 + }, + { + "value": 0.0, + "id": 41 + }, + { + "value": 0.0, + "id": 42 + }, + { + "value": 0.0, + "id": 43 + }, + { + "value": 0.0, + "id": 44 + }, + { + "value": 0.0, + "id": 45 + }, + { + "value": 0.0, + "id": 46 + }, + { + "value": 0.0, + "id": 47 + }, + { + "value": 1.0, + "id": 48 + }, + { + "value": 0.0, + "id": 49 + }, + { + "value": 1.0, + "id": 50 + } + ], + "rightModuleId": 7649815730956881, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Dec 20 2022 09:19:54", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + }, + "modulespecific": { + "halfbandM": 6, + "halfbandSteep": true, + "doDCBlock": true + } + }, + "pos": [ + 4, + 1 + ] + }, + { + "id": 3147629330555360, + "plugin": "GrandeModular", + "model": "Merge8", + "version": "2.0", + "params": [], + "leftModuleId": 3623085877119332, + "rightModuleId": 2528905409371299, + "data": { + "channels_merge": -1 + }, + "pos": [ + 81, + 2 + ] + }, + { + "id": 6408811696897743, + "plugin": "SurgeXTRack", + "model": "SurgeXTOSCModern", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 1.0, + "id": 1 + }, + { + "value": 0.62471598386764526, + "id": 2 + }, + { + "value": 0.60414427518844604, + "id": 3 + }, + { + "value": 0.5, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.094571217894554138, + "id": 6 + }, + { + "value": 0.13726678490638733, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 0.0, + "id": 20 + }, + { + "value": 0.0, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 0.0, + "id": 24 + }, + { + "value": 0.0, + "id": 25 + }, + { + "value": 0.0, + "id": 26 + }, + { + "value": 0.0, + "id": 27 + }, + { + "value": 0.0, + "id": 28 + }, + { + "value": 0.0, + "id": 29 + }, + { + "value": 0.0, + "id": 30 + }, + { + "value": 0.0, + "id": 31 + }, + { + "value": 0.0, + "id": 32 + }, + { + "value": 0.0, + "id": 33 + }, + { + "value": 0.0, + "id": 34 + }, + { + "value": 0.0, + "id": 35 + }, + { + "value": 0.0, + "id": 36 + }, + { + "value": 0.0, + "id": 37 + }, + { + "value": 0.0, + "id": 38 + }, + { + "value": 0.0, + "id": 39 + }, + { + "value": 0.0, + "id": 40 + }, + { + "value": 0.0, + "id": 41 + }, + { + "value": 0.0, + "id": 42 + }, + { + "value": 0.0, + "id": 43 + }, + { + "value": 0.0, + "id": 44 + }, + { + "value": 0.0, + "id": 45 + }, + { + "value": 0.0, + "id": 46 + }, + { + "value": 0.0, + "id": 47 + }, + { + "value": 1.0, + "id": 48 + }, + { + "value": 0.0, + "id": 49 + }, + { + "value": 1.0, + "id": 50 + } + ], + "rightModuleId": 977849113384714, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Dec 20 2022 09:19:54", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + }, + "modulespecific": { + "halfbandM": 6, + "halfbandSteep": true, + "doDCBlock": true + } + }, + "pos": [ + 15, + 2 + ] + }, + { + "id": 977849113384714, + "plugin": "Fundamental", + "model": "Sum", + "version": "2.0", + "params": [ + { + "value": 1.0, + "id": 0 + } + ], + "leftModuleId": 6408811696897743, + "rightModuleId": 1132602188892100, + "pos": [ + 27, + 2 + ] + }, + { + "id": 1132602188892100, + "plugin": "Fundamental", + "model": "Sum", + "version": "2.0", + "params": [ + { + "value": 1.0, + "id": 0 + } + ], + "leftModuleId": 977849113384714, + "pos": [ + 30, + 2 + ] + }, + { + "id": 2364063745493562, + "plugin": "SurgeXTRack", + "model": "SurgeXTMixer", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 0.22814854979515076, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.30172306299209595, + "id": 5 + }, + { + "value": 0.37028577923774719, + "id": 6 + }, + { + "value": 1.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 1.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 0.88200151920318604, + "id": 20 + }, + { + "value": 0.0, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 1.0, + "id": 24 + }, + { + "value": 0.0, + "id": 25 + }, + { + "value": 0.0, + "id": 26 + }, + { + "value": 0.0, + "id": 27 + }, + { + "value": 0.2260001003742218, + "id": 28 + }, + { + "value": 0.0, + "id": 29 + }, + { + "value": 0.0, + "id": 30 + }, + { + "value": 0.0, + "id": 31 + }, + { + "value": 0.67200368642807007, + "id": 32 + }, + { + "value": 0.0, + "id": 33 + }, + { + "value": 0.0, + "id": 34 + }, + { + "value": 0.0, + "id": 35 + }, + { + "value": 0.0, + "id": 36 + }, + { + "value": 0.0, + "id": 37 + }, + { + "value": 0.0, + "id": 38 + }, + { + "value": 0.0, + "id": 39 + }, + { + "value": 0.0, + "id": 40 + }, + { + "value": 0.0, + "id": 41 + }, + { + "value": 0.0, + "id": 42 + }, + { + "value": 0.0, + "id": 43 + }, + { + "value": 0.0, + "id": 44 + }, + { + "value": 0.0, + "id": 45 + }, + { + "value": 0.0, + "id": 46 + }, + { + "value": 0.0, + "id": 47 + }, + { + "value": 0.0, + "id": 48 + }, + { + "value": 0.0, + "id": 49 + }, + { + "value": 0.0, + "id": 50 + }, + { + "value": 0.0, + "id": 51 + } + ], + "leftModuleId": 7649815730956881, + "rightModuleId": 8524145861178282, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Dec 20 2022 09:19:54", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + }, + "modulespecific": { + "vuChannel": 0 + } + }, + "pos": [ + 19, + 1 + ] + }, + { + "id": 8524145861178282, + "plugin": "SurgeXTRack", + "model": "SurgeXTFXChorus", + "version": "2.0", + "params": [ + { + "value": 0.1591431051492691, + "id": 0 + }, + { + "value": 0.6618039608001709, + "id": 1 + }, + { + "value": 0.41764268279075623, + "id": 2 + }, + { + "value": 0.26871439814567566, + "id": 3 + }, + { + "value": 0.27980762720108032, + "id": 4 + }, + { + "value": 0.96663463115692139, + "id": 5 + }, + { + "value": 0.42299914360046387, + "id": 6 + }, + { + "value": 0.5, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 0.0, + "id": 20 + }, + { + "value": 0.0, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 0.0, + "id": 24 + }, + { + "value": 0.0, + "id": 25 + }, + { + "value": 0.0, + "id": 26 + }, + { + "value": 0.0, + "id": 27 + }, + { + "value": 0.0, + "id": 28 + }, + { + "value": 0.0, + "id": 29 + }, + { + "value": 0.0, + "id": 30 + }, + { + "value": 0.0, + "id": 31 + }, + { + "value": 0.0, + "id": 32 + }, + { + "value": 0.0, + "id": 33 + }, + { + "value": 0.0, + "id": 34 + }, + { + "value": 0.0, + "id": 35 + }, + { + "value": 0.0, + "id": 36 + }, + { + "value": 0.0, + "id": 37 + }, + { + "value": 0.0, + "id": 38 + }, + { + "value": 0.0, + "id": 39 + }, + { + "value": 0.0, + "id": 40 + }, + { + "value": 0.0, + "id": 41 + }, + { + "value": 0.0, + "id": 42 + }, + { + "value": 0.0, + "id": 43 + }, + { + "value": 0.0, + "id": 44 + }, + { + "value": 0.0, + "id": 45 + }, + { + "value": 0.0, + "id": 46 + }, + { + "value": 0.0, + "id": 47 + }, + { + "value": 0.0, + "id": 48 + }, + { + "value": 0.0, + "id": 49 + }, + { + "value": 0.0, + "id": 50 + }, + { + "value": 0.0, + "id": 51 + }, + { + "value": 0.0, + "id": 52 + }, + { + "value": 0.0, + "id": 53 + }, + { + "value": 0.0, + "id": 54 + }, + { + "value": 0.0, + "id": 55 + }, + { + "value": 0.0, + "id": 56 + }, + { + "value": 0.0, + "id": 57 + }, + { + "value": 0.0, + "id": 58 + }, + { + "value": 0.0, + "id": 59 + }, + { + "value": 1.0, + "id": 60 + }, + { + "value": 1.0, + "id": 61 + } + ], + "leftModuleId": 2364063745493562, + "rightModuleId": 1772638206753921, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Dec 20 2022 09:19:54", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + }, + "modulespecific": { + "loadedPreset": 0, + "presetName": "Init (Dry)", + "presetIsDirty": true, + "clockStyle": 0, + "polyphonicMode": false + } + }, + "pos": [ + 31, + 1 + ] + }, + { + "id": 1772638206753921, + "plugin": "SurgeXTRack", + "model": "SurgeXTWaveshaper", + "version": "2.0", + "params": [ + { + "value": 7.0902948379516602, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 0.46771752834320068, + "id": 2 + }, + { + "value": -23.228555679321289, + "id": 3 + }, + { + "value": 34.732803344726562, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": 0.094000227749347687, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 0.0, + "id": 20 + }, + { + "value": 0.0, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 0.0, + "id": 24 + }, + { + "value": 41.0, + "id": 25 + }, + { + "value": 1.0, + "id": 26 + }, + { + "value": 1.0, + "id": 27 + } + ], + "leftModuleId": 8524145861178282, + "rightModuleId": 1232093242356119, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Dec 20 2022 09:19:54", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + } + }, + "pos": [ + 43, + 1 + ] + }, + { + "id": 5599750386095483, + "plugin": "Bogaudio", + "model": "Bogaudio-Offset", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.11173717677593231, + "id": 1 + } + ], + "leftModuleId": 931699531175066, + "rightModuleId": 1660124145346554, + "data": { + "disableOutputLimit": false, + "offset_first": false + }, + "pos": [ + 98, + 2 + ] + }, + { + "id": 1660124145346554, + "plugin": "ML_modules", + "model": "Quantum", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + } + ], + "leftModuleId": 5599750386095483, + "data": { + "scale": [ + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0 + ], + "mode": 1, + "transpose_select": 1, + "toggle_mode": 1 + }, + "pos": [ + 101, + 2 + ] + }, + { + "id": 7545907193641280, + "plugin": "Bogaudio", + "model": "Bogaudio-Slew", + "version": "2.0", + "params": [ + { + "value": 0.12289144098758698, + "id": 0 + }, + { + "value": -0.33734920620918274, + "id": 1 + }, + { + "value": 0.12289150059223175, + "id": 2 + }, + { + "value": -0.41927692294120789, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + } + ], + "leftModuleId": 6532964214833122, + "rightModuleId": 7614703401631065, + "data": {}, + "pos": [ + 26, + 0 + ] + }, + { + "id": 7614703401631065, + "plugin": "SurgeXTRack", + "model": "SurgeXTOSCTwist", + "version": "2.0", + "params": [ + { + "value": 1.0, + "id": 0 + }, + { + "value": 0.004999999888241291, + "id": 1 + }, + { + "value": 0.5, + "id": 2 + }, + { + "value": 0.18885940313339233, + "id": 3 + }, + { + "value": 0.68385952711105347, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.91899901628494263, + "id": 6 + }, + { + "value": 0.5, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 0.0, + "id": 20 + }, + { + "value": 0.0, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 0.0, + "id": 24 + }, + { + "value": 0.0, + "id": 25 + }, + { + "value": 0.0, + "id": 26 + }, + { + "value": 0.0, + "id": 27 + }, + { + "value": 0.0, + "id": 28 + }, + { + "value": 0.0, + "id": 29 + }, + { + "value": 0.0, + "id": 30 + }, + { + "value": 0.0, + "id": 31 + }, + { + "value": 0.0, + "id": 32 + }, + { + "value": 0.0, + "id": 33 + }, + { + "value": 0.0, + "id": 34 + }, + { + "value": 0.0, + "id": 35 + }, + { + "value": 0.0, + "id": 36 + }, + { + "value": 0.0, + "id": 37 + }, + { + "value": 0.0, + "id": 38 + }, + { + "value": 0.0, + "id": 39 + }, + { + "value": 0.0, + "id": 40 + }, + { + "value": 0.0, + "id": 41 + }, + { + "value": 0.0, + "id": 42 + }, + { + "value": 0.0, + "id": 43 + }, + { + "value": 0.0, + "id": 44 + }, + { + "value": 0.0, + "id": 45 + }, + { + "value": 0.0, + "id": 46 + }, + { + "value": 0.0, + "id": 47 + }, + { + "value": 1.0, + "id": 48 + }, + { + "value": 0.0, + "id": 49 + }, + { + "value": 1.0, + "id": 50 + } + ], + "leftModuleId": 7545907193641280, + "rightModuleId": 7354440315312540, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Dec 20 2022 09:19:54", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + }, + "modulespecific": { + "halfbandM": 6, + "halfbandSteep": true, + "doDCBlock": true + } + }, + "pos": [ + 29, + 0 + ] + }, + { + "id": 7354440315312540, + "plugin": "SurgeXTRack", + "model": "SurgeXTVCF", + "version": "2.0", + "params": [ + { + "value": 0.23143219947814941, + "id": 0 + }, + { + "value": 0.53199803829193115, + "id": 1 + }, + { + "value": 1.9437248706817627, + "id": 2 + }, + { + "value": 1.0, + "id": 3 + }, + { + "value": 1.4485224485397339, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 1.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 0.0, + "id": 20 + }, + { + "value": 0.44938600063323975, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 0.0, + "id": 24 + }, + { + "value": 16.0, + "id": 25 + }, + { + "value": 3.0, + "id": 26 + } + ], + "leftModuleId": 7614703401631065, + "rightModuleId": 8631911439676095, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Dec 20 2022 09:19:54", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + } + }, + "pos": [ + 41, + 0 + ] + }, + { + "id": 8631911439676095, + "plugin": "SurgeXTRack", + "model": "SurgeXTFXExciter", + "version": "2.0", + "params": [ + { + "value": 1.0, + "id": 0 + }, + { + "value": 0.24036593735218048, + "id": 1 + }, + { + "value": 0.49999994039535522, + "id": 2 + }, + { + "value": 0.49999994039535522, + "id": 3 + }, + { + "value": 0.17706665396690369, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": -1.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 0.0, + "id": 20 + }, + { + "value": 0.0, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 0.0, + "id": 24 + }, + { + "value": 0.0, + "id": 25 + }, + { + "value": 0.0, + "id": 26 + }, + { + "value": 0.0, + "id": 27 + }, + { + "value": 0.0, + "id": 28 + }, + { + "value": 0.0, + "id": 29 + }, + { + "value": 0.0, + "id": 30 + }, + { + "value": 0.0, + "id": 31 + }, + { + "value": 0.0, + "id": 32 + }, + { + "value": 0.0, + "id": 33 + }, + { + "value": 0.0, + "id": 34 + }, + { + "value": 0.0, + "id": 35 + }, + { + "value": 0.0, + "id": 36 + }, + { + "value": 0.0, + "id": 37 + }, + { + "value": 0.0, + "id": 38 + }, + { + "value": 0.0, + "id": 39 + }, + { + "value": 0.0, + "id": 40 + }, + { + "value": 0.0, + "id": 41 + }, + { + "value": 0.0, + "id": 42 + }, + { + "value": 0.0, + "id": 43 + }, + { + "value": 0.0, + "id": 44 + }, + { + "value": 0.0, + "id": 45 + }, + { + "value": 0.0, + "id": 46 + }, + { + "value": 0.0, + "id": 47 + }, + { + "value": 0.0, + "id": 48 + }, + { + "value": 0.0, + "id": 49 + }, + { + "value": 0.0, + "id": 50 + }, + { + "value": 0.0, + "id": 51 + }, + { + "value": 0.0, + "id": 52 + }, + { + "value": 0.0, + "id": 53 + }, + { + "value": 0.0, + "id": 54 + }, + { + "value": 0.0, + "id": 55 + }, + { + "value": 0.0, + "id": 56 + }, + { + "value": 0.0, + "id": 57 + }, + { + "value": 0.0, + "id": 58 + }, + { + "value": 0.0, + "id": 59 + } + ], + "leftModuleId": 7354440315312540, + "rightModuleId": 3538881790933672, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Dec 20 2022 09:19:54", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + }, + "modulespecific": { + "loadedPreset": 0, + "presetName": "Init", + "presetIsDirty": true, + "polyphonicMode": false + } + }, + "pos": [ + 53, + 0 + ] + }, + { + "id": 7744264450943662, + "plugin": "Bogaudio", + "model": "Bogaudio-Slew", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 0.076470956206321716, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + } + ], + "leftModuleId": 8078887273046425, + "rightModuleId": 7693134582131517, + "data": {}, + "pos": [ + 61, + 1 + ] + }, + { + "id": 7693134582131517, + "plugin": "SurgeXTRack", + "model": "SurgeXTMixer", + "version": "2.0", + "params": [ + { + "value": 0.89600133895874023, + "id": 0 + }, + { + "value": 0.0025714286603033543, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 0.55385059118270874, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.75699687004089355, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 1.0, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": 1.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 0.0, + "id": 20 + }, + { + "value": 0.0, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 0.80400252342224121, + "id": 24 + }, + { + "value": 0.0, + "id": 25 + }, + { + "value": -0.1679999977350235, + "id": 26 + }, + { + "value": 0.0, + "id": 27 + }, + { + "value": 0.0, + "id": 28 + }, + { + "value": 0.58688509464263916, + "id": 29 + }, + { + "value": 0.0, + "id": 30 + }, + { + "value": 0.0, + "id": 31 + }, + { + "value": 0.0, + "id": 32 + }, + { + "value": 0.0, + "id": 33 + }, + { + "value": 0.0, + "id": 34 + }, + { + "value": 0.0, + "id": 35 + }, + { + "value": 0.0, + "id": 36 + }, + { + "value": 0.0, + "id": 37 + }, + { + "value": 0.0, + "id": 38 + }, + { + "value": 0.0, + "id": 39 + }, + { + "value": 0.0, + "id": 40 + }, + { + "value": 0.0, + "id": 41 + }, + { + "value": 0.0, + "id": 42 + }, + { + "value": 0.0, + "id": 43 + }, + { + "value": 0.0, + "id": 44 + }, + { + "value": 0.0, + "id": 45 + }, + { + "value": 0.0, + "id": 46 + }, + { + "value": 0.0, + "id": 47 + }, + { + "value": 0.0, + "id": 48 + }, + { + "value": 0.0, + "id": 49 + }, + { + "value": 0.0, + "id": 50 + }, + { + "value": 0.0, + "id": 51 + } + ], + "leftModuleId": 7744264450943662, + "rightModuleId": 1629089543055674, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Dec 20 2022 09:19:54", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + }, + "modulespecific": { + "vuChannel": 0 + } + }, + "pos": [ + 64, + 1 + ] + }, + { + "id": 1629089543055674, + "plugin": "SurgeXTRack", + "model": "SurgeXTDelay", + "version": "2.0", + "params": [ + { + "value": -2.0501079559326172, + "id": 0 + }, + { + "value": -1.4222614765167236, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.41385790705680847, + "id": 3 + }, + { + "value": 0.30214270949363708, + "id": 4 + }, + { + "value": -18.046905517578125, + "id": 5 + }, + { + "value": 70.0, + "id": 6 + }, + { + "value": 2.0, + "id": 7 + }, + { + "value": 0.2314288467168808, + "id": 8 + }, + { + "value": 0.32771065831184387, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 0.0, + "id": 20 + }, + { + "value": 0.0, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 0.0, + "id": 24 + }, + { + "value": 0.0, + "id": 25 + }, + { + "value": 0.0, + "id": 26 + }, + { + "value": 0.0, + "id": 27 + }, + { + "value": 0.0, + "id": 28 + }, + { + "value": 0.0, + "id": 29 + }, + { + "value": 0.0, + "id": 30 + }, + { + "value": 0.0, + "id": 31 + }, + { + "value": 0.0, + "id": 32 + }, + { + "value": 0.0, + "id": 33 + }, + { + "value": 0.0, + "id": 34 + }, + { + "value": 0.0, + "id": 35 + }, + { + "value": 0.0, + "id": 36 + }, + { + "value": 0.0, + "id": 37 + }, + { + "value": 0.0, + "id": 38 + }, + { + "value": 0.0, + "id": 39 + }, + { + "value": 0.0, + "id": 40 + }, + { + "value": 0.0, + "id": 41 + }, + { + "value": 0.0, + "id": 42 + }, + { + "value": 0.0, + "id": 43 + }, + { + "value": 0.0, + "id": 44 + }, + { + "value": 0.0, + "id": 45 + }, + { + "value": 0.0, + "id": 46 + }, + { + "value": 0.0, + "id": 47 + }, + { + "value": 0.0, + "id": 48 + }, + { + "value": 0.0, + "id": 49 + } + ], + "leftModuleId": 7693134582131517, + "rightModuleId": 7411284708330475, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Dec 20 2022 09:19:54", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + }, + "modulespecific": { + "clockStyle": 0 + } + }, + "pos": [ + 76, + 1 + ] + }, + { + "id": 7411284708330475, + "plugin": "SurgeXTRack", + "model": "SurgeXTFXReverb2", + "version": "2.0", + "params": [ + { + "value": 0.31384137272834778, + "id": 0 + }, + { + "value": 0.68128818273544312, + "id": 1 + }, + { + "value": 0.75457382202148438, + "id": 2 + }, + { + "value": 0.59514415264129639, + "id": 3 + }, + { + "value": 0.5, + "id": 4 + }, + { + "value": 0.63371568918228149, + "id": 5 + }, + { + "value": 0.5, + "id": 6 + }, + { + "value": 0.5, + "id": 7 + }, + { + "value": 0.5, + "id": 8 + }, + { + "value": 0.32771065831184387, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 0.0, + "id": 20 + }, + { + "value": 0.0, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 0.0, + "id": 24 + }, + { + "value": 0.0, + "id": 25 + }, + { + "value": 0.0, + "id": 26 + }, + { + "value": 0.0, + "id": 27 + }, + { + "value": 0.0, + "id": 28 + }, + { + "value": 0.0, + "id": 29 + }, + { + "value": 0.0, + "id": 30 + }, + { + "value": 0.0, + "id": 31 + }, + { + "value": 0.0, + "id": 32 + }, + { + "value": 0.0, + "id": 33 + }, + { + "value": 0.0, + "id": 34 + }, + { + "value": 0.0, + "id": 35 + }, + { + "value": 0.0, + "id": 36 + }, + { + "value": 0.0, + "id": 37 + }, + { + "value": 0.0, + "id": 38 + }, + { + "value": 0.0, + "id": 39 + }, + { + "value": 0.0, + "id": 40 + }, + { + "value": 0.0, + "id": 41 + }, + { + "value": 0.0, + "id": 42 + }, + { + "value": 0.0, + "id": 43 + }, + { + "value": 0.0, + "id": 44 + }, + { + "value": 0.0, + "id": 45 + }, + { + "value": 0.0, + "id": 46 + }, + { + "value": 0.0, + "id": 47 + }, + { + "value": 0.0, + "id": 48 + }, + { + "value": 0.0, + "id": 49 + }, + { + "value": 0.0, + "id": 50 + }, + { + "value": 0.0, + "id": 51 + }, + { + "value": 0.0, + "id": 52 + }, + { + "value": 0.0, + "id": 53 + }, + { + "value": 0.0, + "id": 54 + }, + { + "value": 0.0, + "id": 55 + }, + { + "value": 0.0, + "id": 56 + }, + { + "value": 0.0, + "id": 57 + }, + { + "value": 0.0, + "id": 58 + }, + { + "value": 0.0, + "id": 59 + } + ], + "leftModuleId": 1629089543055674, + "rightModuleId": 8500492434533465, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Dec 20 2022 09:19:54", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + }, + "modulespecific": { + "loadedPreset": 0, + "presetName": "Init (Dry)", + "presetIsDirty": true, + "polyphonicMode": false + } + }, + "pos": [ + 88, + 1 + ] + }, + { + "id": 8500492434533465, + "plugin": "SurgeXTRack", + "model": "SurgeXTWaveshaper", + "version": "2.0", + "params": [ + { + "value": 1.5479965209960938, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 1.3262277841567993, + "id": 2 + }, + { + "value": -60.0, + "id": 3 + }, + { + "value": 70.0, + "id": 4 + }, + { + "value": -0.12199990451335907, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 0.0, + "id": 20 + }, + { + "value": 0.0, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 0.0, + "id": 24 + }, + { + "value": 1.0, + "id": 25 + }, + { + "value": 0.0, + "id": 26 + }, + { + "value": 0.0, + "id": 27 + } + ], + "leftModuleId": 7411284708330475, + "rightModuleId": 1, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Dec 20 2022 09:19:54", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + } + }, + "pos": [ + 100, + 1 + ] + }, + { + "id": 359762865999381, + "plugin": "MindMeldModular", + "model": "PatchMaster", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.90200126171112061, + "id": 1 + }, + { + "value": 0.39879244565963745, + "id": 2 + }, + { + "value": 0.45300984382629395, + "id": 3 + }, + { + "value": 0.60240930318832397, + "id": 4 + }, + { + "value": 0.75903826951980591, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + } + ], + "leftModuleId": 2859633263682263, + "rightModuleId": 1748021940156784, + "data": { + "miscSettings": 65793, + "miscSettings2": 1, + "tileInfos": [ + 181, + 217, + 179, + 179, + 179, + 179, + 51, + 51, + 155, + 155, + 155, + 155, + 155, + 155, + 155, + 155 + ], + "tileNames": [ + "Mute", + "Level", + "Lead Dist", + "Bass Top", + "Dist Tone", + "Chord Dist", + "No name", + "No name", + "Lead", + "No name", + "No name", + "No name", + "No name", + "No name", + "No name", + "No name" + ], + "maps": [ + { + "moduleId": 7693134582131517, + "paramId": 9, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": 7693134582131517, + "paramId": 24, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": 8631911439676095, + "paramId": 4, + "rangeMax": 0.44400703907012939, + "rangeMin": 0.0 + }, + { + "moduleId": 7354440315312540, + "paramId": 21, + "rangeMax": 0.67599606513977051, + "rangeMin": 0.75699460506439209 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": 8631911439676095, + "paramId": 1, + "rangeMax": 0.39900767803192139, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + } + ], + "radioLits": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "tileOrders": [ + 8, + 2, + 4, + 0, + 1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ], + "tileSettings": [ + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "pos": [ + 14, + 0 + ] + }, + { + "id": 1748021940156784, + "plugin": "MindMeldModular", + "model": "PatchMaster", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.92800092697143555, + "id": 1 + }, + { + "value": 0.36505457758903503, + "id": 2 + }, + { + "value": 0.45300984382629395, + "id": 3 + }, + { + "value": 0.35060781240463257, + "id": 4 + }, + { + "value": 0.75903826951980591, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + } + ], + "leftModuleId": 359762865999381, + "rightModuleId": 6532964214833122, + "data": { + "miscSettings": 65793, + "miscSettings2": 1, + "tileInfos": [ + 181, + 217, + 179, + 179, + 179, + 179, + 51, + 51, + 155, + 155, + 155, + 155, + 155, + 155, + 155, + 155 + ], + "tileNames": [ + "Mute", + "Level", + "Bass Top", + "Bass Top", + "Filer Cutoff", + "Chord Dist", + "No name", + "No name", + "Bass", + "No name", + "No name", + "No name", + "No name", + "No name", + "No name", + "No name" + ], + "maps": [ + { + "moduleId": 7693134582131517, + "paramId": 10, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": 7693134582131517, + "paramId": 29, + "rangeMax": 0.85500186681747437, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": 1202888979525309, + "paramId": 9, + "rangeMax": 0.70200371742248535, + "rangeMin": 0.43799790740013123 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": 2120522391757438, + "paramId": 0, + "rangeMax": 0.7510036826133728, + "rangeMin": 0.2460002601146698 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + } + ], + "radioLits": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "tileOrders": [ + 8, + 2, + 4, + 0, + 1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ], + "tileSettings": [ + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "pos": [ + 18, + 0 + ] + }, + { + "id": 6532964214833122, + "plugin": "MindMeldModular", + "model": "PatchMaster", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.89600133895874023, + "id": 1 + }, + { + "value": 0.6337316632270813, + "id": 2 + }, + { + "value": 0.45300984382629395, + "id": 3 + }, + { + "value": 0.61325019598007202, + "id": 4 + }, + { + "value": 0.75903826951980591, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + } + ], + "leftModuleId": 1748021940156784, + "rightModuleId": 7545907193641280, + "data": { + "miscSettings": 65793, + "miscSettings2": 1, + "tileInfos": [ + 181, + 217, + 179, + 179, + 179, + 179, + 51, + 51, + 155, + 155, + 155, + 155, + 155, + 155, + 155, + 155 + ], + "tileNames": [ + "Mute", + "Level", + "Chord Dist", + "Bass Top", + "Ringmod", + "Chord Dist", + "No name", + "No name", + "Chods", + "No name", + "No name", + "No name", + "No name", + "No name", + "No name", + "No name" + ], + "maps": [ + { + "moduleId": 7693134582131517, + "paramId": 8, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": 7693134582131517, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": 2364063745493562, + "paramId": 2, + "rangeMax": 0.3600081205368042, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": 2364063745493562, + "paramId": 5, + "rangeMax": 0.49200648069381714, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + }, + { + "moduleId": -1, + "paramId": 0, + "rangeMax": 1.0, + "rangeMin": 0.0 + } + ], + "radioLits": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "tileOrders": [ + 8, + 2, + 4, + 0, + 1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ], + "tileSettings": [ + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "pos": [ + 22, + 0 + ] + }, + { + "id": 1, + "plugin": "Cardinal", + "model": "HostAudio2", + "version": "2.0", + "params": [ + { + "value": 1.1899975538253784, + "id": 0 + } + ], + "leftModuleId": 8500492434533465, + "data": { + "dcFilter": true + }, + "pos": [ + 112, + 1 + ] + } + ], + "cables": [ + { + "id": 2270741436436214, + "outputModuleId": 3492788997026115, + "outputId": 4, + "inputModuleId": 6206908039426907, + "inputId": 1, + "color": "#a852ff" + }, + { + "id": 2097699839995605, + "outputModuleId": 3492788997026115, + "outputId": 1, + "inputModuleId": 6206908039426907, + "inputId": 0, + "color": "#e952ff" + }, + { + "id": 6079412029041749, + "outputModuleId": 3623085877119332, + "outputId": 0, + "inputModuleId": 3147629330555360, + "inputId": 0, + "color": "#ff52d4" + }, + { + "id": 2696582111282382, + "outputModuleId": 3623085877119332, + "outputId": 1, + "inputModuleId": 3147629330555360, + "inputId": 1, + "color": "#ff5293" + }, + { + "id": 5161684793713160, + "outputModuleId": 3623085877119332, + "outputId": 2, + "inputModuleId": 3147629330555360, + "inputId": 2, + "color": "#ff5252" + }, + { + "id": 1131487853388165, + "outputModuleId": 3147629330555360, + "outputId": 0, + "inputModuleId": 6408811696897743, + "inputId": 0, + "color": "#ffd452" + }, + { + "id": 2067186493700170, + "outputModuleId": 6206908039426907, + "outputId": 0, + "inputModuleId": 3623085877119332, + "inputId": 0, + "color": "#52ffff" + }, + { + "id": 1423211978847534, + "outputModuleId": 6408811696897743, + "outputId": 0, + "inputModuleId": 1132602188892100, + "inputId": 0, + "color": "#6752ff" + }, + { + "id": 5494619626061851, + "outputModuleId": 6408811696897743, + "outputId": 1, + "inputModuleId": 977849113384714, + "inputId": 0, + "color": "#e952ff" + }, + { + "id": 4950214390198147, + "outputModuleId": 1132602188892100, + "outputId": 0, + "inputModuleId": 2364063745493562, + "inputId": 0, + "color": "#ff52d4" + }, + { + "id": 7274650136027879, + "outputModuleId": 977849113384714, + "outputId": 0, + "inputModuleId": 2364063745493562, + "inputId": 1, + "color": "#ff5293" + }, + { + "id": 7057149860399312, + "outputModuleId": 1772638206753921, + "outputId": 0, + "inputModuleId": 2364063745493562, + "inputId": 4, + "color": "#ffd452" + }, + { + "id": 3994158684795789, + "outputModuleId": 1772638206753921, + "outputId": 1, + "inputModuleId": 2364063745493562, + "inputId": 5, + "color": "#e8ff52" + }, + { + "id": 3699248077047949, + "outputModuleId": 2364063745493562, + "outputId": 0, + "inputModuleId": 7693134582131517, + "inputId": 0, + "color": "#527dff" + }, + { + "id": 3975712550017439, + "outputModuleId": 2364063745493562, + "outputId": 1, + "inputModuleId": 7693134582131517, + "inputId": 1, + "color": "#6752ff" + }, + { + "id": 5300960027149656, + "outputModuleId": 931699531175066, + "outputId": 0, + "inputModuleId": 1660124145346554, + "inputId": 3, + "color": "#e952ff" + }, + { + "id": 900918383140940, + "outputModuleId": 3147629330555360, + "outputId": 0, + "inputModuleId": 1660124145346554, + "inputId": 2, + "color": "#ff52d4" + }, + { + "id": 6532209984750418, + "outputModuleId": 3492788997026115, + "outputId": 1, + "inputModuleId": 1929072526365403, + "inputId": 0, + "color": "#ff9352" + }, + { + "id": 6564485122333790, + "outputModuleId": 1929072526365403, + "outputId": 0, + "inputModuleId": 931699531175066, + "inputId": 1, + "color": "#ffd452" + }, + { + "id": 2253867120168600, + "outputModuleId": 5599750386095483, + "outputId": 0, + "inputModuleId": 1660124145346554, + "inputId": 0, + "color": "#e8ff52" + }, + { + "id": 2550860768686067, + "outputModuleId": 7614703401631065, + "outputId": 1, + "inputModuleId": 7354440315312540, + "inputId": 1, + "color": "#52beff" + }, + { + "id": 4865743156594477, + "outputModuleId": 7614703401631065, + "outputId": 0, + "inputModuleId": 7354440315312540, + "inputId": 0, + "color": "#52ffff" + }, + { + "id": 3879998451215591, + "outputModuleId": 3492788997026115, + "outputId": 1, + "inputModuleId": 1232093242356119, + "inputId": 2, + "color": "#e8ff52" + }, + { + "id": 6677050153459000, + "outputModuleId": 1232093242356119, + "outputId": 0, + "inputModuleId": 7693134582131517, + "inputId": 6, + "color": "#ff52d4" + }, + { + "id": 3180361347060172, + "outputModuleId": 2364063745493562, + "outputId": 0, + "inputModuleId": 8524145861178282, + "inputId": 0, + "color": "#ff5252" + }, + { + "id": 402678970644369, + "outputModuleId": 2364063745493562, + "outputId": 1, + "inputModuleId": 8524145861178282, + "inputId": 1, + "color": "#ff9352" + }, + { + "id": 5399015047720053, + "outputModuleId": 8524145861178282, + "outputId": 0, + "inputModuleId": 1772638206753921, + "inputId": 0, + "color": "#ff5293" + }, + { + "id": 6958403219190982, + "outputModuleId": 8524145861178282, + "outputId": 1, + "inputModuleId": 1772638206753921, + "inputId": 1, + "color": "#ff5252" + }, + { + "id": 8324132731591866, + "outputModuleId": 7693134582131517, + "outputId": 0, + "inputModuleId": 1629089543055674, + "inputId": 0, + "color": "#52ffff" + }, + { + "id": 7409295800152681, + "outputModuleId": 7693134582131517, + "outputId": 1, + "inputModuleId": 1629089543055674, + "inputId": 1, + "color": "#52beff" + }, + { + "id": 1505608255661643, + "outputModuleId": 1629089543055674, + "outputId": 0, + "inputModuleId": 7411284708330475, + "inputId": 0, + "color": "#ff9352" + }, + { + "id": 3530680245499725, + "outputModuleId": 1629089543055674, + "outputId": 1, + "inputModuleId": 7411284708330475, + "inputId": 1, + "color": "#ffd452" + }, + { + "id": 723471606025095, + "outputModuleId": 7411284708330475, + "outputId": 0, + "inputModuleId": 8500492434533465, + "inputId": 0, + "color": "#52ff7d" + }, + { + "id": 2292539798376987, + "outputModuleId": 7411284708330475, + "outputId": 1, + "inputModuleId": 8500492434533465, + "inputId": 1, + "color": "#52ffbe" + }, + { + "id": 5272528188259111, + "outputModuleId": 8500492434533465, + "outputId": 0, + "inputModuleId": 1, + "inputId": 0, + "color": "#e8ff52" + }, + { + "id": 7210535933050930, + "outputModuleId": 8500492434533465, + "outputId": 1, + "inputModuleId": 1, + "inputId": 1, + "color": "#a8ff52" + }, + { + "id": 7908197179992133, + "outputModuleId": 3623085877119332, + "outputId": 0, + "inputModuleId": 1163775849135581, + "inputId": 0, + "color": "#a8ff52" + }, + { + "id": 8721889034446249, + "outputModuleId": 1163775849135581, + "outputId": 0, + "inputModuleId": 2364063745493562, + "inputId": 2, + "color": "#67ff52" + }, + { + "id": 2789356792875946, + "outputModuleId": 1163775849135581, + "outputId": 1, + "inputModuleId": 2364063745493562, + "inputId": 3, + "color": "#52ff7d" + }, + { + "id": 8293492788993096, + "outputModuleId": 3623085877119332, + "outputId": 0, + "inputModuleId": 7579603213780856, + "inputId": 0, + "color": "#a8ff52" + }, + { + "id": 3137984831161391, + "outputModuleId": 7579603213780856, + "outputId": 0, + "inputModuleId": 3272418169313056, + "inputId": 0, + "color": "#52beff" + }, + { + "id": 2993978308546393, + "outputModuleId": 7579603213780856, + "outputId": 1, + "inputModuleId": 3272418169313056, + "inputId": 1, + "color": "#6752ff" + }, + { + "id": 5085636319967600, + "outputModuleId": 3272418169313056, + "outputId": 0, + "inputModuleId": 2120522391757438, + "inputId": 0, + "color": "#ff52d4" + }, + { + "id": 4971591951242566, + "outputModuleId": 3272418169313056, + "outputId": 1, + "inputModuleId": 2120522391757438, + "inputId": 1, + "color": "#ff5293" + }, + { + "id": 8759272365135115, + "outputModuleId": 3492788997026115, + "outputId": 1, + "inputModuleId": 8078887273046425, + "inputId": 2, + "color": "#e8ff52" + }, + { + "id": 3599544925896906, + "outputModuleId": 8078887273046425, + "outputId": 0, + "inputModuleId": 7693134582131517, + "inputId": 7, + "color": "#ff5252" + }, + { + "id": 750935108020452, + "outputModuleId": 1202888979525309, + "outputId": 1, + "inputModuleId": 7693134582131517, + "inputId": 5, + "color": "#e952ff" + }, + { + "id": 2926615471892406, + "outputModuleId": 1202888979525309, + "outputId": 0, + "inputModuleId": 7693134582131517, + "inputId": 4, + "color": "#a852ff" + }, + { + "id": 7247307875742693, + "outputModuleId": 2120522391757438, + "outputId": 0, + "inputModuleId": 1202888979525309, + "inputId": 0, + "color": "#ff9352" + }, + { + "id": 1658873528417062, + "outputModuleId": 2120522391757438, + "outputId": 1, + "inputModuleId": 1202888979525309, + "inputId": 1, + "color": "#ffd452" + }, + { + "id": 6814850604612890, + "outputModuleId": 3623085877119332, + "outputId": 0, + "inputModuleId": 1202888979525309, + "inputId": 5, + "color": "#a8ff52" + }, + { + "id": 2745201661929078, + "outputModuleId": 3272418169313056, + "outputId": 2, + "inputModuleId": 2120522391757438, + "inputId": 2, + "color": "#e8ff52" + }, + { + "id": 2739608613257288, + "outputModuleId": 8078887273046425, + "outputId": 0, + "inputModuleId": 8500492434533465, + "inputId": 2, + "color": "#ff5252" + }, + { + "id": 1459684846251261, + "outputModuleId": 7545907193641280, + "outputId": 0, + "inputModuleId": 7354440315312540, + "inputId": 3, + "color": "#52ff7d" + }, + { + "id": 163404945941087, + "outputModuleId": 7545907193641280, + "outputId": 0, + "inputModuleId": 7614703401631065, + "inputId": 0, + "color": "#52ff7d" + }, + { + "id": 8864417258847625, + "outputModuleId": 1660124145346554, + "outputId": 0, + "inputModuleId": 7545907193641280, + "inputId": 2, + "color": "#a8ff52" + }, + { + "id": 2484026288669710, + "outputModuleId": 8631911439676095, + "outputId": 1, + "inputModuleId": 7693134582131517, + "inputId": 3, + "color": "#a852ff" + }, + { + "id": 6768411060010098, + "outputModuleId": 8631911439676095, + "outputId": 0, + "inputModuleId": 7693134582131517, + "inputId": 2, + "color": "#6752ff" + }, + { + "id": 1066788645723652, + "outputModuleId": 7354440315312540, + "outputId": 0, + "inputModuleId": 8631911439676095, + "inputId": 0, + "color": "#67ff52" + }, + { + "id": 2180617489026327, + "outputModuleId": 7354440315312540, + "outputId": 1, + "inputModuleId": 8631911439676095, + "inputId": 1, + "color": "#52ff7d" + }, + { + "id": 3530286975247477, + "outputModuleId": 7649815730956881, + "outputId": 0, + "inputModuleId": 2364063745493562, + "inputId": 6, + "color": "#a8ff52" + }, + { + "id": 8860630921626163, + "outputModuleId": 3492788997026115, + "outputId": 1, + "inputModuleId": 7649815730956881, + "inputId": 2, + "color": "#e8ff52" + }, + { + "id": 192850560558353, + "outputModuleId": 3492788997026115, + "outputId": 2, + "inputModuleId": 2528905409371299, + "inputId": 0, + "color": "#67ff52" + }, + { + "id": 1934828668532774, + "outputModuleId": 2528905409371299, + "outputId": 0, + "inputModuleId": 8858399717280256, + "inputId": 0, + "color": "#52ffbe" + }, + { + "id": 6464088990534542, + "outputModuleId": 7649815730956881, + "outputId": 0, + "inputModuleId": 1772638206753921, + "inputId": 2, + "color": "#a8ff52" + }, + { + "id": 2398088907667742, + "outputModuleId": 8631911439676095, + "outputId": 0, + "inputModuleId": 7744264450943662, + "inputId": 2, + "color": "#ff5252" + }, + { + "id": 2878078552254813, + "outputModuleId": 7744264450943662, + "outputId": 0, + "inputModuleId": 7693134582131517, + "inputId": 8, + "color": "#ff9352" + }, + { + "id": 4221700082511182, + "outputModuleId": 7545907193641280, + "outputId": 0, + "inputModuleId": 8631911439676095, + "inputId": 5, + "color": "#ff5252" + }, + { + "id": 655041172928169, + "outputModuleId": 8858399717280256, + "outputId": 0, + "inputModuleId": 5599750386095483, + "inputId": 2, + "color": "#e8ff52" + } + ] +} diff --git a/patches/examples/SpotlightKid_-_Classic-Polysynth.vcv b/patches/examples/SpotlightKid_-_Classic-Polysynth.vcv new file mode 100644 index 00000000..c44e21f7 --- /dev/null +++ b/patches/examples/SpotlightKid_-_Classic-Polysynth.vcv @@ -0,0 +1,711 @@ +{ + "version": "2.1.2", + "zoom": 1.0, + "modules": [ + { + "id": 5726895899473528, + "plugin": "Fundamental", + "model": "ADSR", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.73012268543243408, + "id": 1 + }, + { + "value": 0.73614501953125, + "id": 2 + }, + { + "value": 0.64457994699478149, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + } + ], + "leftModuleId": 5337037007035013, + "rightModuleId": 4828178296911509, + "pos": [ + 58, + 0 + ] + }, + { + "id": 4828178296911509, + "plugin": "Fundamental", + "model": "VCA-1", + "version": "2.0", + "params": [ + { + "value": 1.0, + "id": 0 + }, + { + "value": 1.0, + "id": 1 + } + ], + "leftModuleId": 5726895899473528, + "rightModuleId": 6408981600715695, + "pos": [ + 67, + 0 + ] + }, + { + "id": 5337037007035013, + "plugin": "Fundamental", + "model": "ADSR", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.69156646728515625, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.65542322397232056, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + } + ], + "leftModuleId": 8662611283913679, + "rightModuleId": 5726895899473528, + "pos": [ + 49, + 0 + ] + }, + { + "id": 5012071172439093, + "plugin": "Bogaudio", + "model": "Bogaudio-VCO", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": -0.10602404922246933, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": -0.66505992412567139, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 1.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + } + ], + "leftModuleId": 7829403555464046, + "rightModuleId": 3498834829604531, + "data": { + "poly_input": 0, + "dc_correction": true + }, + "pos": [ + 9, + 0 + ] + }, + { + "id": 3498834829604531, + "plugin": "Bogaudio", + "model": "Bogaudio-VCO", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.10602407157421112, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 1.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + } + ], + "leftModuleId": 5012071172439093, + "rightModuleId": 6599230938402504, + "data": { + "poly_input": 0, + "dc_correction": true + }, + "pos": [ + 19, + 0 + ] + }, + { + "id": 6408981600715695, + "plugin": "Bogaudio", + "model": "Bogaudio-LFO", + "version": "2.0", + "params": [ + { + "value": 1.4879528284072876, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.5, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + } + ], + "leftModuleId": 4828178296911509, + "rightModuleId": 1204823109328701, + "data": { + "offset_cv_to_smoothing": false + }, + "pos": [ + 70, + 0 + ] + }, + { + "id": 8662611283913679, + "plugin": "Bogaudio", + "model": "Bogaudio-VCF", + "version": "2.0", + "params": [ + { + "value": 0.17951798439025879, + "id": 0 + }, + { + "value": 0.27710825204849243, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.33428090810775757, + "id": 5 + } + ], + "leftModuleId": 6599230938402504, + "rightModuleId": 5337037007035013, + "data": { + "bandwidthMode": "pitched" + }, + "pos": [ + 39, + 0 + ] + }, + { + "id": 1204823109328701, + "plugin": "Fundamental", + "model": "8vert", + "version": "2.0", + "params": [ + { + "value": 0.16385534405708313, + "id": 0 + }, + { + "value": 0.099999845027923584, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + } + ], + "leftModuleId": 6408981600715695, + "pos": [ + 80, + 0 + ] + }, + { + "id": 6599230938402504, + "plugin": "Bogaudio", + "model": "Bogaudio-VCM", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.89999997615814209, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.89999997615814209, + "id": 3 + }, + { + "value": 0.80000001192092896, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + } + ], + "leftModuleId": 3498834829604531, + "rightModuleId": 8662611283913679, + "data": { + "disableOutputLimit": false + }, + "pos": [ + 29, + 0 + ] + }, + { + "id": 7829403555464046, + "plugin": "Bogaudio", + "model": "Bogaudio-Matrix44", + "version": "2.0", + "params": [ + { + "value": 1.0, + "id": 0 + }, + { + "value": 0.070000037550926208, + "id": 1 + }, + { + "value": 0.035000000149011612, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 1.0, + "id": 4 + }, + { + "value": -0.069999769330024719, + "id": 5 + }, + { + "value": 0.035000000149011612, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + } + ], + "rightModuleId": 5012071172439093, + "data": { + "clipping_mode": 0, + "input_gain_db": 0.0, + "sum": true, + "indicator_knobs": true, + "unipolar": false + }, + "pos": [ + -1, + 0 + ] + }, + { + "id": 2610715620592544, + "plugin": "Cardinal", + "model": "TextEditor", + "version": "2.0", + "params": [], + "data": { + "filepath": "", + "lang": "None", + "etext": "A classic polyphonic 2-oscillator synthesizer\n---------------------------------------------\n\n* 2 VCOs with blendable sawtooth and pulse waves\n* 1 multi-mode filter\n* 1 filter envelope\n* 1 VCA envelope\n* 1 multi-waveform LFO\n\nNotes:\n\n* The LFO is patched to oscillator pitch by default.\n The amount can be controlled via the 2A and 2B level\n knobs of the \"Matrix44\" mixer module.\n* You can control additional destinations with the LFO by \n patching its output(s) into the \"Matrix44\" module's input \n (optionally via the \"8Vert\" attenuator module) and\n then the outputs of the \"Matrix44\" module into the \n destinations. Then use its corresponding level knobs to \n control the amount.\n* The pitch bend amount can be controlled via the 3A and 3B\n level knobs of the \"Matrix44\" module (3.5% is roughly 2\n semitones).\n* The number of polyphonic voices can be set via the \n context menu of the \"Cardinal Host MIDI\" module.\n\n\n\n\n\n\n", + "width": 30 + }, + "pos": [ + 45, + 1 + ] + }, + { + "id": 1, + "plugin": "Cardinal", + "model": "HostAudio2", + "version": "2.0", + "params": [ + { + "value": 0.70632630586624146, + "id": 0 + } + ], + "data": { + "dcFilter": true + }, + "pos": [ + 80, + 1 + ] + }, + { + "id": 2, + "plugin": "Cardinal", + "model": "HostMIDI", + "version": "2.0", + "params": [], + "rightModuleId": 4, + "data": { + "pwRange": 0.0, + "smooth": false, + "channels": 6, + "polyMode": 0, + "lastPitch": 8192, + "lastMod": 0, + "inputChannel": 0, + "outputChannel": 0 + }, + "pos": [ + -1, + 1 + ] + }, + { + "id": 4, + "plugin": "Cardinal", + "model": "HostParameters", + "version": "2.0", + "params": [], + "leftModuleId": 2, + "data": { + "smooth": true + }, + "pos": [ + 8, + 1 + ] + } + ], + "cables": [ + { + "id": 5155876120487880, + "outputModuleId": 2, + "outputId": 1, + "inputModuleId": 5726895899473528, + "inputId": 4, + "color": "#ff9352" + }, + { + "id": 781753834216137, + "outputModuleId": 2, + "outputId": 6, + "inputModuleId": 5726895899473528, + "inputId": 5, + "color": "#ffd452" + }, + { + "id": 3464471860196875, + "outputModuleId": 5726895899473528, + "outputId": 0, + "inputModuleId": 4828178296911509, + "inputId": 0, + "color": "#e8ff52" + }, + { + "id": 3735627013913285, + "outputModuleId": 2, + "outputId": 1, + "inputModuleId": 5337037007035013, + "inputId": 4, + "color": "#ff9352" + }, + { + "id": 580842343744148, + "outputModuleId": 2, + "outputId": 6, + "inputModuleId": 5337037007035013, + "inputId": 5, + "color": "#ffd452" + }, + { + "id": 3568029120047108, + "outputModuleId": 8662611283913679, + "outputId": 0, + "inputModuleId": 4828178296911509, + "inputId": 1, + "color": "#ff5252" + }, + { + "id": 498514594501880, + "outputModuleId": 5337037007035013, + "outputId": 0, + "inputModuleId": 8662611283913679, + "inputId": 0, + "color": "#a8ff52" + }, + { + "id": 1797497447138497, + "outputModuleId": 6408981600715695, + "outputId": 3, + "inputModuleId": 1204823109328701, + "inputId": 0, + "color": "#6752ff" + }, + { + "id": 4517203320689158, + "outputModuleId": 6408981600715695, + "outputId": 3, + "inputModuleId": 1204823109328701, + "inputId": 1, + "color": "#e952ff" + }, + { + "id": 3320898588984728, + "outputModuleId": 4828178296911509, + "outputId": 0, + "inputModuleId": 1, + "inputId": 0, + "color": "#ff9352" + }, + { + "id": 6368912553945733, + "outputModuleId": 5012071172439093, + "outputId": 0, + "inputModuleId": 6599230938402504, + "inputId": 0, + "color": "#ffd452" + }, + { + "id": 7452422491828867, + "outputModuleId": 5012071172439093, + "outputId": 1, + "inputModuleId": 6599230938402504, + "inputId": 2, + "color": "#527dff" + }, + { + "id": 8322447986534562, + "outputModuleId": 3498834829604531, + "outputId": 0, + "inputModuleId": 6599230938402504, + "inputId": 4, + "color": "#67ff52" + }, + { + "id": 7931051349285735, + "outputModuleId": 3498834829604531, + "outputId": 1, + "inputModuleId": 6599230938402504, + "inputId": 6, + "color": "#52ffff" + }, + { + "id": 5415548314308516, + "outputModuleId": 6599230938402504, + "outputId": 0, + "inputModuleId": 8662611283913679, + "inputId": 3, + "color": "#e8ff52" + }, + { + "id": 8251957244621037, + "outputModuleId": 2, + "outputId": 0, + "inputModuleId": 7829403555464046, + "inputId": 0, + "color": "#52ff7d" + }, + { + "id": 696754494174847, + "outputModuleId": 1204823109328701, + "outputId": 1, + "inputModuleId": 7829403555464046, + "inputId": 1, + "color": "#527dff" + }, + { + "id": 8414987939373829, + "outputModuleId": 7829403555464046, + "outputId": 0, + "inputModuleId": 5012071172439093, + "inputId": 0, + "color": "#52ffff" + }, + { + "id": 3908893753031146, + "outputModuleId": 7829403555464046, + "outputId": 1, + "inputModuleId": 3498834829604531, + "inputId": 0, + "color": "#a852ff" + }, + { + "id": 5892222261492300, + "outputModuleId": 2, + "outputId": 4, + "inputModuleId": 7829403555464046, + "inputId": 2, + "color": "#e952ff" + } + ] +} diff --git a/patches/examples/falkTX_-_Divide-no-Conquer.vcv b/patches/examples/falkTX_-_Divide-no-Conquer.vcv new file mode 100644 index 00000000..ee66da90 --- /dev/null +++ b/patches/examples/falkTX_-_Divide-no-Conquer.vcv @@ -0,0 +1,858 @@ +{ + "version": "2.1.2", + "zoom": 1.0, + "modules": [ + { + "id": 2323510085504344, + "plugin": "Mog", + "model": "Network", + "version": "2.0", + "params": [ + { + "value": 0.5, + "id": 0 + }, + { + "value": 0.5, + "id": 1 + }, + { + "value": 0.5, + "id": 2 + }, + { + "value": 0.5, + "id": 3 + }, + { + "value": 0.5, + "id": 4 + }, + { + "value": 0.5, + "id": 5 + }, + { + "value": 0.5, + "id": 6 + }, + { + "value": 0.5, + "id": 7 + }, + { + "value": 0.5, + "id": 8 + }, + { + "value": 0.5, + "id": 9 + }, + { + "value": 0.5, + "id": 10 + }, + { + "value": 0.5, + "id": 11 + }, + { + "value": 0.5, + "id": 12 + }, + { + "value": 0.5, + "id": 13 + }, + { + "value": 0.5, + "id": 14 + }, + { + "value": 0.5, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.40000000596046448, + "id": 18 + }, + { + "value": 1.0, + "id": 19 + }, + { + "value": 0.0, + "id": 20 + } + ], + "data": { + "channels": 16, + "polyMode": 1, + "nodeStates": [ + -1, + -1, + -1, + -1, + -1, + -1, + -1, + 0, + -2, + -1, + -1, + -1, + -2, + 0, + -2, + -1 + ] + }, + "pos": [ + 5, + 0 + ] + }, + { + "id": 7733409763520287, + "plugin": "Fundamental", + "model": "LFO", + "version": "2.0", + "params": [ + { + "value": 1.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 2.1946320533752441, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.5, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + } + ], + "pos": [ + -5, + -1 + ] + }, + { + "id": 7910322281435707, + "plugin": "GoodSheperd", + "model": "SEQ3st", + "version": "2.0", + "params": [ + { + "value": 1.2771106958389282, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 8.0, + "id": 3 + }, + { + "value": 0.33734941482543945, + "id": 4 + }, + { + "value": 2.1566267013549805, + "id": 5 + }, + { + "value": 1.3012033700942993, + "id": 6 + }, + { + "value": 1.8674684762954712, + "id": 7 + }, + { + "value": 2.4819269180297852, + "id": 8 + }, + { + "value": 1.9036139249801636, + "id": 9 + }, + { + "value": 2.1807231903076172, + "id": 10 + }, + { + "value": 1.493976354598999, + "id": 11 + }, + { + "value": 1.3975902795791626, + "id": 12 + }, + { + "value": 1.4337348937988281, + "id": 13 + }, + { + "value": 1.9277111291885376, + "id": 14 + }, + { + "value": 1.9277104139328003, + "id": 15 + }, + { + "value": 0.74698799848556519, + "id": 16 + }, + { + "value": 1.3614462614059448, + "id": 17 + }, + { + "value": 0.45783132314682007, + "id": 18 + }, + { + "value": 0.98795127868652344, + "id": 19 + }, + { + "value": 0.1686750054359436, + "id": 20 + }, + { + "value": 1.0782999992370605, + "id": 21 + }, + { + "value": 0.65060001611709595, + "id": 22 + }, + { + "value": 0.9337499737739563, + "id": 23 + }, + { + "value": 1.2409499883651733, + "id": 24 + }, + { + "value": 0.95179998874664307, + "id": 25 + }, + { + "value": 1.0903500318527222, + "id": 26 + }, + { + "value": 0.74699997901916504, + "id": 27 + }, + { + "value": 0.0, + "id": 28 + }, + { + "value": 0.0, + "id": 29 + }, + { + "value": 0.0, + "id": 30 + }, + { + "value": 0.0, + "id": 31 + }, + { + "value": 0.0, + "id": 32 + }, + { + "value": 0.0, + "id": 33 + }, + { + "value": 0.0, + "id": 34 + }, + { + "value": 0.0, + "id": 35 + }, + { + "value": 0.0, + "id": 36 + } + ], + "rightModuleId": 7124670414167707, + "data": { + "running": true, + "gates": [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ] + }, + "pos": [ + 5, + -1 + ] + }, + { + "id": 6113641652229320, + "plugin": "Fundamental", + "model": "Quantizer", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + } + ], + "leftModuleId": 7124670414167707, + "data": { + "enabledNotes": [ + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false + ] + }, + "pos": [ + 44, + -1 + ] + }, + { + "id": 6436949913364135, + "plugin": "Befaco", + "model": "EvenVCO", + "version": "2.0", + "params": [ + { + "value": -5.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + } + ], + "pos": [ + 53, + -1 + ] + }, + { + "id": 7124670414167707, + "plugin": "Extratone", + "model": "Ichneumonid", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 1.0, + "id": 7 + }, + { + "value": 1.0, + "id": 8 + }, + { + "value": 1.0, + "id": 9 + }, + { + "value": 1.0, + "id": 10 + }, + { + "value": 1.0, + "id": 11 + }, + { + "value": 1.0, + "id": 12 + }, + { + "value": 1.0, + "id": 13 + }, + { + "value": 1.0, + "id": 14 + }, + { + "value": 1.0, + "id": 15 + } + ], + "leftModuleId": 7910322281435707, + "rightModuleId": 6113641652229320, + "pos": [ + 32, + -1 + ] + }, + { + "id": 6704396017183286, + "plugin": "Bogaudio", + "model": "Bogaudio-Unison", + "version": "2.0", + "params": [ + { + "value": 16.0, + "id": 0 + }, + { + "value": 30.662649154663086, + "id": 1 + } + ], + "data": {}, + "pos": [ + 49, + -1 + ] + }, + { + "id": 5274645123493261, + "plugin": "AudibleInstruments", + "model": "Plaits", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": -2.0, + "id": 2 + }, + { + "value": 0.5, + "id": 3 + }, + { + "value": 0.5, + "id": 4 + }, + { + "value": 0.5, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.5, + "id": 9 + }, + { + "value": 0.5, + "id": 10 + } + ], + "leftModuleId": 3982223550835589, + "rightModuleId": 3927208667084646, + "data": { + "lowCpu": true, + "model": 14 + }, + "pos": [ + 34, + 0 + ] + }, + { + "id": 3927208667084646, + "plugin": "AudibleInstruments", + "model": "Plaits", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": -1.0, + "id": 2 + }, + { + "value": 0.5, + "id": 3 + }, + { + "value": 0.75, + "id": 4 + }, + { + "value": 0.5, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.5, + "id": 9 + }, + { + "value": 0.5, + "id": 10 + } + ], + "leftModuleId": 5274645123493261, + "data": { + "lowCpu": true, + "model": 10 + }, + "pos": [ + 46, + 0 + ] + }, + { + "id": 3982223550835589, + "plugin": "MockbaModular", + "model": "Dividah", + "version": "2.0", + "params": [], + "rightModuleId": 5274645123493261, + "pos": [ + 32, + 0 + ] + }, + { + "id": 3793316304034300, + "plugin": "Cardinal", + "model": "HostAudio2", + "version": "2.0", + "params": [ + { + "value": 0.31600001454353333, + "id": 0 + } + ], + "data": { + "dcFilter": true + }, + "pos": [ + 62, + -1 + ] + }, + { + "id": 4515410204981580, + "plugin": "Cardinal", + "model": "HostAudio2", + "version": "2.0", + "params": [ + { + "value": 1.42400062084198, + "id": 0 + } + ], + "leftModuleId": 4385899070319166, + "data": { + "dcFilter": true + }, + "pos": [ + 67, + 0 + ] + }, + { + "id": 4385899070319166, + "plugin": "Cardinal", + "model": "HostAudio2", + "version": "2.0", + "params": [ + { + "value": 0.8400002121925354, + "id": 0 + } + ], + "rightModuleId": 4515410204981580, + "data": { + "dcFilter": true + }, + "pos": [ + 59, + 0 + ] + } + ], + "cables": [ + { + "id": 8073390375565190, + "outputModuleId": 2323510085504344, + "outputId": 1, + "inputModuleId": 2323510085504344, + "inputId": 9, + "color": "#ffd452" + }, + { + "id": 8282467367250825, + "outputModuleId": 7733409763520287, + "outputId": 3, + "inputModuleId": 2323510085504344, + "inputId": 0, + "color": "#a8ff52" + }, + { + "id": 7741525453916855, + "outputModuleId": 7733409763520287, + "outputId": 3, + "inputModuleId": 7910322281435707, + "inputId": 1, + "color": "#67ff52" + }, + { + "id": 7343310319365506, + "outputModuleId": 7910322281435707, + "outputId": 1, + "inputModuleId": 7124670414167707, + "inputId": 8, + "color": "#527dff" + }, + { + "id": 8663072108782081, + "outputModuleId": 7910322281435707, + "outputId": 2, + "inputModuleId": 7124670414167707, + "inputId": 9, + "color": "#ff5293" + }, + { + "id": 2408554084144896, + "outputModuleId": 7124670414167707, + "outputId": 1, + "inputModuleId": 6113641652229320, + "inputId": 0, + "color": "#ff5252" + }, + { + "id": 1993175531751407, + "outputModuleId": 2323510085504344, + "outputId": 40, + "inputModuleId": 2323510085504344, + "inputId": 22, + "color": "#a8ff52" + }, + { + "id": 3675645084235896, + "outputModuleId": 2323510085504344, + "outputId": 60, + "inputModuleId": 7124670414167707, + "inputId": 4, + "color": "#6752ff" + }, + { + "id": 914539014511784, + "outputModuleId": 2323510085504344, + "outputId": 28, + "inputModuleId": 7124670414167707, + "inputId": 5, + "color": "#a852ff" + }, + { + "id": 4466427789626097, + "outputModuleId": 6704396017183286, + "outputId": 0, + "inputModuleId": 6436949913364135, + "inputId": 1, + "color": "#52beff" + }, + { + "id": 6032249062735731, + "outputModuleId": 6704396017183286, + "outputId": 1, + "inputModuleId": 6436949913364135, + "inputId": 0, + "color": "#527dff" + }, + { + "id": 5205186222022677, + "outputModuleId": 6436949913364135, + "outputId": 2, + "inputModuleId": 3793316304034300, + "inputId": 0, + "color": "#a852ff" + }, + { + "id": 205800917378687, + "outputModuleId": 2323510085504344, + "outputId": 46, + "inputModuleId": 2323510085504344, + "inputId": 31, + "color": "#ffd452" + }, + { + "id": 5650060513024868, + "outputModuleId": 2323510085504344, + "outputId": 16, + "inputModuleId": 2323510085504344, + "inputId": 15, + "color": "#67ff52" + }, + { + "id": 212470725194084, + "outputModuleId": 3927208667084646, + "outputId": 0, + "inputModuleId": 4515410204981580, + "inputId": 0, + "color": "#52ffff" + }, + { + "id": 793863606792629, + "outputModuleId": 5274645123493261, + "outputId": 0, + "inputModuleId": 4385899070319166, + "inputId": 0, + "color": "#52ffff" + }, + { + "id": 940323606941669, + "outputModuleId": 7733409763520287, + "outputId": 3, + "inputModuleId": 3982223550835589, + "inputId": 0, + "color": "#67ff52" + }, + { + "id": 3055152764376614, + "outputModuleId": 3982223550835589, + "outputId": 0, + "inputModuleId": 3927208667084646, + "inputId": 5, + "color": "#52ffff" + }, + { + "id": 5223449680888454, + "outputModuleId": 3982223550835589, + "outputId": 1, + "inputModuleId": 5274645123493261, + "inputId": 5, + "color": "#52ffff" + }, + { + "id": 6071685052548665, + "outputModuleId": 6113641652229320, + "outputId": 0, + "inputModuleId": 6704396017183286, + "inputId": 1, + "color": "#527dff" + }, + { + "id": 1592690071120657, + "outputModuleId": 2323510085504344, + "outputId": 16, + "inputModuleId": 2323510085504344, + "inputId": 20, + "color": "#ff9352" + } + ] +} diff --git a/patches/mini/JTB_-_Proof-Of-Concept.vcv b/patches/mini/JTB_-_Proof-Of-Concept.vcv deleted file mode 100644 index 9cedef0f..00000000 --- a/patches/mini/JTB_-_Proof-Of-Concept.vcv +++ /dev/null @@ -1,2299 +0,0 @@ -{ - "version": "2.1.2", - "zoom": 0.8264508843421936, - "modules": [ - { - "id": 5726895899473528, - "plugin": "Fundamental", - "model": "ADSR", - "version": "2.0", - "params": [ - { - "value": 0.0, - "id": 0 - }, - { - "value": 0.59999996423721313, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 0.60722893476486206, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.0, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - }, - { - "value": 0.0, - "id": 7 - }, - { - "value": 0.0, - "id": 8 - } - ], - "leftModuleId": 3146744790938462, - "rightModuleId": 1394719894730985, - "pos": [ - 30, - 0 - ] - }, - { - "id": 4828178296911509, - "plugin": "Fundamental", - "model": "VCA-1", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - }, - { - "value": 1.0, - "id": 1 - } - ], - "leftModuleId": 1133100648267642, - "rightModuleId": 8394463014211348, - "pos": [ - 64, - 0 - ] - }, - { - "id": 8601159184541723, - "plugin": "Fundamental", - "model": "VCO", - "version": "2.0", - "params": [ - { - "value": 0.0, - "id": 0 - }, - { - "value": 1.0, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 0.0, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.5, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - }, - { - "value": 0.0, - "id": 7 - } - ], - "leftModuleId": 8418253494908594, - "rightModuleId": 1647649757935413, - "pos": [ - 12, - -1 - ] - }, - { - "id": 758005564709860, - "plugin": "Fundamental", - "model": "Quantizer", - "version": "2.0", - "params": [ - { - "value": -0.22650615870952606, - "id": 0 - } - ], - "leftModuleId": 8873341177893106, - "rightModuleId": 8465489170887570, - "data": { - "enabledNotes": [ - false, - true, - false, - true, - false, - false, - true, - false, - false, - false, - true, - false - ] - }, - "pos": [ - 40, - -1 - ] - }, - { - "id": 8465489170887570, - "plugin": "Fundamental", - "model": "Quantizer", - "version": "2.0", - "params": [ - { - "value": -0.30361443758010864, - "id": 0 - } - ], - "leftModuleId": 758005564709860, - "rightModuleId": 4423007809468738, - "data": { - "enabledNotes": [ - false, - false, - false, - true, - false, - false, - true, - false, - true, - false, - false, - true - ] - }, - "pos": [ - 44, - -1 - ] - }, - { - "id": 683104811224040, - "plugin": "Fundamental", - "model": "Quantizer", - "version": "2.0", - "params": [ - { - "value": -0.17831322550773621, - "id": 0 - } - ], - "leftModuleId": 4423007809468738, - "rightModuleId": 4531725331261861, - "data": { - "enabledNotes": [ - false, - true, - false, - false, - false, - true, - false, - false, - true, - false, - true, - false - ] - }, - "pos": [ - 52, - -1 - ] - }, - { - "id": 4423007809468738, - "plugin": "Fundamental", - "model": "Quantizer", - "version": "2.0", - "params": [ - { - "value": -0.55662649869918823, - "id": 0 - } - ], - "leftModuleId": 8465489170887570, - "rightModuleId": 683104811224040, - "data": { - "enabledNotes": [ - false, - true, - false, - false, - false, - true, - true, - false, - false, - false, - true, - false - ] - }, - "pos": [ - 48, - -1 - ] - }, - { - "id": 8873341177893106, - "plugin": "Fundamental", - "model": "SequentialSwitch2", - "version": "2.0", - "params": [ - { - "value": 2.0, - "id": 0 - } - ], - "leftModuleId": 7206256653286977, - "rightModuleId": 758005564709860, - "pos": [ - 37, - -1 - ] - }, - { - "id": 5218974527740722, - "plugin": "Fundamental", - "model": "LFO", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - }, - { - "value": 1.0, - "id": 1 - }, - { - "value": 0.65301215648651123, - "id": 2 - }, - { - "value": 0.0, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.5, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - } - ], - "rightModuleId": 1035685351131893, - "pos": [ - -33, - -1 - ] - }, - { - "id": 1163131007452317, - "plugin": "Fundamental", - "model": "Octave", - "version": "2.0", - "params": [ - { - "value": -1.0, - "id": 0 - } - ], - "leftModuleId": 4531725331261861, - "rightModuleId": 891362589771903, - "pos": [ - 61, - -1 - ] - }, - { - "id": 8418253494908594, - "plugin": "Fundamental", - "model": "Random", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - }, - { - "value": 0.0, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 0.0, - "id": 3 - }, - { - "value": 1.0, - "id": 4 - }, - { - "value": 1.0, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - }, - { - "value": 0.0, - "id": 7 - }, - { - "value": 0.0, - "id": 8 - }, - { - "value": 0.0, - "id": 9 - } - ], - "leftModuleId": 5395301826848558, - "rightModuleId": 8601159184541723, - "pos": [ - 3, - -1 - ] - }, - { - "id": 5395301826848558, - "plugin": "Fundamental", - "model": "LFO", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - }, - { - "value": 1.0, - "id": 1 - }, - { - "value": -2.0, - "id": 2 - }, - { - "value": 0.0, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.5, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - } - ], - "leftModuleId": 731196840446297, - "rightModuleId": 8418253494908594, - "pos": [ - -6, - -1 - ] - }, - { - "id": 731196840446297, - "plugin": "Fundamental", - "model": "LFO", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - }, - { - "value": 1.0, - "id": 1 - }, - { - "value": 3.0, - "id": 2 - }, - { - "value": 0.0, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.5, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - } - ], - "leftModuleId": 1035685351131893, - "rightModuleId": 5395301826848558, - "pos": [ - -15, - -1 - ] - }, - { - "id": 1133100648267642, - "plugin": "Fundamental", - "model": "VCF", - "version": "2.0", - "params": [ - { - "value": 0.1967989057302475, - "id": 0 - }, - { - "value": 0.0, - "id": 1 - }, - { - "value": 0.46144583821296692, - "id": 2 - }, - { - "value": 1.0, - "id": 3 - }, - { - "value": 0.31325310468673706, - "id": 4 - }, - { - "value": 0.433735191822052, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - } - ], - "leftModuleId": 1259717562922476, - "rightModuleId": 4828178296911509, - "pos": [ - 57, - 0 - ] - }, - { - "id": 1394719894730985, - "plugin": "Fundamental", - "model": "ADSR", - "version": "2.0", - "params": [ - { - "value": 0.0, - "id": 0 - }, - { - "value": 0.58072292804718018, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 0.3554217517375946, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.0, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - }, - { - "value": 0.0, - "id": 7 - }, - { - "value": 0.0, - "id": 8 - } - ], - "leftModuleId": 5726895899473528, - "rightModuleId": 1259717562922476, - "pos": [ - 39, - 0 - ] - }, - { - "id": 1259717562922476, - "plugin": "Fundamental", - "model": "VCMixer", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - }, - { - "value": 0.74799954891204834, - "id": 1 - }, - { - "value": 0.50605034828186035, - "id": 2 - }, - { - "value": 0.7495308518409729, - "id": 3 - }, - { - "value": 1.0, - "id": 4 - }, - { - "value": 1.0, - "id": 5 - }, - { - "value": 1.0, - "id": 6 - }, - { - "value": 1.0, - "id": 7 - }, - { - "value": 1.0, - "id": 8 - }, - { - "value": 1.0, - "id": 9 - } - ], - "leftModuleId": 1394719894730985, - "rightModuleId": 1133100648267642, - "pos": [ - 48, - 0 - ] - }, - { - "id": 1647649757935413, - "plugin": "Fundamental", - "model": "8vert", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - }, - { - "value": 0.0, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 0.0, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": -1.0, - "id": 5 - }, - { - "value": 0.35445797443389893, - "id": 6 - }, - { - "value": 0.19518086314201355, - "id": 7 - } - ], - "leftModuleId": 8601159184541723, - "rightModuleId": 5352206433681871, - "pos": [ - 21, - -1 - ] - }, - { - "id": 5352206433681871, - "plugin": "Fundamental", - "model": "Noise", - "version": "2.0", - "params": [], - "leftModuleId": 1647649757935413, - "rightModuleId": 7206256653286977, - "pos": [ - 29, - -1 - ] - }, - { - "id": 891362589771903, - "plugin": "Fundamental", - "model": "Octave", - "version": "2.0", - "params": [ - { - "value": 0.0, - "id": 0 - } - ], - "leftModuleId": 1163131007452317, - "rightModuleId": 5864032949729166, - "pos": [ - 64, - -1 - ] - }, - { - "id": 3146744790938462, - "plugin": "Fundamental", - "model": "LFO", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - }, - { - "value": 1.0, - "id": 1 - }, - { - "value": 3.0, - "id": 2 - }, - { - "value": 0.0, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.5, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - } - ], - "leftModuleId": 8016435651914356, - "rightModuleId": 5726895899473528, - "pos": [ - 21, - 0 - ] - }, - { - "id": 1691892280815347, - "plugin": "Fundamental", - "model": "Random", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - }, - { - "value": 0.0, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 0.0, - "id": 3 - }, - { - "value": 0.030120406299829483, - "id": 4 - }, - { - "value": 1.0, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - }, - { - "value": 0.0, - "id": 7 - }, - { - "value": 1.0, - "id": 8 - }, - { - "value": 0.0, - "id": 9 - } - ], - "leftModuleId": 5864032949729166, - "rightModuleId": 6544530457999805, - "pos": [ - 76, - -1 - ] - }, - { - "id": 6544530457999805, - "plugin": "Fundamental", - "model": "Random", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - }, - { - "value": 0.0, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 0.0, - "id": 3 - }, - { - "value": 1.0, - "id": 4 - }, - { - "value": 1.0, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - }, - { - "value": 0.0, - "id": 7 - }, - { - "value": 0.0, - "id": 8 - }, - { - "value": 0.0, - "id": 9 - } - ], - "leftModuleId": 1691892280815347, - "pos": [ - 85, - -1 - ] - }, - { - "id": 1233074000424232, - "plugin": "Fundamental", - "model": "VCMixer", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - }, - { - "value": 0.75805014371871948, - "id": 1 - }, - { - "value": 0.95399570465087891, - "id": 2 - }, - { - "value": 1.0, - "id": 3 - }, - { - "value": 1.0, - "id": 4 - }, - { - "value": 1.0, - "id": 5 - }, - { - "value": 1.0, - "id": 6 - }, - { - "value": 1.0, - "id": 7 - }, - { - "value": 1.0, - "id": 8 - }, - { - "value": 1.0, - "id": 9 - } - ], - "leftModuleId": 3385514259127415, - "rightModuleId": 1, - "pos": [ - 79, - 0 - ] - }, - { - "id": 2730774444988771, - "plugin": "Fundamental", - "model": "ADSR", - "version": "2.0", - "params": [ - { - "value": 0.33253011107444763, - "id": 0 - }, - { - "value": 0.58072292804718018, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 0.3554217517375946, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.0, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - }, - { - "value": 0.0, - "id": 7 - }, - { - "value": 0.0, - "id": 8 - } - ], - "leftModuleId": 3201369453135267, - "rightModuleId": 7433032281179785, - "pos": [ - -28, - 0 - ] - }, - { - "id": 3201369453135267, - "plugin": "Fundamental", - "model": "ADSR", - "version": "2.0", - "params": [ - { - "value": 0.32168671488761902, - "id": 0 - }, - { - "value": 0.59999996423721313, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 0.32409638166427612, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.0, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - }, - { - "value": 0.0, - "id": 7 - }, - { - "value": 0.0, - "id": 8 - } - ], - "leftModuleId": 5646145412017245, - "rightModuleId": 2730774444988771, - "pos": [ - -37, - 0 - ] - }, - { - "id": 5646145412017245, - "plugin": "Fundamental", - "model": "VCO", - "version": "2.0", - "params": [ - { - "value": 0.0, - "id": 0 - }, - { - "value": 1.0, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 0.0, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.5, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - }, - { - "value": 0.0, - "id": 7 - } - ], - "rightModuleId": 3201369453135267, - "pos": [ - -46, - 0 - ] - }, - { - "id": 2032233011372771, - "plugin": "Fundamental", - "model": "VCA-1", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - }, - { - "value": 1.0, - "id": 1 - } - ], - "leftModuleId": 7382588397539714, - "rightModuleId": 8016435651914356, - "pos": [ - 9, - 0 - ] - }, - { - "id": 5418598651204386, - "plugin": "Fundamental", - "model": "VCMixer", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - }, - { - "value": 0.59294706583023071, - "id": 1 - }, - { - "value": 0.29136249423027039, - "id": 2 - }, - { - "value": 0.55528944730758667, - "id": 3 - }, - { - "value": 1.0, - "id": 4 - }, - { - "value": 1.0, - "id": 5 - }, - { - "value": 1.0, - "id": 6 - }, - { - "value": 1.0, - "id": 7 - }, - { - "value": 1.0, - "id": 8 - }, - { - "value": 1.0, - "id": 9 - } - ], - "leftModuleId": 2580763714379115, - "rightModuleId": 7382588397539714, - "pos": [ - -7, - 0 - ] - }, - { - "id": 7382588397539714, - "plugin": "Fundamental", - "model": "VCF", - "version": "2.0", - "params": [ - { - "value": 0.5689617395401001, - "id": 0 - }, - { - "value": 0.0, - "id": 1 - }, - { - "value": 0.16144582629203796, - "id": 2 - }, - { - "value": 1.0, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.18554241955280304, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - } - ], - "leftModuleId": 5418598651204386, - "rightModuleId": 2032233011372771, - "pos": [ - 2, - 0 - ] - }, - { - "id": 2580763714379115, - "plugin": "Fundamental", - "model": "ADSR", - "version": "2.0", - "params": [ - { - "value": 0.0, - "id": 0 - }, - { - "value": 0.0, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 0.3879525363445282, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.0, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - }, - { - "value": 0.0, - "id": 7 - }, - { - "value": 0.0, - "id": 8 - } - ], - "leftModuleId": 7433032281179785, - "rightModuleId": 5418598651204386, - "pos": [ - -16, - 0 - ] - }, - { - "id": 7433032281179785, - "plugin": "Fundamental", - "model": "Mixer", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - } - ], - "leftModuleId": 2730774444988771, - "rightModuleId": 2580763714379115, - "data": { - "average": false, - "invert": false - }, - "pos": [ - -19, - 0 - ] - }, - { - "id": 8016435651914356, - "plugin": "Fundamental", - "model": "Delay", - "version": "2.0", - "params": [ - { - "value": 0.7241402268409729, - "id": 0 - }, - { - "value": 0.71686756610870361, - "id": 1 - }, - { - "value": 0.5, - "id": 2 - }, - { - "value": 0.66144609451293945, - "id": 3 - }, - { - "value": 0.27951806783676147, - "id": 4 - }, - { - "value": 0.0, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - }, - { - "value": 0.0, - "id": 7 - } - ], - "leftModuleId": 2032233011372771, - "rightModuleId": 3146744790938462, - "pos": [ - 12, - 0 - ] - }, - { - "id": 5864032949729166, - "plugin": "Fundamental", - "model": "LFO", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - }, - { - "value": 1.0, - "id": 1 - }, - { - "value": -2.0, - "id": 2 - }, - { - "value": 0.0, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.75, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - } - ], - "leftModuleId": 891362589771903, - "rightModuleId": 1691892280815347, - "pos": [ - 67, - -1 - ] - }, - { - "id": 6507602521553750, - "plugin": "Fundamental", - "model": "VCO", - "version": "2.0", - "params": [ - { - "value": 0.0, - "id": 0 - }, - { - "value": 1.0, - "id": 1 - }, - { - "value": -24.722892761230469, - "id": 2 - }, - { - "value": 0.0, - "id": 3 - }, - { - "value": 0.24337352812290192, - "id": 4 - }, - { - "value": 0.5, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - }, - { - "value": 0.0, - "id": 7 - } - ], - "leftModuleId": 1527334562618244, - "rightModuleId": 2378286691858201, - "pos": [ - 25, - -2 - ] - }, - { - "id": 3893327492950413, - "plugin": "Fundamental", - "model": "ADSR", - "version": "2.0", - "params": [ - { - "value": 0.0, - "id": 0 - }, - { - "value": 0.25903621315956116, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 0.3554217517375946, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.0, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - }, - { - "value": 0.0, - "id": 7 - }, - { - "value": 0.0, - "id": 8 - } - ], - "rightModuleId": 1527334562618244, - "pos": [ - 7, - -2 - ] - }, - { - "id": 1527334562618244, - "plugin": "Fundamental", - "model": "ADSR", - "version": "2.0", - "params": [ - { - "value": 0.0, - "id": 0 - }, - { - "value": 0.51807236671447754, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 0.49156633019447327, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.0, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - }, - { - "value": 0.0, - "id": 7 - }, - { - "value": 0.0, - "id": 8 - } - ], - "leftModuleId": 3893327492950413, - "rightModuleId": 6507602521553750, - "pos": [ - 16, - -2 - ] - }, - { - "id": 2378286691858201, - "plugin": "Fundamental", - "model": "VCA-1", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - }, - { - "value": 1.0, - "id": 1 - } - ], - "leftModuleId": 6507602521553750, - "rightModuleId": 4455336980892018, - "pos": [ - 34, - -2 - ] - }, - { - "id": 4455336980892018, - "plugin": "Fundamental", - "model": "VCF", - "version": "2.0", - "params": [ - { - "value": 0.83173602819442749, - "id": 0 - }, - { - "value": 0.0, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 0.0, - "id": 3 - }, - { - "value": 0.053012050688266754, - "id": 4 - }, - { - "value": 0.0, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - } - ], - "leftModuleId": 2378286691858201, - "rightModuleId": 6747341247828307, - "pos": [ - 37, - -2 - ] - }, - { - "id": 6747341247828307, - "plugin": "Fundamental", - "model": "VCF", - "version": "2.0", - "params": [ - { - "value": 0.28478816151618958, - "id": 0 - }, - { - "value": 0.0, - "id": 1 - }, - { - "value": 0.25542160868644714, - "id": 2 - }, - { - "value": 0.5951806902885437, - "id": 3 - }, - { - "value": 0.10361450910568237, - "id": 4 - }, - { - "value": 0.0, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - } - ], - "leftModuleId": 4455336980892018, - "pos": [ - 44, - -2 - ] - }, - { - "id": 3385514259127415, - "plugin": "Fundamental", - "model": "Mixer", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - } - ], - "leftModuleId": 8394463014211348, - "rightModuleId": 1233074000424232, - "data": { - "average": false, - "invert": false - }, - "pos": [ - 76, - 0 - ] - }, - { - "id": 7206256653286977, - "plugin": "Fundamental", - "model": "Merge", - "version": "2.0", - "params": [], - "leftModuleId": 5352206433681871, - "rightModuleId": 8873341177893106, - "data": { - "channels": -1 - }, - "pos": [ - 32, - -1 - ] - }, - { - "id": 4531725331261861, - "plugin": "Fundamental", - "model": "Split", - "version": "2.0", - "params": [], - "leftModuleId": 683104811224040, - "rightModuleId": 1163131007452317, - "pos": [ - 56, - -1 - ] - }, - { - "id": 8394463014211348, - "plugin": "Fundamental", - "model": "ADSR", - "version": "2.0", - "params": [ - { - "value": 0.0, - "id": 0 - }, - { - "value": 0.63132643699645996, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 0.62530171871185303, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.0, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - }, - { - "value": 0.0, - "id": 7 - }, - { - "value": 0.0, - "id": 8 - } - ], - "leftModuleId": 4828178296911509, - "rightModuleId": 3385514259127415, - "pos": [ - 67, - 0 - ] - }, - { - "id": 1035685351131893, - "plugin": "Fundamental", - "model": "LFO", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - }, - { - "value": 1.0, - "id": 1 - }, - { - "value": 1.0, - "id": 2 - }, - { - "value": 0.0, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.5, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - } - ], - "leftModuleId": 5218974527740722, - "rightModuleId": 731196840446297, - "pos": [ - -24, - -1 - ] - }, - { - "id": 1, - "plugin": "Cardinal", - "model": "HostAudio2", - "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - } - ], - "leftModuleId": 1233074000424232, - "data": { - "dcFilter": true - }, - "pos": [ - 88, - 0 - ] - } - ], - "cables": [ - { - "id": 8294316115570611, - "outputModuleId": 758005564709860, - "outputId": 0, - "inputModuleId": 8873341177893106, - "inputId": 2, - "color": "#52ffff" - }, - { - "id": 5555057650117096, - "outputModuleId": 8465489170887570, - "outputId": 0, - "inputModuleId": 8873341177893106, - "inputId": 3, - "color": "#52beff" - }, - { - "id": 3575299420836353, - "outputModuleId": 683104811224040, - "outputId": 0, - "inputModuleId": 8873341177893106, - "inputId": 5, - "color": "#6752ff" - }, - { - "id": 6673705553204462, - "outputModuleId": 1163131007452317, - "outputId": 0, - "inputModuleId": 8601159184541723, - "inputId": 0, - "color": "#a852ff" - }, - { - "id": 7936547708694047, - "outputModuleId": 731196840446297, - "outputId": 3, - "inputModuleId": 8418253494908594, - "inputId": 2, - "color": "#ffd452" - }, - { - "id": 6795587122824602, - "outputModuleId": 731196840446297, - "outputId": 3, - "inputModuleId": 5726895899473528, - "inputId": 4, - "color": "#e8ff52" - }, - { - "id": 3019680638787688, - "outputModuleId": 5395301826848558, - "outputId": 3, - "inputModuleId": 8873341177893106, - "inputId": 0, - "color": "#a8ff52" - }, - { - "id": 1666984200392735, - "outputModuleId": 5726895899473528, - "outputId": 0, - "inputModuleId": 4828178296911509, - "inputId": 0, - "color": "#e8ff52" - }, - { - "id": 8766740694668647, - "outputModuleId": 8601159184541723, - "outputId": 2, - "inputModuleId": 1133100648267642, - "inputId": 3, - "color": "#a8ff52" - }, - { - "id": 8237083691879690, - "outputModuleId": 1133100648267642, - "outputId": 0, - "inputModuleId": 4828178296911509, - "inputId": 1, - "color": "#67ff52" - }, - { - "id": 1834953772627333, - "outputModuleId": 731196840446297, - "outputId": 3, - "inputModuleId": 1394719894730985, - "inputId": 4, - "color": "#e8ff52" - }, - { - "id": 4168348114170351, - "outputModuleId": 1394719894730985, - "outputId": 0, - "inputModuleId": 1259717562922476, - "inputId": 1, - "color": "#52ff7d" - }, - { - "id": 5717596310825586, - "outputModuleId": 1259717562922476, - "outputId": 0, - "inputModuleId": 1133100648267642, - "inputId": 0, - "color": "#52ffff" - }, - { - "id": 4350563624640266, - "outputModuleId": 8601159184541723, - "outputId": 3, - "inputModuleId": 1133100648267642, - "inputId": 1, - "color": "#527dff" - }, - { - "id": 8219233151532425, - "outputModuleId": 8601159184541723, - "outputId": 3, - "inputModuleId": 1259717562922476, - "inputId": 2, - "color": "#527dff" - }, - { - "id": 4180550788448825, - "outputModuleId": 5352206433681871, - "outputId": 6, - "inputModuleId": 8418253494908594, - "inputId": 3, - "color": "#a852ff" - }, - { - "id": 2241414982743724, - "outputModuleId": 4423007809468738, - "outputId": 0, - "inputModuleId": 8873341177893106, - "inputId": 4, - "color": "#527dff" - }, - { - "id": 4401638766741046, - "outputModuleId": 3146744790938462, - "outputId": 3, - "inputModuleId": 1691892280815347, - "inputId": 2, - "color": "#ff52d4" - }, - { - "id": 4473547302936863, - "outputModuleId": 5352206433681871, - "outputId": 5, - "inputModuleId": 6544530457999805, - "inputId": 3, - "color": "#ffd452" - }, - { - "id": 2149514714768661, - "outputModuleId": 1691892280815347, - "outputId": 4, - "inputModuleId": 6544530457999805, - "inputId": 2, - "color": "#e8ff52" - }, - { - "id": 5076399399662756, - "outputModuleId": 4828178296911509, - "outputId": 0, - "inputModuleId": 1233074000424232, - "inputId": 1, - "color": "#52beff" - }, - { - "id": 7965867680638860, - "outputModuleId": 3201369453135267, - "outputId": 0, - "inputModuleId": 2032233011372771, - "inputId": 0, - "color": "#e8ff52" - }, - { - "id": 1755370288614689, - "outputModuleId": 7382588397539714, - "outputId": 0, - "inputModuleId": 2032233011372771, - "inputId": 1, - "color": "#67ff52" - }, - { - "id": 7321274404212847, - "outputModuleId": 2730774444988771, - "outputId": 0, - "inputModuleId": 5418598651204386, - "inputId": 1, - "color": "#52ff7d" - }, - { - "id": 5213022936510450, - "outputModuleId": 5418598651204386, - "outputId": 0, - "inputModuleId": 7382588397539714, - "inputId": 0, - "color": "#52ffff" - }, - { - "id": 4958477523630847, - "outputModuleId": 5646145412017245, - "outputId": 3, - "inputModuleId": 5418598651204386, - "inputId": 2, - "color": "#527dff" - }, - { - "id": 806948035554393, - "outputModuleId": 891362589771903, - "outputId": 0, - "inputModuleId": 5646145412017245, - "inputId": 0, - "color": "#52beff" - }, - { - "id": 6076414959882510, - "outputModuleId": 1691892280815347, - "outputId": 4, - "inputModuleId": 2580763714379115, - "inputId": 4, - "color": "#52ffff" - }, - { - "id": 5072464099602064, - "outputModuleId": 7433032281179785, - "outputId": 0, - "inputModuleId": 3201369453135267, - "inputId": 4, - "color": "#6752ff" - }, - { - "id": 7530722628496994, - "outputModuleId": 7433032281179785, - "outputId": 0, - "inputModuleId": 2730774444988771, - "inputId": 4, - "color": "#6752ff" - }, - { - "id": 8200608424961808, - "outputModuleId": 2580763714379115, - "outputId": 0, - "inputModuleId": 7433032281179785, - "inputId": 0, - "color": "#a852ff" - }, - { - "id": 3061807858227116, - "outputModuleId": 2580763714379115, - "outputId": 0, - "inputModuleId": 7433032281179785, - "inputId": 1, - "color": "#a852ff" - }, - { - "id": 7988697270634675, - "outputModuleId": 5646145412017245, - "outputId": 2, - "inputModuleId": 7382588397539714, - "inputId": 1, - "color": "#527dff" - }, - { - "id": 7154492867378238, - "outputModuleId": 8016435651914356, - "outputId": 0, - "inputModuleId": 1233074000424232, - "inputId": 2, - "color": "#52ffbe" - }, - { - "id": 5994859036363313, - "outputModuleId": 2032233011372771, - "outputId": 0, - "inputModuleId": 8016435651914356, - "inputId": 4, - "color": "#e952ff" - }, - { - "id": 8473185137644009, - "outputModuleId": 891362589771903, - "outputId": 0, - "inputModuleId": 5418598651204386, - "inputId": 3, - "color": "#52beff" - }, - { - "id": 8537027609635289, - "outputModuleId": 5646145412017245, - "outputId": 2, - "inputModuleId": 7382588397539714, - "inputId": 3, - "color": "#a8ff52" - }, - { - "id": 7269980652293972, - "outputModuleId": 5864032949729166, - "outputId": 3, - "inputModuleId": 1691892280815347, - "inputId": 4, - "color": "#ff5252" - }, - { - "id": 7057970615240989, - "outputModuleId": 6507602521553750, - "outputId": 0, - "inputModuleId": 2378286691858201, - "inputId": 1, - "color": "#e8ff52" - }, - { - "id": 3226519042405924, - "outputModuleId": 1527334562618244, - "outputId": 0, - "inputModuleId": 2378286691858201, - "inputId": 0, - "color": "#67ff52" - }, - { - "id": 2402945299515265, - "outputModuleId": 3893327492950413, - "outputId": 0, - "inputModuleId": 6507602521553750, - "inputId": 1, - "color": "#52ff7d" - }, - { - "id": 4244874454116090, - "outputModuleId": 1233074000424232, - "outputId": 0, - "inputModuleId": 1, - "inputId": 0, - "color": "#52ffbe" - }, - { - "id": 1193512545516727, - "outputModuleId": 2378286691858201, - "outputId": 0, - "inputModuleId": 4455336980892018, - "inputId": 3, - "color": "#52ffff" - }, - { - "id": 6386216099907021, - "outputModuleId": 6747341247828307, - "outputId": 0, - "inputModuleId": 1233074000424232, - "inputId": 3, - "color": "#a8ff52" - }, - { - "id": 3572923290268663, - "outputModuleId": 4455336980892018, - "outputId": 0, - "inputModuleId": 6747341247828307, - "inputId": 3, - "color": "#52beff" - }, - { - "id": 7653802884040555, - "outputModuleId": 3385514259127415, - "outputId": 0, - "inputModuleId": 1233074000424232, - "inputId": 5, - "color": "#6752ff" - }, - { - "id": 829864317578038, - "outputModuleId": 3385514259127415, - "outputId": 0, - "inputModuleId": 1233074000424232, - "inputId": 6, - "color": "#6752ff" - }, - { - "id": 3373678828632339, - "outputModuleId": 6544530457999805, - "outputId": 0, - "inputModuleId": 1647649757935413, - "inputId": 7, - "color": "#a8ff52" - }, - { - "id": 7351430308772461, - "outputModuleId": 8418253494908594, - "outputId": 0, - "inputModuleId": 1647649757935413, - "inputId": 6, - "color": "#e952ff" - }, - { - "id": 5057619955115593, - "outputModuleId": 7206256653286977, - "outputId": 0, - "inputModuleId": 758005564709860, - "inputId": 0, - "color": "#a8ff52" - }, - { - "id": 4853090475978388, - "outputModuleId": 7206256653286977, - "outputId": 0, - "inputModuleId": 8465489170887570, - "inputId": 0, - "color": "#a8ff52" - }, - { - "id": 4526032538453288, - "outputModuleId": 7206256653286977, - "outputId": 0, - "inputModuleId": 4423007809468738, - "inputId": 0, - "color": "#a8ff52" - }, - { - "id": 3124783542336781, - "outputModuleId": 7206256653286977, - "outputId": 0, - "inputModuleId": 683104811224040, - "inputId": 0, - "color": "#a8ff52" - }, - { - "id": 565654378994967, - "outputModuleId": 1647649757935413, - "outputId": 6, - "inputModuleId": 7206256653286977, - "inputId": 0, - "color": "#e952ff" - }, - { - "id": 3261847816183455, - "outputModuleId": 1647649757935413, - "outputId": 7, - "inputModuleId": 7206256653286977, - "inputId": 1, - "color": "#ff52d4" - }, - { - "id": 8653467738162234, - "outputModuleId": 8873341177893106, - "outputId": 0, - "inputModuleId": 4531725331261861, - "inputId": 0, - "color": "#ff9352" - }, - { - "id": 763700465340890, - "outputModuleId": 4531725331261861, - "outputId": 0, - "inputModuleId": 1163131007452317, - "inputId": 1, - "color": "#ff5293" - }, - { - "id": 8958469082437437, - "outputModuleId": 4531725331261861, - "outputId": 1, - "inputModuleId": 891362589771903, - "inputId": 1, - "color": "#ff9352" - }, - { - "id": 8462724473577648, - "outputModuleId": 1647649757935413, - "outputId": 0, - "inputModuleId": 3385514259127415, - "inputId": 0, - "color": "#e8ff52" - }, - { - "id": 2589536637508587, - "outputModuleId": 1647649757935413, - "outputId": 5, - "inputModuleId": 3385514259127415, - "inputId": 1, - "color": "#a8ff52" - }, - { - "id": 5887432763805406, - "outputModuleId": 8394463014211348, - "outputId": 0, - "inputModuleId": 1647649757935413, - "inputId": 5, - "color": "#ffd452" - }, - { - "id": 7644685380405945, - "outputModuleId": 1035685351131893, - "outputId": 3, - "inputModuleId": 8394463014211348, - "inputId": 4, - "color": "#ff9352" - }, - { - "id": 471611457647672, - "outputModuleId": 1035685351131893, - "outputId": 3, - "inputModuleId": 1527334562618244, - "inputId": 4, - "color": "#ff9352" - }, - { - "id": 8041272677194580, - "outputModuleId": 1035685351131893, - "outputId": 3, - "inputModuleId": 3893327492950413, - "inputId": 4, - "color": "#ff9352" - }, - { - "id": 6914773470225645, - "outputModuleId": 1035685351131893, - "outputId": 3, - "inputModuleId": 5864032949729166, - "inputId": 4, - "color": "#ff9352" - }, - { - "id": 1224715010483309, - "outputModuleId": 1035685351131893, - "outputId": 3, - "inputModuleId": 3146744790938462, - "inputId": 4, - "color": "#ff9352" - }, - { - "id": 2586356355502803, - "outputModuleId": 5218974527740722, - "outputId": 3, - "inputModuleId": 5395301826848558, - "inputId": 4, - "color": "#ff5293" - }, - { - "id": 8944424695894162, - "outputModuleId": 5218974527740722, - "outputId": 3, - "inputModuleId": 731196840446297, - "inputId": 4, - "color": "#ff9352" - }, - { - "id": 6554274278257604, - "outputModuleId": 5218974527740722, - "outputId": 3, - "inputModuleId": 1035685351131893, - "inputId": 4, - "color": "#ff5252" - }, - { - "id": 4008697176669096, - "outputModuleId": 1527334562618244, - "outputId": 0, - "inputModuleId": 6747341247828307, - "inputId": 0, - "color": "#67ff52" - } - ] -} diff --git a/patches/mini/falkTX_-_Moogy.vcv b/patches/mini/falkTX_-_Moogy.vcv new file mode 100644 index 00000000..5a401a80 --- /dev/null +++ b/patches/mini/falkTX_-_Moogy.vcv @@ -0,0 +1,622 @@ +{ + "version": "2.1.2", + "zoom": 1.0, + "gridOffset": [ + -7, + -0.05 + ], + "modules": [ + { + "id": 7797650034473482, + "plugin": "Cardinal", + "model": "TextEditor", + "version": "2.0", + "params": [], + "leftModuleId": 7219430607288126, + "data": { + "filepath": "", + "lang": "None", + "etext": "\n\nThis section spreads\n\nthe unison sound\n\nacross 4 stereo outs\n\n\n\n\n\n", + "width": 14 + }, + "pos": [ + 31, + 1 + ] + }, + { + "id": 8869926954268675, + "plugin": "Bogaudio", + "model": "Bogaudio-Unison", + "version": "2.0", + "params": [ + { + "value": 8.0, + "id": 0 + }, + { + "value": 4.7590360641479492, + "id": 1 + } + ], + "data": {}, + "pos": [ + 4, + 0 + ] + }, + { + "id": 5726895899473528, + "plugin": "Fundamental", + "model": "ADSR", + "version": "2.0", + "params": [ + { + "value": 0.28500017523765564, + "id": 0 + }, + { + "value": 0.50499969720840454, + "id": 1 + }, + { + "value": 0.49999982118606567, + "id": 2 + }, + { + "value": 0.5, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + } + ], + "pos": [ + 8, + 0 + ] + }, + { + "id": 4655444792904207, + "plugin": "MockbaModular", + "model": "CZOsc", + "version": "2.0", + "params": [ + { + "value": 7.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + } + ], + "leftModuleId": 1312836734148177, + "pos": [ + 21, + 0 + ] + }, + { + "id": 1416017514237263, + "plugin": "MockbaModular", + "model": "Filtah", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 79.999984741210938, + "id": 1 + }, + { + "value": 1.348394960132282e-7, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + } + ], + "leftModuleId": 1223772688968402, + "pos": [ + 27, + 0 + ] + }, + { + "id": 1312836734148177, + "plugin": "MockbaModular", + "model": "MaugOsc", + "version": "2.0", + "params": [ + { + "value": 1.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + } + ], + "rightModuleId": 4655444792904207, + "pos": [ + 19, + 0 + ] + }, + { + "id": 1223772688968402, + "plugin": "MockbaModular", + "model": "Filtah", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 79.999984741210938, + "id": 1 + }, + { + "value": 1.348394960132282e-7, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + } + ], + "rightModuleId": 1416017514237263, + "pos": [ + 25, + 0 + ] + }, + { + "id": 4038801811482009, + "plugin": "MockbaModular", + "model": "Mixah", + "version": "2.0", + "params": [ + { + "value": 0.55000019073486328, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + } + ], + "pos": [ + 31, + 0 + ] + }, + { + "id": 7219430607288126, + "plugin": "Fundamental", + "model": "Split", + "version": "2.0", + "params": [], + "leftModuleId": 1, + "rightModuleId": 7797650034473482, + "pos": [ + 26, + 1 + ] + }, + { + "id": 1079059256177472, + "plugin": "Cardinal", + "model": "TextEditor", + "version": "2.0", + "params": [], + "leftModuleId": 32755851899487, + "data": { + "filepath": "", + "lang": "None", + "etext": "\n\n1 - LP Filter\n2 - Resonance\n3 - OSC 1 <> 2\n4 - Attack\n5 - Decay\n6 - Sustain\n\n\n\n\n", + "width": 11 + }, + "pos": [ + 48, + 0 + ] + }, + { + "id": 1, + "plugin": "Cardinal", + "model": "HostAudio2", + "version": "2.0", + "params": [ + { + "value": 0.66632837057113647, + "id": 0 + } + ], + "leftModuleId": 3932369330543212, + "rightModuleId": 7219430607288126, + "data": { + "dcFilter": true + }, + "pos": [ + 18, + 1 + ] + }, + { + "id": 2, + "plugin": "Cardinal", + "model": "HostMIDI", + "version": "2.0", + "params": [], + "data": { + "pwRange": 0.0, + "smooth": false, + "channels": 1, + "polyMode": 0, + "lastPitch": 8192, + "lastMod": 0, + "inputChannel": 0, + "outputChannel": 0 + }, + "pos": [ + -6, + 0 + ] + }, + { + "id": 3932369330543212, + "plugin": "Cardinal", + "model": "HostAudio2", + "version": "2.0", + "params": [ + { + "value": 0.66632837057113647, + "id": 0 + } + ], + "leftModuleId": 1952123403145454, + "rightModuleId": 1, + "data": { + "dcFilter": true + }, + "pos": [ + 10, + 1 + ] + }, + { + "id": 1952123403145454, + "plugin": "Cardinal", + "model": "HostAudio2", + "version": "2.0", + "params": [ + { + "value": 0.66632837057113647, + "id": 0 + } + ], + "leftModuleId": 3890811893602150, + "rightModuleId": 3932369330543212, + "data": { + "dcFilter": true + }, + "pos": [ + 2, + 1 + ] + }, + { + "id": 3890811893602150, + "plugin": "Cardinal", + "model": "HostAudio2", + "version": "2.0", + "params": [ + { + "value": 0.66632837057113647, + "id": 0 + } + ], + "rightModuleId": 1952123403145454, + "data": { + "dcFilter": true + }, + "pos": [ + -6, + 1 + ] + }, + { + "id": 32755851899487, + "plugin": "Cardinal", + "model": "HostParametersMap", + "version": "2.0", + "params": [], + "rightModuleId": 1079059256177472, + "data": { + "maps": [ + { + "hostParamId": 0, + "inverted": false, + "smooth": true, + "moduleId": 1223772688968402, + "paramId": 1 + }, + { + "hostParamId": 0, + "inverted": false, + "smooth": true, + "moduleId": 1416017514237263, + "paramId": 1 + }, + { + "hostParamId": 1, + "inverted": false, + "smooth": true, + "moduleId": 1223772688968402, + "paramId": 2 + }, + { + "hostParamId": 1, + "inverted": false, + "smooth": true, + "moduleId": 1416017514237263, + "paramId": 2 + }, + { + "hostParamId": 2, + "inverted": false, + "smooth": true, + "moduleId": 4038801811482009, + "paramId": 0 + }, + { + "hostParamId": 3, + "inverted": false, + "smooth": true, + "moduleId": 5726895899473528, + "paramId": 0 + }, + { + "hostParamId": 4, + "inverted": false, + "smooth": true, + "moduleId": 5726895899473528, + "paramId": 1 + }, + { + "hostParamId": 5, + "inverted": false, + "smooth": true, + "moduleId": 5726895899473528, + "paramId": 2 + } + ] + }, + "pos": [ + 37, + 0 + ] + } + ], + "cables": [ + { + "id": 8182356705718260, + "outputModuleId": 1312836734148177, + "outputId": 0, + "inputModuleId": 1223772688968402, + "inputId": 2, + "color": "#a8ff52" + }, + { + "id": 5472993478872985, + "outputModuleId": 5726895899473528, + "outputId": 0, + "inputModuleId": 1223772688968402, + "inputId": 0, + "color": "#e8ff52" + }, + { + "id": 5127890094838131, + "outputModuleId": 2, + "outputId": 1, + "inputModuleId": 8869926954268675, + "inputId": 2, + "color": "#ff5252" + }, + { + "id": 4024923731736886, + "outputModuleId": 2, + "outputId": 0, + "inputModuleId": 8869926954268675, + "inputId": 1, + "color": "#ff5252" + }, + { + "id": 2334907509933159, + "outputModuleId": 8869926954268675, + "outputId": 0, + "inputModuleId": 1312836734148177, + "inputId": 0, + "color": "#ff5252" + }, + { + "id": 3002878830249735, + "outputModuleId": 8869926954268675, + "outputId": 1, + "inputModuleId": 5726895899473528, + "inputId": 4, + "color": "#ff5252" + }, + { + "id": 3630780656969299, + "outputModuleId": 7219430607288126, + "outputId": 0, + "inputModuleId": 1, + "inputId": 0, + "color": "#e952ff" + }, + { + "id": 2252461163745874, + "outputModuleId": 7219430607288126, + "outputId": 2, + "inputModuleId": 1, + "inputId": 1, + "color": "#e952ff" + }, + { + "id": 285917638623769, + "outputModuleId": 7219430607288126, + "outputId": 3, + "inputModuleId": 3932369330543212, + "inputId": 1, + "color": "#e952ff" + }, + { + "id": 8064030762561300, + "outputModuleId": 7219430607288126, + "outputId": 7, + "inputModuleId": 3890811893602150, + "inputId": 1, + "color": "#e952ff" + }, + { + "id": 5150351568049518, + "outputModuleId": 7219430607288126, + "outputId": 5, + "inputModuleId": 1952123403145454, + "inputId": 1, + "color": "#e952ff" + }, + { + "id": 1530942990840499, + "outputModuleId": 7219430607288126, + "outputId": 6, + "inputModuleId": 3890811893602150, + "inputId": 0, + "color": "#e952ff" + }, + { + "id": 6358946006960973, + "outputModuleId": 7219430607288126, + "outputId": 4, + "inputModuleId": 1952123403145454, + "inputId": 0, + "color": "#e952ff" + }, + { + "id": 6965224767727040, + "outputModuleId": 7219430607288126, + "outputId": 1, + "inputModuleId": 3932369330543212, + "inputId": 0, + "color": "#e952ff" + }, + { + "id": 5380295368493604, + "outputModuleId": 4655444792904207, + "outputId": 0, + "inputModuleId": 1416017514237263, + "inputId": 2, + "color": "#a8ff52" + }, + { + "id": 2435962983629702, + "outputModuleId": 1223772688968402, + "outputId": 0, + "inputModuleId": 4038801811482009, + "inputId": 2, + "color": "#e952ff" + }, + { + "id": 8984394551942722, + "outputModuleId": 1416017514237263, + "outputId": 0, + "inputModuleId": 4038801811482009, + "inputId": 3, + "color": "#e952ff" + }, + { + "id": 8445580184820759, + "outputModuleId": 5726895899473528, + "outputId": 0, + "inputModuleId": 1416017514237263, + "inputId": 0, + "color": "#e8ff52" + }, + { + "id": 7727190565279635, + "outputModuleId": 8869926954268675, + "outputId": 0, + "inputModuleId": 4655444792904207, + "inputId": 0, + "color": "#ff5252" + }, + { + "id": 6359733527436216, + "outputModuleId": 5726895899473528, + "outputId": 0, + "inputModuleId": 4038801811482009, + "inputId": 1, + "color": "#e8ff52" + }, + { + "id": 8765471407154125, + "outputModuleId": 2, + "outputId": 6, + "inputModuleId": 5726895899473528, + "inputId": 5, + "color": "#ff9352" + }, + { + "id": 8605661946106678, + "outputModuleId": 4038801811482009, + "outputId": 0, + "inputModuleId": 7219430607288126, + "inputId": 0, + "color": "#e952ff" + } + ] +} diff --git a/patches/mini/falkTX_-_Saw_For_One.vcv b/patches/mini/falkTX_-_Saw_For_One.vcv new file mode 100644 index 00000000..4c85e67a --- /dev/null +++ b/patches/mini/falkTX_-_Saw_For_One.vcv @@ -0,0 +1,971 @@ +{ + "version": "2.1.2", + "zoom": 1.0, + "gridOffset": [ + -3.8666665554046631, + -0.33421051502227783 + ], + "modules": [ + { + "id": 3530479703931215, + "plugin": "Fundamental", + "model": "LFO", + "version": "2.0", + "params": [ + { + "value": 1.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": -0.99517768621444702, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.5, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + } + ], + "pos": [ + 0, + -1 + ] + }, + { + "id": 2617521628379532, + "plugin": "Fundamental", + "model": "ADSR", + "version": "2.0", + "params": [ + { + "value": 0.2975899875164032, + "id": 0 + }, + { + "value": 0.53734946250915527, + "id": 1 + }, + { + "value": 0.31204831600189209, + "id": 2 + }, + { + "value": 0.5, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + } + ], + "rightModuleId": 6351707277679558, + "pos": [ + 44, + 0 + ] + }, + { + "id": 8914754292241465, + "plugin": "SurgeXTRack", + "model": "SurgeXTOSCSine", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.44499999284744263, + "id": 1 + }, + { + "value": 0.60414284467697144, + "id": 2 + }, + { + "value": 0.99500000476837158, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 1.0, + "id": 5 + }, + { + "value": 0.11999999731779099, + "id": 6 + }, + { + "value": 0.1276666522026062, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": -0.14399991929531097, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 0.0, + "id": 20 + }, + { + "value": 0.0, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 0.0, + "id": 24 + }, + { + "value": 0.0, + "id": 25 + }, + { + "value": 0.0, + "id": 26 + }, + { + "value": 0.0, + "id": 27 + }, + { + "value": 0.0, + "id": 28 + }, + { + "value": 0.0, + "id": 29 + }, + { + "value": 0.0, + "id": 30 + }, + { + "value": 0.0, + "id": 31 + }, + { + "value": 0.0, + "id": 32 + }, + { + "value": 0.061999920755624771, + "id": 33 + }, + { + "value": 0.0, + "id": 34 + }, + { + "value": 0.0, + "id": 35 + }, + { + "value": 0.0, + "id": 36 + }, + { + "value": 0.0, + "id": 37 + }, + { + "value": 0.0, + "id": 38 + }, + { + "value": 0.0, + "id": 39 + }, + { + "value": 0.0, + "id": 40 + }, + { + "value": 0.0, + "id": 41 + }, + { + "value": 0.0, + "id": 42 + }, + { + "value": 0.0, + "id": 43 + }, + { + "value": 0.0, + "id": 44 + }, + { + "value": 0.0, + "id": 45 + }, + { + "value": 0.0, + "id": 46 + }, + { + "value": 0.0, + "id": 47 + }, + { + "value": 1.0, + "id": 48 + }, + { + "value": 0.078000001609325409, + "id": 49 + }, + { + "value": 1.0, + "id": 50 + } + ], + "leftModuleId": 287325898511014, + "rightModuleId": 6895418575305544, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Feb 19 2023 23:43:29", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + }, + "modulespecific": { + "halfbandM": 6, + "halfbandSteep": true, + "doDCBlock": true + } + }, + "pos": [ + 22, + 0 + ] + }, + { + "id": 287325898511014, + "plugin": "SurgeXTRack", + "model": "SurgeXTOSCModern", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 1.0, + "id": 1 + }, + { + "value": 0.32114300131797791, + "id": 2 + }, + { + "value": 0.8151429295539856, + "id": 3 + }, + { + "value": 0.5, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.11999999731779099, + "id": 6 + }, + { + "value": 0.13699999451637268, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": -1.0, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.16599999368190765, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": -0.28200000524520874, + "id": 20 + }, + { + "value": 0.0, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 0.0, + "id": 24 + }, + { + "value": 0.0, + "id": 25 + }, + { + "value": 0.0, + "id": 26 + }, + { + "value": 0.0, + "id": 27 + }, + { + "value": 0.0, + "id": 28 + }, + { + "value": 0.0, + "id": 29 + }, + { + "value": 0.0, + "id": 30 + }, + { + "value": 0.0, + "id": 31 + }, + { + "value": 0.0, + "id": 32 + }, + { + "value": 0.0, + "id": 33 + }, + { + "value": 0.0, + "id": 34 + }, + { + "value": 0.0, + "id": 35 + }, + { + "value": 0.0, + "id": 36 + }, + { + "value": 0.0, + "id": 37 + }, + { + "value": 0.0, + "id": 38 + }, + { + "value": 0.0, + "id": 39 + }, + { + "value": 0.0, + "id": 40 + }, + { + "value": 0.0, + "id": 41 + }, + { + "value": 0.0, + "id": 42 + }, + { + "value": 0.0, + "id": 43 + }, + { + "value": 0.0, + "id": 44 + }, + { + "value": 0.0, + "id": 45 + }, + { + "value": 0.0, + "id": 46 + }, + { + "value": 0.0, + "id": 47 + }, + { + "value": 1.0, + "id": 48 + }, + { + "value": 0.066999994218349457, + "id": 49 + }, + { + "value": 1.0, + "id": 50 + } + ], + "rightModuleId": 8914754292241465, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Feb 19 2023 23:43:29", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + }, + "modulespecific": { + "halfbandM": 6, + "halfbandSteep": true, + "doDCBlock": true + } + }, + "pos": [ + 10, + 0 + ] + }, + { + "id": 6895418575305544, + "plugin": "AriaSalvatrice", + "model": "Swerge", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + } + ], + "leftModuleId": 8914754292241465, + "rightModuleId": 6420065476624550, + "pos": [ + 34, + 0 + ] + }, + { + "id": 702164998788601, + "plugin": "Fundamental", + "model": "Sum", + "version": "2.0", + "params": [ + { + "value": 1.0, + "id": 0 + } + ], + "leftModuleId": 6420065476624550, + "pos": [ + 40, + 0 + ] + }, + { + "id": 6420065476624550, + "plugin": "Fundamental", + "model": "Sum", + "version": "2.0", + "params": [ + { + "value": 1.0, + "id": 0 + } + ], + "leftModuleId": 6895418575305544, + "rightModuleId": 702164998788601, + "pos": [ + 37, + 0 + ] + }, + { + "id": 6351707277679558, + "plugin": "SurgeXTRack", + "model": "SurgeXTWaveshaper", + "version": "2.0", + "params": [ + { + "value": -8.6468648910522461, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": -60.0, + "id": 3 + }, + { + "value": 70.0, + "id": 4 + }, + { + "value": 0.12800015509128571, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.21600000560283661, + "id": 10 + }, + { + "value": 0.0, + "id": 11 + }, + { + "value": 0.0, + "id": 12 + }, + { + "value": 0.50200003385543823, + "id": 13 + }, + { + "value": 0.0, + "id": 14 + }, + { + "value": 0.0, + "id": 15 + }, + { + "value": 0.0, + "id": 16 + }, + { + "value": 0.0, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 0.0, + "id": 20 + }, + { + "value": 0.0, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 0.0, + "id": 23 + }, + { + "value": 0.0, + "id": 24 + }, + { + "value": 15.0, + "id": 25 + }, + { + "value": 0.0, + "id": 26 + }, + { + "value": 0.0, + "id": 27 + } + ], + "leftModuleId": 2617521628379532, + "data": { + "xtshared": { + "streamingVersion": 1, + "buildInfo": "os:linux pluggit:Cardinal surgegit:Cardinal buildtime=Feb 19 2023 23:43:29", + "isCoupledToGlobalStyle": true, + "localStyle": 10001, + "localDisplayRegionColor": 900001, + "localModulationColor": 900005, + "localControlValueColor": 900001, + "localPowerButtonColor": 900003 + }, + "modulespecific": { + "doDCBlock": false + } + }, + "pos": [ + 53, + 0 + ] + }, + { + "id": 1, + "plugin": "Cardinal", + "model": "HostAudio2", + "version": "2.0", + "params": [ + { + "value": 0.45032820105552673, + "id": 0 + } + ], + "data": { + "dcFilter": true + }, + "pos": [ + 66, + 0 + ] + }, + { + "id": 2, + "plugin": "Cardinal", + "model": "HostMIDI", + "version": "2.0", + "params": [], + "data": { + "pwRange": 0.0, + "smooth": false, + "channels": 1, + "polyMode": 0, + "lastPitch": 8192, + "lastMod": 0, + "inputChannel": 0, + "outputChannel": 0 + }, + "pos": [ + 0, + 0 + ] + } + ], + "cables": [ + { + "id": 7078442804356951, + "outputModuleId": 2, + "outputId": 0, + "inputModuleId": 287325898511014, + "inputId": 0, + "color": "#52beff" + }, + { + "id": 2637993111379757, + "outputModuleId": 2, + "outputId": 0, + "inputModuleId": 8914754292241465, + "inputId": 0, + "color": "#52beff" + }, + { + "id": 7645122439500280, + "outputModuleId": 2, + "outputId": 6, + "inputModuleId": 287325898511014, + "inputId": 1, + "color": "#527dff" + }, + { + "id": 456636951896817, + "outputModuleId": 2, + "outputId": 6, + "inputModuleId": 8914754292241465, + "inputId": 1, + "color": "#527dff" + }, + { + "id": 4908672560602015, + "outputModuleId": 2, + "outputId": 1, + "inputModuleId": 2617521628379532, + "inputId": 4, + "color": "#a852ff" + }, + { + "id": 3911345250761309, + "outputModuleId": 2, + "outputId": 6, + "inputModuleId": 2617521628379532, + "inputId": 5, + "color": "#527dff" + }, + { + "id": 1721551606636812, + "outputModuleId": 6351707277679558, + "outputId": 0, + "inputModuleId": 1, + "inputId": 0, + "color": "#ff5252" + }, + { + "id": 8567652559342014, + "outputModuleId": 6351707277679558, + "outputId": 1, + "inputModuleId": 1, + "inputId": 1, + "color": "#ff5252" + }, + { + "id": 7051140988441255, + "outputModuleId": 287325898511014, + "outputId": 1, + "inputModuleId": 6895418575305544, + "inputId": 4, + "color": "#ff5252" + }, + { + "id": 780441311761289, + "outputModuleId": 8914754292241465, + "outputId": 0, + "inputModuleId": 6895418575305544, + "inputId": 1, + "color": "#ff5252" + }, + { + "id": 2400958554319452, + "outputModuleId": 8914754292241465, + "outputId": 1, + "inputModuleId": 6895418575305544, + "inputId": 5, + "color": "#ff5252" + }, + { + "id": 5935487313164681, + "outputModuleId": 287325898511014, + "outputId": 0, + "inputModuleId": 6895418575305544, + "inputId": 0, + "color": "#ff5252" + }, + { + "id": 7922595614504923, + "outputModuleId": 6895418575305544, + "outputId": 0, + "inputModuleId": 6420065476624550, + "inputId": 0, + "color": "#ff5252" + }, + { + "id": 5223439046078660, + "outputModuleId": 6420065476624550, + "outputId": 0, + "inputModuleId": 6351707277679558, + "inputId": 0, + "color": "#ff5252" + }, + { + "id": 1550005732923321, + "outputModuleId": 6895418575305544, + "outputId": 1, + "inputModuleId": 702164998788601, + "inputId": 0, + "color": "#ff5252" + }, + { + "id": 3466384847513146, + "outputModuleId": 702164998788601, + "outputId": 0, + "inputModuleId": 6351707277679558, + "inputId": 1, + "color": "#ff5252" + }, + { + "id": 6350073656502047, + "outputModuleId": 2617521628379532, + "outputId": 0, + "inputModuleId": 287325898511014, + "inputId": 2, + "color": "#a852ff" + }, + { + "id": 4319366098337873, + "outputModuleId": 2617521628379532, + "outputId": 0, + "inputModuleId": 8914754292241465, + "inputId": 2, + "color": "#a852ff" + }, + { + "id": 960118561480436, + "outputModuleId": 2617521628379532, + "outputId": 0, + "inputModuleId": 6351707277679558, + "inputId": 2, + "color": "#a852ff" + }, + { + "id": 6295963384449957, + "outputModuleId": 3530479703931215, + "outputId": 0, + "inputModuleId": 287325898511014, + "inputId": 3, + "color": "#ff5293" + }, + { + "id": 5112615215271363, + "outputModuleId": 3530479703931215, + "outputId": 1, + "inputModuleId": 6351707277679558, + "inputId": 3, + "color": "#ff5293" + } + ] +} diff --git a/patches/init/fx.vcv b/patches/templates/fx.vcv similarity index 100% rename from patches/init/fx.vcv rename to patches/templates/fx.vcv diff --git a/patches/init/main.vcv b/patches/templates/main.vcv similarity index 100% rename from patches/init/main.vcv rename to patches/templates/main.vcv diff --git a/patches/templates/mini.vcv b/patches/templates/mini.vcv new file mode 100644 index 00000000..aae888ef --- /dev/null +++ b/patches/templates/mini.vcv @@ -0,0 +1,283 @@ +{ + "version": "2.1.1", + "zoom": 1.0, + "modules": [ + { + "id": 8712245256622475, + "plugin": "Cardinal", + "model": "TextEditor", + "version": "2.0", + "params": [], + "leftModuleId": 1202678850202654, + "data": { + "filepath": "", + "lang": "None", + "etext": "Welcome to Cardinal!\n\nThis is the mini variant\nIt has 2 audio ports, 5 CV ports, plus MIDI\n\nThe most relevant modules for host\nintegration are in this default patch\n\nA basic VCO + ADSR + VCA is\nthe default patch\n\nHave fun!\n\n", + "width": 23 + }, + "pos": [ + 58, + 0 + ] + }, + { + "id": 5726895899473528, + "plugin": "Fundamental", + "model": "ADSR", + "version": "2.0", + "params": [ + { + "value": 0.5, + "id": 0 + }, + { + "value": 0.5, + "id": 1 + }, + { + "value": 0.5, + "id": 2 + }, + { + "value": 0.5, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + } + ], + "leftModuleId": 8601159184541723, + "rightModuleId": 4828178296911509, + "pos": [ + 18, + 0 + ] + }, + { + "id": 4828178296911509, + "plugin": "Fundamental", + "model": "VCA-1", + "version": "2.0", + "params": [ + { + "value": 1.0, + "id": 0 + }, + { + "value": 1.0, + "id": 1 + } + ], + "leftModuleId": 5726895899473528, + "rightModuleId": 1, + "pos": [ + 27, + 0 + ] + }, + { + "id": 8601159184541723, + "plugin": "Fundamental", + "model": "VCO", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 1.0, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + }, + { + "value": 0.5, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": 0.0, + "id": 7 + } + ], + "leftModuleId": 2, + "rightModuleId": 5726895899473528, + "pos": [ + 9, + 0 + ] + }, + { + "id": 1, + "plugin": "Cardinal", + "model": "HostAudio2", + "version": "2.0", + "params": [ + { + "value": 0.79432821273803711, + "id": 0 + } + ], + "leftModuleId": 4828178296911509, + "rightModuleId": 4, + "data": { + "dcFilter": true + }, + "pos": [ + 30, + 0 + ] + }, + { + "id": 2, + "plugin": "Cardinal", + "model": "HostMIDI", + "version": "2.0", + "params": [], + "rightModuleId": 8601159184541723, + "data": { + "pwRange": 0.0, + "smooth": false, + "channels": 1, + "polyMode": 0, + "lastPitch": 8192, + "lastMod": 0, + "inputChannel": 0, + "outputChannel": 0 + }, + "pos": [ + 0, + 0 + ] + }, + { + "id": 4, + "plugin": "Cardinal", + "model": "HostParameters", + "version": "2.0", + "params": [], + "leftModuleId": 1, + "rightModuleId": 1202678850202654, + "data": { + "smooth": true + }, + "pos": [ + 38, + 0 + ] + }, + { + "id": 1202678850202654, + "plugin": "Cardinal", + "model": "HostParametersMap", + "version": "2.0", + "params": [], + "leftModuleId": 4, + "rightModuleId": 8712245256622475, + "data": { + "maps": [ + { + "hostParamId": 255, + "inverted": false, + "smooth": true, + "moduleId": -1, + "paramId": 0 + } + ] + }, + "pos": [ + 47, + 0 + ] + } + ], + "cables": [ + { + "id": 5155876120487880, + "outputModuleId": 2, + "outputId": 1, + "inputModuleId": 5726895899473528, + "inputId": 4, + "color": "#ff9352" + }, + { + "id": 781753834216137, + "outputModuleId": 2, + "outputId": 6, + "inputModuleId": 5726895899473528, + "inputId": 5, + "color": "#ffd452" + }, + { + "id": 3464471860196875, + "outputModuleId": 5726895899473528, + "outputId": 0, + "inputModuleId": 4828178296911509, + "inputId": 0, + "color": "#e8ff52" + }, + { + "id": 739552540616113, + "outputModuleId": 4828178296911509, + "outputId": 0, + "inputModuleId": 1, + "inputId": 0, + "color": "#52beff" + }, + { + "id": 6701970185765111, + "outputModuleId": 2, + "outputId": 0, + "inputModuleId": 8601159184541723, + "inputId": 0, + "color": "#ff5252" + }, + { + "id": 6959800657121782, + "outputModuleId": 2, + "outputId": 2, + "inputModuleId": 8601159184541723, + "inputId": 1, + "color": "#52ff7d" + }, + { + "id": 1598271319373837, + "outputModuleId": 8601159184541723, + "outputId": 0, + "inputModuleId": 4828178296911509, + "inputId": 1, + "color": "#a8ff52" + } + ] +} diff --git a/patches/init/native.vcv b/patches/templates/native.vcv similarity index 100% rename from patches/init/native.vcv rename to patches/templates/native.vcv diff --git a/patches/init/synth.vcv b/patches/templates/synth.vcv similarity index 100% rename from patches/init/synth.vcv rename to patches/templates/synth.vcv diff --git a/patches/touchosc/24-direct-fader-params.tosc b/patches/touchosc/24-direct-fader-params.tosc new file mode 100644 index 00000000..656c485e Binary files /dev/null and b/patches/touchosc/24-direct-fader-params.tosc differ diff --git a/patches/welcome-wasm-mini.vcv b/patches/welcome-wasm-mini.vcv index fe62fa02..0187bbe4 100644 --- a/patches/welcome-wasm-mini.vcv +++ b/patches/welcome-wasm-mini.vcv @@ -1,6 +1,5 @@ { - "version": "2.1.2", - "unsaved": true, + "version": "2.1.1", "zoom": 1.0, "modules": [ { @@ -9,15 +8,15 @@ "model": "TextEditor", "version": "2.0", "params": [], - "leftModuleId": 799138358763949, + "leftModuleId": 1202678850202654, "data": { "filepath": "", "lang": "None", - "etext": "Welcome to Cardinal!\n\nThis is the Web/Wasm variant\nIt has 2 audio outputs, enabled by default.\nUse Engine menu to enable input and/or MIDI.\n\nA basic VCO + ADSR + VCA is the default patch\n\n", - "width": 23 + "etext": "Welcome to Cardinal!\n\nThis is the mini variant\nIt has 2 audio outputs, with optional audio input and MIDI (enabled via Engine menu)\n\nA basic VCO + ADSR + VCA is the default patch\n\nHave fun!\n\n", + "width": 19 }, "pos": [ - 49, + 58, 0 ] }, @@ -151,7 +150,7 @@ } ], "leftModuleId": 4828178296911509, - "rightModuleId": 799138358763949, + "rightModuleId": 4, "data": { "dcFilter": true }, @@ -183,26 +182,42 @@ ] }, { - "id": 799138358763949, + "id": 4, "plugin": "Cardinal", - "model": "HostMIDIMap", + "model": "HostParameters", "version": "2.0", "params": [], "leftModuleId": 1, + "rightModuleId": 1202678850202654, + "data": { + "smooth": true + }, + "pos": [ + 38, + 0 + ] + }, + { + "id": 1202678850202654, + "plugin": "Cardinal", + "model": "HostParametersMap", + "version": "2.0", + "params": [], + "leftModuleId": 4, "rightModuleId": 8712245256622475, "data": { "maps": [ { - "cc": -1, + "hostParamId": 255, + "inverted": false, + "smooth": true, "moduleId": -1, "paramId": 0 } - ], - "smooth": true, - "channel": 0 + ] }, "pos": [ - 38, + 47, 0 ] } diff --git a/patches/welcome-wasm.vcv b/patches/welcome-wasm.vcv index 26438d29..01d742b2 100644 --- a/patches/welcome-wasm.vcv +++ b/patches/welcome-wasm.vcv @@ -1,910 +1,101 @@ { - "version": "2.1.2", + "version": "2.1.1", "zoom": 1.0, - "gridOffset": [ - -2.0, - -0.078947365283966064 - ], - "modules": [ - { - "id": 3056105853448179, - "plugin": "JW-Modules", - "model": "GridSeq", - "version": "2.0", - "params": [ - { - "value": 0.0, - "id": 0 - }, - { - "value": 0.0, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 6.9614028930664062, - "id": 3 - }, - { - "value": 1.702531099319458, - "id": 4 - }, - { - "value": 5.3844399452209473, - "id": 5 - }, - { - "value": 4.2987494468688965, - "id": 6 - }, - { - "value": 4.388275146484375, - "id": 7 - }, - { - "value": 3.8028616905212402, - "id": 8 - }, - { - "value": 7.9583587646484375, - "id": 9 - }, - { - "value": 4.8640403747558594, - "id": 10 - }, - { - "value": 5.1489453315734863, - "id": 11 - }, - { - "value": 1.265117883682251, - "id": 12 - }, - { - "value": 9.5869827270507812, - "id": 13 - }, - { - "value": 5.5940794944763184, - "id": 14 - }, - { - "value": 3.1475725173950195, - "id": 15 - }, - { - "value": 3.6948256492614746, - "id": 16 - }, - { - "value": 8.8199691772460938, - "id": 17 - }, - { - "value": 4.5301790237426758, - "id": 18 - }, - { - "value": 0.0, - "id": 19 - }, - { - "value": 0.0, - "id": 20 - }, - { - "value": 0.0, - "id": 21 - }, - { - "value": 0.0, - "id": 22 - }, - { - "value": 0.0, - "id": 23 - }, - { - "value": 0.0, - "id": 24 - }, - { - "value": 0.0, - "id": 25 - }, - { - "value": 0.0, - "id": 26 - }, - { - "value": 0.0, - "id": 27 - }, - { - "value": 0.0, - "id": 28 - }, - { - "value": 0.0, - "id": 29 - }, - { - "value": 0.0, - "id": 30 - }, - { - "value": 0.0, - "id": 31 - }, - { - "value": 0.0, - "id": 32 - }, - { - "value": 0.0, - "id": 33 - }, - { - "value": 0.0, - "id": 34 - }, - { - "value": 0.0, - "id": 35 - }, - { - "value": 0.0, - "id": 36 - }, - { - "value": 11.0, - "id": 37 - }, - { - "value": 0.0, - "id": 38 - }, - { - "value": 0.0, - "id": 39 - }, - { - "value": 0.0, - "id": 40 - }, - { - "value": 0.0, - "id": 41 - }, - { - "value": 0.0, - "id": 42 - }, - { - "value": 0.0, - "id": 43 - }, - { - "value": 0.0, - "id": 44 - }, - { - "value": 2.0, - "id": 45 - }, - { - "value": -1.0, - "id": 46 - }, - { - "value": 1.0, - "id": 47 - }, - { - "value": 1.0, - "id": 48 - }, - { - "value": 1.0, - "id": 49 - }, - { - "value": 1.0, - "id": 50 - }, - { - "value": 1.0, - "id": 51 - }, - { - "value": 1.0, - "id": 52 - }, - { - "value": 1.0, - "id": 53 - }, - { - "value": 1.0, - "id": 54 - }, - { - "value": 1.0, - "id": 55 - }, - { - "value": 1.0, - "id": 56 - }, - { - "value": 1.0, - "id": 57 - }, - { - "value": 1.0, - "id": 58 - }, - { - "value": 1.0, - "id": 59 - }, - { - "value": 1.0, - "id": 60 - }, - { - "value": 1.0, - "id": 61 - }, - { - "value": 1.0, - "id": 62 - }, - { - "value": 0.0, - "id": 63 - } - ], - "data": { - "running": true, - "ignoreGateOnPitchOut": false, - "gates": [ - 1, - 0, - 0, - 1, - 1, - 0, - 1, - 0, - 0, - 1, - 0, - 0, - 1, - 1, - 1, - 0 - ], - "gateMode": 0, - "randomMode": 0 - }, - "pos": [ - 11, - 0 - ] - }, - { - "id": 8226081794468965, - "plugin": "JW-Modules", - "model": "GridSeq", - "version": "2.0", - "params": [ - { - "value": 0.0, - "id": 0 - }, - { - "value": 0.0, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 2.4226007461547852, - "id": 3 - }, - { - "value": 4.1613302230834961, - "id": 4 - }, - { - "value": 6.0629558563232422, - "id": 5 - }, - { - "value": 4.2443413734436035, - "id": 6 - }, - { - "value": 0.48779934644699097, - "id": 7 - }, - { - "value": 8.9526882171630859, - "id": 8 - }, - { - "value": 0.25175490975379944, - "id": 9 - }, - { - "value": 2.360055685043335, - "id": 10 - }, - { - "value": 3.1495692729949951, - "id": 11 - }, - { - "value": 3.4717011451721191, - "id": 12 - }, - { - "value": 5.4548091888427734, - "id": 13 - }, - { - "value": 5.216486930847168, - "id": 14 - }, - { - "value": 8.6701240539550781, - "id": 15 - }, - { - "value": 0.87081128358840942, - "id": 16 - }, - { - "value": 1.0363615751266479, - "id": 17 - }, - { - "value": 6.2397761344909668, - "id": 18 - }, - { - "value": 0.0, - "id": 19 - }, - { - "value": 0.0, - "id": 20 - }, - { - "value": 0.0, - "id": 21 - }, - { - "value": 0.0, - "id": 22 - }, - { - "value": 0.0, - "id": 23 - }, - { - "value": 0.0, - "id": 24 - }, - { - "value": 0.0, - "id": 25 - }, - { - "value": 0.0, - "id": 26 - }, - { - "value": 0.0, - "id": 27 - }, - { - "value": 0.0, - "id": 28 - }, - { - "value": 0.0, - "id": 29 - }, - { - "value": 0.0, - "id": 30 - }, - { - "value": 0.0, - "id": 31 - }, - { - "value": 0.0, - "id": 32 - }, - { - "value": 0.0, - "id": 33 - }, - { - "value": 0.0, - "id": 34 - }, - { - "value": 0.0, - "id": 35 - }, - { - "value": 0.0, - "id": 36 - }, - { - "value": 11.0, - "id": 37 - }, - { - "value": 0.0, - "id": 38 - }, - { - "value": 0.0, - "id": 39 - }, - { - "value": 0.0, - "id": 40 - }, - { - "value": 0.0, - "id": 41 - }, - { - "value": 0.0, - "id": 42 - }, - { - "value": 0.0, - "id": 43 - }, - { - "value": 0.0, - "id": 44 - }, - { - "value": 2.0, - "id": 45 - }, - { - "value": -1.0, - "id": 46 - }, - { - "value": 1.0, - "id": 47 - }, - { - "value": 1.0, - "id": 48 - }, - { - "value": 1.0, - "id": 49 - }, - { - "value": 1.0, - "id": 50 - }, - { - "value": 1.0, - "id": 51 - }, - { - "value": 1.0, - "id": 52 - }, - { - "value": 1.0, - "id": 53 - }, - { - "value": 1.0, - "id": 54 - }, - { - "value": 1.0, - "id": 55 - }, - { - "value": 1.0, - "id": 56 - }, - { - "value": 1.0, - "id": 57 - }, - { - "value": 1.0, - "id": 58 - }, - { - "value": 1.0, - "id": 59 - }, - { - "value": 1.0, - "id": 60 - }, - { - "value": 1.0, - "id": 61 - }, - { - "value": 1.0, - "id": 62 - }, - { - "value": 0.0, - "id": 63 - } - ], - "data": { - "running": true, - "ignoreGateOnPitchOut": false, - "gates": [ - 1, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 0, - 1, - 0, - 0, - 1, - 1, - 0 - ], - "gateMode": 0, - "randomMode": 0 - }, - "pos": [ - 11, - 1 - ] - }, - { - "id": 8508123945855866, - "plugin": "AudibleInstruments", - "model": "Plaits", - "version": "2.0", - "params": [ - { - "value": 0.0, - "id": 0 - }, - { - "value": 0.0, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 0.5, - "id": 3 - }, - { - "value": 0.5, - "id": 4 - }, - { - "value": 0.5, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - }, - { - "value": 0.0, - "id": 7 - }, - { - "value": 0.0, - "id": 8 - }, - { - "value": 0.5, - "id": 9 - }, - { - "value": 0.5, - "id": 10 - } - ], - "data": { - "lowCpu": false, - "model": 0 - }, - "pos": [ - 32, - 0 - ] - }, - { - "id": 7968649719176584, - "plugin": "AudibleInstruments", - "model": "Plaits", - "version": "2.0", - "params": [ - { - "value": 0.0, - "id": 0 - }, - { - "value": 0.0, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 0.5, - "id": 3 - }, - { - "value": 0.35903587937355042, - "id": 4 - }, - { - "value": 0.0, - "id": 5 - }, - { - "value": 0.59199827909469604, - "id": 6 - }, - { - "value": 0.0, - "id": 7 - }, - { - "value": 0.66399794816970825, - "id": 8 - }, - { - "value": 0.5, - "id": 9 - }, - { - "value": 0.50722956657409668, - "id": 10 - } - ], + "modules": [ + { + "id": 8712245256622475, + "plugin": "Cardinal", + "model": "TextEditor", + "version": "2.0", + "params": [], + "leftModuleId": 1202678850202654, "data": { - "lowCpu": false, - "model": 0 + "filepath": "", + "lang": "None", + "etext": "Welcome to Cardinal!\n\nnThis is the web/wasm variant\nIt has 2 audio outputs, with optional audio input and MIDI (enabled via Engine menu)\n\nA basic VCO + ADSR + VCA is the default patch\n\nHave fun!\n\n", + "width": 19 }, "pos": [ - 32, - 1 + 58, + 0 ] }, { - "id": 2222764725422974, - "plugin": "Valley", - "model": "Plateau", + "id": 5726895899473528, + "plugin": "Fundamental", + "model": "ADSR", "version": "2.0", "params": [ { - "value": 1.0, + "value": 0.5, "id": 0 }, - { - "value": 0.10649359971284866, - "id": 1 - }, - { - "value": 0.0, - "id": 2 - }, - { - "value": 10.0, - "id": 3 - }, - { - "value": 10.0, - "id": 4 - }, { "value": 0.5, - "id": 5 - }, - { - "value": 10.0, - "id": 6 - }, - { - "value": 0.5499500036239624, - "id": 7 - }, - { - "value": 10.0, - "id": 8 - }, - { - "value": 10.0, - "id": 9 - }, - { - "value": 0.0, - "id": 10 + "id": 1 }, { "value": 0.5, - "id": 11 + "id": 2 }, { "value": 0.5, - "id": 12 - }, - { - "value": 0.0, - "id": 13 - }, - { - "value": 0.0, - "id": 14 - }, - { - "value": 0.0, - "id": 15 - }, - { - "value": 0.0, - "id": 16 - }, - { - "value": 0.0, - "id": 17 - }, - { - "value": 0.0, - "id": 18 - }, - { - "value": 0.0, - "id": 19 - }, - { - "value": 0.0, - "id": 20 - }, - { - "value": 0.0, - "id": 21 - }, - { - "value": 0.0, - "id": 22 - }, - { - "value": 0.0, - "id": 23 - }, - { - "value": 0.0, - "id": 24 + "id": 3 }, { "value": 0.0, - "id": 25 + "id": 4 }, { "value": 0.0, - "id": 26 + "id": 5 }, { "value": 0.0, - "id": 27 + "id": 6 }, { "value": 0.0, - "id": 28 + "id": 7 }, { "value": 0.0, - "id": 29 - }, - { - "value": 1.0, - "id": 30 + "id": 8 } ], - "data": { - "frozen": false, - "freezeToggle": false, - "panelStyle": 0, - "tuned": 0, - "diffuseInput": 1, - "preDelayCVSens": 0, - "inputSensitivity": 0, - "outputSaturation": 0, - "dspMode": 1140097024 - }, + "leftModuleId": 8601159184541723, + "rightModuleId": 4828178296911509, "pos": [ - 45, + 18, 0 ] }, { - "id": 7292693033358561, - "plugin": "rackwindows", - "model": "mv", + "id": 4828178296911509, + "plugin": "Fundamental", + "model": "VCA-1", "version": "2.0", "params": [ { - "value": 0.75568318367004395, + "value": 1.0, "id": 0 }, { - "value": 0.87236917018890381, + "value": 1.0, "id": 1 - }, - { - "value": 0.81842118501663208, - "id": 2 - }, - { - "value": 0.50658416748046875, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.0, - "id": 5 - }, - { - "value": 0.0, - "id": 6 - }, - { - "value": 0.0, - "id": 7 } ], + "leftModuleId": 5726895899473528, + "rightModuleId": 1, "pos": [ - 46, - 1 + 27, + 0 ] }, { - "id": 6271512627190487, - "plugin": "Bogaudio", - "model": "Bogaudio-LFO", + "id": 8601159184541723, + "plugin": "Fundamental", + "model": "VCO", "version": "2.0", "params": [ { @@ -928,71 +119,62 @@ "id": 4 }, { - "value": 1.0, + "value": 0.5, "id": 5 }, { "value": 0.0, "id": 6 + }, + { + "value": 0.0, + "id": 7 } ], - "data": { - "offset_cv_to_smoothing": false - }, + "leftModuleId": 2, + "rightModuleId": 5726895899473528, "pos": [ - 0, - 1 + 9, + 0 ] }, { - "id": 8615243856518388, - "plugin": "ZZC", - "model": "Clock", + "id": 1, + "plugin": "Cardinal", + "model": "HostAudio2", "version": "2.0", "params": [ { - "value": 120.0, + "value": 0.79432821273803711, "id": 0 - }, - { - "value": 50.0, - "id": 1 - }, - { - "value": 50.0, - "id": 2 - }, - { - "value": 0.0, - "id": 3 - }, - { - "value": 0.0, - "id": 4 - }, - { - "value": 0.0, - "id": 5 - }, - { - "value": 1.0, - "id": 6 } ], + "leftModuleId": 4828178296911509, + "rightModuleId": 4, + "data": { + "dcFilter": true + }, + "pos": [ + 30, + 0 + ] + }, + { + "id": 2, + "plugin": "Cardinal", + "model": "HostMIDI", + "version": "2.0", + "params": [], + "rightModuleId": 8601159184541723, "data": { - "running": 1, - "reverse": 0, - "baseClockGateMode": false, - "x2ClockGateMode": false, - "x4ClockGateMode": false, - "resetOnStart": false, - "resetOnStop": false, - "runInputIsGate": false, - "runOutputIsGate": false, - "phaseOutputOffset": 0.0, - "useCompatibleBPMCV": true, - "snapCV": false, - "externalClockPPQN": 1 + "pwRange": 0.0, + "smooth": false, + "channels": 1, + "polyMode": 0, + "lastPitch": 8192, + "lastMod": 0, + "inputChannel": 0, + "outputChannel": 0 }, "pos": [ 0, @@ -1000,212 +182,102 @@ ] }, { - "id": 1, + "id": 4, "plugin": "Cardinal", - "model": "HostAudio2", + "model": "HostParameters", "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - } - ], + "params": [], + "leftModuleId": 1, + "rightModuleId": 1202678850202654, "data": { - "dcFilter": true + "smooth": true }, "pos": [ - 58, + 38, 0 ] }, { - "id": 8823371391903591, + "id": 1202678850202654, "plugin": "Cardinal", - "model": "HostAudio2", + "model": "HostParametersMap", "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - } - ], + "params": [], + "leftModuleId": 4, + "rightModuleId": 8712245256622475, "data": { - "dcFilter": true + "maps": [ + { + "hostParamId": 255, + "inverted": false, + "smooth": true, + "moduleId": -1, + "paramId": 0 + } + ] }, "pos": [ - 58, - 1 + 47, + 0 ] } ], "cables": [ { - "id": 5256747357000261, - "outputModuleId": 2222764725422974, + "id": 5155876120487880, + "outputModuleId": 2, "outputId": 1, - "inputModuleId": 1, - "inputId": 0, - "color": "#52beff" + "inputModuleId": 5726895899473528, + "inputId": 4, + "color": "#ff9352" }, { - "id": 8897922774860438, - "outputModuleId": 2222764725422974, - "outputId": 0, - "inputModuleId": 1, - "inputId": 1, - "color": "#52beff" + "id": 781753834216137, + "outputModuleId": 2, + "outputId": 6, + "inputModuleId": 5726895899473528, + "inputId": 5, + "color": "#ffd452" }, { - "id": 3747720534742971, - "outputModuleId": 8508123945855866, + "id": 3464471860196875, + "outputModuleId": 5726895899473528, "outputId": 0, - "inputModuleId": 2222764725422974, + "inputModuleId": 4828178296911509, "inputId": 0, - "color": "#52beff" - }, - { - "id": 6982301964263462, - "outputModuleId": 3056105853448179, - "outputId": 1, - "inputModuleId": 8508123945855866, - "inputId": 7, - "color": "#ff5252" - }, - { - "id": 1401313906365255, - "outputModuleId": 3056105853448179, - "outputId": 0, - "inputModuleId": 8508123945855866, - "inputId": 5, - "color": "#ff5252" + "color": "#e8ff52" }, { - "id": 6460111621879423, - "outputModuleId": 7968649719176584, + "id": 739552540616113, + "outputModuleId": 4828178296911509, "outputId": 0, - "inputModuleId": 7292693033358561, - "inputId": 4, - "color": "#527dff" + "inputModuleId": 1, + "inputId": 0, + "color": "#52beff" }, { - "id": 3841941645043202, - "outputModuleId": 7292693033358561, + "id": 6701970185765111, + "outputModuleId": 2, "outputId": 0, - "inputModuleId": 8823371391903591, + "inputModuleId": 8601159184541723, "inputId": 0, - "color": "#527dff" + "color": "#ff5252" }, { - "id": 8675002981215611, - "outputModuleId": 7292693033358561, - "outputId": 1, - "inputModuleId": 8823371391903591, + "id": 6959800657121782, + "outputModuleId": 2, + "outputId": 2, + "inputModuleId": 8601159184541723, "inputId": 1, - "color": "#527dff" - }, - { - "id": 6764849616399273, - "outputModuleId": 8226081794468965, - "outputId": 1, - "inputModuleId": 7968649719176584, - "inputId": 7, - "color": "#ff9352" + "color": "#52ff7d" }, { - "id": 4925869863866398, - "outputModuleId": 8226081794468965, + "id": 1598271319373837, + "outputModuleId": 8601159184541723, "outputId": 0, - "inputModuleId": 7968649719176584, - "inputId": 5, - "color": "#ff9352" - }, - { - "id": 8437293765463613, - "outputModuleId": 6271512627190487, - "outputId": 4, - "inputModuleId": 7968649719176584, + "inputModuleId": 4828178296911509, "inputId": 1, - "color": "#67ff52" - }, - { - "id": 3320530906916692, - "outputModuleId": 7968649719176584, - "outputId": 1, - "inputModuleId": 7292693033358561, - "inputId": 5, - "color": "#527dff" - }, - { - "id": 6354035082244830, - "outputModuleId": 8615243856518388, - "outputId": 7, - "inputModuleId": 8226081794468965, - "inputId": 2, - "color": "#a8ff52" - }, - { - "id": 1376715750370954, - "outputModuleId": 8615243856518388, - "outputId": 7, - "inputModuleId": 3056105853448179, - "inputId": 2, - "color": "#e8ff52" - }, - { - "id": 3759968541154564, - "outputModuleId": 8615243856518388, - "outputId": 0, - "inputModuleId": 8226081794468965, - "inputId": 9, - "color": "#a8ff52" - }, - { - "id": 4875056227962635, - "outputModuleId": 8615243856518388, - "outputId": 0, - "inputModuleId": 3056105853448179, - "inputId": 9, - "color": "#e8ff52" - }, - { - "id": 6716582837706859, - "outputModuleId": 8615243856518388, - "outputId": 2, - "inputModuleId": 8226081794468965, - "inputId": 6, - "color": "#a8ff52" - }, - { - "id": 7180324831364564, - "outputModuleId": 8615243856518388, - "outputId": 2, - "inputModuleId": 3056105853448179, - "inputId": 5, - "color": "#e8ff52" - }, - { - "id": 4709048866687789, - "outputModuleId": 8615243856518388, - "outputId": 3, - "inputModuleId": 8226081794468965, - "inputId": 3, "color": "#a8ff52" - }, - { - "id": 3629693289772365, - "outputModuleId": 8615243856518388, - "outputId": 3, - "inputModuleId": 3056105853448179, - "inputId": 3, - "color": "#e8ff52" - }, - { - "id": 1418873142775142, - "outputModuleId": 8615243856518388, - "outputId": 1, - "inputModuleId": 7968649719176584, - "inputId": 3, - "color": "#67ff52" } ] -} \ No newline at end of file +} diff --git a/plugins/AS b/plugins/AS index 93aa1d0b..b5fdb76c 160000 --- a/plugins/AS +++ b/plugins/AS @@ -1 +1 @@ -Subproject commit 93aa1d0bbb2550bf05998e331e603e87425aeb91 +Subproject commit b5fdb76c79688207e56bd5b07b01e9c63a102797 diff --git a/plugins/AnimatedCircuits b/plugins/AnimatedCircuits index 76c2912f..bf78cd8e 160000 --- a/plugins/AnimatedCircuits +++ b/plugins/AnimatedCircuits @@ -1 +1 @@ -Subproject commit 76c2912fd6ebdd7c3e33fca88096bea9c67209a1 +Subproject commit bf78cd8ed22970fe9dc5ebff8e3907898904c747 diff --git a/plugins/ArableInstruments b/plugins/ArableInstruments index 890448f0..a2de62d0 160000 --- a/plugins/ArableInstruments +++ b/plugins/ArableInstruments @@ -1 +1 @@ -Subproject commit 890448f087e3ab47eac391f9bcfe03f7bbd2123e +Subproject commit a2de62d0c3b9f764ce6b42441366788d1e52bfcc diff --git a/plugins/AudibleInstruments b/plugins/AudibleInstruments index 2a19bb25..1f279a02 160000 --- a/plugins/AudibleInstruments +++ b/plugins/AudibleInstruments @@ -1 +1 @@ -Subproject commit 2a19bb25c0da725756390ad96dca55632800c74d +Subproject commit 1f279a02d955667341d08f74ddf2054d10e82c65 diff --git a/plugins/BaconPlugs b/plugins/BaconPlugs index adf84fc0..a86d5081 160000 --- a/plugins/BaconPlugs +++ b/plugins/BaconPlugs @@ -1 +1 @@ -Subproject commit adf84fc00a953f8e8a1b378531a08ee68b9a68d7 +Subproject commit a86d5081d12a72ae0d0c775c61813b695cde8a9c diff --git a/plugins/Befaco b/plugins/Befaco index dcd9a59e..fcf9b564 160000 --- a/plugins/Befaco +++ b/plugins/Befaco @@ -1 +1 @@ -Subproject commit dcd9a59ea785d7efebd39ea5564823c72f2fdddf +Subproject commit fcf9b564017d8eee63504771a3006bea81749ff8 diff --git a/plugins/Bidoo b/plugins/Bidoo index 97f61b36..8610d4c8 160000 --- a/plugins/Bidoo +++ b/plugins/Bidoo @@ -1 +1 @@ -Subproject commit 97f61b3616a6e0935ac84f02b1e35734413c6b34 +Subproject commit 8610d4c86740d9d67ebfa4ded70279df7aeb95be diff --git a/plugins/BidooDark/plugin.cpp b/plugins/BidooDark/plugin.cpp index 59077fd3..0fc3ddfd 100644 --- a/plugins/BidooDark/plugin.cpp +++ b/plugins/BidooDark/plugin.cpp @@ -1,5 +1,4 @@ #include "../Bidoo/src/plugin.hpp" -#undef ModuleWidget void InstantiateExpanderItem::onAction(const event::Action &e) { engine::Module* module = model->createModule(); @@ -16,7 +15,7 @@ void InstantiateExpanderItem::onAction(const event::Action &e) { } json_t* BidooModule::dataToJson() { - return nullptr; + return json_object(); } void BidooModule::dataFromJson(json_t*) { @@ -36,5 +35,5 @@ void BidooWidget::prepareThemes(const std::string& filename) { } void BidooWidget::step() { - CardinalModuleWidget::step(); + ModuleWidget::step(); } diff --git a/plugins/Cardinal/plugin.json b/plugins/Cardinal/plugin.json index ff96849d..4086063a 100644 --- a/plugins/Cardinal/plugin.json +++ b/plugins/Cardinal/plugin.json @@ -117,6 +117,16 @@ "Visual" ] }, + { + "slug": "AIDA-X", + "name": "AIDA-X", + "description": "Amp Model Player leveraging AI", + "manualUrl": "https://github.com/DISTRHO/Cardinal/blob/main/docs/CARDINAL-MODULES.md#aidax", + "tags": [ + "Distortion", + "Effect" + ] + }, { "slug": "Blank", "name": "Blank", diff --git a/plugins/Cardinal/res/AIDA-X.svg b/plugins/Cardinal/res/AIDA-X.svg new file mode 100644 index 00000000..ea37b2fa --- /dev/null +++ b/plugins/Cardinal/res/AIDA-X.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + diff --git a/plugins/Cardinal/res/aida-x-background-p2.png b/plugins/Cardinal/res/aida-x-background-p2.png new file mode 100644 index 00000000..af207c04 Binary files /dev/null and b/plugins/Cardinal/res/aida-x-background-p2.png differ diff --git a/plugins/Cardinal/res/aida-x-knob.svg b/plugins/Cardinal/res/aida-x-knob.svg new file mode 100644 index 00000000..84639250 --- /dev/null +++ b/plugins/Cardinal/res/aida-x-knob.svg @@ -0,0 +1,46 @@ + + + + + + + diff --git a/plugins/Cardinal/res/aida-x-logo.png b/plugins/Cardinal/res/aida-x-logo.png new file mode 100644 index 00000000..e2c9a142 Binary files /dev/null and b/plugins/Cardinal/res/aida-x-logo.png differ diff --git a/plugins/Cardinal/res/aida-x-scale.svg b/plugins/Cardinal/res/aida-x-scale.svg new file mode 100644 index 00000000..020bd1e3 --- /dev/null +++ b/plugins/Cardinal/res/aida-x-scale.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/Cardinal/src/AIDA-X.cpp b/plugins/Cardinal/src/AIDA-X.cpp new file mode 100644 index 00000000..5ec02cf9 --- /dev/null +++ b/plugins/Cardinal/src/AIDA-X.cpp @@ -0,0 +1,1114 @@ +/* + * AIDA-X Cardinal plugin + * Copyright (C) 2022-2023 Massimo Pennazio + * Copyright (C) 2023 Filipe Coelho + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "plugincontext.hpp" +#include "ModuleWidgets.hpp" + +#ifndef HEADLESS +# include "ImGuiWidget.hpp" +# include "ghc/filesystem.hpp" +#endif + +// #define QUICK_BUILD_TESTING + +#ifndef QUICK_BUILD_TESTING +# include "extra/Sleep.hpp" +# include "AIDA-X/Biquad.cpp" +# include "AIDA-X/model_variant.hpp" + +template class RTNeural::Model; +template class RTNeural::Layer; + +// -------------------------------------------------------------------------------------------------------------------- + +/* Define a constexpr for converting a gain in dB to a coefficient */ +static constexpr float DB_CO(const float g) { return g > -90.f ? std::pow(10.f, g * 0.05f) : 0.f; } + +/* Define a macro to re-maps a number from one range to another */ +static constexpr float MAP(const float x, const float in_min, const float in_max, const float out_min, const float out_max) +{ + return ((x - in_min) * (out_max - out_min) / (in_max - in_min)) + out_min; +} + +/* Defines for tone controls */ +static constexpr const float COMMON_Q = 0.707f; +static constexpr const float DEPTH_FREQ = 75.f; +static constexpr const float PRESENCE_FREQ = 900.f; + +/* Defines for antialiasing filter */ +static constexpr const float INLPF_MAX_CO = 0.99f * 0.5f; /* coeff * ((samplerate / 2) / samplerate) */ +static constexpr const float INLPF_MIN_CO = 0.25f * 0.5f; /* coeff * ((samplerate / 2) / samplerate) */ + +// -------------------------------------------------------------------------------------------------------------------- + +struct DynamicModel { + ModelVariantType variant; + bool input_skip; /* Means the model has been trained with first input element skipped to the output */ + float input_gain; + float output_gain; +}; + +// -------------------------------------------------------------------------------------------------------------------- +// This function carries model calculations + +static inline +void applyModelOffline(DynamicModel* model, float* const out, uint32_t numSamples) +{ + const bool input_skip = model->input_skip; + const float input_gain = model->input_gain; + const float output_gain = model->output_gain; + + std::visit( + [&out, numSamples, input_skip, input_gain, output_gain] (auto&& custom_model) + { + using ModelType = std::decay_t; + + if (d_isNotEqual(input_gain, 1.f)) + { + for (uint32_t i=0; ivariant + ); +} + +static inline +float applyModel(DynamicModel* model, float sample, const float param1, const float param2) +{ + const bool input_skip = model->input_skip; + const float input_gain = model->input_gain; + const float output_gain = model->output_gain; + + sample *= input_gain; + + std::visit( + [&sample, input_skip, output_gain, param1, param2] (auto&& custom_model) + { + using ModelType = std::decay_t; + + if constexpr (ModelType::input_size == 1) + { + float* out = &sample; + if (input_skip) + { + sample += custom_model.forward(out); + sample *= output_gain; + } + else + { + sample = custom_model.forward(out) * output_gain; + } + } + else if constexpr (ModelType::input_size == 2) + { + float inArray1 alignas(RTNEURAL_DEFAULT_ALIGNMENT)[2] = {sample, param1}; + if (input_skip) + { + sample += custom_model.forward(inArray1); + sample *= output_gain; + } + else + { + sample = custom_model.forward(inArray1) * output_gain; + } + } + else if constexpr (ModelType::input_size == 3) + { + float inArray2 alignas(RTNEURAL_DEFAULT_ALIGNMENT)[3] = {sample, param1, param2}; + if (input_skip) + { + sample += custom_model.forward(inArray2); + sample *= output_gain; + } + else + { + sample = custom_model.forward(inArray2) * output_gain; + } + } + }, + model->variant + ); + + return sample; +} +#endif + +// -------------------------------------------------------------------------------------------------------------------- + +struct AidaPluginModule : Module { + enum Parameters { + kParameterINLPF, + kParameterINLEVEL, + kParameterNETBYPASS, + kParameterEQBYPASS, + kParameterEQPOS, + kParameterBASSGAIN, + kParameterBASSFREQ, + kParameterMIDGAIN, + kParameterMIDFREQ, + kParameterMIDQ, + kParameterMTYPE, + kParameterTREBLEGAIN, + kParameterTREBLEFREQ, + kParameterDEPTH, + kParameterPRESENCE, + kParameterOUTLEVEL, + kParameterPARAM1, + kParameterPARAM2, + NUM_PARAMS + }; + enum EqPos { + kEqPost, + kEqPre + }; + enum MidEqType { + kMidEqPeak, + kMidEqBandpass + }; + enum InputIds { + AUDIO_INPUT, + NUM_INPUTS + }; + enum OutputIds { + AUDIO_OUTPUT, + NUM_OUTPUTS + }; + enum LightIds { + NUM_LIGHTS + }; + + CardinalPluginContext* const pcontext; + bool fileChanged = false; + std::string currentFile; + +#ifndef QUICK_BUILD_TESTING + Biquad dc_blocker { bq_type_highpass, 0.5f, COMMON_Q, 0.0f }; + Biquad in_lpf { bq_type_lowpass, 0.5f, COMMON_Q, 0.0f }; + Biquad bass { bq_type_lowshelf, 0.5f, COMMON_Q, 0.0f }; + Biquad mid { bq_type_peak, 0.5f, COMMON_Q, 0.0f }; + Biquad treble { bq_type_highshelf, 0.5f, COMMON_Q, 0.0f }; + Biquad depth { bq_type_peak, 0.5f, COMMON_Q, 0.0f }; + Biquad presence { bq_type_highshelf, 0.5f, COMMON_Q, 0.0f }; + + float cachedParams[NUM_PARAMS] = {}; + + dsp::ExponentialFilter inlevel; + dsp::ExponentialFilter outlevel; + DynamicModel* model = nullptr; + std::atomic activeModel { false }; +#endif + + AidaPluginModule() + : pcontext(static_cast(APP)) + { + config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + + configInput(AUDIO_INPUT, "Audio"); + configOutput(AUDIO_OUTPUT, "Audio"); + configParam(kParameterINLPF, -0.f, 100.f, 66.216f, "ANTIALIASING", " %"); + configParam(kParameterINLEVEL, -12.f, 12.f, 0.f, "INPUT", " dB"); + configSwitch(kParameterNETBYPASS, 0.f, 1.f, 0.f, "NETBYPASS"); + configSwitch(kParameterEQBYPASS, 0.f, 1.f, 0.f, "EQBYPASS"); + configSwitch(kParameterEQPOS, 0.f, 1.f, 0.f, "EQPOS"); + configParam(kParameterBASSGAIN, -8.f, 8.f, 0.f, "BASS", " dB"); + configParam(kParameterBASSFREQ, 60.f, 305.f, 75.f, "BFREQ", " Hz"); + configParam(kParameterMIDGAIN, -8.f, 8.f, 0.f, "MID", " dB"); + configParam(kParameterMIDFREQ, 150.f, 5000.f, 750.f, "MFREQ", " Hz"); + configParam(kParameterMIDQ, 0.2f, 5.f, 0.707f, "MIDQ"); + configSwitch(kParameterMTYPE, 0.f, 1.f, 0.f, "MTYPE"); + configParam(kParameterTREBLEGAIN, -8.f, 8.f, 0.f, "TREBLE", " dB"); + configParam(kParameterTREBLEFREQ, 1000.f, 4000.f, 2000.f, "TFREQ", " Hz"); + configParam(kParameterDEPTH, -8.f, 8.f, 0.f, "DEPTH", " dB"); + configParam(kParameterPRESENCE, -8.f, 8.f, 0.f, "PRESENCE", " dB"); + configParam(kParameterOUTLEVEL, -15.f, 15.f, 0.f, "OUTPUT", " dB"); + configParam(kParameterPARAM1, 0.f, 1.f, 0.f, "PARAM1"); + configParam(kParameterPARAM2, 0.f, 1.f, 0.f, "PARAM2"); + +#ifndef QUICK_BUILD_TESTING + cachedParams[kParameterINLPF] = 66.216f; + cachedParams[kParameterBASSGAIN] = 0.f; + cachedParams[kParameterBASSFREQ] = 75.f; + cachedParams[kParameterMIDGAIN] = 0.f; + cachedParams[kParameterMIDFREQ] = 750.f; + cachedParams[kParameterMIDQ] = 0.707f; + cachedParams[kParameterTREBLEGAIN] = 0.f; + cachedParams[kParameterTREBLEFREQ] = 2000.f; + cachedParams[kParameterDEPTH] = 0.f; + cachedParams[kParameterPRESENCE] = 0.f; + + in_lpf.setFc(MAP(66.216f, 0.0f, 100.0f, INLPF_MAX_CO, INLPF_MIN_CO)); + inlevel.setTau(1 / 30.f); + outlevel.setTau(1 / 30.f); +#endif + } + + ~AidaPluginModule() override + { +#ifndef QUICK_BUILD_TESTING + delete model; +#endif + } + + json_t* dataToJson() override + { + json_t* const rootJ = json_object(); + DISTRHO_SAFE_ASSERT_RETURN(rootJ != nullptr, nullptr); + + json_object_set_new(rootJ, "filepath", json_string(currentFile.c_str())); + + return rootJ; + } + + void dataFromJson(json_t* const rootJ) override + { + fileChanged = false; + + if (json_t* const filepathJ = json_object_get(rootJ, "filepath")) + { + const char* const filepath = json_string_value(filepathJ); + + if (filepath[0] != '\0') + { + currentFile = filepath; + fileChanged = true; + + loadModelFromFile(filepath, false); + } + } + + if (! fileChanged) + { + currentFile.clear(); + fileChanged = true; + } + } + + void loadModelFromFile(const char* const filename, const bool showError) + { + try { + std::ifstream jsonStream(filename, std::ifstream::binary); + loadModelFromStream(jsonStream); + } + catch (const std::exception& e) { + d_stderr2("Unable to load aida-x file: %s\nError: %s", filename, e.what()); + + if (showError) + async_dialog_message((std::string("Unable to load aida-x file: ") + e.what()).c_str()); + }; + } + + void loadModelFromStream(std::istream& jsonStream) + { +#ifndef QUICK_BUILD_TESTING + int input_size; + int input_skip; + float input_gain; + float output_gain; + nlohmann::json model_json; + + jsonStream >> model_json; + + /* Understand which model type to load */ + input_size = model_json["in_shape"].back().get(); + if (input_size > MAX_INPUT_SIZE) { + throw std::invalid_argument("Value for input_size not supported"); + } + + if (model_json["in_skip"].is_number()) { + input_skip = model_json["in_skip"].get(); + if (input_skip > 1) + throw std::invalid_argument("Values for in_skip > 1 are not supported"); + } + else { + input_skip = 0; + } + + if (model_json["in_gain"].is_number()) { + input_gain = DB_CO(model_json["in_gain"].get()); + } + else { + input_gain = 1.0f; + } + + if (model_json["out_gain"].is_number()) { + output_gain = DB_CO(model_json["out_gain"].get()); + } + else { + output_gain = 1.0f; + } + + std::unique_ptr newmodel = std::make_unique(); + + if (! custom_model_creator(model_json, newmodel->variant)) + throw std::runtime_error("Unable to identify a known model architecture!"); + + std::visit ( + [&model_json] (auto&& custom_model) + { + using ModelType = std::decay_t; + if constexpr (! std::is_same_v) + { + custom_model.parseJson (model_json, true); + custom_model.reset(); + } + }, + newmodel->variant); + + // save extra info + newmodel->input_skip = input_skip != 0; + newmodel->input_gain = input_gain; + newmodel->output_gain = output_gain; + + // Pre-buffer to avoid "clicks" during initialization + float out[2048] = {}; + applyModelOffline(newmodel.get(), out, ARRAY_SIZE(out)); + + // swap active model + DynamicModel* const oldmodel = model; + model = newmodel.release(); + + // if processing, wait for process cycle to complete + while (oldmodel != nullptr && activeModel.load()) + d_msleep(1); + + delete oldmodel; +#endif + } + +#ifndef QUICK_BUILD_TESTING + MidEqType getMidType() const + { + return cachedParams[kParameterMTYPE] > 0.5f ? kMidEqBandpass : kMidEqPeak; + } + + float applyToneControls(float sample) + { + return getMidType() == kMidEqBandpass + ? mid.process(sample) + : presence.process( + treble.process( + mid.process( + bass.process( + depth.process(sample))))); + } +#endif + + void process(const ProcessArgs& args) override + { +#ifndef QUICK_BUILD_TESTING + const float stime = args.sampleTime; + const float inlevelv = DB_CO(params[kParameterINLEVEL].getValue()); + const float outlevelv = DB_CO(params[kParameterOUTLEVEL].getValue()); + + const bool net_bypass = params[kParameterNETBYPASS].getValue() > 0.5f; + const bool eq_bypass = params[kParameterEQBYPASS].getValue() > 0.5f; + const EqPos eq_pos = params[kParameterEQPOS].getValue() > 0.5f ? kEqPre : kEqPost; + + // update tone controls + bool changed = false; + float value; + + value = params[kParameterINLPF].getValue(); + if (d_isNotEqual(cachedParams[kParameterINLPF], value)) + { + cachedParams[kParameterINLPF] = value; + in_lpf.setFc(MAP(value, 0.0f, 100.0f, INLPF_MAX_CO, INLPF_MIN_CO)); + } + + value = params[kParameterBASSGAIN].getValue(); + if (d_isNotEqual(cachedParams[kParameterBASSGAIN], value)) + { + cachedParams[kParameterBASSGAIN] = value; + changed = true; + } + + value = params[kParameterBASSFREQ].getValue(); + if (d_isNotEqual(cachedParams[kParameterBASSFREQ], value)) + { + cachedParams[kParameterBASSFREQ] = value; + changed = true; + } + + if (changed) + { + changed = false; + bass.setBiquad(bq_type_lowshelf, + cachedParams[kParameterBASSFREQ] / args.sampleRate, + COMMON_Q, + cachedParams[kParameterBASSGAIN]); + } + + value = params[kParameterMIDGAIN].getValue(); + if (d_isNotEqual(cachedParams[kParameterMIDGAIN], value)) + { + cachedParams[kParameterMIDGAIN] = value; + changed = true; + } + + value = params[kParameterMIDFREQ].getValue(); + if (d_isNotEqual(cachedParams[kParameterMIDFREQ], value)) + { + cachedParams[kParameterMIDFREQ] = value; + changed = true; + } + + value = params[kParameterMIDQ].getValue(); + if (d_isNotEqual(cachedParams[kParameterMIDQ], value)) + { + cachedParams[kParameterMIDQ] = value; + changed = true; + } + + value = params[kParameterMTYPE].getValue(); + if (d_isNotEqual(cachedParams[kParameterMTYPE], value)) + { + cachedParams[kParameterMTYPE] = value; + changed = true; + } + + if (changed) + { + changed = false; + mid.setBiquad(getMidType() == kMidEqBandpass ? bq_type_bandpass : bq_type_peak, + cachedParams[kParameterMIDFREQ] / args.sampleRate, + cachedParams[kParameterMIDQ], + cachedParams[kParameterMIDGAIN]); + } + + value = params[kParameterTREBLEGAIN].getValue(); + if (d_isNotEqual(cachedParams[kParameterTREBLEGAIN], value)) + { + cachedParams[kParameterTREBLEGAIN] = value; + changed = true; + } + + value = params[kParameterTREBLEFREQ].getValue(); + if (d_isNotEqual(cachedParams[kParameterTREBLEFREQ], value)) + { + cachedParams[kParameterTREBLEFREQ] = value; + changed = true; + } + + if (changed) + { + changed = false; + treble.setBiquad(bq_type_highshelf, + cachedParams[kParameterTREBLEFREQ] / args.sampleRate, + COMMON_Q, + cachedParams[kParameterTREBLEGAIN]); + } + + value = params[kParameterDEPTH].getValue(); + if (d_isNotEqual(cachedParams[kParameterDEPTH], value)) + { + cachedParams[kParameterDEPTH] = value; + depth.setPeakGain(value); + } + + value = params[kParameterPRESENCE].getValue(); + if (d_isNotEqual(cachedParams[kParameterPRESENCE], value)) + { + cachedParams[kParameterPRESENCE] = value; + presence.setPeakGain(value); + } + + // High frequencies roll-off (lowpass) + float sample = in_lpf.process(inputs[AUDIO_INPUT].getVoltage() * 0.1f) * inlevel.process(stime, inlevelv); + + // Equalizer section + if (!eq_bypass && eq_pos == kEqPre) + sample = applyToneControls(sample); + + // run model + if (!net_bypass && model != nullptr) + { + activeModel.store(true); + sample = applyModel(model, sample, + params[kParameterPARAM1].getValue(), + params[kParameterPARAM2].getValue()); + activeModel.store(false); + } + + // DC blocker filter (highpass) + sample = dc_blocker.process(sample); + + // Equalizer section + if (!eq_bypass && eq_pos == kEqPost) + sample = applyToneControls(sample); + + // Output volume + outputs[AUDIO_OUTPUT].setVoltage(sample * outlevel.process(stime, outlevelv) * 10.f); +#endif + } + +#ifndef QUICK_BUILD_TESTING + void onSampleRateChange(const SampleRateChangeEvent& e) override + { + cachedParams[kParameterBASSGAIN] = params[kParameterBASSGAIN].getValue(); + cachedParams[kParameterBASSFREQ] = params[kParameterBASSFREQ].getValue(); + cachedParams[kParameterMIDGAIN] = params[kParameterMIDGAIN].getValue(); + cachedParams[kParameterMIDFREQ] = params[kParameterMIDFREQ].getValue(); + cachedParams[kParameterMIDQ] = params[kParameterMIDQ].getValue(); + cachedParams[kParameterMTYPE] = params[kParameterMTYPE].getValue(); + cachedParams[kParameterTREBLEGAIN] = params[kParameterTREBLEGAIN].getValue(); + cachedParams[kParameterTREBLEFREQ] = params[kParameterTREBLEFREQ].getValue(); + cachedParams[kParameterDEPTH] = params[kParameterDEPTH].getValue(); + cachedParams[kParameterPRESENCE] = params[kParameterPRESENCE].getValue(); + + dc_blocker.setFc(35.0f / e.sampleRate); + + bass.setBiquad(bq_type_lowshelf, + cachedParams[kParameterBASSFREQ] / e.sampleRate, + COMMON_Q, + cachedParams[kParameterBASSGAIN]); + + mid.setBiquad(getMidType() == kMidEqBandpass ? bq_type_bandpass : bq_type_peak, + cachedParams[kParameterMIDFREQ] / e.sampleRate, + cachedParams[kParameterMIDQ], + cachedParams[kParameterMIDGAIN]); + + treble.setBiquad(bq_type_highshelf, + cachedParams[kParameterTREBLEFREQ] / e.sampleRate, + COMMON_Q, + cachedParams[kParameterTREBLEGAIN]); + + depth.setBiquad(bq_type_peak, + DEPTH_FREQ / e.sampleRate, + COMMON_Q, + cachedParams[kParameterDEPTH]); + + presence.setBiquad(bq_type_highshelf, + PRESENCE_FREQ / e.sampleRate, + COMMON_Q, + cachedParams[kParameterPRESENCE]); + } +#endif + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AidaPluginModule) +}; + +// -------------------------------------------------------------------------------------------------------------------- + +#ifndef HEADLESS +struct AidaModelListWidget : ImGuiWidget { + AidaPluginModule* const module; + + struct ghcFile { + std::string full, base; + bool operator<(const ghcFile& other) const noexcept { return base < other.base; } + }; + std::string currentDirectory; + std::vector currentFiles; + size_t selectedFile = (size_t)-1; + + AidaModelListWidget(AidaPluginModule* const m) + : ImGuiWidget(), + module(m) + { + if (module != nullptr && module->fileChanged) + reloadDir(); + } + + void drawImGui() override + { + const float scaleFactor = getScaleFactor(); + + // transparent background + { + ImGuiStyle& style(ImGui::GetStyle()); + style.WindowRounding = 12 * scaleFactor; + style.WindowBorderSize = style.FrameBorderSize = 0.f; + style.ScrollbarSize = 12 * scaleFactor; + + ImVec4* const colors = style.Colors; + colors[ImGuiCol_Text] = ImVec4(0.f, 0.f, 0.f, 1.f); + colors[ImGuiCol_WindowBg] = ImVec4(0.f, 0.f, 0.f, 0.f); + colors[ImGuiCol_FrameBg] = ImVec4(0.f, 0.f, 0.f, 0.f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.f, 0.f, 0.f, 0.f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.f, 0.f, 0.f, 0.f); + colors[ImGuiCol_Header] = ImVec4(0.f, 0.f, 0.f, 0.4f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.f, 0.f, 0.f, 0.35f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.f, 0.f, 0.f, 0.5f); + } + + const int flags = ImGuiWindowFlags_NoBackground + | ImGuiWindowFlags_NoSavedSettings + | ImGuiWindowFlags_NoTitleBar + | ImGuiWindowFlags_NoResize + | ImGuiWindowFlags_NoCollapse + | ImGuiWindowFlags_NoScrollbar + | ImGuiWindowFlags_NoScrollWithMouse; + + ImGui::SetNextWindowPos(ImVec2(0, 0)); + ImGui::SetNextWindowSize(ImVec2(box.size.x * scaleFactor, box.size.y * scaleFactor)); + + if (ImGui::Begin("Model File List", nullptr, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize)) + { + if (ImGui::BeginTable("modellist", 1, ImGuiTableFlags_NoSavedSettings)) + { + for (size_t i=0, count=currentFiles.size(); i < count; ++i) + { + bool wasSelected = selectedFile == i; + bool selected = wasSelected; + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGui::Selectable(currentFiles[i].base.c_str(), &selected); + + if (selected && ! wasSelected) + { + selectedFile = i; + module->currentFile = currentFiles[i].full; + module->loadModelFromFile(currentFiles[i].full.c_str(), true); + } + } + + ImGui::EndTable(); + } + } + + ImGui::End(); + } + + void step() override + { + if (module->fileChanged) + reloadDir(); + + ImGuiWidget::step(); + } + + void reloadDir() + { + module->fileChanged = false; + + currentFiles.clear(); + selectedFile = (size_t)-1; + + static constexpr const char* const supportedExtensions[] = { + ".json" + }; + + using namespace ghc::filesystem; + const path currentFile = u8path(module->currentFile); + currentDirectory = currentFile.parent_path().generic_u8string(); + + directory_iterator it; + + try { + it = directory_iterator(u8path(currentDirectory)); + } DISTRHO_SAFE_EXCEPTION_RETURN("Failed to open current directory",); + + for (directory_iterator itb = begin(it), ite=end(it); itb != ite; ++itb) + { + if (! itb->is_regular_file()) + continue; + const path filepath = itb->path(); + const path extension = filepath.extension(); + for (size_t i=0; i image; + bool hasModule; + + AidaLogo(const bool hasModule) { + box.size = Vec(74, 16.666f); + this->hasModule = hasModule; + } + + void draw(const DrawArgs& args) override + { + if (image.get() == nullptr) + image = APP->window->loadImage(asset::plugin(pluginInstance, "res/aida-x-logo.png")); + + if (Image* const img = image.get()) + { + const float pixelRatio = hasModule ? APP->window->pixelRatio : 1.0f; + const float boxscale = std::min(box.size.x / 111, box.size.y / 25); + const float imgHeight = (25 / pixelRatio) * boxscale; + nvgBeginPath(args.vg); + nvgRect(args.vg, 0, 0, box.size.x, box.size.y); + nvgFillPaint(args.vg, nvgImagePattern(args.vg, + 0, + (box.size.y / pixelRatio) * 0.5f - imgHeight * 0.5f, + box.size.x / pixelRatio, + imgHeight, 0, img->handle, 1.0f)); + nvgFill(args.vg); + } + } +}; + +struct AidaKnob : app::SvgKnob { + AidaKnob() + { + minAngle = -0.76 * M_PI; + maxAngle = 0.76 * M_PI; + shadow->opacity = 0; + setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/aida-x-knob.svg"))); + } +}; + +struct AidaSwitch : app::Switch { + static constexpr const float kSwitchWidth = 15.f; + static constexpr const float kSwitchHeight = 34.f; + + bool inverted = false; + + AidaSwitch() + { + box.size.x = kSwitchWidth; + box.size.y = kSwitchHeight; + } + + void draw(const DrawArgs& args) override + { + engine::ParamQuantity* pq = getParamQuantity(); + + bool checked; + if (pq != nullptr) + checked = inverted ? pq->getValue() <= pq->getMinValue() : pq->getValue() > pq->getMinValue(); + else + checked = true; + + nvgBeginPath(args.vg); + nvgRoundedRect(args.vg, 0, 0, box.size.x, box.size.y, kSwitchWidth/2); + nvgFillColor(args.vg, checked ? nvgRGB(84, 84, 84) : nvgRGB(129, 247, 0)); + nvgFill(args.vg); + + nvgBeginPath(args.vg); + nvgCircle(args.vg, + box.size.x / 2, + checked ? box.size.y/2 + kSwitchHeight/2 - kSwitchWidth/2 + : box.size.y/2 - kSwitchHeight/2 + kSwitchWidth/2, + 6.f); + nvgFillColor(args.vg, checked ? nvgRGB(218, 214, 203) : nvgRGB(24, 112, 4)); + nvgFill(args.vg); + } +}; + +struct AidaWidget : ModuleWidgetWithSideScrews<23> { + static constexpr const uint kPedalMargin = 10; + static constexpr const uint kPedalMarginVertical = 25; + static constexpr const uint kFileListHeight = 200; + + struct { + std::shared_ptr background; + std::shared_ptr header; + std::shared_ptr logo; + } images; + + AidaPluginModule* const module; + + AidaWidget(AidaPluginModule* const m) + : module(m) + { + setModule(module); + setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/AIDA-X.svg"))); + + createAndAddScrews(); + + addInput(createInputCentered(Vec(box.size.x / 2 - 120, box.size.y - 115), module, 0)); + addOutput(createOutputCentered(Vec(box.size.x / 2 + 120, box.size.y - 115), module, 0)); + + addChild(createParamCentered(Vec(box.size.x / 2 - 80, box.size.y - 115), + module, AidaPluginModule::kParameterINLEVEL)); + + addChild(createParamCentered(Vec(box.size.x / 2 + 80, box.size.y - 115), + module, AidaPluginModule::kParameterOUTLEVEL)); + + addChild(createParamCentered(Vec(104, box.size.y - 55), + module, AidaPluginModule::kParameterBASSGAIN)); + + addChild(createParamCentered(Vec(152, box.size.y - 55), + module, AidaPluginModule::kParameterMIDGAIN)); + + addChild(createParamCentered(Vec(200, box.size.y - 55), + module, AidaPluginModule::kParameterTREBLEGAIN)); + + addChild(createParamCentered(Vec(252, box.size.y - 55), + module, AidaPluginModule::kParameterDEPTH)); + + addChild(createParamCentered(Vec(300, box.size.y - 55), + module, AidaPluginModule::kParameterPRESENCE)); + + addChild(createParamCentered(Vec(34, box.size.y - 53), + module, AidaPluginModule::kParameterEQPOS)); + + addChild(createParamCentered(Vec(64, box.size.y - 53), + module, AidaPluginModule::kParameterMTYPE)); + + AidaLogo* const logow = new AidaLogo(module != nullptr); + + FramebufferWidget* const fbw = new FramebufferWidget; + fbw->oversample = 2.0; + fbw->addChild(logow); + fbw->box.size = logow->box.size; + fbw->box.pos.x = box.size.x / 2 - fbw->box.size.x / 2; + fbw->box.pos.y = 8; + addChild(fbw); + + if (m != nullptr) + { + AidaModelListWidget* const listw = new AidaModelListWidget(m); + listw->box.pos = Vec(kPedalMargin * 2, kPedalMargin * 3); + listw->box.size = Vec(box.size.x - kPedalMargin * 4, kFileListHeight); + addChild(listw); + } + } + + void draw(const DrawArgs& args) override + { + const int cornerRadius = 12; + + // load images as needed + if (images.background.get() == nullptr) + images.background = APP->window->loadImage(asset::plugin(pluginInstance, "res/aida-x-background-p2.png")); + + // background gradient + nvgBeginPath(args.vg); + nvgRect(args.vg, 0, 0, box.size.x, box.size.y); + + nvgFillPaint(args.vg, + nvgLinearGradient(args.vg, + 0, 0, + box.size.x * 0.52f, 0, + nvgRGB(28, 23, 12), + nvgRGB(42, 34, 15))); + nvgFill(args.vg); + + nvgFillPaint(args.vg, + nvgLinearGradient(args.vg, + box.size.x * 0.5f, 0, + box.size.x, 0, + nvgRGB(42, 34, 15), + nvgRGB(19, 19, 19))); + nvgFill(args.vg); + + // splitter + nvgBeginPath(args.vg); + nvgMoveTo(args.vg, 226, box.size.y - 80); + nvgLineTo(args.vg, 226, box.size.y - 32); + nvgLineCap(args.vg, NVG_ROUND); + nvgStrokeColor(args.vg, nvgRGBA(97, 97, 97, 123)); + nvgStrokeWidth(args.vg, 2); + nvgStroke(args.vg); + + // .rt-neural .background_head + nvgBeginPath(args.vg); + nvgRoundedRect(args.vg, + kPedalMargin * 2, + kPedalMargin + kPedalMarginVertical, + box.size.x - kPedalMargin * 4, + kFileListHeight, + cornerRadius); + nvgFillPaint(args.vg, + nvgLinearGradient(args.vg, + kPedalMargin * 2, + kPedalMargin + kPedalMarginVertical, + kPedalMargin * 2, + kPedalMargin + kPedalMarginVertical + kFileListHeight, + nvgRGB(0x8b, 0xf7, 0x00), + nvgRGB(0xcd, 0xff, 0x05))); + nvgFill(args.vg); + + if (Image* const img = images.background.get()) + { + nvgFillPaint(args.vg, nvgImagePattern(args.vg, + kPedalMargin * 2, + kPedalMargin + kPedalMarginVertical, + 256.f, 128.f, 0.f, img->handle, 1.f)); + nvgFill(args.vg); + } + + nvgFillPaint(args.vg, + nvgBoxGradient(args.vg, + kPedalMargin * 2, + kPedalMargin + kPedalMarginVertical, + box.size.x - kPedalMargin * 4, + kFileListHeight, + cornerRadius, + cornerRadius, + nvgRGBAf(0,0,0,0.f), + nvgRGBAf(0,0,0,1.f))); + nvgFill(args.vg); + + // a bit darker so the text is readable + nvgFillColor(args.vg, nvgRGBAf(0.f,0.f,0.f,0.1f)); + nvgFill(args.vg); + + // plugin label + nvgFillColor(args.vg, nvgRGBA(0x8b, 0xf7, 0x00, 255)); + nvgFontSize(args.vg, 24); + nvgTextAlign(args.vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); + nvgText(args.vg, box.size.x / 2, box.size.y - 110, "AIDA-X", nullptr); + + nvgFontSize(args.vg, 14); + nvgTextAlign(args.vg, NVG_ALIGN_CENTER | NVG_ALIGN_TOP); + nvgText(args.vg, box.size.x / 2, box.size.y - 105, "AI CRAFTED TONE", nullptr); + + // text stuff + nvgFontSize(args.vg, 11); + nvgFillColor(args.vg, nvgRGB(0xff,0xff,0xff)); + nvgTextAlign(args.vg, NVG_ALIGN_CENTER); + + nvgText(args.vg, 34, box.size.y - 75, "POST", nullptr); + nvgText(args.vg, 34, box.size.y - 25, "PRE", nullptr); + + nvgText(args.vg, 64, box.size.y - 75, "PEAK", nullptr); + nvgText(args.vg, 64, box.size.y - 25, "BPASS", nullptr); + + nvgText(args.vg, 104, box.size.y - 25, "BASS", nullptr); + nvgText(args.vg, 152, box.size.y - 25, "MID", nullptr); + nvgText(args.vg, 200, box.size.y - 25, "TREBLE", nullptr); + nvgText(args.vg, 252, box.size.y - 25, "DEPTH", nullptr); + nvgText(args.vg, 300, box.size.y - 25, "PRESENCE", nullptr); + + nvgText(args.vg, box.size.x / 2 - 80, box.size.y - 85, "INPUT", nullptr); + nvgText(args.vg, box.size.x / 2 + 80, box.size.y - 85, "OUTPUT", nullptr); + + ModuleWidget::draw(args); + } + + void appendContextMenu(ui::Menu* const menu) override + { + menu->addChild(new ui::MenuSeparator); + + struct LoadModelFileItem : MenuItem { + AidaPluginModule* const module; + + LoadModelFileItem(AidaPluginModule* const m) + : module(m) + { + text = "Load model file..."; + } + + void onAction(const event::Action&) override + { + AidaPluginModule* const module = this->module; + async_dialog_filebrowser(false, nullptr, nullptr, text.c_str(), [module](char* path) + { + if (path == nullptr) + return; + + module->currentFile = path; + module->fileChanged = true; + module->loadModelFromFile(path, true); + std::free(path); + }); + } + }; + + menu->addChild(new LoadModelFileItem(module)); + } + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AidaWidget) +}; +#else +struct AidaWidget : ModuleWidget { + AidaWidget(AidaPluginModule* const module) { + setModule(module); + + addInput(createInput({}, module, 0)); + addOutput(createOutput({}, module, 0)); + } +}; +#endif + +// -------------------------------------------------------------------------------------------------------------------- + +Model* modelAidaX = createModel("AIDA-X"); + +// -------------------------------------------------------------------------------------------------------------------- diff --git a/plugins/Cardinal/src/AIDA-X/Biquad.cpp b/plugins/Cardinal/src/AIDA-X/Biquad.cpp new file mode 100644 index 00000000..d01e29bd --- /dev/null +++ b/plugins/Cardinal/src/AIDA-X/Biquad.cpp @@ -0,0 +1,165 @@ +// +// Biquad.cpp +// +// Created by Nigel Redmon on 11/24/12 +// EarLevel Engineering: earlevel.com +// Copyright 2012 Nigel Redmon +// +// For a complete explanation of the Biquad code: +// http://www.earlevel.com/main/2012/11/26/biquad-c-source-code/ +// +// License: +// +// This source code is provided as is, without warranty. +// You may copy and distribute verbatim copies of this document. +// You may modify and use this source code to create binary code +// for your own purposes, free or commercial. +// + +#include +#include "Biquad.h" + +Biquad::Biquad() { + type = bq_type_lowpass; + a0 = 1.0; + a1 = a2 = b1 = b2 = 0.0; + Fc = 0.50; + Q = 0.707; + peakGain = 0.0; + z1 = z2 = 0.0; +} + +Biquad::Biquad(int type, double Fc, double Q, double peakGainDB) { + setBiquad(type, Fc, Q, peakGainDB); + z1 = z2 = 0.0; +} + +Biquad::~Biquad() { +} + +void Biquad::setType(int type) { + this->type = type; + calcBiquad(); +} + +void Biquad::setQ(double Q) { + this->Q = Q; + calcBiquad(); +} + +void Biquad::setFc(double Fc) { + this->Fc = Fc; + calcBiquad(); +} + +void Biquad::setPeakGain(double peakGainDB) { + this->peakGain = peakGainDB; + calcBiquad(); +} + +void Biquad::setBiquad(int type, double Fc, double Q, double peakGainDB) { + this->type = type; + this->Q = Q; + this->Fc = Fc; + setPeakGain(peakGainDB); +} + +void Biquad::calcBiquad(void) { + double norm; + double V = pow(10, fabs(peakGain) / 20.0); + double K = tan(M_PI * Fc); + switch (this->type) { + case bq_type_lowpass: + norm = 1 / (1 + K / Q + K * K); + a0 = K * K * norm; + a1 = 2 * a0; + a2 = a0; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - K / Q + K * K) * norm; + break; + + case bq_type_highpass: + norm = 1 / (1 + K / Q + K * K); + a0 = 1 * norm; + a1 = -2 * a0; + a2 = a0; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - K / Q + K * K) * norm; + break; + + case bq_type_bandpass: + norm = 1 / (1 + K / Q + K * K); + a0 = K / Q * norm; + a1 = 0; + a2 = -a0; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - K / Q + K * K) * norm; + break; + + case bq_type_notch: + norm = 1 / (1 + K / Q + K * K); + a0 = (1 + K * K) * norm; + a1 = 2 * (K * K - 1) * norm; + a2 = a0; + b1 = a1; + b2 = (1 - K / Q + K * K) * norm; + break; + + case bq_type_peak: + if (peakGain >= 0) { // boost + norm = 1 / (1 + 1/Q * K + K * K); + a0 = (1 + V/Q * K + K * K) * norm; + a1 = 2 * (K * K - 1) * norm; + a2 = (1 - V/Q * K + K * K) * norm; + b1 = a1; + b2 = (1 - 1/Q * K + K * K) * norm; + } + else { // cut + norm = 1 / (1 + V/Q * K + K * K); + a0 = (1 + 1/Q * K + K * K) * norm; + a1 = 2 * (K * K - 1) * norm; + a2 = (1 - 1/Q * K + K * K) * norm; + b1 = a1; + b2 = (1 - V/Q * K + K * K) * norm; + } + break; + case bq_type_lowshelf: + if (peakGain >= 0) { // boost + norm = 1 / (1 + sqrt(2) * K + K * K); + a0 = (1 + sqrt(2*V) * K + V * K * K) * norm; + a1 = 2 * (V * K * K - 1) * norm; + a2 = (1 - sqrt(2*V) * K + V * K * K) * norm; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - sqrt(2) * K + K * K) * norm; + } + else { // cut + norm = 1 / (1 + sqrt(2*V) * K + V * K * K); + a0 = (1 + sqrt(2) * K + K * K) * norm; + a1 = 2 * (K * K - 1) * norm; + a2 = (1 - sqrt(2) * K + K * K) * norm; + b1 = 2 * (V * K * K - 1) * norm; + b2 = (1 - sqrt(2*V) * K + V * K * K) * norm; + } + break; + case bq_type_highshelf: + if (peakGain >= 0) { // boost + norm = 1 / (1 + sqrt(2) * K + K * K); + a0 = (V + sqrt(2*V) * K + K * K) * norm; + a1 = 2 * (K * K - V) * norm; + a2 = (V - sqrt(2*V) * K + K * K) * norm; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - sqrt(2) * K + K * K) * norm; + } + else { // cut + norm = 1 / (V + sqrt(2*V) * K + K * K); + a0 = (1 + sqrt(2) * K + K * K) * norm; + a1 = 2 * (K * K - 1) * norm; + a2 = (1 - sqrt(2) * K + K * K) * norm; + b1 = 2 * (K * K - V) * norm; + b2 = (V - sqrt(2*V) * K + K * K) * norm; + } + break; + } + + return; +} diff --git a/plugins/Cardinal/src/AIDA-X/Biquad.h b/plugins/Cardinal/src/AIDA-X/Biquad.h new file mode 100644 index 00000000..ee1b9553 --- /dev/null +++ b/plugins/Cardinal/src/AIDA-X/Biquad.h @@ -0,0 +1,60 @@ +// +// Biquad.h +// +// Created by Nigel Redmon on 11/24/12 +// EarLevel Engineering: earlevel.com +// Copyright 2012 Nigel Redmon +// +// For a complete explanation of the Biquad code: +// http://www.earlevel.com/main/2012/11/26/biquad-c-source-code/ +// +// License: +// +// This source code is provided as is, without warranty. +// You may copy and distribute verbatim copies of this document. +// You may modify and use this source code to create binary code +// for your own purposes, free or commercial. +// + +#ifndef Biquad_h +#define Biquad_h + +enum { + bq_type_lowpass = 0, + bq_type_highpass, + bq_type_bandpass, + bq_type_notch, + bq_type_peak, + bq_type_lowshelf, + bq_type_highshelf +}; + +class Biquad { +public: + Biquad(); + Biquad(int type, double Fc, double Q, double peakGainDB); + ~Biquad(); + void setType(int type); + void setQ(double Q); + void setFc(double Fc); + void setPeakGain(double peakGainDB); + void setBiquad(int type, double Fc, double Q, double peakGainDB); + float process(float in); + +protected: + void calcBiquad(void); + + int type; + double a0, a1, a2, b1, b2; + double Fc, Q, peakGain; + double z1, z2; +}; + +inline float Biquad::process(float in) { + double out = in * a0 + z1; + z1 = in * a1 + z2 - b1 * out; + z2 = in * a2 - b2 * out; + return out; +} + +#endif // Biquad_h diff --git a/plugins/Cardinal/src/AIDA-X/RTNeural b/plugins/Cardinal/src/AIDA-X/RTNeural new file mode 160000 index 00000000..74e9d354 --- /dev/null +++ b/plugins/Cardinal/src/AIDA-X/RTNeural @@ -0,0 +1 @@ +Subproject commit 74e9d354937346f31858e976a2eefc1c25cdcccd diff --git a/plugins/Cardinal/src/AIDA-X/model_variant.hpp b/plugins/Cardinal/src/AIDA-X/model_variant.hpp new file mode 100644 index 00000000..b7305915 --- /dev/null +++ b/plugins/Cardinal/src/AIDA-X/model_variant.hpp @@ -0,0 +1,683 @@ +#include +#include + +#define MAX_INPUT_SIZE 3 +struct NullModel { static constexpr int input_size = 0; static constexpr int output_size = 0; }; +using ModelType_GRU_8_1 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_8_2 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_8_3 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_12_1 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_12_2 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_12_3 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_16_1 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_16_2 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_16_3 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_20_1 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_20_2 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_20_3 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_32_1 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_32_2 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_32_3 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_40_1 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_40_2 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_40_3 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_64_1 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_64_2 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_GRU_64_3 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_8_1 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_8_2 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_8_3 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_12_1 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_12_2 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_12_3 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_16_1 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_16_2 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_16_3 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_20_1 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_20_2 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_20_3 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_32_1 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_32_2 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_32_3 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_40_1 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_40_2 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_40_3 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_64_1 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_64_2 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelType_LSTM_64_3 = RTNeural::ModelT, RTNeural::DenseT>; +using ModelVariantType = std::variant; + +inline bool is_model_type_ModelType_GRU_8_1 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 8; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 1; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_8_2 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 8; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 2; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_8_3 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 8; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 3; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_12_1 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 12; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 1; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_12_2 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 12; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 2; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_12_3 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 12; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 3; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_16_1 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 16; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 1; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_16_2 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 16; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 2; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_16_3 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 16; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 3; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_20_1 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 20; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 1; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_20_2 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 20; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 2; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_20_3 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 20; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 3; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_32_1 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 32; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 1; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_32_2 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 32; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 2; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_32_3 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 32; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 3; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_40_1 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 40; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 1; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_40_2 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 40; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 2; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_40_3 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 40; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 3; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_64_1 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 64; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 1; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_64_2 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 64; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 2; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_GRU_64_3 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "gru"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 64; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 3; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_8_1 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 8; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 1; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_8_2 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 8; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 2; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_8_3 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 8; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 3; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_12_1 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 12; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 1; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_12_2 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 12; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 2; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_12_3 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 12; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 3; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_16_1 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 16; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 1; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_16_2 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 16; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 2; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_16_3 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 16; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 3; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_20_1 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 20; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 1; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_20_2 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 20; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 2; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_20_3 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 20; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 3; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_32_1 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 32; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 1; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_32_2 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 32; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 2; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_32_3 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 32; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 3; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_40_1 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 40; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 1; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_40_2 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 40; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 2; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_40_3 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 40; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 3; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_64_1 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 64; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 1; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_64_2 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 64; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 2; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool is_model_type_ModelType_LSTM_64_3 (const nlohmann::json& model_json) { + const auto json_layers = model_json.at ("layers"); + const auto rnn_layer_type = json_layers.at (0).at ("type").get(); + const auto is_layer_type_correct = rnn_layer_type == "lstm"; + const auto hidden_size = json_layers.at (0).at ("shape").back().get(); + const auto is_hidden_size_correct = hidden_size == 64; + const auto input_size = model_json.at ("in_shape").back().get(); + const auto is_input_size_correct = input_size == 3; + return is_layer_type_correct && is_hidden_size_correct && is_input_size_correct; +} + +inline bool custom_model_creator (const nlohmann::json& model_json, ModelVariantType& model) { + if (is_model_type_ModelType_GRU_8_1 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_8_2 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_8_3 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_12_1 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_12_2 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_12_3 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_16_1 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_16_2 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_16_3 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_20_1 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_20_2 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_20_3 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_32_1 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_32_2 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_32_3 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_40_1 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_40_2 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_40_3 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_64_1 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_64_2 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_GRU_64_3 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_8_1 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_8_2 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_8_3 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_12_1 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_12_2 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_12_3 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_16_1 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_16_2 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_16_3 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_20_1 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_20_2 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_20_3 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_32_1 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_32_2 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_32_3 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_40_1 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_40_2 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_40_3 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_64_1 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_64_2 (model_json)) { + model.emplace(); + return true; + } + else if (is_model_type_ModelType_LSTM_64_3 (model_json)) { + model.emplace(); + return true; + } + model.emplace(); + return false; +} diff --git a/plugins/Cardinal/src/AudioFile.cpp b/plugins/Cardinal/src/AudioFile.cpp index c52b4db2..5bec077d 100644 --- a/plugins/Cardinal/src/AudioFile.cpp +++ b/plugins/Cardinal/src/AudioFile.cpp @@ -79,6 +79,7 @@ struct CarlaInternalPluginModule : Module, Runner { kParameterHostSync, kParameterVolume, kParameterEnabled, + kParameterQuadChannels, kParameterInfoChannels, kParameterInfoBitRate, kParameterInfoBitDepth, @@ -96,8 +97,8 @@ struct CarlaInternalPluginModule : Module, Runner { NativeHostDescriptor fCarlaHostDescriptor = {}; NativeTimeInfo fCarlaTimeInfo; - float dataOut[NUM_OUTPUTS][BUFFER_SIZE]; - float* dataOutPtr[NUM_OUTPUTS]; + float dataOut[NUM_OUTPUTS+1][BUFFER_SIZE]; + float* dataOutPtr[NUM_OUTPUTS+1]; unsigned audioDataFill = 0; uint32_t lastProcessCounter = 0; bool fileChanged = false; @@ -105,11 +106,11 @@ struct CarlaInternalPluginModule : Module, Runner { struct { float preview[108]; - uint channels; // 4 - uint bitDepth; // 6 - uint sampleRate; // 7 - uint length; // 8 - float position; // 9 + uint channels; + uint bitDepth; + uint sampleRate; + uint length; + float position; } audioInfo; CarlaInternalPluginModule() @@ -122,6 +123,7 @@ struct CarlaInternalPluginModule : Module, Runner { dataOutPtr[0] = dataOut[0]; dataOutPtr[1] = dataOut[1]; + dataOutPtr[2] = dataOut[2]; std::memset(dataOut, 0, sizeof(dataOut)); std::memset(&audioInfo, 0, sizeof(audioInfo)); @@ -315,11 +317,11 @@ struct CarlaInternalPluginModule : Module, Runner { audioDataFill = 0; fCarlaPluginDescriptor->process(fCarlaPluginHandle, nullptr, dataOutPtr, BUFFER_SIZE, nullptr, 0); - audioInfo.channels = fCarlaPluginDescriptor->get_parameter_value(fCarlaPluginHandle, 4); - audioInfo.bitDepth = fCarlaPluginDescriptor->get_parameter_value(fCarlaPluginHandle, 6); - audioInfo.sampleRate = fCarlaPluginDescriptor->get_parameter_value(fCarlaPluginHandle, 7); - audioInfo.length = fCarlaPluginDescriptor->get_parameter_value(fCarlaPluginHandle, 8); - audioInfo.position = fCarlaPluginDescriptor->get_parameter_value(fCarlaPluginHandle, 9); + audioInfo.channels = fCarlaPluginDescriptor->get_parameter_value(fCarlaPluginHandle, kParameterInfoChannels); + audioInfo.bitDepth = fCarlaPluginDescriptor->get_parameter_value(fCarlaPluginHandle, kParameterInfoBitDepth); + audioInfo.sampleRate = fCarlaPluginDescriptor->get_parameter_value(fCarlaPluginHandle, kParameterInfoSampleRate); + audioInfo.length = fCarlaPluginDescriptor->get_parameter_value(fCarlaPluginHandle, kParameterInfoLength); + audioInfo.position = fCarlaPluginDescriptor->get_parameter_value(fCarlaPluginHandle, kParameterInfoPosition); } } @@ -471,10 +473,10 @@ struct AudioFileListWidget : ImGuiWidget { selectedFile = (size_t)-1; static constexpr const char* const supportedExtensions[] = { - #ifdef HAVE_SNDFILE + #ifdef HAVE_SNDFILE ".aif",".aifc",".aiff",".au",".bwf",".flac",".htk",".iff",".mat4",".mat5",".oga",".ogg",".opus", ".paf",".pvf",".pvf5",".sd2",".sf",".snd",".svx",".vcc",".w64",".wav",".xi", - #endif + #endif ".mp3" }; diff --git a/plugins/Cardinal/src/AudioToCVPitch.cpp b/plugins/Cardinal/src/AudioToCVPitch.cpp index 89d9e69b..2c79720b 100644 --- a/plugins/Cardinal/src/AudioToCVPitch.cpp +++ b/plugins/Cardinal/src/AudioToCVPitch.cpp @@ -95,6 +95,14 @@ struct AudioToCVPitch : Module { configParam(PARAM_TOLERANCE, 0.f, 99.f, kDefaultTolerance, "Tolerance", " %"); } + ~AudioToCVPitch() override + { + if (pitchDetector != nullptr) + del_aubio_pitch(pitchDetector); + del_fvec(detectedPitch); + del_fvec(inputBuffer); + } + void process(const ProcessArgs& args) override { float cvPitch = lastUsedOutputPitch; diff --git a/plugins/Cardinal/src/Blank.cpp b/plugins/Cardinal/src/Blank.cpp index 8351e701..18244d6f 100644 --- a/plugins/Cardinal/src/Blank.cpp +++ b/plugins/Cardinal/src/Blank.cpp @@ -41,7 +41,7 @@ struct CardinalBlankModule : Module { }; struct CardinalBlankImage : Widget { - int imageId = -2; + std::shared_ptr image; int imageWidth = 0; int imageHeight = 0; bool hasModule; @@ -53,26 +53,28 @@ struct CardinalBlankImage : Widget { void draw(const DrawArgs& args) override { - if (imageId == -2) + Image* img = image.get(); + + if (img == nullptr) { - imageId = nvgCreateImage(args.vg, asset::plugin(pluginInstance, "res/Miku/Miku.png").c_str(), 0); + image = APP->window->loadImage(asset::plugin(pluginInstance, "res/Miku/Miku.png")); - if (imageId != -1) - nvgImageSize(args.vg, imageId, &imageWidth, &imageHeight); + if ((img = image.get()) != nullptr) + nvgImageSize(args.vg, img->handle, &imageWidth, &imageHeight); } - if (imageId != -1 && imageWidth != 0 && imageHeight != 0) + if (img != nullptr && imageWidth != 0 && imageHeight != 0) { const float pixelRatio = hasModule ? APP->window->pixelRatio : 1.0f; const float boxscale = std::min(box.size.x / imageWidth, box.size.y / imageHeight); const float imgHeight = (imageHeight / pixelRatio) * boxscale; nvgBeginPath(args.vg); - nvgRect(args.vg, 0, 0, box.size.x, box.size.y); + nvgRect(args.vg, 0, box.size.y * 0.5f - imgHeight * 0.5f, box.size.x, imgHeight); nvgFillPaint(args.vg, nvgImagePattern(args.vg, 0, (box.size.y / pixelRatio) * 0.5f - imgHeight * 0.5f, box.size.x / pixelRatio, - imgHeight, 0, imageId, 1.0f)); + imgHeight, 0, img->handle, 1.0f)); nvgFill(args.vg); } } diff --git a/plugins/Cardinal/src/Carla.cpp b/plugins/Cardinal/src/Carla.cpp index 30fef47f..b9122835 100644 --- a/plugins/Cardinal/src/Carla.cpp +++ b/plugins/Cardinal/src/Carla.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -132,7 +132,17 @@ struct CarlaModule : Module { const char* binaryDir = nullptr; const char* resourceDir = nullptr; -#if defined(CARLA_OS_MAC) + #if defined(CARLA_OS_WIN) + const std::string winBinaryDir = system::join(asset::systemDir, "Carla"); + + if (system::exists(winBinaryDir)) + { + winResourceDir = system::join(winBinaryDir, "resources"); + binaryDir = winBinaryDir.c_str(); + resourceDir = winResourceDir.c_str(); + } + #else // CARLA_OS_WIN + #if defined(CARLA_OS_MAC) if (system::exists("~/Applications/Carla.app")) { binaryDir = "~/Applications/Carla.app/Contents/MacOS"; @@ -143,17 +153,10 @@ struct CarlaModule : Module { binaryDir = "/Applications/Carla.app/Contents/MacOS"; resourceDir = "/Applications/Carla.app/Contents/MacOS/resources"; } -#elif defined(CARLA_OS_WIN) - const std::string winBinaryDir = system::join(asset::systemDir, "Carla"); - - if (system::exists(winBinaryDir)) - { - winResourceDir = system::join(winBinaryDir, "resources"); - binaryDir = winBinaryDir.c_str(); - resourceDir = winResourceDir.c_str(); - } -#else - if (system::exists("/usr/local/lib/carla")) + #else // CARLA_OS_MAC + if (false) {} + #endif // CARLA_OS_MAC + else if (system::exists("/usr/local/lib/carla")) { binaryDir = "/usr/local/lib/carla"; resourceDir = "/usr/local/share/carla/resources"; @@ -163,7 +166,7 @@ struct CarlaModule : Module { binaryDir = "/usr/lib/carla"; resourceDir = "/usr/share/carla/resources"; } -#endif + #endif // CARLA_OS_WIN if (binaryDir == nullptr) { diff --git a/plugins/Cardinal/src/DearImGui.cpp b/plugins/Cardinal/src/DearImGui.cpp index df0de0ce..79228eae 100644 --- a/plugins/Cardinal/src/DearImGui.cpp +++ b/plugins/Cardinal/src/DearImGui.cpp @@ -28,7 +28,7 @@ #include "DearImGui/imgui_draw.cpp" #include "DearImGui/imgui_tables.cpp" #include "DearImGui/imgui_widgets.cpp" -#if defined(DGL_USE_GLES2) || defined(DGL_USE_GLES3) || defined(DGL_USE_OPENGL3) +#if defined(DGL_USE_OPENGL3) # include "DearImGui/imgui_impl_opengl3.cpp" #else # include "DearImGui/imgui_impl_opengl2.cpp" diff --git a/plugins/Cardinal/src/DearImGuiColorTextEditor/TextEditor.cpp b/plugins/Cardinal/src/DearImGuiColorTextEditor/TextEditor.cpp index 4f17d251..6bc4a0fb 100644 --- a/plugins/Cardinal/src/DearImGuiColorTextEditor/TextEditor.cpp +++ b/plugins/Cardinal/src/DearImGuiColorTextEditor/TextEditor.cpp @@ -2038,11 +2038,11 @@ const TextEditor::Palette & TextEditor::GetDarkPalette() const TextEditor::Palette & TextEditor::GetLightPalette() { const static Palette p = { { - 0xff7f7f7f, // None + 0xff000000, // None 0xffff0c06, // Keyword 0xff008000, // Number 0xff2020a0, // String - 0xff304070, // Char literal + 0xff000000, // Char literal 0xff000000, // Punctuation 0xff406060, // Preprocessor 0xff404040, // Identifier diff --git a/plugins/Cardinal/src/HostAudio.cpp b/plugins/Cardinal/src/HostAudio.cpp index 482a8f45..09c7949f 100644 --- a/plugins/Cardinal/src/HostAudio.cpp +++ b/plugins/Cardinal/src/HostAudio.cpp @@ -127,20 +127,13 @@ struct HostAudio2 : HostAudio<2> { #ifndef HEADLESS // for stereo meter uint32_t internalDataFrame = 0; - float internalDataBuffer[2][128]; + float internalDataBufferL[128] = {}; + float internalDataBufferR[128] = {}; volatile bool resetMeters = true; float gainMeterL = 0.0f; float gainMeterR = 0.0f; #endif - HostAudio2() - : HostAudio<2>() - { -#ifndef HEADLESS - std::memset(internalDataBuffer, 0, sizeof(internalDataBuffer)); -#endif - } - #ifndef HEADLESS void onReset() override { @@ -189,6 +182,9 @@ struct HostAudio2 : HostAudio<2> { if (in1connected) { + if (!std::isfinite(dataOuts[0][k])) + __builtin_unreachable(); + valueL = inputs[0].getVoltageSum() * 0.1f; if (dcFilterEnabled) @@ -207,6 +203,9 @@ struct HostAudio2 : HostAudio<2> { if (in2connected) { + if (!std::isfinite(dataOuts[1][k])) + __builtin_unreachable(); + valueR = inputs[1].getVoltageSum() * 0.1f; if (dcFilterEnabled) @@ -229,25 +228,51 @@ struct HostAudio2 : HostAudio<2> { valueR = 0.0f; } - const uint32_t j = internalDataFrame++; - internalDataBuffer[0][j] = valueL; - internalDataBuffer[1][j] = valueR; + if (pcontext->variant == kCardinalVariantMini) + { + const uint32_t j = internalDataFrame++; + internalDataBufferL[j] = valueL; + internalDataBufferR[j] = valueR; - if (internalDataFrame == 128) + if (internalDataFrame == 4) + { + internalDataFrame = 0; + + if (resetMeters) + gainMeterL = gainMeterR = 0.0f; + + gainMeterL = std::max(gainMeterL, d_findMaxNormalizedFloat<4>(internalDataBufferL)); + + if (in2connected) + gainMeterR = std::max(gainMeterR, d_findMaxNormalizedFloat<4>(internalDataBufferR)); + else + gainMeterR = gainMeterL; + + resetMeters = false; + } + } + else { - internalDataFrame = 0; + const uint32_t j = internalDataFrame++; + internalDataBufferL[j] = valueL; + internalDataBufferR[j] = valueR; - if (resetMeters) - gainMeterL = gainMeterR = 0.0f; + if (internalDataFrame == 128) + { + internalDataFrame = 0; - gainMeterL = std::max(gainMeterL, d_findMaxNormalizedFloat(internalDataBuffer[0], 128)); + if (resetMeters) + gainMeterL = gainMeterR = 0.0f; - if (in2connected) - gainMeterR = std::max(gainMeterR, d_findMaxNormalizedFloat(internalDataBuffer[1], 128)); - else - gainMeterR = gainMeterL; + gainMeterL = std::max(gainMeterL, d_findMaxNormalizedFloat128(internalDataBufferL)); - resetMeters = false; + if (in2connected) + gainMeterR = std::max(gainMeterR, d_findMaxNormalizedFloat128(internalDataBufferR)); + else + gainMeterR = gainMeterL; + + resetMeters = false; + } } #endif } @@ -294,19 +319,23 @@ struct HostAudio8 : HostAudio<8> { template struct HostAudioWidget : ModuleWidgetWith8HP { HostAudio* const module; + CardinalPluginContext* const pcontext; HostAudioWidget(HostAudio* const m) - : module(m) + : module(m), + pcontext(static_cast(APP)) { setModule(m); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostAudio.svg"))); createAndAddScrews(); + const uint8_t ioCount = pcontext->variant == kCardinalVariantMain ? 8 : 2; + for (uint i=0; i { void draw(const DrawArgs& args) override { + const uint8_t ioCount = pcontext->variant == kCardinalVariantMain ? 8 : 2; + drawBackground(args.vg); - drawOutputJacksArea(args.vg, 8); + drawOutputJacksArea(args.vg, ioCount); setupTextLines(args.vg); - for (int i=0; i<8; ++i) + for (int i=0; i('0'+i+1),'\0'}; drawTextLine(args.vg, i, text); diff --git a/plugins/Cardinal/src/HostCV.cpp b/plugins/Cardinal/src/HostCV.cpp index 1be4141c..fee8aec9 100644 --- a/plugins/Cardinal/src/HostCV.cpp +++ b/plugins/Cardinal/src/HostCV.cpp @@ -18,8 +18,6 @@ #include "plugincontext.hpp" #include "ModuleWidgets.hpp" -#define CARDINAL_AUDIO_IO_OFFSET 8 - // ----------------------------------------------------------------------------------------------------------- USE_NAMESPACE_DISTRHO; @@ -54,17 +52,28 @@ struct HostCV : TerminalModule { throw rack::Exception("Plugin context is null"); config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); - configParam(BIPOLAR_INPUTS_1_5, 0.f, 1.f, 0.f, "Bipolar Inputs 1-5")->randomizeEnabled = false; + + if (pcontext->variant == kCardinalVariantMini) + { + configParam(BIPOLAR_INPUTS_1_5, 0.f, 1.f, 0.f, "Bipolar Inputs")->randomizeEnabled = false; + configParam(BIPOLAR_OUTPUTS_1_5, 0.f, 1.f, 0.f, "Bipolar Outputs")->randomizeEnabled = false; + } + else + { + configParam(BIPOLAR_INPUTS_1_5, 0.f, 1.f, 0.f, "Bipolar Inputs 1-5")->randomizeEnabled = false; + configParam(BIPOLAR_OUTPUTS_1_5, 0.f, 1.f, 0.f, "Bipolar Outputs 1-5")->randomizeEnabled = false; + } + configParam(BIPOLAR_INPUTS_6_10, 0.f, 1.f, 0.f, "Bipolar Inputs 6-10")->randomizeEnabled = false; - configParam(BIPOLAR_OUTPUTS_1_5, 0.f, 1.f, 0.f, "Bipolar Outputs 1-5")->randomizeEnabled = false; configParam(BIPOLAR_OUTPUTS_6_10, 0.f, 1.f, 0.f, "Bipolar Outputs 6-10")->randomizeEnabled = false; } void processTerminalInput(const ProcessArgs&) override { - if (pcontext->variant != kCardinalVariantMain) + if (pcontext->variant != kCardinalVariantMain && pcontext->variant != kCardinalVariantMini) return; + const uint8_t ioOffset = pcontext->variant == kCardinalVariantMini ? 2 : 8; const uint32_t bufferSize = pcontext->bufferSize; const uint32_t processCounter = pcontext->processCounter; @@ -87,27 +96,38 @@ struct HostCV : TerminalModule { } else if (const float* const* const dataIns = pcontext->dataIns) { - if (dataIns[CARDINAL_AUDIO_IO_OFFSET] == nullptr) + if (dataIns[ioOffset] == nullptr) return; float outputOffset; - outputOffset = params[BIPOLAR_OUTPUTS_1_5].getValue() > 0.1f ? 5.0f : 0.0f; + outputOffset = params[BIPOLAR_OUTPUTS_1_5].getValue() > 0.1f ? 5.f : 0.f; for (int i=0; i<5; ++i) - outputs[i].setVoltage(dataIns[i+CARDINAL_AUDIO_IO_OFFSET][k] - outputOffset); - - outputOffset = params[BIPOLAR_OUTPUTS_6_10].getValue() > 0.1f ? 5.0f : 0.0f; - - for (int i=5; i<10; ++i) - outputs[i].setVoltage(dataIns[i+CARDINAL_AUDIO_IO_OFFSET][k] - outputOffset); + outputs[i].setVoltage(dataIns[i+ioOffset][k] - outputOffset); + + if (pcontext->variant == kCardinalVariantMain) + { + outputOffset = params[BIPOLAR_OUTPUTS_6_10].getValue() > 0.1f ? 5.f : 0.f; + + for (int i=5; i<10; ++i) + outputs[i].setVoltage(dataIns[i+ioOffset][k] - outputOffset); + } + else + { + for (int i=5; i<10; ++i) + outputs[i].setVoltage(0.f); + } } } void processTerminalOutput(const ProcessArgs&) override { - if (pcontext->variant != kCardinalVariantMain || pcontext->bypassed) + if (pcontext->variant != kCardinalVariantMain && pcontext->variant != kCardinalVariantMini) + return; + if (pcontext->bypassed) return; + const uint8_t ioOffset = pcontext->variant == kCardinalVariantMini ? 2 : 8; const uint32_t bufferSize = pcontext->bufferSize; // only incremented on output @@ -119,54 +139,95 @@ struct HostCV : TerminalModule { float** const dataOuts = pcontext->dataOuts; - if (dataOuts[CARDINAL_AUDIO_IO_OFFSET] == nullptr) + if (dataOuts[ioOffset] == nullptr) return; float inputOffset; inputOffset = params[BIPOLAR_INPUTS_1_5].getValue() > 0.1f ? 5.0f : 0.0f; for (int i=0; i<5; ++i) - dataOuts[i+CARDINAL_AUDIO_IO_OFFSET][k] += inputs[i].getVoltage() + inputOffset; + { + if (!std::isfinite(dataOuts[i+ioOffset][k])) + __builtin_unreachable(); + dataOuts[i+ioOffset][k] += inputs[i].getVoltage() + inputOffset; + } - inputOffset = params[BIPOLAR_INPUTS_6_10].getValue() > 0.1f ? 5.0f : 0.0f; + if (pcontext->variant == kCardinalVariantMain) + { + inputOffset = params[BIPOLAR_INPUTS_6_10].getValue() > 0.1f ? 5.0f : 0.0f; - for (int i=5; i<10; ++i) - dataOuts[i+CARDINAL_AUDIO_IO_OFFSET][k] += inputs[i].getVoltage() + inputOffset; + for (int i=5; i<10; ++i) + { + if (!std::isfinite(dataOuts[i+ioOffset][k])) + __builtin_unreachable(); + dataOuts[i+ioOffset][k] += inputs[i].getVoltage() + inputOffset; + } + } } }; #ifndef HEADLESS struct HostCVWidget : ModuleWidgetWith8HP { + CardinalPluginContext* const pcontext; + HostCVWidget(HostCV* const module) + : pcontext(static_cast(APP)) { setModule(module); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostCV.svg"))); createAndAddScrews(); + uint8_t maxVisible; + switch (pcontext->variant) + { + case kCardinalVariantMain: + maxVisible = HostCV::NUM_INPUTS; + break; + case kCardinalVariantMini: + maxVisible = 5; + break; + default: + maxVisible = 0; + break; + } + for (uint i=0; ivariant == kCardinalVariantMain || pcontext->variant == kCardinalVariantMini) + { + drawOutputJacksArea(args.vg, pcontext->variant == kCardinalVariantMini ? 5 : HostCV::NUM_INPUTS); + setupTextLines(args.vg); + + switch (pcontext->variant) + { + case kCardinalVariantMain: + drawTextLine(args.vg, 5, "CV 6"); + drawTextLine(args.vg, 6, "CV 7"); + drawTextLine(args.vg, 7, "CV 8"); + drawTextLine(args.vg, 8, "CV 9"); + drawTextLine(args.vg, 9, "CV 10"); + // fall through + case kCardinalVariantMini: + drawTextLine(args.vg, 0, "CV 1"); + drawTextLine(args.vg, 1, "CV 2"); + drawTextLine(args.vg, 2, "CV 3"); + drawTextLine(args.vg, 3, "CV 4"); + drawTextLine(args.vg, 4, "CV 5"); + break; + default: + break; + } + } ModuleWidgetWith8HP::draw(args); } @@ -175,25 +236,40 @@ struct HostCVWidget : ModuleWidgetWith8HP { { menu->addChild(new ui::MenuSeparator); - menu->addChild(createCheckMenuItem("Bipolar Inputs 1-5", "", - [=]() {return module->params[HostCV::BIPOLAR_INPUTS_1_5].getValue() > 0.1f;}, - [=]() {module->params[HostCV::BIPOLAR_INPUTS_1_5].setValue(1.0f - module->params[HostCV::BIPOLAR_INPUTS_1_5].getValue());} - )); - - menu->addChild(createCheckMenuItem("Bipolar Inputs 6-10", "", - [=]() {return module->params[HostCV::BIPOLAR_INPUTS_6_10].getValue() > 0.1f;}, - [=]() {module->params[HostCV::BIPOLAR_INPUTS_6_10].setValue(1.0f - module->params[HostCV::BIPOLAR_INPUTS_6_10].getValue());} - )); - - menu->addChild(createCheckMenuItem("Bipolar Outputs 1-5", "", - [=]() {return module->params[HostCV::BIPOLAR_OUTPUTS_1_5].getValue() > 0.1f;}, - [=]() {module->params[HostCV::BIPOLAR_OUTPUTS_1_5].setValue(1.0f - module->params[HostCV::BIPOLAR_OUTPUTS_1_5].getValue());} - )); - - menu->addChild(createCheckMenuItem("Bipolar Outputs 6-10", "", - [=]() {return module->params[HostCV::BIPOLAR_OUTPUTS_6_10].getValue() > 0.1f;}, - [=]() {module->params[HostCV::BIPOLAR_OUTPUTS_6_10].setValue(1.0f - module->params[HostCV::BIPOLAR_OUTPUTS_6_10].getValue());} - )); + if (pcontext->variant == kCardinalVariantMini) + { + menu->addChild(createCheckMenuItem("Bipolar Inputs", "", + [=]() {return module->params[HostCV::BIPOLAR_INPUTS_1_5].getValue() > 0.1f;}, + [=]() {module->params[HostCV::BIPOLAR_INPUTS_1_5].setValue(1.0f - module->params[HostCV::BIPOLAR_INPUTS_1_5].getValue());} + )); + + menu->addChild(createCheckMenuItem("Bipolar Outputs", "", + [=]() {return module->params[HostCV::BIPOLAR_OUTPUTS_1_5].getValue() > 0.1f;}, + [=]() {module->params[HostCV::BIPOLAR_OUTPUTS_1_5].setValue(1.0f - module->params[HostCV::BIPOLAR_OUTPUTS_1_5].getValue());} + )); + } + else + { + menu->addChild(createCheckMenuItem("Bipolar Inputs 1-5", "", + [=]() {return module->params[HostCV::BIPOLAR_INPUTS_1_5].getValue() > 0.1f;}, + [=]() {module->params[HostCV::BIPOLAR_INPUTS_1_5].setValue(1.0f - module->params[HostCV::BIPOLAR_INPUTS_1_5].getValue());} + )); + + menu->addChild(createCheckMenuItem("Bipolar Inputs 6-10", "", + [=]() {return module->params[HostCV::BIPOLAR_INPUTS_6_10].getValue() > 0.1f;}, + [=]() {module->params[HostCV::BIPOLAR_INPUTS_6_10].setValue(1.0f - module->params[HostCV::BIPOLAR_INPUTS_6_10].getValue());} + )); + + menu->addChild(createCheckMenuItem("Bipolar Outputs 1-5", "", + [=]() {return module->params[HostCV::BIPOLAR_OUTPUTS_1_5].getValue() > 0.1f;}, + [=]() {module->params[HostCV::BIPOLAR_OUTPUTS_1_5].setValue(1.0f - module->params[HostCV::BIPOLAR_OUTPUTS_1_5].getValue());} + )); + + menu->addChild(createCheckMenuItem("Bipolar Outputs 6-10", "", + [=]() {return module->params[HostCV::BIPOLAR_OUTPUTS_6_10].getValue() > 0.1f;}, + [=]() {module->params[HostCV::BIPOLAR_OUTPUTS_6_10].setValue(1.0f - module->params[HostCV::BIPOLAR_OUTPUTS_6_10].getValue());} + )); + } } }; #else diff --git a/plugins/Cardinal/src/HostMIDI.cpp b/plugins/Cardinal/src/HostMIDI.cpp index 7469a8ea..6d13ea3e 100644 --- a/plugins/Cardinal/src/HostMIDI.cpp +++ b/plugins/Cardinal/src/HostMIDI.cpp @@ -148,22 +148,27 @@ struct HostMIDI : TerminalModule { channels = 1; polyMode = ROTATE_MODE; pwRange = 0; - panic(); + panic(true); } /** Resets performance state */ - void panic() + void panic(const bool resetPitch) { for (int c = 0; c < 16; c++) { notes[c] = 60; gates[c] = false; velocities[c] = 0; aftertouches[c] = 0; - pws[c] = 8192; - mods[c] = 0; pwFilters[c].reset(); modFilters[c].reset(); } + if (resetPitch) { + for (int c = 0; c < 16; c++) { + notes[c] = 60; + pws[c] = 8192; + mods[c] = 0; + } + } pedal = false; rotateIndex = -1; heldNotes.clear(); @@ -374,7 +379,7 @@ struct HostMIDI : TerminalModule { // all notes off (panic) case 0x7b: { if (msg.getValue() == 0) { - panic(); + panic(false); } } break; default: break; @@ -529,7 +534,7 @@ struct HostMIDI : TerminalModule { if (channels == this->channels) return; this->channels = channels; - panic(); + panic(true); } void setPolyMode(const PolyMode polyMode) @@ -537,7 +542,7 @@ struct HostMIDI : TerminalModule { if (polyMode == this->polyMode) return; this->polyMode = polyMode; - panic(); + panic(true); } } midiInput; @@ -886,7 +891,7 @@ struct HostMIDIWidget : ModuleWidgetWith9HP { menu->addChild(createMenuLabel("MIDI Input & Output")); menu->addChild(createMenuItem("Panic", "", - [=]() { module->midiInput.panic(); module->midiOutput.panic(); } + [=]() { module->midiInput.panic(true); module->midiOutput.panic(); } )); } }; diff --git a/plugins/Cardinal/src/HostParameters-Map.cpp b/plugins/Cardinal/src/HostParameters-Map.cpp index edfa93c7..eed89b50 100644 --- a/plugins/Cardinal/src/HostParameters-Map.cpp +++ b/plugins/Cardinal/src/HostParameters-Map.cpp @@ -63,8 +63,8 @@ struct HostParametersMap : TerminalModule { uint8_t learningId = UINT8_MAX; CardinalPluginContext* const pcontext; - bool parametersChanged[kModuleParameters] = {}; - float parameterValues[kModuleParameters]; + bool parametersChanged[kModuleParameterCount] = {}; + float parameterValues[kModuleParameterCount]; bool bypassed = false; bool firstRun = true; uint32_t lastProcessCounter = 0; @@ -135,7 +135,7 @@ struct HostParametersMap : TerminalModule { if (isBypassed()) return; - for (uint32_t i = 0; i < kModuleParameters; ++i) + for (uint32_t i = 0; i < kModuleParameterCount; ++i) { if (d_isEqual(pcontext->parameters[i], parameterValues[i])) continue; @@ -161,7 +161,7 @@ struct HostParametersMap : TerminalModule { // Validate hostParamId const uint8_t hostParamId = mappings[id].hostParamId; - if (hostParamId >= kModuleParameters) + if (hostParamId >= kModuleParameterCount) continue; // Set filter from param value if filter is uninitialized @@ -350,7 +350,7 @@ struct ParameterIndexQuantity : Quantity { return 0; } float getMaxValue() override { - return kModuleParameters - 1; + return kModuleParameterCount - 1; } float getDefaultValue() override { return 0; @@ -360,7 +360,7 @@ struct ParameterIndexQuantity : Quantity { } void setValue(float value) override { v = math::clamp(value, getMinValue(), getMaxValue()); - mapping.hostParamId = math::clamp(static_cast(v + 0.5f), 0, kModuleParameters - 1); + mapping.hostParamId = math::clamp(static_cast(v + 0.5f), 0, kModuleParameterCount - 1); } float getDisplayValue() override { return mapping.hostParamId + 1; @@ -437,7 +437,7 @@ struct HostParametersMapChoice : CardinalLedDisplayChoice { if (ParamWidget* const touchedParam = APP->scene->rack->touchedParam) { APP->scene->rack->touchedParam = nullptr; - DISTRHO_SAFE_ASSERT_RETURN(mapping.hostParamId < kModuleParameters,); + DISTRHO_SAFE_ASSERT_RETURN(mapping.hostParamId < kModuleParameterCount,); const int64_t moduleId = touchedParam->module->id; const int paramId = touchedParam->paramId; @@ -453,7 +453,7 @@ struct HostParametersMapChoice : CardinalLedDisplayChoice { text.clear(); // mapped - if (module->mappings[id].hostParamId < kModuleParameters) + if (module->mappings[id].hostParamId < kModuleParameterCount) text += string::f("P%02d: ", module->mappings[id].hostParamId + 1); if (module->mappings[id].paramHandle.moduleId >= 0) text += getParamName(); diff --git a/plugins/Cardinal/src/HostParameters.cpp b/plugins/Cardinal/src/HostParameters.cpp index a2e57ae6..97c89122 100644 --- a/plugins/Cardinal/src/HostParameters.cpp +++ b/plugins/Cardinal/src/HostParameters.cpp @@ -28,15 +28,15 @@ struct HostParameters : TerminalModule { NUM_INPUTS }; enum OutputIds { - NUM_OUTPUTS = 24 + NUM_OUTPUTS = kModuleParameterCount }; enum LightIds { NUM_LIGHTS }; CardinalPluginContext* const pcontext; - rack::dsp::SlewLimiter parameters[kModuleParameters]; - bool parametersConnected[kModuleParameters] = {}; + rack::dsp::SlewLimiter parameters[kModuleParameterCount]; + bool parametersConnected[kModuleParameterCount] = {}; bool bypassed = false; bool smooth = true; uint32_t lastProcessCounter = 0; @@ -59,7 +59,7 @@ struct HostParameters : TerminalModule { bypassed = isBypassed(); lastProcessCounter = processCounter; - for (uint32_t i=0; iparameters[i]) @@ -89,7 +89,7 @@ struct HostParameters : TerminalModule { { const double fall = 1.0 / (double(pcontext->bufferSize) / e.sampleRate); - for (uint32_t i=0; i + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -34,9 +34,12 @@ # include "extra/Mutex.hpp" # include "extra/Runner.hpp" # include "extra/ScopedPointer.hpp" +# include "water/files/FileInputStream.h" +# include "water/files/FileOutputStream.h" # include "../../src/extra/SharedResourcePointer.hpp" #else # include "extra/Mutex.hpp" +# include "extra/String.hpp" #endif #include "CarlaNativePlugin.h" @@ -62,6 +65,7 @@ enum SpecialPath { kSpecialPathCommonProgramFiles, kSpecialPathProgramFiles, kSpecialPathAppData, + kSpecialPathMyDocuments, }; std::string getSpecialPath(const SpecialPath type); #endif @@ -106,12 +110,198 @@ static void host_ui_custom_data_changed(NativeHostHandle handle, const char* key static void host_ui_closed(NativeHostHandle handle); static const char* host_ui_open_file(NativeHostHandle handle, bool isDir, const char* title, const char* filter); static const char* host_ui_save_file(NativeHostHandle handle, bool isDir, const char* title, const char* filter); -static intptr_t host_dispatcher(NativeHostHandle handle, NativeHostDispatcherOpcode opcode, int32_t index, intptr_t value, void* ptr, float opt); +static intptr_t host_dispatcher(NativeHostHandle h, NativeHostDispatcherOpcode op, int32_t, intptr_t, void*, float); static void projectLoadedFromDSP(void* ui); // -------------------------------------------------------------------------------------------------------------------- -static Mutex sPluginInfoLoadMutex; +static const char* getPathForLADSPA() +{ + static std::string path; + + if (path.empty()) + { + #if defined(CARLA_OS_HAIKU) + path = homeDir() + "/.ladspa:/system/add-ons/media/ladspaplugins:/system/lib/ladspa"; + #elif defined(CARLA_OS_MAC) + path = homeDir() + "/Library/Audio/Plug-Ins/LADSPA:/Library/Audio/Plug-Ins/LADSPA"; + #elif defined(CARLA_OS_WASM) + path = "/ladspa"; + #elif defined(CARLA_OS_WIN) + path = getSpecialPath(kSpecialPathAppData) + "\\LADSPA;"; + path += getSpecialPath(kSpecialPathProgramFiles) + "\\LADSPA"; + #else + path = homeDir() + "/.ladspa:/usr/lib/ladspa:/usr/local/lib/ladspa"; + #endif + } + + return path.c_str(); +} + +static const char* getPathForDSSI() +{ + static std::string path; + + if (path.empty()) + { + #if defined(CARLA_OS_HAIKU) + path = homeDir() + "/.dssi:/system/add-ons/media/dssiplugins:/system/lib/dssi"; + #elif defined(CARLA_OS_MAC) + path = homeDir() + "/Library/Audio/Plug-Ins/DSSI:/Library/Audio/Plug-Ins/DSSI"; + #elif defined(CARLA_OS_WASM) + path = "/dssi"; + #elif defined(CARLA_OS_WIN) + path = getSpecialPath(kSpecialPathAppData) + "\\DSSI;"; + path += getSpecialPath(kSpecialPathProgramFiles) + "\\DSSI"; + #else + path = homeDir() + "/.dssi:/usr/lib/dssi:/usr/local/lib/dssi"; + #endif + } + + return path.c_str(); +} + +static const char* getPathForLV2() +{ + static std::string path; + + if (path.empty()) + { + #if defined(CARLA_OS_HAIKU) + path = homeDir() + "/.lv2:/system/add-ons/media/lv2plugins"; + #elif defined(CARLA_OS_MAC) + path = homeDir() + "/Library/Audio/Plug-Ins/LV2:/Library/Audio/Plug-Ins/LV2"; + #elif defined(CARLA_OS_WASM) + path = "/lv2"; + #elif defined(CARLA_OS_WIN) + path = getSpecialPath(kSpecialPathAppData) + "\\LV2;"; + path += getSpecialPath(kSpecialPathCommonProgramFiles) + "\\LV2"; + #else + path = homeDir() + "/.lv2:/usr/lib/lv2:/usr/local/lib/lv2"; + #endif + } + + return path.c_str(); +} + +static const char* getPathForVST2() +{ + static std::string path; + + if (path.empty()) + { + #if defined(CARLA_OS_HAIKU) + path = homeDir() + "/.vst:/system/add-ons/media/vstplugins"; + #elif defined(CARLA_OS_MAC) + path = homeDir() + "/Library/Audio/Plug-Ins/VST:/Library/Audio/Plug-Ins/VST"; + #elif defined(CARLA_OS_WASM) + path = "/vst"; + #elif defined(CARLA_OS_WIN) + path = getSpecialPath(kSpecialPathProgramFiles) + "\\VstPlugins;"; + path += getSpecialPath(kSpecialPathProgramFiles) + "\\Steinberg\\VstPlugins;"; + path += getSpecialPath(kSpecialPathCommonProgramFiles) + "\\VST2"; + #else + path = homeDir() + "/.vst:/usr/lib/vst:/usr/local/lib/vst"; + + std::string winePrefix; + if (const char* const envWINEPREFIX = std::getenv("WINEPREFIX")) + winePrefix = envWINEPREFIX; + + if (winePrefix.empty()) + winePrefix = homeDir() + "/.wine"; + + if (system::exists(winePrefix)) + { + path += ":" + winePrefix + "/drive_c/Program Files/Common Files/VST2"; + path += ":" + winePrefix + "/drive_c/Program Files/VstPlugins"; + path += ":" + winePrefix + "/drive_c/Program Files/Steinberg/VstPlugins"; + #ifdef CARLA_OS_64BIT + path += ":" + winePrefix + "/drive_c/Program Files (x86)/Common Files/VST2"; + path += ":" + winePrefix + "/drive_c/Program Files (x86)/VstPlugins"; + path += ":" + winePrefix + "/drive_c/Program Files (x86)/Steinberg/VstPlugins"; + #endif + } + #endif + } + + return path.c_str(); +} + +static const char* getPathForVST3() +{ + static std::string path; + + if (path.empty()) + { + #if defined(CARLA_OS_HAIKU) + path = homeDir() + "/.vst3:/system/add-ons/media/dssiplugins"; + #elif defined(CARLA_OS_MAC) + path = homeDir() + "/Library/Audio/Plug-Ins/VST3:/Library/Audio/Plug-Ins/VST3"; + #elif defined(CARLA_OS_WASM) + path = "/vst3"; + #elif defined(CARLA_OS_WIN) + path = getSpecialPath(kSpecialPathAppData) + "\\VST3;"; + path += getSpecialPath(kSpecialPathCommonProgramFiles) + "\\VST3"; + #else + path = homeDir() + "/.vst3:/usr/lib/vst3:/usr/local/lib/vst3"; + + std::string winePrefix; + if (const char* const envWINEPREFIX = std::getenv("WINEPREFIX")) + winePrefix = envWINEPREFIX; + + if (winePrefix.empty()) + winePrefix = homeDir() + "/.wine"; + + if (system::exists(winePrefix)) + { + path += ":" + winePrefix + "/drive_c/Program Files/Common Files/VST3"; + #ifdef CARLA_OS_64BIT + path += ":" + winePrefix + "/drive_c/Program Files (x86)/Common Files/VST3"; + #endif + } + #endif + } + + return path.c_str(); +} + +static const char* getPathForCLAP() +{ + static std::string path; + + if (path.empty()) + { + #if defined(CARLA_OS_HAIKU) + path = homeDir() + "/.clap:/system/add-ons/media/clapplugins"; + #elif defined(CARLA_OS_MAC) + path = homeDir() + "/Library/Audio/Plug-Ins/CLAP:/Library/Audio/Plug-Ins/CLAP"; + #elif defined(CARLA_OS_WASM) + path = "/clap"; + #elif defined(CARLA_OS_WIN) + path = getSpecialPath(kSpecialPathAppData) + "\\CLAP;"; + path += getSpecialPath(kSpecialPathCommonProgramFiles) + "\\CLAP"; + #else + path = homeDir() + "/.clap:/usr/lib/clap:/usr/local/lib/clap"; + + std::string winePrefix; + if (const char* const envWINEPREFIX = std::getenv("WINEPREFIX")) + winePrefix = envWINEPREFIX; + + if (winePrefix.empty()) + winePrefix = homeDir() + "/.wine"; + + if (system::exists(winePrefix)) + { + path += ":" + winePrefix + "/drive_c/Program Files/Common Files/CLAP"; + #ifdef CARLA_OS_64BIT + path += ":" + winePrefix + "/drive_c/Program Files (x86)/Common Files/CLAP"; + #endif + } + #endif + } + + return path.c_str(); +} static const char* getPathForJSFX() { @@ -139,6 +329,45 @@ static const char* getPathForJSFX() return path.c_str(); } +static const char* getPluginPath(const PluginType ptype) +{ + switch (ptype) + { + case PLUGIN_LADSPA: + if (const char* const path = std::getenv("LADSPA_PATH")) + return path; + return getPathForLADSPA(); + case PLUGIN_DSSI: + if (const char* const path = std::getenv("DSSI_PATH")) + return path; + return getPathForDSSI(); + case PLUGIN_LV2: + if (const char* const path = std::getenv("LV2_PATH")) + return path; + return getPathForLV2(); + case PLUGIN_VST2: + if (const char* const path = std::getenv("VST_PATH")) + return path; + return getPathForVST2(); + case PLUGIN_VST3: + if (const char* const path = std::getenv("VST3_PATH")) + return path; + return getPathForVST3(); + case PLUGIN_CLAP: + if (const char* const path = std::getenv("CLAP_PATH")) + return path; + return getPathForCLAP(); + case PLUGIN_JSFX: + return getPathForJSFX(); + default: + return nullptr; + } +} + +// -------------------------------------------------------------------------------------------------------------------- + +static Mutex sPluginInfoLoadMutex; + /* #ifndef HEADLESS struct JuceInitializer { @@ -182,6 +411,8 @@ struct IldaeilModule : Module { NativeTimeInfo fCarlaTimeInfo; + String fBinaryPath; + void* fUI = nullptr; bool canUseBridges = true; @@ -244,41 +475,48 @@ struct IldaeilModule : Module { fCarlaHostHandle = carla_create_native_plugin_host_handle(fCarlaPluginDescriptor, fCarlaPluginHandle); DISTRHO_SAFE_ASSERT_RETURN(fCarlaHostHandle != nullptr,); -#if defined(CARLA_OS_MAC) + #if defined(CARLA_OS_WIN) + const std::string winBinaryDir = system::join(asset::systemDir, "Carla"); + + if (system::exists(winBinaryDir)) + { + const std::string winResourceDir = system::join(winBinaryDir, "resources"); + fBinaryPath = winBinaryDir.c_str(); + carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PATH_BINARIES, 0, winBinaryDir.c_str()); + carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PATH_RESOURCES, 0, winResourceDir.c_str()); + } + #else // CARLA_OS_WIN + #if defined(CARLA_OS_MAC) if (system::exists("~/Applications/Carla.app")) { + fBinaryPath = "~/Applications/Carla.app/Contents/MacOS"; carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PATH_BINARIES, 0, "~/Applications/Carla.app/Contents/MacOS"); carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PATH_RESOURCES, 0, "~/Applications/Carla.app/Contents/MacOS/resources"); } else if (system::exists("/Applications/Carla.app")) { + fBinaryPath = "/Applications/Carla.app/Contents/MacOS"; carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PATH_BINARIES, 0, "/Applications/Carla.app/Contents/MacOS"); carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PATH_RESOURCES, 0, "/Applications/Carla.app/Contents/MacOS/resources"); } -#elif defined(CARLA_OS_WASM) - if (true) - {} -#elif defined(CARLA_OS_WIN) - const std::string winBinaryDir = system::join(asset::systemDir, "Carla"); - - if (system::exists(winBinaryDir)) - { - const std::string winResourceDir = system::join(winBinaryDir, "resources"); - carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PATH_BINARIES, 0, winBinaryDir.c_str()); - carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PATH_RESOURCES, 0, winResourceDir.c_str()); - } -#else - if (system::exists("/usr/local/lib/carla")) + #elif defined(CARLA_OS_WASM) + if (true) {} + #else + if (false) {} + #endif + else if (system::exists("/usr/local/lib/carla")) { + fBinaryPath = "/usr/local/lib/carla"; carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PATH_BINARIES, 0, "/usr/local/lib/carla"); carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PATH_RESOURCES, 0, "/usr/local/share/carla/resources"); } else if (system::exists("/usr/lib/carla")) { + fBinaryPath = "/usr/lib/carla"; carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PATH_BINARIES, 0, "/usr/lib/carla"); carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PATH_RESOURCES, 0, "/usr/share/carla/resources"); } -#endif + #endif // CARLA_OS_WIN else { canUseBridges = false; @@ -287,18 +525,25 @@ struct IldaeilModule : Module { if (! warningShown) { warningShown = true; - async_dialog_message("Carla is not installed on this system, bridged plugins will not work"); + async_dialog_message("Carla is not installed on this system, plugin discovery will not work"); } } - if (const char* const path = std::getenv("LV2_PATH")) - carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PLUGIN_PATH, PLUGIN_LV2, path); + if (fBinaryPath.isNotEmpty()) + carla_stdout("Using binary path for discovery tools: %s", fBinaryPath.buffer()); - carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PLUGIN_PATH, PLUGIN_JSFX, getPathForJSFX()); + carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PLUGIN_PATH, PLUGIN_LADSPA, getPluginPath(PLUGIN_LADSPA)); + carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PLUGIN_PATH, PLUGIN_DSSI, getPluginPath(PLUGIN_DSSI)); + carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PLUGIN_PATH, PLUGIN_LV2, getPluginPath(PLUGIN_LV2)); + carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PLUGIN_PATH, PLUGIN_VST2, getPluginPath(PLUGIN_VST2)); + carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PLUGIN_PATH, PLUGIN_VST3, getPluginPath(PLUGIN_VST3)); + carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PLUGIN_PATH, PLUGIN_CLAP, getPluginPath(PLUGIN_CLAP)); + carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PLUGIN_PATH, PLUGIN_JSFX, getPluginPath(PLUGIN_JSFX)); -#ifdef CARLA_OS_MAC + #ifdef CARLA_OS_MAC + // cannot set transient window hints for UI bridges on macOS, so disable them carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PREFER_UI_BRIDGES, 0, nullptr); -#endif + #endif fCarlaPluginDescriptor->dispatcher(fCarlaPluginHandle, NATIVE_PLUGIN_OPCODE_HOST_USES_EMBED, 0, 0, nullptr, 0.0f); @@ -328,7 +573,7 @@ struct IldaeilModule : Module { { switch (opcode) { - // cannnot be supported + // cannnot be supported? case NATIVE_HOST_OPCODE_HOST_IDLE: break; // other stuff @@ -365,11 +610,11 @@ struct IldaeilModule : Module { engine->saveProjectInternal(projectState); const size_t dataSize = projectState.getDataSize(); -#ifndef CARDINAL_SYSDEPS + #ifndef CARDINAL_SYSDEPS return jsonp_stringn_nocheck_own(static_cast(projectState.getDataAndRelease()), dataSize); -#else + #else return json_stringn(static_cast(projectState.getData()), dataSize); -#endif + #endif } void dataFromJson(json_t* const rootJ) override @@ -462,9 +707,10 @@ struct IldaeilModule : Module { NativeMidiEvent* midiEvents; uint midiEventCount; - if (CardinalExpanderFromCVToCarlaMIDI* const midiInExpander = leftExpander.module != nullptr && leftExpander.module->model == modelExpanderInputMIDI - ? static_cast(leftExpander.module) - : nullptr) + if (CardinalExpanderFromCVToCarlaMIDI* const midiInExpander + = leftExpander.module != nullptr && leftExpander.module->model == modelExpanderInputMIDI + ? static_cast(leftExpander.module) + : nullptr) { midiEvents = midiInExpander->midiEvents; midiEventCount = midiInExpander->midiEventCount; @@ -488,16 +734,16 @@ struct IldaeilModule : Module { if (resetMeterIn) meterInL = meterInR = 0.0f; - meterInL = std::max(meterInL, d_findMaxNormalizedFloat(audioDataIn1, BUFFER_SIZE)); - meterInR = std::max(meterInR, d_findMaxNormalizedFloat(audioDataIn2, BUFFER_SIZE)); + meterInL = std::max(meterInL, d_findMaxNormalizedFloat128(audioDataIn1)); + meterInR = std::max(meterInR, d_findMaxNormalizedFloat128(audioDataIn2)); fCarlaPluginDescriptor->process(fCarlaPluginHandle, ins, outs, BUFFER_SIZE, midiEvents, midiEventCount); if (resetMeterOut) meterOutL = meterOutR = 0.0f; - meterOutL = std::max(meterOutL, d_findMaxNormalizedFloat(audioDataOut1, BUFFER_SIZE)); - meterOutR = std::max(meterOutR, d_findMaxNormalizedFloat(audioDataOut2, BUFFER_SIZE)); + meterOutL = std::max(meterOutL, d_findMaxNormalizedFloat128(audioDataOut1)); + meterOutR = std::max(meterOutR, d_findMaxNormalizedFloat128(audioDataOut2)); resetMeterIn = resetMeterOut = false; } @@ -593,18 +839,11 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { static constexpr const uint kButtonHeight = 20; struct PluginInfoCache { - char* name; - char* label; - - PluginInfoCache() - : name(nullptr), - label(nullptr) {} - - ~PluginInfoCache() - { - std::free(name); - std::free(label); - } + BinaryType btype; + uint64_t uniqueId; + std::string filename; + std::string name; + std::string label; }; struct PluginGenericUI { @@ -634,17 +873,35 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { }* parameters; float* values; + uint presetCount; + struct Preset { + uint32_t index; + char* name; + ~Preset() + { + std::free(name); + } + }* presets; + int currentPreset; + const char** presetStrings; + PluginGenericUI() : title(nullptr), parameterCount(0), parameters(nullptr), - values(nullptr) {} + values(nullptr), + presetCount(0), + presets(nullptr), + currentPreset(-1), + presetStrings(nullptr) {} ~PluginGenericUI() { std::free(title); delete[] parameters; delete[] values; + delete[] presets; + delete[] presetStrings; } }; @@ -673,17 +930,21 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { struct RunnerData { bool needsReinit = true; - uint pluginCount = 0; - uint pluginIndex = 0; + CarlaPluginDiscoveryHandle handle = nullptr; void init() { needsReinit = true; - pluginCount = 0; - pluginIndex = 0; + + if (handle != nullptr) + { + carla_plugin_discovery_stop(handle); + handle = nullptr; + } } } fRunnerData; + BinaryType fBinaryType = BINARY_NATIVE; #ifdef CARLA_OS_WASM PluginType fPluginType = PLUGIN_JSFX; #else @@ -692,20 +953,22 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { PluginType fNextPluginType = fPluginType; uint fPluginCount = 0; int fPluginSelected = -1; - bool fPluginScanningFinished = false; bool fPluginHasCustomUI = false; bool fPluginHasFileOpen = false; bool fPluginHasOutputParameters = false; + bool fPluginIsBridge = false; bool fPluginRunning = false; bool fPluginWillRunInBridgeMode = false; - PluginInfoCache* fPlugins = nullptr; + Mutex fPluginsMutex; + PluginInfoCache fCurrentPluginInfo; + std::vector fPlugins; ScopedPointer fPluginGenericUI; bool fPluginSearchActive = false; bool fPluginSearchFirstShow = false; char fPluginSearchString[0xff] = {}; - String fPopupError; + String fPopupError, fPluginFilename, fDiscoveryTool; bool idleCallbackActive = false; IldaeilModule* const module; @@ -756,8 +1019,6 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { stopRunner(); fPluginGenericUI = nullptr; - - delete[] fPlugins; } bool checkIfPluginIsLoaded() @@ -786,6 +1047,8 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { fPluginHasCustomUI = hints & PLUGIN_HAS_CUSTOM_UI; fPluginHasFileOpen = false; } + + fPluginIsBridge = hints & PLUGIN_IS_BRIDGE; } void projectLoadedFromDSP() @@ -870,10 +1133,10 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { fPluginHasOutputParameters = false; - const uint32_t pcount = ui->parameterCount = carla_get_parameter_count(handle, 0); + const uint32_t parameterCount = ui->parameterCount = carla_get_parameter_count(handle, 0); // make count of valid parameters - for (uint32_t i=0; i < pcount; ++i) + for (uint32_t i=0; i < parameterCount; ++i) { const ParameterData* const pdata = carla_get_parameter_data(handle, 0, i); @@ -891,7 +1154,7 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { ui->values = new float[ui->parameterCount]; // now safely fill in details - for (uint32_t i=0, j=0; i < pcount; ++i) + for (uint32_t i=0, j=0; i < parameterCount; ++i) { const ParameterData* const pdata = carla_get_parameter_data(handle, 0, i); @@ -930,6 +1193,41 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { ++j; } + // handle presets too + const uint32_t presetCount = ui->presetCount = carla_get_program_count(handle, 0); + + for (uint32_t i=0; i < presetCount; ++i) + { + const char* const pname = carla_get_program_name(handle, 0, i); + + if (pname[0] == '\0') + { + --ui->presetCount; + continue; + } + } + + ui->presets = new PluginGenericUI::Preset[ui->presetCount]; + ui->presetStrings = new const char*[ui->presetCount]; + + for (uint32_t i=0, j=0; i < presetCount; ++i) + { + const char* const pname = carla_get_program_name(handle, 0, i); + + if (pname[0] == '\0') + continue; + + PluginGenericUI::Preset& preset(ui->presets[j]); + preset.index = i; + preset.name = strdup(pname); + + ui->presetStrings[j] = preset.name; + + ++j; + } + + ui->currentPreset = -1; + fPluginGenericUI = ui; } @@ -947,7 +1245,7 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { } } - void loadPlugin(const CarlaHostHandle handle, const char* const label) + bool loadPlugin(const CarlaHostHandle handle, const PluginInfoCache& info) { if (fPluginRunning) { @@ -957,20 +1255,60 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { carla_set_engine_option(handle, ENGINE_OPTION_PREFER_PLUGIN_BRIDGES, fPluginWillRunInBridgeMode, nullptr); + setDirty(true); + const MutexLocker cml(sPluginInfoLoadMutex); - if (carla_add_plugin(handle, BINARY_NATIVE, fPluginType, nullptr, nullptr, - label, 0, 0x0, PLUGIN_OPTIONS_NULL)) + if (carla_add_plugin(handle, + info.btype, + fPluginType, + info.filename.c_str(), + info.name.c_str(), + info.label.c_str(), + info.uniqueId, + nullptr, + PLUGIN_OPTIONS_NULL)) { fPluginRunning = true; fPluginGenericUI = nullptr; + fPluginFilename.clear(); createOrUpdatePluginGenericUI(handle); + return true; } else { fPopupError = carla_get_last_error(handle); d_stdout("got error: %s", fPopupError.buffer()); fDrawingState = kDrawingPluginError; + return false; + } + } + + void loadFileAsPlugin(const CarlaHostHandle handle, const char* const filename) + { + if (fPluginRunning) + { + carla_show_custom_ui(handle, 0, false); + carla_replace_plugin(handle, 0); + } + + carla_set_engine_option(handle, ENGINE_OPTION_PREFER_PLUGIN_BRIDGES, fPluginWillRunInBridgeMode, nullptr); + + const MutexLocker cml(sPluginInfoLoadMutex); + + if (carla_load_file(handle, filename)) + { + fPluginRunning = true; + fPluginGenericUI = nullptr; + fPluginFilename = filename; + createOrUpdatePluginGenericUI(handle); + } + else + { + fPopupError = carla_get_last_error(handle); + d_stdout("got error: %s", fPopupError.buffer()); + fPluginFilename.clear(); + fDrawingState = kDrawingPluginError; } setDirty(true); @@ -1087,7 +1425,10 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { case kIdleResetPlugin: fIdleState = kIdleNothing; - loadPlugin(handle, carla_get_plugin_info(handle, 0)->label); + if (fPluginFilename.isNotEmpty()) + loadFileAsPlugin(handle, fPluginFilename.buffer()); + else + loadPlugin(handle, fCurrentPluginInfo); break; case kIdleOpenFileUI: @@ -1112,10 +1453,27 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { case kIdleChangePluginType: fIdleState = kIdleNothing; - fPluginSelected = -1; - stopRunner(); - fPluginType = fNextPluginType; - initAndStartRunner(); + if (fNextPluginType == PLUGIN_TYPE_COUNT) + { + if (fPluginRunning) + carla_show_custom_ui(handle, 0, false); + + async_dialog_filebrowser(false, nullptr, nullptr, "Load from file", [this](char* path) + { + if (path == nullptr) + return; + + loadFileAsPlugin(module->fCarlaHostHandle, path); + std::free(path); + }); + } + else + { + fPluginSelected = -1; + stopRunner(); + fPluginType = fNextPluginType; + initAndStartRunner(); + } break; case kIdleNothing: @@ -1127,32 +1485,16 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { { DISTRHO_SAFE_ASSERT_RETURN(fPluginSelected >= 0,); - const PluginInfoCache& info(fPlugins[fPluginSelected]); - - const char* label = nullptr; - - switch (fPluginType) + PluginInfoCache info; { - case PLUGIN_INTERNAL: - case PLUGIN_AU: - case PLUGIN_JSFX: - case PLUGIN_SFZ: - label = info.label; - break; - case PLUGIN_LV2: { - const char* const slash = std::strchr(info.label, DISTRHO_OS_SEP); - DISTRHO_SAFE_ASSERT_RETURN(slash != nullptr,); - label = slash+1; - break; - } - default: - break; + const MutexLocker cml(fPluginsMutex); + info = fPlugins[fPluginSelected]; } - DISTRHO_SAFE_ASSERT_RETURN(label != nullptr,); + d_stdout("Loading %s...", info.name.c_str()); - d_stdout("Loading %s...", info.name); - loadPlugin(handle, label); + if (loadPlugin(handle, info)) + fCurrentPluginInfo = info; } bool initAndStartRunner() @@ -1170,29 +1512,33 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { { fRunnerData.needsReinit = false; - const char* path; - switch (fPluginType) { - case PLUGIN_LV2: - path = std::getenv("LV2_PATH"); - break; - case PLUGIN_JSFX: - path = getPathForJSFX(); - break; - default: - path = nullptr; - break; + const MutexLocker cml(fPluginsMutex); + fPlugins.clear(); } - fPluginCount = 0; - delete[] fPlugins; + d_stdout("Will scan plugins now..."); + + const String& binaryPath(module->fBinaryPath); + if (binaryPath.isNotEmpty()) { - const MutexLocker cml(sPluginInfoLoadMutex); + fBinaryType = BINARY_NATIVE; + + fDiscoveryTool = binaryPath; + fDiscoveryTool += DISTRHO_OS_SEP_STR "carla-discovery-native"; + #ifdef CARLA_OS_WIN + fDiscoveryTool += ".exe"; + #endif + + fRunnerData.handle = carla_plugin_discovery_start(fDiscoveryTool, + fBinaryType, + fPluginType, + getPluginPath(fPluginType), + _binaryPluginSearchCallback, + _binaryPluginCheckCacheCallback, + this); - d_stdout("Will scan plugins now..."); - fRunnerData.pluginCount = carla_get_cached_plugin_count(fPluginType, path); - d_stdout("Scanning found %u plugins", fRunnerData.pluginCount); } if (fDrawingState == kDrawingLoading) @@ -1201,70 +1547,280 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { fPluginSearchFirstShow = true; } - if (fRunnerData.pluginCount != 0) + if (binaryPath.isEmpty() || (fRunnerData.handle == nullptr && !startNextDiscovery())) { - fPlugins = new PluginInfoCache[fRunnerData.pluginCount]; - fPluginScanningFinished = false; + d_stdout("Nothing found!"); + return false; + } + } + + DISTRHO_SAFE_ASSERT_RETURN(fRunnerData.handle != nullptr, false); + + if (carla_plugin_discovery_idle(fRunnerData.handle)) + return true; + + // stop here + carla_plugin_discovery_stop(fRunnerData.handle); + fRunnerData.handle = nullptr; + + if (startNextDiscovery()) + return true; + + d_stdout("Found %lu plugins!", (ulong)fPlugins.size()); + return false; + } + + bool startNextDiscovery() + { + if (! setNextDiscoveryTool()) + return false; + + fRunnerData.handle = carla_plugin_discovery_start(fDiscoveryTool, + fBinaryType, + fPluginType, + getPluginPath(fPluginType), + _binaryPluginSearchCallback, + _binaryPluginCheckCacheCallback, + this); + + if (fRunnerData.handle == nullptr) + return startNextDiscovery(); + + return true; + } + + bool setNextDiscoveryTool() + { + switch (fPluginType) + { + case PLUGIN_VST2: + case PLUGIN_VST3: + case PLUGIN_CLAP: + break; + default: + return false; + } + + #ifdef CARLA_OS_WIN + #ifdef CARLA_OS_WIN64 + // look for win32 plugins on win64 + if (fBinaryType == BINARY_NATIVE) + { + fBinaryType = BINARY_WIN32; + fDiscoveryTool = module->fBinaryPath; + fDiscoveryTool += CARLA_OS_SEP_STR "carla-discovery-win32.exe"; + + if (system::exists(fDiscoveryTool.buffer())) + return true; + } + #endif + + // no other types to try + return false; + #else // CARLA_OS_WIN + + #ifndef CARLA_OS_MAC + // try 32bit plugins on 64bit systems, skipping macOS where 32bit is no longer supported + if (fBinaryType == BINARY_NATIVE) + { + fBinaryType = BINARY_POSIX32; + fDiscoveryTool = module->fBinaryPath; + fDiscoveryTool += CARLA_OS_SEP_STR "carla-discovery-posix32"; + + if (system::exists(fDiscoveryTool.buffer())) + return true; + } + #endif + + // try wine bridges + #ifdef CARLA_OS_64BIT + if (fBinaryType == BINARY_NATIVE || fBinaryType == BINARY_POSIX32) + { + fBinaryType = BINARY_WIN64; + fDiscoveryTool = module->fBinaryPath; + fDiscoveryTool += CARLA_OS_SEP_STR "carla-discovery-win64.exe"; + + if (system::exists(fDiscoveryTool.buffer())) + return true; + } + #endif + + if (fBinaryType != BINARY_WIN32) + { + fBinaryType = BINARY_WIN32; + fDiscoveryTool = module->fBinaryPath; + fDiscoveryTool += CARLA_OS_SEP_STR "carla-discovery-win32.exe"; + + if (system::exists(fDiscoveryTool.buffer())) return true; + } + + return false; + #endif // CARLA_OS_WIN + } + + void binaryPluginSearchCallback(const CarlaPluginDiscoveryInfo* const info, const char* const sha1sum) + { + // save plugin info into cache + if (sha1sum != nullptr) + { + const water::String configDir(asset::config("Ildaeil")); + const water::File cacheFile(configDir + CARLA_OS_SEP_STR "cache" CARLA_OS_SEP_STR + sha1sum); + + if (cacheFile.create().ok()) + { + water::FileOutputStream stream(cacheFile); + + if (stream.openedOk()) + { + if (info != nullptr) + { + stream.writeString(getBinaryTypeAsString(info->btype)); + stream.writeString(getPluginTypeAsString(info->ptype)); + stream.writeString(info->filename); + stream.writeString(info->label); + stream.writeInt64(info->uniqueId); + stream.writeString(info->metadata.name); + stream.writeString(info->metadata.maker); + stream.writeString(getPluginCategoryAsString(info->metadata.category)); + stream.writeInt(info->metadata.hints); + stream.writeCompressedInt(info->io.audioIns); + stream.writeCompressedInt(info->io.audioOuts); + stream.writeCompressedInt(info->io.cvIns); + stream.writeCompressedInt(info->io.cvOuts); + stream.writeCompressedInt(info->io.midiIns); + stream.writeCompressedInt(info->io.midiOuts); + stream.writeCompressedInt(info->io.parameterIns); + stream.writeCompressedInt(info->io.parameterOuts); + } + } + else + { + d_stderr("Failed to write cache file for %s", sha1sum); + } } else { - fPlugins = nullptr; - fPluginScanningFinished = true; - return false; + d_stderr("Failed to write cache file directories for %s", sha1sum); } } - const uint index = fRunnerData.pluginIndex++; - DISTRHO_SAFE_ASSERT_UINT2_RETURN(index < fRunnerData.pluginCount, - index, fRunnerData.pluginCount, false); + if (info == nullptr) + return; - do { - const MutexLocker cml(sPluginInfoLoadMutex); + if (info->io.cvIns != 0 || info->io.cvOuts != 0) + return; + if (info->io.midiIns != 0 && info->io.midiIns != 1) + return; + if (info->io.midiOuts != 0 && info->io.midiOuts != 1) + return; - const CarlaCachedPluginInfo* const info = carla_get_cached_plugin_info(fPluginType, index); - DISTRHO_SAFE_ASSERT_CONTINUE(info != nullptr); + if (fPluginType == PLUGIN_INTERNAL) + { + if (std::strcmp(info->label, "audiogain") == 0) + return; + if (std::strcmp(info->label, "cv2audio") == 0) + return; + if (std::strcmp(info->label, "lfo") == 0) + return; + if (std::strcmp(info->label, "midi2cv") == 0) + return; + if (std::strcmp(info->label, "midithrough") == 0) + return; + if (std::strcmp(info->label, "3bandsplitter") == 0) + return; + } - if (! info->valid) - break; - if (info->audioIns > 2) - break; - if (info->midiIns != 0 && info->midiIns != 1) - break; - if (info->midiOuts != 0 && info->midiOuts != 1) - break; + const PluginInfoCache pinfo = { + info->btype, + info->uniqueId, + info->filename, + info->metadata.name, + info->label, + }; + + const MutexLocker cml(fPluginsMutex); + fPlugins.push_back(pinfo); + } + + static void _binaryPluginSearchCallback(void* const ptr, + const CarlaPluginDiscoveryInfo* const info, + const char* const sha1sum) + { + static_cast(ptr)->binaryPluginSearchCallback(info, sha1sum); + } - if (fPluginType == PLUGIN_INTERNAL) + bool binaryPluginCheckCacheCallback(const char* const filename, const char* const sha1sum) + { + if (sha1sum == nullptr) + return false; + + const water::String configDir(asset::config("Ildaeil")); + const water::File cacheFile(configDir + CARLA_OS_SEP_STR "cache" CARLA_OS_SEP_STR + sha1sum); + + if (cacheFile.existsAsFile()) + { + water::FileInputStream stream(cacheFile); + + if (stream.openedOk()) { - if (std::strcmp(info->label, "audiogain_s") == 0) - break; - if (std::strcmp(info->label, "cv2audio") == 0) - break; - if (std::strcmp(info->label, "lfo") == 0) - break; - if (std::strcmp(info->label, "midi2cv") == 0) - break; - if (std::strcmp(info->label, "midithrough") == 0) - break; - if (std::strcmp(info->label, "3bandsplitter") == 0) - break; - } + while (! stream.isExhausted()) + { + CarlaPluginDiscoveryInfo info = {}; + + // read back everything the same way and order as we wrote it + info.btype = getBinaryTypeFromString(stream.readString().toRawUTF8()); + info.ptype = getPluginTypeFromString(stream.readString().toRawUTF8()); + const water::String pfilename(stream.readString()); + const water::String label(stream.readString()); + info.uniqueId = stream.readInt64(); + const water::String name(stream.readString()); + const water::String maker(stream.readString()); + info.metadata.category = getPluginCategoryFromString(stream.readString().toRawUTF8()); + info.metadata.hints = stream.readInt(); + info.io.audioIns = stream.readCompressedInt(); + info.io.audioOuts = stream.readCompressedInt(); + info.io.cvIns = stream.readCompressedInt(); + info.io.cvOuts = stream.readCompressedInt(); + info.io.midiIns = stream.readCompressedInt(); + info.io.midiOuts = stream.readCompressedInt(); + info.io.parameterIns = stream.readCompressedInt(); + info.io.parameterOuts = stream.readCompressedInt(); + + // string stuff + info.filename = pfilename.toRawUTF8(); + info.label = label.toRawUTF8(); + info.metadata.name = name.toRawUTF8(); + info.metadata.maker = maker.toRawUTF8(); + + // check sha1 collisions + if (pfilename != filename) + { + d_stderr("Cache hash collision for %s: \"%s\" vs \"%s\"", + sha1sum, pfilename.toRawUTF8(), filename); + return false; + } - const uint pindex = fPluginCount; - fPlugins[pindex].name = strdup(info->name); - fPlugins[pindex].label = strdup(info->label); - ++fPluginCount; - } while (false); + // purposefully not passing sha1sum, to not override cache file + binaryPluginSearchCallback(&info, nullptr); + } - // run again - if (fRunnerData.pluginIndex != fRunnerData.pluginCount) - return true; + return true; + } + else + { + d_stderr("Failed to read cache file for %s", sha1sum); + } + } - // stop here - fPluginScanningFinished = true; return false; } + static bool _binaryPluginCheckCacheCallback(void* const ptr, const char* const filename, const char* const sha1) + { + return static_cast(ptr)->binaryPluginCheckCacheCallback(filename, sha1); + } + void drawImGui() override { switch (fDrawingState) @@ -1417,6 +1973,36 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { { const CarlaHostHandle handle = module->fCarlaHostHandle; + if (fPluginIsBridge) + { + const bool active = carla_get_internal_parameter_value(handle, 0, PARAMETER_ACTIVE) > 0.5f; + + if (active) + { + ImGui::BeginDisabled(); + ImGui::Button("Reload bridge"); + ImGui::EndDisabled(); + } + else + { + if (ImGui::Button("Reload bridge")) + carla_set_active(handle, 0, true); + } + } + + if (ui->presetCount != 0) + { + ImGui::Text("Preset:"); + ImGui::SameLine(); + + if (ImGui::Combo("##presets", &ui->currentPreset, ui->presetStrings, ui->presetCount)) + { + PluginGenericUI::Preset& preset(ui->presets[ui->currentPreset]); + + carla_set_program(handle, 0, preset.index); + } + } + for (uint32_t i=0; i < ui->parameterCount; ++i) { PluginGenericUI::Parameter& param(ui->parameters[i]); @@ -1488,8 +2074,14 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { { static const char* pluginTypes[] = { getPluginTypeAsString(PLUGIN_INTERNAL), + getPluginTypeAsString(PLUGIN_LADSPA), + getPluginTypeAsString(PLUGIN_DSSI), getPluginTypeAsString(PLUGIN_LV2), + getPluginTypeAsString(PLUGIN_VST2), + getPluginTypeAsString(PLUGIN_VST3), + getPluginTypeAsString(PLUGIN_CLAP), getPluginTypeAsString(PLUGIN_JSFX), + "Load from file..." }; setupMainWindowPos(); @@ -1535,15 +2127,14 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { int current; switch (fPluginType) { - case PLUGIN_JSFX: - current = 2; - break; - case PLUGIN_LV2: - current = 1; - break; - default: - current = 0; - break; + case PLUGIN_JSFX: current = 7; break; + case PLUGIN_CLAP: current = 6; break; + case PLUGIN_VST3: current = 5; break; + case PLUGIN_VST2: current = 4; break; + case PLUGIN_LV2: current = 3; break; + case PLUGIN_DSSI: current = 2; break; + case PLUGIN_LADSPA: current = 1; break; + default: current = 0; break; } if (ImGui::Combo("##plugintypes", ¤t, pluginTypes, ARRAY_SIZE(pluginTypes))) @@ -1551,19 +2142,19 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { fIdleState = kIdleChangePluginType; switch (current) { - case 0: - fNextPluginType = PLUGIN_INTERNAL; - break; - case 1: - fNextPluginType = PLUGIN_LV2; - break; - case 2: - fNextPluginType = PLUGIN_JSFX; - break; + case 0: fNextPluginType = PLUGIN_INTERNAL; break; + case 1: fNextPluginType = PLUGIN_LADSPA; break; + case 2: fNextPluginType = PLUGIN_DSSI; break; + case 3: fNextPluginType = PLUGIN_LV2; break; + case 4: fNextPluginType = PLUGIN_VST2; break; + case 5: fNextPluginType = PLUGIN_VST3; break; + case 6: fNextPluginType = PLUGIN_CLAP; break; + case 7: fNextPluginType = PLUGIN_JSFX; break; + case 8: fNextPluginType = PLUGIN_TYPE_COUNT; break; } } - ImGui::BeginDisabled(!fPluginScanningFinished || fPluginSelected < 0); + ImGui::BeginDisabled(fPluginSelected < 0); if (ImGui::Button("Load Plugin")) fIdleState = kIdleLoadSelectedPlugin; @@ -1596,8 +2187,6 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { { case PLUGIN_INTERNAL: case PLUGIN_AU: - case PLUGIN_SFZ: - case PLUGIN_JSFX: ImGui::TableSetupColumn("Name"); ImGui::TableSetupColumn("Label"); ImGui::TableHeadersRow(); @@ -1608,14 +2197,19 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { ImGui::TableHeadersRow(); break; default: + ImGui::TableSetupColumn("Name"); + ImGui::TableSetupColumn("Filename"); + ImGui::TableHeadersRow(); break; } - for (uint i=0; i= 0 && static_cast(fPluginSelected) == i; @@ -1624,25 +2218,25 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Runner { { case PLUGIN_INTERNAL: case PLUGIN_AU: - case PLUGIN_JSFX: - case PLUGIN_SFZ: ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); - ImGui::Selectable(info.name, &selected); + ImGui::Selectable(info.name.c_str(), &selected); ImGui::TableSetColumnIndex(1); - ImGui::Selectable(info.label, &selected); + ImGui::Selectable(info.label.c_str(), &selected); break; - case PLUGIN_LV2: { - const char* const slash = std::strchr(info.label, DISTRHO_OS_SEP); - DISTRHO_SAFE_ASSERT_CONTINUE(slash != nullptr); + case PLUGIN_LV2: ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); - ImGui::Selectable(info.name, &selected); + ImGui::Selectable(info.name.c_str(), &selected); ImGui::TableSetColumnIndex(1); - ImGui::Selectable(slash+1, &selected); + ImGui::Selectable(info.label.c_str(), &selected); break; - } default: + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGui::Selectable(info.name.c_str(), &selected); + ImGui::TableSetColumnIndex(1); + ImGui::Selectable(info.filename.c_str(), &selected); break; } diff --git a/plugins/Cardinal/src/ImGuiWidget.cpp b/plugins/Cardinal/src/ImGuiWidget.cpp index ec88a824..e0af7020 100644 --- a/plugins/Cardinal/src/ImGuiWidget.cpp +++ b/plugins/Cardinal/src/ImGuiWidget.cpp @@ -23,7 +23,7 @@ # include "../../../dpf/dgl/src/Resources.hpp" #endif -#if defined(DGL_USE_GLES2) || defined(DGL_USE_GLES3) || defined(DGL_USE_OPENGL3) +#if defined(DGL_USE_OPENGL3) # include "DearImGui/imgui_impl_opengl3.h" #else # include "DearImGui/imgui_impl_opengl2.h" @@ -97,7 +97,7 @@ struct ImGuiWidget::PrivateData { if (created) { ImGui::SetCurrentContext(context); -#if defined(DGL_USE_GLES2) || defined(DGL_USE_GLES3) || defined(DGL_USE_OPENGL3) +#if defined(DGL_USE_OPENGL3) ImGui_ImplOpenGL3_Shutdown(); #else ImGui_ImplOpenGL2_Shutdown(); @@ -171,7 +171,7 @@ struct ImGuiWidget::PrivateData { if (created) { ImGui::SetCurrentContext(context); -#if defined(DGL_USE_GLES2) || defined(DGL_USE_GLES3) || defined(DGL_USE_OPENGL3) +#if defined(DGL_USE_OPENGL3) ImGui_ImplOpenGL3_Shutdown(); #else ImGui_ImplOpenGL2_Shutdown(); @@ -191,7 +191,7 @@ struct ImGuiWidget::PrivateData { if (doInit) { -#if defined(DGL_USE_GLES2) || defined(DGL_USE_GLES3) || defined(DGL_USE_OPENGL3) +#if defined(DGL_USE_OPENGL3) ImGui_ImplOpenGL3_Init(); #else ImGui_ImplOpenGL2_Init(); @@ -262,7 +262,7 @@ void ImGuiWidget::onContextCreate(const ContextCreateEvent& e) DISTRHO_SAFE_ASSERT_RETURN(!imData->created,); ImGui::SetCurrentContext(imData->context); -#if defined(DGL_USE_GLES2) || defined(DGL_USE_GLES3) || defined(DGL_USE_OPENGL3) +#if defined(DGL_USE_OPENGL3) ImGui_ImplOpenGL3_Init(); #else ImGui_ImplOpenGL2_Init(); @@ -275,7 +275,7 @@ void ImGuiWidget::onContextDestroy(const ContextDestroyEvent& e) if (imData->created) { ImGui::SetCurrentContext(imData->context); -#if defined(DGL_USE_GLES2) || defined(DGL_USE_GLES3) || defined(DGL_USE_OPENGL3) +#if defined(DGL_USE_OPENGL3) ImGui_ImplOpenGL3_Shutdown(); #else ImGui_ImplOpenGL2_Shutdown(); @@ -481,7 +481,7 @@ void ImGuiWidget::drawFramebufferCommon(const Vec& fbSize, const float scaleFact } } -#if defined(DGL_USE_GLES2) || defined(DGL_USE_GLES3) || defined(DGL_USE_OPENGL3) +#if defined(DGL_USE_OPENGL3) // TODO? #else glMatrixMode(GL_PROJECTION); @@ -492,6 +492,9 @@ void ImGuiWidget::drawFramebufferCommon(const Vec& fbSize, const float scaleFact glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT); #endif io.DisplaySize = ImVec2(box.size.x * scaleFactor, box.size.y * scaleFactor); @@ -499,7 +502,7 @@ void ImGuiWidget::drawFramebufferCommon(const Vec& fbSize, const float scaleFact if (!imData->created) { -#if defined(DGL_USE_GLES2) || defined(DGL_USE_GLES3) || defined(DGL_USE_OPENGL3) +#if defined(DGL_USE_OPENGL3) ImGui_ImplOpenGL3_Init(); #else ImGui_ImplOpenGL2_Init(); @@ -511,7 +514,7 @@ void ImGuiWidget::drawFramebufferCommon(const Vec& fbSize, const float scaleFact io.DeltaTime = time - imData->lastFrameTime; imData->lastFrameTime = time; -#if defined(DGL_USE_GLES2) || defined(DGL_USE_GLES3) || defined(DGL_USE_OPENGL3) +#if defined(DGL_USE_OPENGL3) ImGui_ImplOpenGL3_NewFrame(); #else ImGui_ImplOpenGL2_NewFrame(); @@ -523,7 +526,7 @@ void ImGuiWidget::drawFramebufferCommon(const Vec& fbSize, const float scaleFact if (ImDrawData* const data = ImGui::GetDrawData()) { -#if defined(DGL_USE_GLES2) || defined(DGL_USE_GLES3) || defined(DGL_USE_OPENGL3) +#if defined(DGL_USE_OPENGL3) ImGui_ImplOpenGL3_RenderDrawData(data); #else ImGui_ImplOpenGL2_RenderDrawData(data); diff --git a/plugins/Cardinal/src/ModuleWidgets.hpp b/plugins/Cardinal/src/ModuleWidgets.hpp index 9a3f1ed6..4cf46fed 100644 --- a/plugins/Cardinal/src/ModuleWidgets.hpp +++ b/plugins/Cardinal/src/ModuleWidgets.hpp @@ -37,16 +37,20 @@ struct ModuleWidgetWithSideScrews : ModuleWidget { createAndAddInput(paramId, paramId); } - void createAndAddInput(const uint posY, const uint paramId) { - addInput(createInput(Vec(startX_In, startY + padding * posY), module, paramId)); + void createAndAddInput(const uint posY, const uint paramId, bool visible = true) { + PortWidget* const widget = createInput(Vec(startX_In, startY + padding * posY), module, paramId); + widget->visible = visible; + addInput(widget); } void createAndAddOutput(const uint paramId) { createAndAddOutput(paramId, paramId); } - void createAndAddOutput(const uint posY, const uint paramId) { - addOutput(createOutput(Vec(startX_Out, startY + padding * posY), module, paramId)); + void createAndAddOutput(const uint posY, const uint paramId, bool visible = true) { + PortWidget* const widget = createOutput(Vec(startX_Out, startY + padding * posY), module, paramId); + widget->visible = visible; + addOutput(widget); } void createAndAddScrews() { diff --git a/plugins/Cardinal/src/SassyScope.cpp b/plugins/Cardinal/src/SassyScope.cpp index df79ccee..8f866af1 100644 --- a/plugins/Cardinal/src/SassyScope.cpp +++ b/plugins/Cardinal/src/SassyScope.cpp @@ -284,7 +284,9 @@ struct SassyScopeWidget : ImGuiWidget { ImGui::SetNextWindowPos(ImVec2(0, 0)); ImGui::SetNextWindowSize(ImVec2(box.size.x * scaleFactor, box.size.y * scaleFactor)); - do_show_scope_window(module != nullptr ? &module->scope : getFakeScopeInstance(), scaleFactor); + ScopeData* const scope = module != nullptr ? &module->scope : getFakeScopeInstance(); + scope->darkMode = settings::darkMode; + do_show_scope_window(scope, scaleFactor); } void onButton(const ButtonEvent& e) override diff --git a/plugins/Cardinal/src/Widgets.hpp b/plugins/Cardinal/src/Widgets.hpp index 7faff609..f836e58b 100644 --- a/plugins/Cardinal/src/Widgets.hpp +++ b/plugins/Cardinal/src/Widgets.hpp @@ -231,7 +231,7 @@ struct NanoKnob : Knob { // bottom label (name) bndIconLabelValue(args.vg, -w, knobStartY + knobSize + BND_WIDGET_HEIGHT * 0.75f, w*3, BND_WIDGET_HEIGHT, -1, - SCHEME_WHITE, BND_CENTER, + settings::darkMode ? SCHEME_WHITE : SCHEME_BLACK, BND_CENTER, BND_LABEL_FONT_SIZE, displayLabel.c_str(), nullptr); } diff --git a/plugins/Cardinal/src/plugin.hpp b/plugins/Cardinal/src/plugin.hpp index 96a5a9bb..0b55a02c 100644 --- a/plugins/Cardinal/src/plugin.hpp +++ b/plugins/Cardinal/src/plugin.hpp @@ -28,6 +28,7 @@ using namespace rack; extern Plugin* pluginInstance; +extern Model* modelAidaX; extern Model* modelAudioFile; extern Model* modelAudioToCVPitch; extern Model* modelCarla; @@ -55,32 +56,60 @@ extern std::vector hostTerminalModels; /* * Find the highest absolute and normalized value within a float array. */ +template static inline -float d_findMaxNormalizedFloat(const float floats[], const std::size_t count) +float d_findMaxNormalizedFloat(const float floats[size]) { - DISTRHO_SAFE_ASSERT_RETURN(floats != nullptr, 0.0f); - DISTRHO_SAFE_ASSERT_RETURN(count > 0, 0.0f); + static constexpr const float kEmptyFloats[size] = {}; - static constexpr const float kEmptyFloats[8192] = {}; + if (std::memcmp(floats, kEmptyFloats, sizeof(float)*size) == 0) + return 0.f; - if (count <= 8192 && std::memcmp(floats, kEmptyFloats, count) == 0) - return 0.0f; + float tmp, maxf2 = std::abs(floats[0]); + + for (std::size_t i=1; i maxf2) + maxf2 = tmp; + } + + if (maxf2 > 1.f) + maxf2 = 1.f; + + return maxf2; +} + +/* + * Find the highest absolute and normalized value within a float array. + */ +static inline +float d_findMaxNormalizedFloat128(const float floats[128]) +{ + static constexpr const float kEmptyFloats[128] = {}; + + if (std::memcmp(floats, kEmptyFloats, sizeof(float)*128) == 0) + return 0.f; float tmp, maxf2 = std::abs(floats[0]); - for (std::size_t i=1; i maxf2) maxf2 = tmp; } - if (maxf2 > 1.0f) - maxf2 = 1.0f; + if (maxf2 > 1.f) + maxf2 = 1.f; return maxf2; } diff --git a/plugins/Cardinal/src/plugincontext.hpp b/plugins/Cardinal/src/plugincontext.hpp index f48b2a83..f7fcc030 100644 --- a/plugins/Cardinal/src/plugincontext.hpp +++ b/plugins/Cardinal/src/plugincontext.hpp @@ -20,21 +20,24 @@ #include "plugin.hpp" #include "DistrhoUtils.hpp" -#ifndef HEADLESS -# include "../dgl/Base.hpp" -#else -# include "extra/LeakDetector.hpp" -#endif +#include "../dgl/Base.hpp" // ----------------------------------------------------------------------------------------------------------- // from PluginContext.hpp +START_NAMESPACE_DGL +class TopLevelWidget; +template class NanoBaseWidget; +typedef NanoBaseWidget NanoTopLevelWidget; +END_NAMESPACE_DGL + START_NAMESPACE_DISTRHO -static constexpr const uint32_t kModuleParameters = 24; +static constexpr const uint32_t kModuleParameterCount = 24; enum CardinalVariant { kCardinalVariantMain, + kCardinalVariantMini, kCardinalVariantFX, kCardinalVariantNative, kCardinalVariantSynth, @@ -54,7 +57,7 @@ struct MidiEvent { struct CardinalPluginContext : rack::Context { uint32_t bufferSize, processCounter; double sampleRate; - float parameters[kModuleParameters]; + float parameters[kModuleParameterCount]; CardinalVariant variant; bool bypassed, playing, reset, bbtValid; int32_t bar, beat, beatsPerBar, beatType; @@ -67,9 +70,8 @@ struct CardinalPluginContext : rack::Context { const MidiEvent* midiEvents; uint32_t midiEventCount; Plugin* const plugin; -#ifndef HEADLESS + DGL_NAMESPACE::NanoTopLevelWidget* tlw; UI* ui; -#endif CardinalPluginContext(Plugin* const p); void writeMidiMessage(const rack::midi::Message& message, uint8_t channel); #ifndef HEADLESS diff --git a/plugins/Cardinal/src/sassy/sassy.hpp b/plugins/Cardinal/src/sassy/sassy.hpp index 254db7fd..9ab9f6b7 100644 --- a/plugins/Cardinal/src/sassy/sassy.hpp +++ b/plugins/Cardinal/src/sassy/sassy.hpp @@ -59,6 +59,7 @@ struct ScopeData { int mDisplay = 0; int mFFTZoom = 0; int mPot = 0; + bool darkMode = true; float fft1[65536 * 2]; float fft2[65536 * 2]; float ffta[65536 * 2]; diff --git a/plugins/Cardinal/src/sassy/sassy_scope.cpp b/plugins/Cardinal/src/sassy/sassy_scope.cpp index 2904be7c..88715573 100644 --- a/plugins/Cardinal/src/sassy/sassy_scope.cpp +++ b/plugins/Cardinal/src/sassy/sassy_scope.cpp @@ -759,11 +759,13 @@ void do_show_scope_window(ScopeData* gScope, const float uiScale) } else { - ImGui::PushStyleColor(ImGuiCol_FrameBg, 0xff3f3f3f); - ImGui::PushStyleColor(ImGuiCol_FrameBgActive, 0xff3f3f3f); - ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, 0xff3f3f3f); - ImGui::PushStyleColor(ImGuiCol_SliderGrab, 0xff7f7f7f); - ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, 0xff7f7f7f); + const ImU32 bgCol = gScope->darkMode ? 0xff3f3f3f : 0xffc0c0c0; + const ImU32 sliderCol = gScope->darkMode ? 0xff7f7f7f : 0xff808080; + ImGui::PushStyleColor(ImGuiCol_FrameBg, bgCol); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, bgCol); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, bgCol); + ImGui::PushStyleColor(ImGuiCol_SliderGrab, sliderCol); + ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, sliderCol); ImGui::SetNextItemWidth(grid_size * uiScale); float x = gScope->mScroll; ImGui::SliderFloat("###scroll", &x, -10.0f, 0.0f, "%.3f s"); @@ -810,12 +812,13 @@ void do_show_scope_window(ScopeData* gScope, const float uiScale) if (gScope->mMode == 0) { + const ImU32 bgCol = gScope->darkMode ? 0xff3f3f3f : 0xffc0c0c0; if (ImGui::Button("Pause", ImVec2(80 * uiScale, 20 * uiScale))) gScope->mMode = 1; ImGui::Text("Nudge (ms)"); - ImGui::PushStyleColor(ImGuiCol_Button, 0xff3f3f3f); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, 0xff3f3f3f); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, 0xff3f3f3f); + ImGui::PushStyleColor(ImGuiCol_Button, bgCol); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, bgCol); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, bgCol); ImGui::Button("-0.1", ImVec2(38 * uiScale, 20 * uiScale)); ImGui::SameLine(); ImGui::Button("+0.1", ImVec2(38 * uiScale, 20 * uiScale)); diff --git a/plugins/DrumKit b/plugins/DrumKit index 7681d30a..f2a7d717 160000 --- a/plugins/DrumKit +++ b/plugins/DrumKit @@ -1 +1 @@ -Subproject commit 7681d30ac0b9246605d3d8d71dc7e25030748ec6 +Subproject commit f2a7d717e2ae066ba0127fa5ffade775baba1512 diff --git a/plugins/EnigmaCurry b/plugins/EnigmaCurry new file mode 160000 index 00000000..550b4355 --- /dev/null +++ b/plugins/EnigmaCurry @@ -0,0 +1 @@ +Subproject commit 550b435575c550d829e8cabd97a430e39df836cc diff --git a/plugins/Fundamental b/plugins/Fundamental index 9ac0cdb9..63d54b65 160000 --- a/plugins/Fundamental +++ b/plugins/Fundamental @@ -1 +1 @@ -Subproject commit 9ac0cdb93938c3f01aba58ec01fdd01257abf353 +Subproject commit 63d54b6575657c8bd8d221178253c750baf0ed3b diff --git a/plugins/GlueTheGiant b/plugins/GlueTheGiant index 2c535bc3..5f05d62d 160000 --- a/plugins/GlueTheGiant +++ b/plugins/GlueTheGiant @@ -1 +1 @@ -Subproject commit 2c535bc38d61fd4d776aad7307c1dfbbed062b66 +Subproject commit 5f05d62ddc2773098daf1044eb6698581acd4eb6 diff --git a/plugins/GrandeModular b/plugins/GrandeModular index 3d652432..bc7ef815 160000 --- a/plugins/GrandeModular +++ b/plugins/GrandeModular @@ -1 +1 @@ -Subproject commit 3d6524320ce33569e3553a53571c45425ba5d078 +Subproject commit bc7ef8157f6ad1284d7c4706eb89132f59555ca1 diff --git a/plugins/JW-Modules b/plugins/JW-Modules index f7399c47..356588dd 160000 --- a/plugins/JW-Modules +++ b/plugins/JW-Modules @@ -1 +1 @@ -Subproject commit f7399c473735c0a5bec95bb40953e781f9a47ca4 +Subproject commit 356588ddb142dab99837af58681bc0d8afb88e4c diff --git a/plugins/ML_modules b/plugins/ML_modules index 66527f10..31104227 160000 --- a/plugins/ML_modules +++ b/plugins/ML_modules @@ -1 +1 @@ -Subproject commit 66527f10d0ad18d03aca3bbabceb198396da5d81 +Subproject commit 311042275900650c0b0cc57fcd2b57333820adde diff --git a/plugins/MSM b/plugins/MSM index abe3c24d..3315c11e 160000 --- a/plugins/MSM +++ b/plugins/MSM @@ -1 +1 @@ -Subproject commit abe3c24d40b11d31f9f38b2125eff9280c77ad1b +Subproject commit 3315c11e8506c28cece304fe4b772383a2820f86 diff --git a/plugins/Makefile b/plugins/Makefile index 95645538..7e9d982d 100644 --- a/plugins/Makefile +++ b/plugins/Makefile @@ -4,23 +4,9 @@ # Created by falkTX # -# -------------------------------------------------------------- -# Import base definitions - -DISTRHO_NAMESPACE = CardinalDISTRHO -DGL_NAMESPACE = CardinalDGL -USE_NANOVG_FBO = true -WASM_EXCEPTIONS = true -include ../dpf/Makefile.base.mk - -# -------------------------------------------------------------- -# Build config - -ifeq ($(BSD),true) -SYSDEPS ?= true -else -SYSDEPS ?= false -endif +BUILDING_RACK = true +ROOT = .. +include $(ROOT)/Makefile.base.mk # -------------------------------------------------------------- # List of drwav functions, used in several modules @@ -232,10 +218,12 @@ DRWAV += drwav_write_raw # Files to build PLUGIN_FILES = plugins.cpp +MINIPLUGIN_FILES = plugins-mini.cpp # -------------------------------------------------------------- # Cardinal (built-in) +PLUGIN_FILES += Cardinal/src/AIDA-X.cpp PLUGIN_FILES += Cardinal/src/Blank.cpp PLUGIN_FILES += Cardinal/src/ExpanderInputMIDI.cpp PLUGIN_FILES += Cardinal/src/ExpanderOutputMIDI.cpp @@ -250,6 +238,17 @@ PLUGIN_FILES += Cardinal/src/HostParameters-Map.cpp PLUGIN_FILES += Cardinal/src/HostTime.cpp PLUGIN_FILES += Cardinal/src/TextEditor.cpp +MINIPLUGIN_FILES += Cardinal/src/HostAudio.cpp +MINIPLUGIN_FILES += Cardinal/src/HostCV.cpp +MINIPLUGIN_FILES += Cardinal/src/HostMIDI.cpp +MINIPLUGIN_FILES += Cardinal/src/HostMIDI-CC.cpp +MINIPLUGIN_FILES += Cardinal/src/HostMIDI-Gate.cpp +MINIPLUGIN_FILES += Cardinal/src/HostMIDI-Map.cpp +MINIPLUGIN_FILES += Cardinal/src/HostParameters.cpp +MINIPLUGIN_FILES += Cardinal/src/HostParameters-Map.cpp +MINIPLUGIN_FILES += Cardinal/src/HostTime.cpp +MINIPLUGIN_FILES += Cardinal/src/TextEditor.cpp + ifneq ($(USE_GLES2),true) ifneq ($(USE_GLES3),true) PLUGIN_FILES += Cardinal/src/glBars.cpp @@ -260,8 +259,8 @@ ifneq ($(STATIC_BUILD),true) PLUGIN_FILES += Cardinal/src/AudioFile.cpp ifneq ($(WASM),true) PLUGIN_FILES += Cardinal/src/Carla.cpp -endif PLUGIN_FILES += Cardinal/src/Ildaeil.cpp +endif ifneq ($(HEADLESS),true) ifeq ($(HAVE_X11),true) PLUGIN_FILES += Cardinal/src/EmbedWidget.cpp @@ -276,10 +275,15 @@ PLUGIN_FILES += Cardinal/src/ImGuiTextEditor.cpp PLUGIN_FILES += Cardinal/src/SassyScope.cpp PLUGIN_FILES += Cardinal/src/DearImGui.cpp PLUGIN_FILES += Cardinal/src/DearImGuiColorTextEditor.cpp +MINIPLUGIN_FILES += Cardinal/src/ImGuiWidget.cpp +MINIPLUGIN_FILES += Cardinal/src/ImGuiTextEditor.cpp +MINIPLUGIN_FILES += Cardinal/src/DearImGui.cpp +MINIPLUGIN_FILES += Cardinal/src/DearImGuiColorTextEditor.cpp endif ifeq ($(shell $(PKG_CONFIG) --exists fftw3f && echo true),true) PLUGIN_FILES += Cardinal/src/AudioToCVPitch.cpp +# MINIPLUGIN_FILES += Cardinal/src/AudioToCVPitch.cpp BASE_FLAGS += -DHAVE_FFTW3F endif @@ -289,15 +293,29 @@ endif PLUGIN_FILES += $(filter-out Fundamental/src/plugin.cpp,$(wildcard Fundamental/src/*.cpp)) PLUGIN_FILES += Fundamental/src/dr_wav.c +MINIPLUGIN_FILES += Fundamental/src/ADSR.cpp +MINIPLUGIN_FILES += Fundamental/src/LFO.cpp +MINIPLUGIN_FILES += Fundamental/src/Merge.cpp +MINIPLUGIN_FILES += Fundamental/src/MidSide.cpp +MINIPLUGIN_FILES += Fundamental/src/Noise.cpp +MINIPLUGIN_FILES += Fundamental/src/Quantizer.cpp +MINIPLUGIN_FILES += Fundamental/src/Random.cpp +MINIPLUGIN_FILES += Fundamental/src/Scope.cpp +MINIPLUGIN_FILES += Fundamental/src/Split.cpp +MINIPLUGIN_FILES += Fundamental/src/Sum.cpp +MINIPLUGIN_FILES += Fundamental/src/VCA-1.cpp +MINIPLUGIN_FILES += Fundamental/src/VCF.cpp +MINIPLUGIN_FILES += Fundamental/src/VCMixer.cpp +MINIPLUGIN_FILES += Fundamental/src/VCO.cpp + # modules/types which are present in other plugins FUNDAMENTAL_CUSTOM = $(DRWAV) # -------------------------------------------------------------- -# ZamAudio (always enabled) +# ZamAudio (always enabled) - TODO -PLUGIN_FILES += $(wildcard ZamAudio/src/*.cpp) +# PLUGIN_FILES += $(wildcard ZamAudio/src/*.cpp) -ifneq ($(NOPLUGINS),true) # -------------------------------------------------------------- # 21kHz @@ -308,6 +326,14 @@ PLUGIN_FILES += $(filter-out 21kHz/src/21kHz.cpp,$(wildcard 21kHz/src/*.cpp)) PLUGIN_FILES += $(filter-out 8Mode/src/8mode.cpp,$(wildcard 8Mode/src/*.cpp)) +# -------------------------------------------------------------- +# alefsbits + +PLUGIN_FILES += $(filter-out alefsbits/src/plugin.cpp,$(wildcard alefsbits/src/*.cpp)) + +# modules/types which are present in other plugins +ALEFSBITS_CUSTOM = Steps Logic + # -------------------------------------------------------------- # AlgoritmArte @@ -372,6 +398,9 @@ PLUGIN_FILES += AriaModules/src/Splort.cpp PLUGIN_FILES += AriaModules/src/Swerge.cpp PLUGIN_FILES += AriaModules/src/Undular.cpp +MINIPLUGIN_FILES += AriaModules/src/Spleet.cpp +MINIPLUGIN_FILES += AriaModules/src/Swerge.cpp + # modules/types which are present in other plugins ARIA_CUSTOM = Blank @@ -484,6 +513,21 @@ PLUGIN_FILES += AudibleInstruments/eurorack/streams/svf.cc PLUGIN_FILES += AudibleInstruments/eurorack/streams/vactrol.cc PLUGIN_FILES += AudibleInstruments/eurorack/streams/compressor.cc +MINIPLUGIN_FILES += AudibleInstruments/src/Plaits.cpp +# MINIPLUGIN_FILES += AudibleInstruments/eurorack/braids/macro_oscillator.cc +# MINIPLUGIN_FILES += AudibleInstruments/eurorack/braids/analog_oscillator.cc +# MINIPLUGIN_FILES += AudibleInstruments/eurorack/braids/digital_oscillator.cc +# MINIPLUGIN_FILES += AudibleInstruments/eurorack/braids/quantizer.cc +# MINIPLUGIN_FILES += AudibleInstruments/eurorack/braids/resources.cc +MINIPLUGIN_FILES += $(wildcard AudibleInstruments/eurorack/plaits/dsp/*.cc) +MINIPLUGIN_FILES += $(wildcard AudibleInstruments/eurorack/plaits/dsp/engine/*.cc) +MINIPLUGIN_FILES += $(wildcard AudibleInstruments/eurorack/plaits/dsp/speech/*.cc) +MINIPLUGIN_FILES += $(wildcard AudibleInstruments/eurorack/plaits/dsp/physical_modelling/*.cc) +MINIPLUGIN_FILES += AudibleInstruments/eurorack/plaits/resources.cc +MINIPLUGIN_FILES += AudibleInstruments/eurorack/stmlib/dsp/atan.cc +MINIPLUGIN_FILES += AudibleInstruments/eurorack/stmlib/dsp/units.cc +MINIPLUGIN_FILES += AudibleInstruments/eurorack/stmlib/utils/random.cc + # -------------------------------------------------------------- # Autinn @@ -503,6 +547,8 @@ PLUGIN_FILES += $(filter-out BaconPlugs/src/BaconPlugs.cpp,$(wildcard BaconPlugs PLUGIN_FILES += $(wildcard BaconPlugs/libs/midifile/src/*.cpp) PLUGIN_FILES += $(wildcard BaconPlugs/libs/open303-code/Source/DSPCode/*.cpp) +MINIPLUGIN_FILES += BaconPlugs/src/Style.cpp + # -------------------------------------------------------------- # Befaco @@ -511,7 +557,7 @@ PLUGIN_FILES += $(wildcard Befaco/src/noise-plethora/*/*.cpp) PLUGIN_BINARIES += Befaco/src/SpringReverbIR.pcm # modules/types which are present in other plugins -BEFACO_CUSTOM = ADSR Mixer +BEFACO_CUSTOM = ADSR Mixer chowdsp # -------------------------------------------------------------- # Bidoo @@ -525,7 +571,7 @@ PLUGIN_FILES += $(filter-out Bidoo/src/dep/resampler/main.cpp,$(wildcard Bidoo/s PLUGIN_FILES += BidooDark/plugin.cpp # modules/types which are present in other plugins -BIDOO_CUSTOM = ChannelDisplay InstantiateExpanderItem LadderFilter $(DRWAV) +BIDOO_CUSTOM = ChannelDisplay InstantiateExpanderItem LadderFilter PitchShifter $(DRWAV) BIDOO_CUSTOM_PER_FILE = channel channel filterType # -------------------------------------------------------------- @@ -535,6 +581,42 @@ PLUGIN_FILES += $(filter-out BogaudioModules/src/bogaudio.cpp,$(wildcard Bogaudi PLUGIN_FILES += $(wildcard BogaudioModules/src/dsp/*.cpp) PLUGIN_FILES += $(wildcard BogaudioModules/src/dsp/filters/*.cpp) +MINIPLUGIN_FILES += BogaudioModules/src/AD.cpp +MINIPLUGIN_FILES += BogaudioModules/src/LFO.cpp +MINIPLUGIN_FILES += BogaudioModules/src/Noise.cpp +MINIPLUGIN_FILES += BogaudioModules/src/Offset.cpp +MINIPLUGIN_FILES += BogaudioModules/src/SampleHold.cpp +MINIPLUGIN_FILES += BogaudioModules/src/Switch.cpp +MINIPLUGIN_FILES += BogaudioModules/src/Switch18.cpp +MINIPLUGIN_FILES += BogaudioModules/src/Unison.cpp +MINIPLUGIN_FILES += BogaudioModules/src/VCA.cpp +MINIPLUGIN_FILES += BogaudioModules/src/VCF.cpp +MINIPLUGIN_FILES += BogaudioModules/src/VCO.cpp +MINIPLUGIN_FILES += BogaudioModules/src/disable_output_limit.cpp +MINIPLUGIN_FILES += BogaudioModules/src/lfo_base.cpp +MINIPLUGIN_FILES += BogaudioModules/src/matrix_base.cpp +MINIPLUGIN_FILES += BogaudioModules/src/menu.cpp +MINIPLUGIN_FILES += BogaudioModules/src/module.cpp +MINIPLUGIN_FILES += BogaudioModules/src/param_quantities.cpp +MINIPLUGIN_FILES += BogaudioModules/src/poly_channels.cpp +MINIPLUGIN_FILES += BogaudioModules/src/rack_overrides.cpp +MINIPLUGIN_FILES += BogaudioModules/src/save_latch_to_patch.cpp +MINIPLUGIN_FILES += BogaudioModules/src/skins.cpp +MINIPLUGIN_FILES += BogaudioModules/src/utils.cpp +MINIPLUGIN_FILES += BogaudioModules/src/vco_base.cpp +MINIPLUGIN_FILES += BogaudioModules/src/widgets.cpp +MINIPLUGIN_FILES += BogaudioModules/src/dsp/analyzer.cpp +MINIPLUGIN_FILES += BogaudioModules/src/dsp/envelope.cpp +MINIPLUGIN_FILES += BogaudioModules/src/dsp/math.cpp +MINIPLUGIN_FILES += BogaudioModules/src/dsp/noise.cpp +MINIPLUGIN_FILES += BogaudioModules/src/dsp/oscillator.cpp +MINIPLUGIN_FILES += BogaudioModules/src/dsp/signal.cpp +MINIPLUGIN_FILES += BogaudioModules/src/dsp/table.cpp +MINIPLUGIN_FILES += BogaudioModules/src/dsp/filters/experiments.cpp +MINIPLUGIN_FILES += BogaudioModules/src/dsp/filters/filter.cpp +MINIPLUGIN_FILES += BogaudioModules/src/dsp/filters/multimode.cpp +MINIPLUGIN_FILES += BogaudioModules/src/dsp/filters/resample.cpp + # modules/types which are present in other plugins BOGAUDIO_CUSTOM = ADSR BlueNoiseGenerator LFO Noise VCA VCO VCF BOGAUDIO_CUSTOM_PER_FILE = ARQuantity AttackMenuItem ReleaseMenuItem @@ -546,6 +628,9 @@ PLUGIN_FILES += $(wildcard ChowDSP/src/*/*.cpp) PLUGIN_FILES += $(wildcard ChowDSP/src/*/*/*.cpp) PLUGIN_FILES += $(wildcard ChowDSP/lib/r8lib/*.cpp) +# modules/types which are present in other plugins +CHOWDSP_CUSTOM = sign + # -------------------------------------------------------------- # CatroModulo @@ -562,6 +647,15 @@ PLUGIN_FILES += $(filter-out cf/src/plugin.cpp,$(wildcard cf/src/*.cpp)) # modules/types which are present in other plugins CF_CUSTOM = $(DRWAV) +# -------------------------------------------------------------- +# dBiz + +PLUGIN_FILES += $(filter-out dBiz/src/plugin.cpp,$(wildcard dBiz/src/*.cpp)) + +# modules/types which are present in other plugins +DBIZ_CUSTOM = Chord DarkDefaultItem Divider FourSeq FourSeqWidget OrangeLight VCA4 Wavefolder darkPanelID lightPanelID +DBIZ_CUSTOM_PER_FILE = LERP MultiFilter Oscillator calcOutput sineOsc subBank + # -------------------------------------------------------------- # DrumKit @@ -575,6 +669,13 @@ PLUGIN_FILES += $(wildcard DrumKit/deps/SynthDevKit/src/*.cpp) # modules/types which are present in other plugins DRUMKIT_CUSTOM = ADSR Envelope LowFrequencyOscillator +# -------------------------------------------------------------- +# EnigmaCurry + +PLUGIN_FILES += $(filter-out EnigmaCurry/src/plugin.cpp,$(wildcard EnigmaCurry/src/*.cpp)) +# modules/types which are present in other plugins +ENIGMACURRY_CUSTOM = Pulse + # -------------------------------------------------------------- # ESeries @@ -618,6 +719,11 @@ PLUGIN_FILES += $(filter-out GoodSheperd/src/plugin.cpp,$(wildcard GoodSheperd/s PLUGIN_FILES += $(filter-out GrandeModular/src/plugin.cpp,$(wildcard GrandeModular/src/*.cpp)) +# -------------------------------------------------------------- +# H4N4 Modules + +PLUGIN_FILES += $(filter-out h4n4-modules/src/plugin.cpp,$(wildcard h4n4-modules/src/*.cpp)) + # -------------------------------------------------------------- # Hampton Harmonics @@ -741,11 +847,12 @@ PLUGIN_FILES += $(wildcard MindMeldModular/src/*.cpp) PLUGIN_FILES += $(wildcard MindMeldModular/src/comp/*.cpp) PLUGIN_FILES += $(wildcard MindMeldModular/src/EqMaster/*.cpp) PLUGIN_FILES += $(wildcard MindMeldModular/src/MixMaster/*.cpp) +PLUGIN_FILES += $(wildcard MindMeldModular/src/PatchSet/*.cpp) PLUGIN_FILES += $(wildcard MindMeldModular/src/ShapeMaster/*.cpp) PLUGIN_FILES += $(wildcard MindMeldModular/src/Utilities/*.cpp) # modules/types which are present in other plugins -MINDMELD_CUSTOM = printNote +MINDMELD_CUSTOM = Trigger printNote # -------------------------------------------------------------- # ML_modules @@ -764,6 +871,14 @@ PLUGIN_FILES += $(filter-out MockbaModular/src/plugin.cpp MockbaModular/src/Mock # modules/types which are present in other plugins MOCKBAMODULAR_CUSTOM = Blank Comparator +MINIPLUGIN_FILES += MockbaModular/src/CZOsc.cpp +MINIPLUGIN_FILES += MockbaModular/src/Filtah.cpp +MINIPLUGIN_FILES += MockbaModular/src/MaugOsc.cpp +MINIPLUGIN_FILES += MockbaModular/src/Mixah.cpp +MINIPLUGIN_FILES += MockbaModular/src/Pannah.cpp +MINIPLUGIN_FILES += MockbaModular/src/ReVoltah.cpp +MINIPLUGIN_FILES += MockbaModular/src/Shapah.cpp + # -------------------------------------------------------------- # Mog @@ -824,6 +939,9 @@ PARABLE_CUSTOM = Clouds CustomPanel CloudsWidget FreezeLight clouds stmlib PLUGIN_FILES += $(filter-out PathSet/src/plugin.cpp,$(wildcard PathSet/src/*.cpp)) +# modules/types which are present in other plugins +PATHSET_CUSTOM = PitchShifter + # -------------------------------------------------------------- # PinkTrombone @@ -847,6 +965,14 @@ PRISM_CUSTOM = bogaudio Scale PLUGIN_FILES += $(filter-out rackwindows/src/plugin.cpp,$(wildcard rackwindows/src/*.cpp)) +# -------------------------------------------------------------- +# RebelTech + +PLUGIN_FILES += $(filter-out RebelTech/src/plugin.cpp,$(wildcard RebelTech/src/*.cpp)) + +# modules/types which are present in other plugins +REBELTECH_CUSTOM = BefacoInputPort BefacoOutputPort + # -------------------------------------------------------------- # repelzen @@ -855,6 +981,11 @@ PLUGIN_FILES += $(filter-out repelzen/src/repelzen.cpp,$(wildcard repelzen/src/* # modules/types which are present in other plugins REPELZEN_CUSTOM = Blank Mixer Werner tanh_pade +# -------------------------------------------------------------- +# Sapphire + +PLUGIN_FILES += $(filter-out Sapphire/src/plugin.cpp,$(wildcard Sapphire/src/*.cpp)) + # -------------------------------------------------------------- # sonusmodular @@ -876,13 +1007,114 @@ STARLINGVIA_CUSTOM = Scanner PLUGIN_FILES += $(filter-out stocaudio/src/plugin.cpp,$(wildcard stocaudio/src/*.cpp)) # -------------------------------------------------------------- +# stoermelder-packone + +STOERMELDER_PACKONE_IGNORED = pluginsettings + +# will never work +STOERMELDER_PACKONE_IGNORED += AudioInterface64 + +# maybe? +STOERMELDER_PACKONE_IGNORED += MidiCat MidiCatCtx MidiCatMem MidiKey MidiMon MidiPlug MidiStep + +PLUGIN_FILES += $(filter-out $(STOERMELDER_PACKONE_IGNORED:%=stoermelder-packone/src/%.cpp),$(wildcard stoermelder-packone/src/*.cpp stoermelder-packone/src/mb/*.cpp)) + +# modules/types which are present in other plugins +STOERMELDER_PACKONE_CUSTOM = LongPressButton +STOERMELDER_PACKONE_CUSTOM_PER_FILE = InputLedDisplay IntermixEnvModule + +# -------------------------------------------------------------- +# surgext + +PLUGIN_FILES += $(filter-out surgext/src/SurgeXT.cpp,$(wildcard surgext/src/*.cpp)) +PLUGIN_FILES += surgext-helper/surgext-helper.cpp + +# modules/types which are present in other plugins +SURGEXT_CUSTOM = HysteresisProcessing Patch SolverType Tunings Wavetable ghc clouds plaits stmlib + +SURGEXT_FLAGS = $(filter-out -fsingle-precision-constant,$(filter-out -std=gnu++11,$(BUILD_CXX_FLAGS))) +SURGEXT_FLAGS += $(NOFINITE_FLAGS) +SURGEXT_FLAGS += -std=gnu++17 +SURGEXT_FLAGS += -DTIXML_USE_STL=1 +SURGEXT_FLAGS += \ + -Isurgext/libs/sst/sst-basic-blocks/include \ + -Isurgext/surge/src/common \ + -Isurgext/surge/src/common/dsp \ + -Isurgext/surge/src/common/dsp/filters \ + -Isurgext/surge/src/common/dsp/vembertech \ + -Isurgext/surge/src/common/dsp/utilities \ + -Isurgext/surge/src/common/dsp/oscillators \ + -Isurgext/surge/src/common/dsp/modulators \ + -Isurgext/surge/src/surge-testrunner \ + -Isurgext/surge/libs/sst/sst-filters/include \ + -Isurgext/surge/libs/sst/sst-cpputils/include \ + -Isurgext/surge/libs/sst/sst-waveshapers/include \ + -Isurgext/surge/libs/sst/sst-plugininfra/include \ + -Isurgext/surge/libs/sst/sst-plugininfra/libs/tinyxml/include \ + -Isurgext/surge/libs/sst/sst-plugininfra/libs/filesystem \ + -Isurgext/surge/libs/fmt/include \ + -Isurgext/surge/libs/LuaJitLib/LuaJIT/src \ + -Isurgext/surge/libs/strnatcmp \ + -Isurgext/surge/src/headless \ + -Isurgext/surge/libs/tuning-library/include \ + -I../deps/surge-build/libs/sst/sst-plugininfra/libs/filesystem/include \ + -include limits \ + -include cstdint \ + -DSURGE_COMPILE_BLOCK_SIZE=8 \ + -DSURGE_SKIP_ODDSOUND_MTS \ + -DHAS_LUA=0 \ + -DHAS_JUCE=0 \ + -DSKIP_JUCE=1 + +ifneq ($(DEBUG),true) +SURGEXT_FLAGS += -DRELEASE=1 +endif + +ifeq ($(MACOS),true) +SURGEXT_FLAGS += -Wno-undefined-bool-conversion -Wno-unused-variable -Wno-reorder -Wno-char-subscripts -Wno-sign-compare -Wno-ignored-qualifiers -Wno-c++17-extensions -Wno-unused-private-field +SURGEXT_FLAGS += -DMAC +else ifeq ($(WINDOWS),true) +SURGEXT_FLAGS += -Wno-suggest-override -Wno-sign-compare -Wno-ignored-qualifiers -Wno-unused-variable -Wno-char-subscripts -Wno-reorder -Wno-int-in-bool-context +SURGEXT_FLAGS += -DWINDOWS +SURGEXT_FLAGS += -DSKIP_MINGW_FORMAT +else +SURGEXT_FLAGS += -Wno-unused-value -Wno-suggest-override -Wno-implicit-fallthrough -Wno-ignored-qualifiers +SURGEXT_FLAGS += -Wno-nonnull-compare -Wno-sign-compare -Wno-char-subscripts -Wno-unused-variable -Wno-unused-but-set-variable -Wno-reorder -Wno-multichar +SURGEXT_FLAGS += -DLINUX +SURGEXT_FLAGS += -Isurge/src/linux +endif +SURGEXT_FLAGS += -DSURGE_RACK_BASE_VERSION=XT1-0-1 +SURGEXT_FLAGS += -DSURGE_RACK_PLUG_VERSION=Cardinal +SURGEXT_FLAGS += -DSURGE_RACK_SURGE_VERSION=Cardinal + +SURGEXT_FLAGS += -I$(abspath ../carla/source/modules) + +MINIPLUGIN_FILES += surgext/src/Delay.cpp +MINIPLUGIN_FILES += surgext/src/DelayLineByFreq.cpp +MINIPLUGIN_FILES += surgext/src/DelayLineByFreqExpanded.cpp +MINIPLUGIN_FILES += surgext/src/EGxVCA.cpp +MINIPLUGIN_FILES += surgext/src/FX.cpp +MINIPLUGIN_FILES += surgext/src/LFO.cpp +MINIPLUGIN_FILES += surgext/src/Mixer.cpp +MINIPLUGIN_FILES += surgext/src/ModMatrix.cpp +MINIPLUGIN_FILES += surgext/src/QuadAD.cpp +MINIPLUGIN_FILES += surgext/src/QuadLFO.cpp +MINIPLUGIN_FILES += surgext/src/VCO.cpp +MINIPLUGIN_FILES += surgext/src/VCF.cpp +MINIPLUGIN_FILES += surgext/src/Waveshaper.cpp +MINIPLUGIN_FILES += surgext/src/XTModule.cpp +MINIPLUGIN_FILES += surgext/src/XTModuleWidget.cpp +MINIPLUGIN_FILES += surgext/src/XTStyle.cpp +MINIPLUGIN_FILES += surgext-helper/surgext-helper.cpp + +# -------------------------------------------------------------- # unless_modules PLUGIN_FILES += $(filter-out unless_modules/src/unless.cpp,$(wildcard unless_modules/src/*.cpp)) # modules/types which are present in other plugins -UNLESS_MODULES_CUSTOM = Selection +UNLESS_MODULES_CUSTOM = Selection sign # -------------------------------------------------------------- # ValleyAudio @@ -956,6 +1188,58 @@ PLUGIN_BINARIES += ValleyAudio/src/VOICE_6.bin PLUGIN_BINARIES += ValleyAudio/src/VOX_MACH.bin PLUGIN_BINARIES += ValleyAudio/src/XFADE.bin +# MINIPLUGIN_FILES += ValleyAudio/src/PlainText.cpp +# MINIPLUGIN_FILES += ValleyAudio/src/SteppedSlider.cpp +# MINIPLUGIN_FILES += ValleyAudio/src/ValleyChoiceMenu.cpp +# MINIPLUGIN_FILES += ValleyAudio/src/Common/FreqLUT.cpp +# MINIPLUGIN_FILES += ValleyAudio/src/Common/Utilities.cpp +# MINIPLUGIN_FILES += ValleyAudio/src/Common/DSP/OnePoleFilters.cpp +# MINIPLUGIN_FILES += ValleyAudio/src/Common/DSP/OTAFilter.cpp +# MINIPLUGIN_FILES += ValleyAudio/src/Common/SIMD/QuadOsc.cpp +# MINIPLUGIN_FILES += ValleyAudio/src/Common/SIMD/VecLoopingADSR.cpp +# MINIPLUGIN_FILES += ValleyAudio/src/Common/SIMD/VecOnePoleFilters.cpp +# MINIPLUGIN_FILES += ValleyAudio/src/Common/SIMD/VecOTAFilter.cpp +# MINIPLUGIN_FILES += ValleyAudio/src/Dexter/Dexter.cpp +# MINIPLUGIN_FILES += ValleyAudio/src/Dexter/DexterRoutingMatrix.cpp +# MINIPLUGIN_FILES += ValleyAudio/src/Dexter/Osc4Core_SIMD.cpp +# MINIPLUGIN_FILES += ValleyAudio/src/Interzone/Interzone.cpp + +# MINIPLUGIN_BINARIES += ValleyAudio/src/ADD_BANK1.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/ADD_SAW.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/ADD_SINE.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/ADD_SQR.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/ALTOSAX.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/AM_HARM.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/BASIC.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/BITCRUSH1.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/BITCRUSH2.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/BI_PULSE.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/CELLO_1.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/CELLO_2.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/CHIP_1.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/CHIP_2.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/OBOE.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/OPAL.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/OVERTONE1.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/OVERTONE2.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/PIANO.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/PLUCK.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/PWM.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/SAW_GAP1.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/SAW_GAP2.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/SINE_HARM.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/SWEEPHARM.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/SYMMETRY.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/TEE_EKS.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/THEREMIN.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/VIDEOGAME.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/VIOLIN.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/VOICE_1.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/VOICE_2.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/VOICE_3.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/VOICE_4.bin +# MINIPLUGIN_BINARIES += ValleyAudio/src/VOICE_5.bin + # modules/types which are present in other plugins VALLEYAUDIO_CUSTOM = $(DRWAV) DigitalDisplay VALLEYAUDIO_CUSTOM_PER_FILE = TempoKnob @@ -966,7 +1250,7 @@ VALLEYAUDIO_CUSTOM_PER_FILE = TempoKnob PLUGIN_FILES += $(filter-out voxglitch/src/plugin.cpp,$(wildcard voxglitch/src/*.cpp)) # modules/types which are present in other plugins -VOXGLITCH_CUSTOM = $(DRWAV) ADSR AudioFile Looper Readout +VOXGLITCH_CUSTOM = ADSR AudioFile Looper Readout VOXGLITCH_CUSTOM_PER_FILE = AudioBuffer GateSequencer Grain SamplePlayer Sequencer SequencerDisplay VoltageSequencer # -------------------------------------------------------------- @@ -989,127 +1273,36 @@ PLUGIN_FILES += $(filter-out ZZC/src/ZZC.cpp ZZC/src/WavetablePlayer.cpp,$(wildc # modules/types which are present in other plugins ZZC_CUSTOM = Clock LowFrequencyOscillator -# -------------------------------------------------------------- - -endif # !NOPLUGINS - # -------------------------------------------------------------- # Build setup -BUILD_DIR = ../build/plugins - -ifeq ($(MACOS),true) -BASE_FLAGS += -DARCH_MAC -else ifeq ($(WINDOWS),true) -BASE_FLAGS += -DARCH_WIN +ifeq ($(HEADLESS),true) +BUILD_DIR = ../build-headless/plugins else -BASE_FLAGS += -DARCH_LIN +BUILD_DIR = ../build/plugins endif BASE_FLAGS += -DBUILDING_PLUGIN_MODULES -BASE_FLAGS += -I../dpf/dgl/src/nanovg -BASE_FLAGS += -I../dpf/distrho - -BASE_FLAGS += -I../include -BASE_FLAGS += -I../include/osdialog-stub -BASE_FLAGS += -I../include/simd-compat - -ifeq ($(HAVE_X11),true) -BASE_FLAGS += -DHAVE_X11 -endif - -ifeq ($(SYSDEPS),true) -BASE_FLAGS += -DCARDINAL_SYSDEPS -BASE_FLAGS += $(shell $(PKG_CONFIG) --cflags jansson libarchive samplerate speexdsp) -BASE_FLAGS += -I../deps/sysroot/include -else -BASE_FLAGS += -DZSTDLIB_VISIBILITY= -BASE_FLAGS += -I../src/Rack/dep/include -endif - -BASE_FLAGS += -I../src -BASE_FLAGS += -I../src/Rack/include -BASE_FLAGS += -I../src/Rack/include/dsp -BASE_FLAGS += -I../src/Rack/dep/filesystem/include -# # BASE_FLAGS += -I../src/Rack/dep/fuzzysearchdatabase/src -BASE_FLAGS += -I../src/Rack/dep/glfw/include -BASE_FLAGS += -I../src/Rack/dep/nanosvg/src -BASE_FLAGS += -I../src/Rack/dep/oui-blendish -BASE_FLAGS += -I../src/Rack/dep/pffft - -ifeq ($(DEBUG),true) -BASE_FLAGS += -UDEBUG -ifeq ($(WASM),true) -# SSE must always be enabled on wasm, even in debug builds -BASE_FLAGS += -msse -msse2 -msse3 -msimd128 -endif -endif - -ifeq ($(HEADLESS),true) -BASE_FLAGS += -DHEADLESS -ifeq ($(WITH_LTO),true) -BASE_FLAGS += -ffat-lto-objects -endif -endif +BASE_FLAGS += -I$(abspath $(ROOT)/include/osdialog-stub) ifeq ($(BSD)$(WASM),true) BASE_FLAGS += -D'aligned_alloc_16(ptr)'='aligned_alloc(16,ptr)' BASE_FLAGS += -D'aligned_free_16(ptr)'='free(ptr)' endif -ifneq ($(WASM),true) -ifneq ($(HAIKU),true) -BASE_FLAGS += -pthread -endif -endif - -ifeq ($(WINDOWS),true) -BASE_FLAGS += -D_USE_MATH_DEFINES -BASE_FLAGS += -DWIN32_LEAN_AND_MEAN -BASE_FLAGS += -I../include/mingw-compat -BASE_FLAGS += -I../include/mingw-std-threads -endif - -ifeq ($(NOPLUGINS),true) -BASE_FLAGS += -DNOPLUGINS -endif - -ifeq ($(USE_GLES2),true) -BASE_FLAGS += -DNANOVG_GLES2_FORCED -else ifeq ($(USE_GLES3),true) -BASE_FLAGS += -DNANOVG_GLES3_FORCED -endif - ifeq ($(shell $(PKG_CONFIG) --exists sndfile && echo true),true) BASE_FLAGS += -DHAVE_SNDFILE endif -BUILD_C_FLAGS += -std=gnu11 -BUILD_C_FLAGS += -fno-finite-math-only -fno-strict-aliasing -BUILD_CXX_FLAGS += -fno-finite-math-only -fno-strict-aliasing - -ifneq ($(MACOS),true) -BUILD_CXX_FLAGS += -faligned-new -Wno-abi +ifeq ($(HAVE_X11),true) +BASE_FLAGS += -DHAVE_X11 endif -# Rack code is not tested for this flag, unset it -BUILD_CXX_FLAGS += -U_GLIBCXX_ASSERTIONS -Wp,-U_GLIBCXX_ASSERTIONS - -# Ignore bad behaviour from Rack API -BUILD_CXX_FLAGS += -Wno-format-security - -ifeq ($(WASM),true) -BUILD_CXX_FLAGS += -fexceptions -endif +# Use this for any plugins that rely on NaN presence +NOFINITE_FLAGS = -fno-finite-math-only -fno-strict-aliasing # -------------------------------------------------------------- -# lots of warnings from VCV side - -BASE_FLAGS += -Wno-unused-parameter -BASE_FLAGS += -Wno-unused-variable - -# -------------------------------------------------------------- -# also from plugins +# lots of warnings from plugins BASE_FLAGS += -Wno-deprecated-declarations @@ -1134,29 +1327,46 @@ ifeq ($(WASM),true) CARLA_FLAGS += -DDISTRHO_RUNNER_INDIRECT_WASM_CALLS endif +# -------------------------------------------------------------- +# RTNeural flags, used in AIDA-X + +RTNEURAL_FLAGS = -std=gnu++17 +RTNEURAL_FLAGS += -DBiquad=AidaBiquad +RTNEURAL_FLAGS += -DEigen=Aida_Eigen +RTNEURAL_FLAGS += -Dconst_blas_data_mapper=Aida_const_blas_data_mapper +RTNEURAL_FLAGS += -Devaluator=Aida_evaluator +RTNEURAL_FLAGS += -DSKIP_MINGW_FORMAT +RTNEURAL_FLAGS += -DRTNEURAL_DEFAULT_ALIGNMENT=16 +RTNEURAL_FLAGS += -DRTNEURAL_USE_EIGEN=1 + +ifeq ($(WASM),true) +RTNEURAL_FLAGS += -DEIGEN_DONT_VECTORIZE=1 +endif + +RTNEURAL_FLAGS += -ICardinal/src/AIDA-X/RTNeural +RTNEURAL_FLAGS += -ICardinal/src/AIDA-X/RTNeural/modules/Eigen + # -------------------------------------------------------------- # Build targets -TARGET = plugins.a +ifeq ($(HEADLESS),true) +TARGET_SUFFIX = -headless +endif -all: $(TARGET) +TARGETS = plugins$(TARGET_SUFFIX).a plugins-mini$(TARGET_SUFFIX).a + +all: $(TARGETS) +ifneq ($(HEADLESS),true) + $(MAKE) HEADLESS=true plugins-mini-headless.a +endif clean: - rm -f $(TARGET) + rm -f *.a rm -rf $(BUILD_DIR) + rm -rf surgext/build # -------------------------------------------------------------- -ifeq ($(NOPLUGINS),true) -PLUGIN_LIST = Cardinal Fundamental ZamAudio - -RESOURCE_FILES = \ - $(wildcard Cardinal/res/*.svg) \ - $(wildcard Fundamental/res/*.svg) \ - $(wildcard Fundamental/res/components/*.svg) \ - $(wildcard ZamAudio/res/*.svg) \ - Fundamental/presets -else PLUGIN_LIST = $(subst /plugin.json,,$(wildcard */plugin.json)) UNWANTED_FILES = HetrickCV/res/illustrator - deprecated/MyModule.svg @@ -1170,6 +1380,8 @@ RESOURCE_FILES = \ $(wildcard */res/*.svg) \ $(wildcard */res/*/*.svg) \ $(wildcard */res/*/*/*.svg) \ + $(wildcard */res/*/*/*/*.svg) \ + $(wildcard */res/*/*/*/*/*.svg) \ $(wildcard */res/*.otf) \ $(wildcard */res/*/*.otf) \ $(wildcard */res/*/*/*.otf) \ @@ -1194,44 +1406,383 @@ RESOURCE_FILES += Meander/res RESOURCE_FILES += Mog/res RESOURCE_FILES += nonlinearcircuits/res RESOURCE_FILES += ParableInstruments/res/Neil.png +RESOURCE_FILES += surgext/build/surge-data/configuration.xml +RESOURCE_FILES += surgext/build/surge-data/fx_presets +RESOURCE_FILES += surgext/build/surge-data/wavetables +RESOURCE_FILES += surgext/build/surge-data/windows.wt +RESOURCE_FILES += surgext/patches +RESOURCE_FILES += $(wildcard surgext/res/xt/fonts/quicksand/*.ttf) RESOURCE_FILES += $(wildcard unless_modules/art/*.art) RESOURCE_FILES += $(wildcard unless_modules/art/svg/*/*.svg) RESOURCE_FILES += $(wildcard unless_modules/font/*.ttf) # RESOURCE_FILES += $(wildcard unless_modules/manual/*) -endif +JACK_RESOURCES = $(CURDIR)/surgext/build/surge-data/configuration.xml +JACK_RESOURCES += $(CURDIR)/surgext/build/surge-data/fx_presets +JACK_RESOURCES += $(CURDIR)/surgext/build/surge-data/wavetables +JACK_RESOURCES += $(CURDIR)/surgext/build/surge-data/windows.wt + +RESOURCE_FILES += $(wildcard Cardinal/res/*.png) RESOURCE_FILES += Cardinal/res/Miku/Miku.png +MINIPLUGIN_LIST = Cardinal +MINIPLUGIN_LIST += AriaModules +MINIPLUGIN_LIST += AudibleInstruments +MINIPLUGIN_LIST += BogaudioModules +MINIPLUGIN_LIST += Fundamental +MINIPLUGIN_LIST += MockbaModular +MINIPLUGIN_LIST += surgext +# MINIPLUGIN_LIST += ValleyAudio + +MINIRESOURCE_FILES = AriaModules/res/components/jack-transparent.svg +MINIRESOURCE_FILES += AriaModules/res/components/pushbutton-500-off.svg +MINIRESOURCE_FILES += AriaModules/res/components/pushbutton-500-on.svg +MINIRESOURCE_FILES += AriaModules/res/components/pushbutton-500-pink.svg +MINIRESOURCE_FILES += AriaModules/res/components/screw.svg +MINIRESOURCE_FILES += AriaModules/res/faceplates/Spleet.svg +MINIRESOURCE_FILES += AriaModules/res/faceplates/Swerge.svg +MINIRESOURCE_FILES += AriaModules/res/signature/signature.svg + +MINIRESOURCE_FILES += AudibleInstruments/res/Plaits.svg +# MINIRESOURCE_FILES += AudibleInstruments/res/hdad-segment14-1.002/Segment14.ttf + +MINIRESOURCE_FILES += BogaudioModules/res/AD-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Additator-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/AddrSeq-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/AddrSeqX-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/ADSR-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/AMRM-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Analyzer-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/AnalyzerXL.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Arp-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/ASR-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Assign-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Bool-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/button_18px_0.svg +MINIRESOURCE_FILES += BogaudioModules/res/button_18px_1_green.svg +MINIRESOURCE_FILES += BogaudioModules/res/button_18px_1_orange.svg +MINIRESOURCE_FILES += BogaudioModules/res/button_18px_1.svg +MINIRESOURCE_FILES += BogaudioModules/res/button_9px_0.svg +MINIRESOURCE_FILES += BogaudioModules/res/button_9px_1_green.svg +MINIRESOURCE_FILES += BogaudioModules/res/button_9px_1.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Chirp-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Clpr-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Cmp-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/CmpDist-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/CVD-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/DADSRH-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/DADSRHPlus-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Detune-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/DGate-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Edge-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/EightFO-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/EightOne-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/EQ-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/EQS-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/FFB-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/FlipFlop-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/FMOp-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Follow-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/FourFO-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/FourMan-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Inv-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/knob_16px-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/knob_19px-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/knob_26px-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/knob_29px-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/knob_38px-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/knob_45px-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/knob_68px-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Lag-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/LFO-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Lgsw-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/LLFO-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/LLPG-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Lmtr-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/LPG-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/LVCF-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/LVCO-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Manual-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/MegaGate-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Mix1-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Mix2-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Mix4-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Mix4x-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Mix8-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Mix8x-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Mono-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Mult-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Mumix-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Mute8-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/Noise-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Nsgt-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/Offset-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/OneEight-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Pan-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/PEQ14-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/PEQ14XF-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/PEQ14XR-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/PEQ14XV-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/PEQ6-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/PEQ6XF-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/PEQ-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Pgmr-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/PgmrX-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/PolyCon16-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/PolyCon8-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/PolyMult-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/PolyOff16-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/PolyOff8-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/port-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Pressor-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Pulse-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Ranalyzer.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Reftone-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/RGate-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/SampleHold-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Shaper-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/ShaperPlus-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Sine-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Slew-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/slider_switch_2_14px_0.svg +MINIRESOURCE_FILES += BogaudioModules/res/slider_switch_2_14px_1.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Stack-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Sums-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/Switch-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Switch1616-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/Switch18-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Switch44-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Switch81-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Switch88-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Test-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Test2-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/TestExpanderBase-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/TestExpanderExtension-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/TestGl-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/TestVCF-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/UMix-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/Unison-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/VCA-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/VCAmp-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/VCF-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/VCM-dark.svg +MINIRESOURCE_FILES += BogaudioModules/res/VCO-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Velo-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Vish-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/VU-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Walk2-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/Walk-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/XCO-dark.svg +# MINIRESOURCE_FILES += BogaudioModules/res/XFade-dark.svg + +MINIRESOURCE_FILES += Cardinal/res/HostAudio.svg +MINIRESOURCE_FILES += Cardinal/res/HostCV.svg +MINIRESOURCE_FILES += Cardinal/res/HostMIDICC.svg +MINIRESOURCE_FILES += Cardinal/res/HostMIDIGate.svg +MINIRESOURCE_FILES += Cardinal/res/HostMIDIMap.svg +MINIRESOURCE_FILES += Cardinal/res/HostMIDI.svg +MINIRESOURCE_FILES += Cardinal/res/HostParameters.svg +MINIRESOURCE_FILES += Cardinal/res/HostParamsMap.svg +MINIRESOURCE_FILES += Cardinal/res/HostTime.svg + +MINIRESOURCE_FILES += Fundamental/presets +MINIRESOURCE_FILES += Fundamental/res/ADSR.svg +MINIRESOURCE_FILES += Fundamental/res/LFO.svg +MINIRESOURCE_FILES += Fundamental/res/Merge.svg +MINIRESOURCE_FILES += Fundamental/res/MidSide.svg +MINIRESOURCE_FILES += Fundamental/res/Noise.svg +MINIRESOURCE_FILES += Fundamental/res/Quantizer.svg +MINIRESOURCE_FILES += Fundamental/res/Random.svg +MINIRESOURCE_FILES += Fundamental/res/Scope.svg +MINIRESOURCE_FILES += Fundamental/res/Split.svg +MINIRESOURCE_FILES += Fundamental/res/Sum.svg +MINIRESOURCE_FILES += Fundamental/res/VCA-1.svg +MINIRESOURCE_FILES += Fundamental/res/VCF.svg +MINIRESOURCE_FILES += Fundamental/res/VCMixer.svg +MINIRESOURCE_FILES += Fundamental/res/VCO.svg +MINIRESOURCE_FILES += Fundamental/res/components/ADSR-bg.svg +MINIRESOURCE_FILES += Fundamental/res/components/button-off.svg +MINIRESOURCE_FILES += Fundamental/res/components/button-on.svg +MINIRESOURCE_FILES += Fundamental/res/components/knob-marker-small.svg +MINIRESOURCE_FILES += Fundamental/res/components/knob-marker.svg +MINIRESOURCE_FILES += Fundamental/res/components/knob-small.svg +MINIRESOURCE_FILES += Fundamental/res/components/knob.svg +MINIRESOURCE_FILES += Fundamental/res/components/port.svg +MINIRESOURCE_FILES += Fundamental/res/components/Quantizer-keyboard.svg +MINIRESOURCE_FILES += Fundamental/res/components/Scope-bg.svg + +MINIRESOURCE_FILES += MockbaModular/res/CZOsc.svg +MINIRESOURCE_FILES += MockbaModular/res/Empty_gray.svg +MINIRESOURCE_FILES += MockbaModular/res/Filtah.svg +MINIRESOURCE_FILES += MockbaModular/res/HSW_0.svg +MINIRESOURCE_FILES += MockbaModular/res/HSW_1.svg +MINIRESOURCE_FILES += MockbaModular/res/HSW_2.svg +MINIRESOURCE_FILES += MockbaModular/res/knob.svg +MINIRESOURCE_FILES += MockbaModular/res/MaugOsc.svg +MINIRESOURCE_FILES += MockbaModular/res/Mixah.svg +MINIRESOURCE_FILES += MockbaModular/res/Pannah.svg +MINIRESOURCE_FILES += MockbaModular/res/port.svg +MINIRESOURCE_FILES += MockbaModular/res/ReVoltah.svg +MINIRESOURCE_FILES += MockbaModular/res/screw.svg +MINIRESOURCE_FILES += MockbaModular/res/selector.svg +MINIRESOURCE_FILES += MockbaModular/res/Shapah.svg + +MINIRESOURCE_FILES += surgext/build/surge-data/configuration.xml +MINIRESOURCE_FILES += surgext/build/surge-data/windows.wt +MINIRESOURCE_FILES += surgext/res/xt/fonts/quicksand/Quicksand-Regular.ttf +MINIRESOURCE_FILES += surgext/res/xt/fonts/quicksand/Quicksand-Bold.ttf +MINIRESOURCE_FILES += surgext/res/xt/dark/components/fader_bg.svg +MINIRESOURCE_FILES += surgext/res/xt/dark/components/fader_bg_25.svg +MINIRESOURCE_FILES += surgext/res/xt/dark/components/fader_handle.svg +MINIRESOURCE_FILES += surgext/res/xt/dark/components/knob-9.svg +MINIRESOURCE_FILES += surgext/res/xt/dark/components/knob-12.svg +MINIRESOURCE_FILES += surgext/res/xt/dark/components/knob-14.svg +MINIRESOURCE_FILES += surgext/res/xt/dark/components/knob-16.svg +MINIRESOURCE_FILES += surgext/res/xt/dark/components/knob-pointer-9.svg +MINIRESOURCE_FILES += surgext/res/xt/dark/components/knob-pointer-12.svg +MINIRESOURCE_FILES += surgext/res/xt/dark/components/knob-pointer-14.svg +MINIRESOURCE_FILES += surgext/res/xt/dark/components/knob-pointer-16.svg +MINIRESOURCE_FILES += surgext/res/xt/dark/components/mod-button.svg +MINIRESOURCE_FILES += surgext/res/xt/dark/components/port.svg +MINIRESOURCE_FILES += surgext/res/xt/dark/panels/other/EGLFO.svg +MINIRESOURCE_FILES += surgext/res/xt/dark/panels/other/Matrix.svg +MINIRESOURCE_FILES += surgext/res/xt/dark/panels/other/Mixer.svg +MINIRESOURCE_FILES += surgext/res/xt/dark/panels/vco/BlankVCO.svg +MINIRESOURCE_FILES += surgext/res/xt/glyphs/lt_0.svg +MINIRESOURCE_FILES += surgext/res/xt/glyphs/lt_1.svg +MINIRESOURCE_FILES += surgext/res/xt/glyphs/lt_2.svg +MINIRESOURCE_FILES += surgext/res/xt/glyphs/lt_3.svg +MINIRESOURCE_FILES += surgext/res/xt/glyphs/lt_4.svg +MINIRESOURCE_FILES += surgext/res/xt/glyphs/lt_5.svg +MINIRESOURCE_FILES += surgext/res/xt/glyphs/lt_6.svg +MINIRESOURCE_FILES += surgext/res/xt/glyphs/lt_7.svg + +# MINIRESOURCE_FILES += ValleyAudio/res/DexterPanelDark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/InterzonePanelDark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/LightLEDButton80.svg +# MINIRESOURCE_FILES += ValleyAudio/res/PJ301MDarkSmallOut.svg +# MINIRESOURCE_FILES += ValleyAudio/res/PJ301MDarkSmall.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo0.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo1.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo2.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo3.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo4.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo5.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo6.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo7.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo8.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo9.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo10.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo11.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo12.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo13.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo14.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo15.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo16.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo17.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo18.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo19.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo20.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo21.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo22.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo0Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo1Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo2Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo3Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo4Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo5Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo6Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo7Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo8Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo9Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo10Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo11Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo12Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo13Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo14Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo15Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo16Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo17Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo18Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo19Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo20Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo21Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/algo22Dark.svg +# MINIRESOURCE_FILES += ValleyAudio/res/din1451alt.ttf +# MINIRESOURCE_FILES += ValleyAudio/res/sliderBlue.svg +# MINIRESOURCE_FILES += ValleyAudio/res/sliderGreen.svg +# MINIRESOURCE_FILES += ValleyAudio/res/sliderRed.svg +# MINIRESOURCE_FILES += ValleyAudio/res/sliderOrange.svg +# MINIRESOURCE_FILES += ValleyAudio/res/sliderYellow.svg +# MINIRESOURCE_FILES += ValleyAudio/res/valleySliderBackground.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Med/Rogan1PSBlueMed.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Med/Rogan1PSBlueMed-fg.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Med/Rogan1PSBlueMedSmall.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Med/Rogan1PSBlueMedSmall-fg.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Med/Rogan1PSMed-bg.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Med/Rogan1PSMedSmall-bg.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Med/Rogan1PSGreenMed.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Med/Rogan1PSGreenMed-fg.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Med/Rogan1PSOrangeMed.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Med/Rogan1PSOrangeMed-fg.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Med/Rogan1PSRedMed.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Med/Rogan1PSRedMed-fg.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Med/Rogan1PSPurpleMed.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Med/Rogan1PSPurpleMed-fg.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Small/Rogan1PSSmall-bg.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Small/Rogan1PSBlueSmall.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Small/Rogan1PSBlueSmall-fg.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Small/Rogan1PSOrangeSmall.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Small/Rogan1PSOrangeSmall-fg.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Small/Rogan1PSGreenSmall.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Small/Rogan1PSGreenSmall-fg.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Small/Rogan1PSRedSmall.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Small/Rogan1PSRedSmall-fg.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Small/Rogan1PSMustardSmall.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Small/Rogan1PSMustardSmall-fg.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Small/Rogan1PSPurpleSmall.svg +# MINIRESOURCE_FILES += ValleyAudio/res/v2/Small/Rogan1PSPurpleSmall-fg.svg + # MOD builds only have LV2 main and FX variant ifeq ($(MOD_BUILD),true) LV2_RESOURCES = $(PLUGIN_LIST:%=../bin/Cardinal.lv2/resources/PluginManifests/%.json) LV2_RESOURCES += $(PLUGIN_LIST:%=../bin/CardinalFX.lv2/resources/PluginManifests/%.json) +LV2_RESOURCES += $(MINIPLUGIN_LIST:%=../bin/CardinalMini.lv2/resources/PluginManifests/%.json) LV2_RESOURCES += $(RESOURCE_FILES:%=../bin/Cardinal.lv2/resources/%) LV2_RESOURCES += $(RESOURCE_FILES:%=../bin/CardinalFX.lv2/resources/%) +LV2_RESOURCES += $(MINIRESOURCE_FILES:%=../bin/CardinalMini.lv2/resources/%) # MOD builds only have LV2 FX variant for now else ifeq ($(WASM),true) LV2_RESOURCES = $(PLUGIN_LIST:%=../bin/CardinalNative.lv2/resources/PluginManifests/%.json) +LV2_RESOURCES += $(MINIPLUGIN_LIST:%=../bin/CardinalMini.lv2/resources/PluginManifests/%.json) LV2_RESOURCES += $(RESOURCE_FILES:%=../bin/CardinalNative.lv2/resources/%) +LV2_RESOURCES += $(MINIRESOURCE_FILES:%=../bin/CardinalMini.lv2/resources/%) else LV2_RESOURCES = $(PLUGIN_LIST:%=../bin/Cardinal.lv2/resources/PluginManifests/%.json) LV2_RESOURCES += $(PLUGIN_LIST:%=../bin/CardinalFX.lv2/resources/PluginManifests/%.json) +LV2_RESOURCES += $(MINIPLUGIN_LIST:%=../bin/CardinalMini.lv2/resources/PluginManifests/%.json) LV2_RESOURCES += $(PLUGIN_LIST:%=../bin/CardinalSynth.lv2/resources/PluginManifests/%.json) LV2_RESOURCES += $(RESOURCE_FILES:%=../bin/Cardinal.lv2/resources/%) LV2_RESOURCES += $(RESOURCE_FILES:%=../bin/CardinalFX.lv2/resources/%) LV2_RESOURCES += $(RESOURCE_FILES:%=../bin/CardinalSynth.lv2/resources/%) +LV2_RESOURCES += $(MINIRESOURCE_FILES:%=../bin/CardinalMini.lv2/resources/%) ifeq ($(MACOS),true) VST2_RESOURCES = $(PLUGIN_LIST:%=../bin/CardinalFX.vst/Contents/Resources/PluginManifests/%.json) VST2_RESOURCES += $(PLUGIN_LIST:%=../bin/CardinalSynth.vst/Contents/Resources/PluginManifests/%.json) VST2_RESOURCES += $(RESOURCE_FILES:%=../bin/CardinalFX.vst/Contents/Resources/%) VST2_RESOURCES += $(RESOURCE_FILES:%=../bin/CardinalSynth.vst/Contents/Resources/%) -CLAP_RESOURCES = $(PLUGIN_LIST:%=../bin/CardinalFX.clap/Contents/Resources/PluginManifests/%.json) +CLAP_RESOURCES = $(PLUGIN_LIST:%=../bin/Cardinal.clap/Contents/Resources/PluginManifests/%.json) +CLAP_RESOURCES += $(PLUGIN_LIST:%=../bin/CardinalFX.clap/Contents/Resources/PluginManifests/%.json) +CLAP_RESOURCES += $(PLUGIN_LIST:%=../bin/CardinalSynth.clap/Contents/Resources/PluginManifests/%.json) +CLAP_RESOURCES += $(RESOURCE_FILES:%=../bin/Cardinal.clap/Contents/Resources/%) CLAP_RESOURCES += $(RESOURCE_FILES:%=../bin/CardinalFX.clap/Contents/Resources/%) +CLAP_RESOURCES += $(RESOURCE_FILES:%=../bin/CardinalSynth.clap/Contents/Resources/%) else VST2_RESOURCES = $(PLUGIN_LIST:%=../bin/Cardinal.vst/resources/PluginManifests/%.json) VST2_RESOURCES += $(RESOURCE_FILES:%=../bin/Cardinal.vst/resources/%) @@ -1248,7 +1799,7 @@ VST3_RESOURCES += $(RESOURCE_FILES:%=../bin/CardinalSynth.vst3/Contents/Resource endif -resources: $(LV2_RESOURCES) $(VST2_RESOURCES) $(VST3_RESOURCES) $(CLAP_RESOURCES) +resources: $(JACK_RESOURCES) $(LV2_RESOURCES) $(VST2_RESOURCES) $(VST3_RESOURCES) $(CLAP_RESOURCES) ../bin/Cardinal.lv2/resources/%: % -@mkdir -p "$(shell dirname $@)" @@ -1258,6 +1809,10 @@ resources: $(LV2_RESOURCES) $(VST2_RESOURCES) $(VST3_RESOURCES) $(CLAP_RESOURCES -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ +../bin/CardinalMini.lv2/resources/%: % + -@mkdir -p "$(shell dirname $@)" + $(SILENT)ln -sf $(abspath $<) $@ + ../bin/CardinalNative.lv2/resources/%: % -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ @@ -1267,9 +1822,17 @@ resources: $(LV2_RESOURCES) $(VST2_RESOURCES) $(VST3_RESOURCES) $(CLAP_RESOURCES $(SILENT)ln -sf $(abspath $<) $@ ifeq ($(MOD_BUILD),true) +../bin/Cardinal.lv2/resources/%.svg: %.svg ../deps/svg2stub.py + -@mkdir -p "$(shell dirname $@)" + $(SILENT)python3 ../deps/svg2stub.py $< $@ + ../bin/CardinalFX.lv2/resources/%.svg: %.svg ../deps/svg2stub.py -@mkdir -p "$(shell dirname $@)" $(SILENT)python3 ../deps/svg2stub.py $< $@ + +../bin/CardinalMini.lv2/resources/%.svg: %.svg ../deps/svg2stub.py + -@mkdir -p "$(shell dirname $@)" + $(SILENT)python3 ../deps/svg2stub.py $< $@ endif ../bin/Cardinal.lv2/resources/PluginManifests/%.json: %/plugin.json @@ -1280,6 +1843,10 @@ endif -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ +../bin/CardinalMini.lv2/resources/PluginManifests/%.json: %/plugin.json + -@mkdir -p "$(shell dirname $@)" + $(SILENT)ln -sf $(abspath $<) $@ + ../bin/CardinalNative.lv2/resources/PluginManifests/%.json: %/plugin.json -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ @@ -1317,15 +1884,31 @@ ifeq ($(MACOS),true) -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ +../bin/CardinalSynth.vst/Contents/Resources/%: % + -@mkdir -p "$(shell dirname $@)" + $(SILENT)ln -sf $(abspath $<) $@ + +../bin/CardinalFX.vst/Contents/Resources/PluginManifests/%.json: %/plugin.json + -@mkdir -p "$(shell dirname $@)" + $(SILENT)ln -sf $(abspath $<) $@ + +../bin/CardinalSynth.vst/Contents/Resources/PluginManifests/%.json: %/plugin.json + -@mkdir -p "$(shell dirname $@)" + $(SILENT)ln -sf $(abspath $<) $@ + +../bin/Cardinal.clap/Contents/Resources/%: % + -@mkdir -p "$(shell dirname $@)" + $(SILENT)ln -sf $(abspath $<) $@ + ../bin/CardinalFX.clap/Contents/Resources/%: % -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ -../bin/CardinalSynth.vst/Contents/Resources/%: % +../bin/CardinalSynth.clap/Contents/Resources/%: % -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ -../bin/CardinalFX.vst/Contents/Resources/PluginManifests/%.json: %/plugin.json +../bin/Cardinal.clap/Contents/Resources/PluginManifests/%.json: %/plugin.json -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ @@ -1333,7 +1916,7 @@ ifeq ($(MACOS),true) -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ -../bin/CardinalSynth.vst/Contents/Resources/PluginManifests/%.json: %/plugin.json +../bin/CardinalSynth.clap/Contents/Resources/PluginManifests/%.json: %/plugin.json -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ else @@ -1341,11 +1924,11 @@ else -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ -../bin/Cardinal.clap/resources/%: % +../bin/Cardinal.vst/resources/PluginManifests/%.json: %/plugin.json -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ -../bin/Cardinal.vst/resources/PluginManifests/%.json: %/plugin.json +../bin/Cardinal.clap/resources/%: % -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ @@ -1354,19 +1937,44 @@ else $(SILENT)ln -sf $(abspath $<) $@ endif +%/surgext/build/surge-data/configuration.xml: surgext/surge/resources/surge-shared/configuration.xml + -@mkdir -p "$(shell dirname $@)" + $(SILENT)ln -sf $(abspath $<) $@ + +%/surgext/build/surge-data/fx_presets: + -@mkdir -p "$@" + cp -R surgext/surge/resources/data/fx_presets/* $@/ + cp -R surgext/res/surge_extra_data/fx_presets/* $@/ + +%/surgext/build/surge-data/wavetables: surgext/surge/resources/data/wavetables + -@mkdir -p "$(shell dirname $@)" + $(SILENT)ln -sf $(abspath $<) $@ + +%/surgext/build/surge-data/windows.wt: surgext/surge/resources/surge-shared/windows.wt + -@mkdir -p "$(shell dirname $@)" + $(SILENT)ln -sf $(abspath $<) $@ + # -------------------------------------------------------------- # Build commands PLUGIN_OBJS = $(PLUGIN_FILES:%=$(BUILD_DIR)/%.o) PLUGIN_OBJS += $(PLUGIN_BINARIES:%=$(BUILD_DIR)/%.bin.o) +MINIPLUGIN_OBJS = $(MINIPLUGIN_FILES:%=$(BUILD_DIR)/%.o) +MINIPLUGIN_OBJS += $(MINIPLUGIN_BINARIES:%=$(BUILD_DIR)/%.bin.o) + .PRECIOUS: $(PLUGIN_BINARIES:%=$(BUILD_DIR)/%.bin.c) # function for custom module names macro custom_module_names = -D${1}=${2}${1} -Dmodel${1}=model${2}${1} -D${1}Widget=${2}${1}Widget custom_per_file_names = -D${1}=${2}_${1} -$(TARGET): $(PLUGIN_OBJS) +plugins$(TARGET_SUFFIX).a: $(PLUGIN_OBJS) + @echo "Creating $@" + $(SILENT)rm -f $@ + $(SILENT)$(AR) crs $@ $^ + +plugins-mini$(TARGET_SUFFIX).a: $(MINIPLUGIN_OBJS) @echo "Creating $@" $(SILENT)rm -f $@ $(SILENT)$(AR) crs $@ $^ @@ -1386,6 +1994,16 @@ $(BUILD_DIR)/plugins.cpp.o: plugins.cpp @echo "Compiling $<" $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ +$(BUILD_DIR)/plugins-mini.cpp.o: plugins-mini.cpp + -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" + @echo "Compiling $<" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ + +$(BUILD_DIR)/noplugins.cpp.o: plugins.cpp + -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" + @echo "Compiling $<" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ + $(BUILD_DIR)/Cardinal/%.cpp.o: Cardinal/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" @@ -1398,6 +2016,19 @@ $(BUILD_DIR)/Cardinal/%.cpp.o: Cardinal/%.cpp -Dstbrp_rect=stbrp_rect_cardinal \ $(CARLA_FLAGS) +$(BUILD_DIR)/Cardinal/src/AIDA-X.cpp.o: Cardinal/src/AIDA-X.cpp + -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" + @echo "Compiling $<" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + -DpluginInstance=pluginInstance__Cardinal \ + -Dstbrp_context=stbrp_context_cardinal \ + -Dstbrp_coord=stbrp_coord_cardinal \ + -Dstbtt_fontinfo=stbtt_fontinfo_cardinal \ + -Dstbrp_node=stbrp_node_cardinal \ + -Dstbrp_rect=stbrp_rect_cardinal \ + $(RTNEURAL_FLAGS) \ + $(CARLA_FLAGS) + $(BUILD_DIR)/21kHz/%.cpp.o: 21kHz/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" @@ -1420,6 +2051,13 @@ $(BUILD_DIR)/AaronStatic/%.cpp.o: AaronStatic/%.cpp -DpluginInstance=pluginInstance__AaronStatic \ -Dinit=init__AaronStatic +$(BUILD_DIR)/alefsbits/%.cpp.o: alefsbits/%.cpp + -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" + @echo "Compiling $<" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(foreach m,$(ALEFSBITS_CUSTOM),$(call custom_module_names,$(m),alefsbits)) \ + -DpluginInstance=pluginInstance__alefsbits + $(BUILD_DIR)/Algoritmarte/%.cpp.o: Algoritmarte/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" @@ -1483,12 +2121,11 @@ $(BUILD_DIR)/AudibleInstruments/%.o: AudibleInstruments/% $(BUILD_DIR)/Autinn/%.cpp.o: Autinn/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(NOFINITE_FLAGS) -c -o $@ \ $(foreach m,$(AUTINN_CUSTOM),$(call custom_module_names,$(m),Autinn)) \ -DpluginInstance=pluginInstance__Autinn \ -Dinit=init__Autinn - $(BUILD_DIR)/Axioma/%.cpp.o: Axioma/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" @@ -1499,7 +2136,7 @@ $(BUILD_DIR)/Axioma/%.cpp.o: Axioma/%.cpp $(BUILD_DIR)/BaconPlugs/%.cpp.o: BaconPlugs/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -std=gnu++17 -c -o $@ \ $(foreach m,$(BACON_CUSTOM),$(call custom_module_names,$(m),BaconPlugs)) \ -DpluginInstance=pluginInstance__Bacon \ -DDARK_BACON \ @@ -1562,7 +2199,7 @@ $(BUILD_DIR)/CatroModulo/src/%.cpp.o: CatroModulo/src/%.cpp $(BUILD_DIR)/cf/src/%.cpp.o: cf/src/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(NOFINITE_FLAGS) -c -o $@ \ $(foreach m,$(CF_CUSTOM),$(call custom_module_names,$(m),cf)) \ -DpluginInstance=pluginInstance__cf \ -Wno-misleading-indentation @@ -1570,7 +2207,7 @@ $(BUILD_DIR)/cf/src/%.cpp.o: cf/src/%.cpp $(BUILD_DIR)/ChowDSP/%.cpp.o: ChowDSP/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(NOFINITE_FLAGS) -c -o $@ \ $(foreach m,$(CHOWDSP_CUSTOM),$(call custom_module_names,$(m),ChowDSP)) \ -DpluginInstance=pluginInstance__ChowDSP \ -DUSE_EIGEN \ @@ -1579,6 +2216,14 @@ $(BUILD_DIR)/ChowDSP/%.cpp.o: ChowDSP/%.cpp -IChowDSP/lib/chowdsp_utils/modules/chowdsp_dsp/WDF \ -Wno-deprecated-copy +$(BUILD_DIR)/dBiz/src/%.cpp.o: dBiz/src/%.cpp + -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" + @echo "Compiling $<" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(foreach m,$(DBIZ_CUSTOM),$(call custom_module_names,$(m),dBiz)) \ + $(foreach m,$(DBIZ_CUSTOM_PER_FILE),$(call custom_per_file_names,$(m),dBiz_$(shell basename $*))) \ + -DpluginInstance=pluginInstance__dBiz + $(BUILD_DIR)/DrumKit/%.cpp.o: DrumKit/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" @@ -1588,6 +2233,14 @@ $(BUILD_DIR)/DrumKit/%.cpp.o: DrumKit/%.cpp -Dinit=init__DrumKit \ -Wno-sign-compare +$(BUILD_DIR)/EnigmaCurry/src/%.cpp.o: EnigmaCurry/src/%.cpp + -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" + @echo "Compiling $<" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(NOFINITE_FLAGS) -c -o $@ \ + $(foreach m,$(ENIGMACURRY_CUSTOM),$(call custom_module_names,$(m),EnigmaCurry)) \ + -DpluginInstance=pluginInstance__EnigmaCurry \ + -Wno-misleading-indentation + $(BUILD_DIR)/ESeries/%.cpp.o: ESeries/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" @@ -1612,7 +2265,7 @@ $(BUILD_DIR)/Extratone/src/%.cpp.o: Extratone/src/%.cpp $(BUILD_DIR)/FehlerFabrik/%.cpp.o: FehlerFabrik/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(NOFINITE_FLAGS) -c -o $@ \ $(foreach m,$(FEHLERFABRIK_CUSTOM),$(call custom_module_names,$(m),FehlerFabrik)) \ -DpluginInstance=pluginInstance__FehlerFabrik @@ -1620,7 +2273,7 @@ $(BUILD_DIR)/forsitan-modulare/%.cpp.o: forsitan-modulare/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ - $(foreach m,$(GLUETHEGIANT_CUSTOM),$(call custom_module_names,$(m),forsitan)) \ + $(foreach m,$(FORSITAN_CUSTOM),$(call custom_module_names,$(m),forsitan)) \ -DpluginInstance=pluginInstance__forsitan $(BUILD_DIR)/Fundamental/%.c.o: Fundamental/%.c @@ -1637,6 +2290,13 @@ $(BUILD_DIR)/Fundamental/%.cpp.o: Fundamental/%.cpp $(foreach m,$(FUNDAMENTAL_CUSTOM),$(call custom_module_names,$(m),Fundamental)) \ -DpluginInstance=pluginInstance__Fundamental +$(BUILD_DIR)/Fundamental/src/Scope.cpp.o: Fundamental/src/Scope.cpp + -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" + @echo "Compiling $<" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(NOFINITE_FLAGS) -c -o $@ \ + $(foreach m,$(FUNDAMENTAL_CUSTOM),$(call custom_module_names,$(m),Fundamental)) \ + -DpluginInstance=pluginInstance__Fundamental + $(BUILD_DIR)/GlueTheGiant/%.cpp.o: GlueTheGiant/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" @@ -1663,13 +2323,20 @@ $(BUILD_DIR)/GoodSheperd/%.cpp.o: GoodSheperd/%.cpp $(BUILD_DIR)/GrandeModular/%.cpp.o: GrandeModular/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(NOFINITE_FLAGS) -c -o $@ \ $(foreach m,$(GRANDEMODULAR_CUSTOM),$(call custom_module_names,$(m),GrandeModular)) \ -DpluginInstance=pluginInstance__GrandeModular \ -Wno-missing-braces \ -Wno-narrowing \ -Wno-self-assign +$(BUILD_DIR)/h4n4-modules/%.cpp.o: h4n4-modules/%.cpp + -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" + @echo "Compiling $<" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(foreach m,$(H4N4_CUSTOM),$(call custom_module_names,$(m),H4N4)) \ + -DpluginInstance=pluginInstance__H4N4 + $(BUILD_DIR)/HamptonHarmonics/%.cpp.o: HamptonHarmonics/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" @@ -1680,7 +2347,7 @@ $(BUILD_DIR)/HamptonHarmonics/%.cpp.o: HamptonHarmonics/%.cpp $(BUILD_DIR)/HetrickCV/%.cpp.o: HetrickCV/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(NOFINITE_FLAGS) -c -o $@ \ $(foreach m,$(HETRICKCV_CUSTOM),$(call custom_module_names,$(m),HetrickCV)) \ -DpluginInstance=pluginInstance__HetrickCV \ -DSTDIO_OVERRIDE=HetrickCV \ @@ -1690,7 +2357,7 @@ $(BUILD_DIR)/HetrickCV/%.cpp.o: HetrickCV/%.cpp $(BUILD_DIR)/ImpromptuModular/src/Foundr%.cpp.o: ImpromptuModular/src/Foundr%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(NOFINITE_FLAGS) -c -o $@ \ $(foreach m,$(IMPROMPTUMODULAR_CUSTOM),$(call custom_module_names,$(m),ImpromptuModular)) \ -DpluginInstance=pluginInstance__ImpromptuModular \ -DStepAttributes=StepAttributesKernel \ @@ -1698,16 +2365,15 @@ $(BUILD_DIR)/ImpromptuModular/src/Foundr%.cpp.o: ImpromptuModular/src/Foundr%.cp $(BUILD_DIR)/ImpromptuModular/src/ImpromptuModular.cpp.o: ImpromptuModular/src/ImpromptuModular.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(NOFINITE_FLAGS) -c -o $@ \ $(foreach m,$(IMPROMPTUMODULAR_CUSTOM),$(call custom_module_names,$(m),ImpromptuModular)) \ -DpluginInstance=pluginInstance__ImpromptuModular \ - -Dinit=init__ImpromptuModular \ - -UBUILDING_PLUGIN_MODULES + -Dinit=init__ImpromptuModular $(BUILD_DIR)/ImpromptuModular%.cpp.o: ImpromptuModular%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(NOFINITE_FLAGS) -c -o $@ \ $(foreach m,$(IMPROMPTUMODULAR_CUSTOM),$(call custom_module_names,$(m),ImpromptuModular)) \ $(foreach m,$(IMPROMPTUMODULAR_CUSTOM_PER_FILE),$(call custom_per_file_names,$(m),ImpromptuModular_$(shell basename $*))) \ -DpluginInstance=pluginInstance__ImpromptuModular \ @@ -1771,7 +2437,7 @@ $(BUILD_DIR)/LilacLoop/%.cpp.o: LilacLoop/%.cpp $(BUILD_DIR)/LittleUtils/%.cpp.o: LittleUtils/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(NOFINITE_FLAGS) -c -o $@ \ $(foreach m,$(LITTLEUTILS_CUSTOM),$(call custom_module_names,$(m),LittleUtils)) \ -DpluginInstance=pluginInstance__LittleUtils @@ -1801,7 +2467,7 @@ $(BUILD_DIR)/Meander/src/Meander.cpp.o: Meander/src/Meander.cpp $(BUILD_DIR)/MindMeldModular/src/MindMeldModular.cpp.o: MindMeldModular/src/MindMeldModular.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(NOFINITE_FLAGS) -c -o $@ \ $(foreach m,$(MINDMELD_CUSTOM),$(call custom_module_names,$(m),MindMeld)) \ -DpluginInstance=pluginInstance__MindMeld \ -Dinit=init__MindMeld @@ -1809,7 +2475,7 @@ $(BUILD_DIR)/MindMeldModular/src/MindMeldModular.cpp.o: MindMeldModular/src/Mind $(BUILD_DIR)/MindMeldModular/%.cpp.o: MindMeldModular/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(NOFINITE_FLAGS) -c -o $@ \ $(foreach m,$(MINDMELD_CUSTOM),$(call custom_module_names,$(m),MindMeld)) \ -DpluginInstance=pluginInstance__MindMeld @@ -1837,7 +2503,7 @@ $(BUILD_DIR)/Mog/%.cpp.o: Mog/%.cpp $(BUILD_DIR)/mscHack/%.cpp.o: mscHack/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(NOFINITE_FLAGS) -c -o $@ \ $(foreach m,$(MSCHACK_CUSTOM),$(call custom_module_names,$(m),mscHack)) \ $(foreach m,$(MSCHACK_CUSTOM_PER_FILE),$(call custom_per_file_names,$(m),mscHack_$(shell basename $*))) \ -DthePlugin=pluginInstance__mscHack \ @@ -1852,8 +2518,7 @@ $(BUILD_DIR)/MSM/%.cpp.o: MSM/%.cpp @echo "Compiling $<" $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ $(foreach m,$(MSM_CUSTOM),$(call custom_module_names,$(m),MSM)) \ - -DpluginInstance=pluginInstance__MSM \ - -DDARKTHEME + -DpluginInstance=pluginInstance__MSM $(BUILD_DIR)/myth-modules/%.cpp.o: myth-modules/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @@ -1891,7 +2556,7 @@ $(BUILD_DIR)/ParableInstruments/%.o: ParableInstruments/% $(BUILD_DIR)/PathSet/%.cpp.o: PathSet/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(NOFINITE_FLAGS) -c -o $@ \ $(foreach m,$(PATHSET_CUSTOM),$(call custom_module_names,$(m),PathSet)) \ -DpluginInstance=pluginInstance__PathSet @@ -1919,6 +2584,13 @@ $(BUILD_DIR)/rackwindows/%.cpp.o: rackwindows/%.cpp -Wno-implicit-fallthrough \ -Wno-sign-compare +$(BUILD_DIR)/RebelTech/%.cpp.o: RebelTech/%.cpp + -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" + @echo "Compiling $<" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(foreach m,$(REBELTECH_CUSTOM),$(call custom_module_names,$(m),RebelTech)) \ + -DpluginInstance=pluginInstance__RebelTech + $(BUILD_DIR)/repelzen/%.cpp.o: repelzen/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" @@ -1926,6 +2598,13 @@ $(BUILD_DIR)/repelzen/%.cpp.o: repelzen/%.cpp $(foreach m,$(REPELZEN_CUSTOM),$(call custom_module_names,$(m),repelzen)) \ -DpluginInstance=pluginInstance__repelzen +$(BUILD_DIR)/Sapphire/%.cpp.o: Sapphire/%.cpp + -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" + @echo "Compiling $<" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(NOFINITE_FLAGS) -c -o $@ \ + $(foreach m,$(SAPPHIRE_CUSTOM),$(call custom_module_names,$(m),Sapphire)) \ + -DpluginInstance=pluginInstance__sapphire + $(BUILD_DIR)/sonusmodular/%.cpp.o: sonusmodular/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" @@ -1947,6 +2626,15 @@ $(BUILD_DIR)/StarlingVia/%.cpp.o: StarlingVia/%.cpp -IStarlingVia/Via/ui/inc \ -I./dep/starling-dsp +$(BUILD_DIR)/stoermelder-packone/%.cpp.o: stoermelder-packone/%.cpp + -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" + @echo "Compiling $<" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(foreach m,$(STOERMELDER_PACKONE_CUSTOM),$(call custom_module_names,$(m),stoermelder_p1)) \ + $(foreach m,$(STOERMELDER_PACKONE_CUSTOM_PER_FILE),$(call custom_per_file_names,$(m),stoermelder_p1_$(shell basename $*))) \ + -DpluginInstance=pluginInstance__stoermelder_p1 \ + -Dinit=init__stoermelder_p1 + $(BUILD_DIR)/stocaudio/%.cpp.o: stocaudio/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" @@ -1954,6 +2642,13 @@ $(BUILD_DIR)/stocaudio/%.cpp.o: stocaudio/%.cpp $(foreach m,$(STOCAUDIO_CUSTOM),$(call custom_module_names,$(m),stocaudio)) \ -DpluginInstance=pluginInstance__stocaudio +$(BUILD_DIR)/surgext%.cpp.o: surgext%.cpp + -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" + @echo "Compiling $<" + $(SILENT)$(CXX) $< $(SURGEXT_FLAGS) -c -o $@ \ + $(foreach m,$(SURGEXT_CUSTOM),$(call custom_module_names,$(m),surgext)) \ + -DpluginInstance=pluginInstance__surgext + $(BUILD_DIR)/unless_modules/%.cpp.o: unless_modules/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" diff --git a/plugins/Meander b/plugins/Meander index c0958247..b3686597 160000 --- a/plugins/Meander +++ b/plugins/Meander @@ -1 +1 @@ -Subproject commit c095824708947630d9db6a6b7afcd51bdaa0a009 +Subproject commit b36865978358ffdbeb80ad603c4c54f5a535107a diff --git a/plugins/MindMeldModular b/plugins/MindMeldModular index f526208d..18f4fa89 160000 --- a/plugins/MindMeldModular +++ b/plugins/MindMeldModular @@ -1 +1 @@ -Subproject commit f526208d9b54f9fc8950919ed3f9d9793c6e54e2 +Subproject commit 18f4fa89ca08e9943e38548440d3e02e1ee2e170 diff --git a/plugins/PathSet b/plugins/PathSet index de53c786..66e69a2f 160000 --- a/plugins/PathSet +++ b/plugins/PathSet @@ -1 +1 @@ -Subproject commit de53c78658c42638b7c356b78d1559634644f733 +Subproject commit 66e69a2f2047e3dab06275b12852e56d143388cf diff --git a/plugins/PinkTrombone b/plugins/PinkTrombone index 87ecd0ff..1e96d7b8 160000 --- a/plugins/PinkTrombone +++ b/plugins/PinkTrombone @@ -1 +1 @@ -Subproject commit 87ecd0ff5212a65b064444362e76c9bf94c01826 +Subproject commit 1e96d7b898eca6101f438dfd8224d713985486e2 diff --git a/plugins/Prism b/plugins/Prism index 4d95ace8..8d2796da 160000 --- a/plugins/Prism +++ b/plugins/Prism @@ -1 +1 @@ -Subproject commit 4d95ace8b073e9e8e30b8671ecdb04101d943905 +Subproject commit 8d2796da76e5d7f79bbf461c95a7858035bb0736 diff --git a/plugins/RebelTech b/plugins/RebelTech new file mode 160000 index 00000000..6ac79f59 --- /dev/null +++ b/plugins/RebelTech @@ -0,0 +1 @@ +Subproject commit 6ac79f59c5b95433d82bcc759c4cd0642ec35098 diff --git a/plugins/Sapphire b/plugins/Sapphire new file mode 160000 index 00000000..2d374e22 --- /dev/null +++ b/plugins/Sapphire @@ -0,0 +1 @@ +Subproject commit 2d374e2222475aa4207aec8c541716ed467e2619 diff --git a/plugins/ValleyAudio b/plugins/ValleyAudio index 9745a4c6..b2ed19ad 160000 --- a/plugins/ValleyAudio +++ b/plugins/ValleyAudio @@ -1 +1 @@ -Subproject commit 9745a4c63747a2225a31da69b085e6185b4c8407 +Subproject commit b2ed19ad46e91c650d0ba3e18eae9a1bbecb1f3c diff --git a/plugins/WhatTheRack b/plugins/WhatTheRack index e3733784..82c3c5e1 160000 --- a/plugins/WhatTheRack +++ b/plugins/WhatTheRack @@ -1 +1 @@ -Subproject commit e373378491d2cf3b8257137d154aef1d389c5204 +Subproject commit 82c3c5e11176c364b61d501059d9182e86464eca diff --git a/plugins/alefsbits b/plugins/alefsbits new file mode 160000 index 00000000..af534ff4 --- /dev/null +++ b/plugins/alefsbits @@ -0,0 +1 @@ +Subproject commit af534ff487db6689c3be527f5acb34ea90efc195 diff --git a/plugins/cf b/plugins/cf index b6c4a66f..8aca80cb 160000 --- a/plugins/cf +++ b/plugins/cf @@ -1 +1 @@ -Subproject commit b6c4a66ffc153d78c7efa00fa886657eb182b15d +Subproject commit 8aca80cbaa30787e0aed1edb886767fa756b9846 diff --git a/plugins/dBiz b/plugins/dBiz new file mode 160000 index 00000000..88f1bd64 --- /dev/null +++ b/plugins/dBiz @@ -0,0 +1 @@ +Subproject commit 88f1bd64cff6e96a1a48566a1692de86b9a7de2a diff --git a/plugins/forsitan-modulare b/plugins/forsitan-modulare index 056cc2ec..494fefaf 160000 --- a/plugins/forsitan-modulare +++ b/plugins/forsitan-modulare @@ -1 +1 @@ -Subproject commit 056cc2ec9186a4175d9214eee91e4ff5cc2e5fb1 +Subproject commit 494fefaf38cb48928a165fd20d1535a0690bf613 diff --git a/plugins/h4n4-modules b/plugins/h4n4-modules new file mode 160000 index 00000000..bb1b1587 --- /dev/null +++ b/plugins/h4n4-modules @@ -0,0 +1 @@ +Subproject commit bb1b15870d9dad4dd8a562957f45c2383506795d diff --git a/plugins/mscHack b/plugins/mscHack index 80883512..e5c60480 160000 --- a/plugins/mscHack +++ b/plugins/mscHack @@ -1 +1 @@ -Subproject commit 80883512cc397c173e40e3bc014640b838ab343a +Subproject commit e5c6048071b9e1fc34b4a97072f1966b88235455 diff --git a/plugins/nonlinearcircuits b/plugins/nonlinearcircuits index 57eb090f..dc154fd9 160000 --- a/plugins/nonlinearcircuits +++ b/plugins/nonlinearcircuits @@ -1 +1 @@ -Subproject commit 57eb090f233c21b2edee541ea17d800f22045d91 +Subproject commit dc154fd9c179db75f88ea6cfd3000f7a936a7e35 diff --git a/plugins/plugins-mini.cpp b/plugins/plugins-mini.cpp new file mode 100644 index 00000000..38fdb17e --- /dev/null +++ b/plugins/plugins-mini.cpp @@ -0,0 +1,670 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the LICENSE file. + */ + +#include "rack.hpp" +#include "plugin.hpp" + +#include "DistrhoUtils.hpp" + +// Cardinal (built-in) +#include "Cardinal/src/plugin.hpp" + +// Fundamental +#include "Fundamental/src/plugin.hpp" + +// Aria +extern Model* modelSpleet; +extern Model* modelSwerge; + +// AudibleInstruments +#include "AudibleInstruments/src/plugin.hpp" + +// BogaudioModules - integrate theme/skin support +#include +#include +#include +#include +#include +#define private public +#include "BogaudioModules/src/skins.hpp" +#undef private + +// BogaudioModules +extern Model* modelAD; +extern Model* modelBogaudioLFO; +extern Model* modelBogaudioNoise; +extern Model* modelBogaudioVCA; +extern Model* modelBogaudioVCF; +extern Model* modelBogaudioVCO; +extern Model* modelOffset; +extern Model* modelSampleHold; +extern Model* modelSwitch; +extern Model* modelSwitch18; +extern Model* modelUnison; + +// MockbaModular +#include "MockbaModular/src/plugin.hpp" +#include "MockbaModular/src/MockbaModular.hpp" +#undef min +#define saveBack ignoreMockbaModular1 +#define loadBack ignoreMockbaModular2 +#include "MockbaModular/src/MockbaModular.cpp" +#undef saveBack +#undef loadBack +std::string loadBack(int) { return "res/Empty_gray.svg"; } + +// surgext +#include "surgext/src/SurgeXT.h" +void surgext_rack_initialize(); +void surgext_rack_update_theme(); + +// ValleyAudio +#include "ValleyAudio/src/Valley.hpp" + +// known terminal modules +std::vector hostTerminalModels; + +// plugin instances +Plugin* pluginInstance__Cardinal; +Plugin* pluginInstance__Fundamental; +Plugin* pluginInstance__Aria; +Plugin* pluginInstance__AudibleInstruments; +Plugin* pluginInstance__BogaudioModules; +Plugin* pluginInstance__MockbaModular; +Plugin* pluginInstance__surgext; +Plugin* pluginInstance__ValleyAudio; + +namespace rack { + +namespace asset { +std::string pluginManifest(const std::string& dirname); +std::string pluginPath(const std::string& dirname); +} + +namespace plugin { + +struct StaticPluginLoader { + Plugin* const plugin; + FILE* file; + json_t* rootJ; + + StaticPluginLoader(Plugin* const p, const char* const name) + : plugin(p), + file(nullptr), + rootJ(nullptr) + { +#ifdef DEBUG + DEBUG("Loading plugin module %s", name); +#endif + + p->path = asset::pluginPath(name); + + const std::string manifestFilename = asset::pluginManifest(name); + + if ((file = std::fopen(manifestFilename.c_str(), "r")) == nullptr) + { + d_stderr2("Manifest file %s does not exist", manifestFilename.c_str()); + return; + } + + json_error_t error; + if ((rootJ = json_loadf(file, 0, &error)) == nullptr) + { + d_stderr2("JSON parsing error at %s %d:%d %s", manifestFilename.c_str(), error.line, error.column, error.text); + return; + } + + // force ABI, we use static plugins so this doesnt matter as long as it builds + json_t* const version = json_string((APP_VERSION_MAJOR + ".0").c_str()); + json_object_set(rootJ, "version", version); + json_decref(version); + + // Load manifest + p->fromJson(rootJ); + + // Reject plugin if slug already exists + if (Plugin* const existingPlugin = getPlugin(p->slug)) + throw Exception("Plugin %s is already loaded, not attempting to load it again", p->slug.c_str()); + } + + ~StaticPluginLoader() + { + if (rootJ != nullptr) + { + // Load modules manifest + json_t* const modulesJ = json_object_get(rootJ, "modules"); + plugin->modulesFromJson(modulesJ); + + json_decref(rootJ); + plugins.push_back(plugin); + } + + if (file != nullptr) + std::fclose(file); + } + + bool ok() const noexcept + { + return rootJ != nullptr; + } + + void removeModule(const char* const slugToRemove) const noexcept + { + json_t* const modules = json_object_get(rootJ, "modules"); + DISTRHO_SAFE_ASSERT_RETURN(modules != nullptr,); + + size_t i; + json_t* v; + json_array_foreach(modules, i, v) + { + if (json_t* const slug = json_object_get(v, "slug")) + { + if (const char* const value = json_string_value(slug)) + { + if (std::strcmp(value, slugToRemove) == 0) + { + json_array_remove(modules, i); + break; + } + } + } + } + } +}; + +static void initStatic__Cardinal() +{ + Plugin* const p = new Plugin; + pluginInstance__Cardinal = p; + + const StaticPluginLoader spl(p, "Cardinal"); + if (spl.ok()) + { + p->addModel(modelHostAudio2); + p->addModel(modelHostCV); + p->addModel(modelHostMIDI); + p->addModel(modelHostMIDICC); + p->addModel(modelHostMIDIGate); + p->addModel(modelHostMIDIMap); + p->addModel(modelHostParameters); + p->addModel(modelHostParametersMap); + p->addModel(modelHostTime); + p->addModel(modelTextEditor); + /* TODO + #ifdef HAVE_FFTW3F + p->addModel(modelAudioToCVPitch); + #else + */ + spl.removeModule("AudioToCVPitch"); + /* + #endif + */ + spl.removeModule("AIDA-X"); + spl.removeModule("AudioFile"); + spl.removeModule("Blank"); + spl.removeModule("Carla"); + spl.removeModule("ExpanderInputMIDI"); + spl.removeModule("ExpanderOutputMIDI"); + spl.removeModule("HostAudio8"); + spl.removeModule("Ildaeil"); + spl.removeModule("MPV"); + spl.removeModule("SassyScope"); + spl.removeModule("glBars"); + + hostTerminalModels = { + modelHostAudio2, + modelHostCV, + modelHostMIDI, + modelHostMIDICC, + modelHostMIDIGate, + modelHostMIDIMap, + modelHostParameters, + modelHostParametersMap, + modelHostTime, + }; + } +} + +static void initStatic__Fundamental() +{ + Plugin* const p = new Plugin; + pluginInstance__Fundamental = p; + + const StaticPluginLoader spl(p, "Fundamental"); + if (spl.ok()) + { + p->addModel(modelADSR); + p->addModel(modelLFO); + p->addModel(modelMerge); + p->addModel(modelMidSide); + p->addModel(modelNoise); + p->addModel(modelQuantizer); + p->addModel(modelRandom); + p->addModel(modelScope); + p->addModel(modelSplit); + p->addModel(modelSum); + p->addModel(modelVCA_1); + p->addModel(modelVCF); + p->addModel(modelVCMixer); + p->addModel(modelVCO); + spl.removeModule("8vert"); + spl.removeModule("Delay"); + spl.removeModule("LFO2"); + spl.removeModule("Mixer"); + spl.removeModule("Mutes"); + spl.removeModule("Octave"); + spl.removeModule("Pulses"); + spl.removeModule("SEQ3"); + spl.removeModule("SequentialSwitch1"); + spl.removeModule("SequentialSwitch2"); + spl.removeModule("VCA"); + spl.removeModule("VCO2"); + } +} + +static void initStatic__Aria() +{ + Plugin* const p = new Plugin; + pluginInstance__Aria = p; + + const StaticPluginLoader spl(p, "AriaModules"); + if (spl.ok()) + { + p->addModel(modelSpleet); + p->addModel(modelSwerge); + + spl.removeModule("Aleister"); + spl.removeModule("Arcane"); + spl.removeModule("Atout"); + spl.removeModule("Blank"); + spl.removeModule("Darius"); + spl.removeModule("Grabby"); + spl.removeModule("Pokies4"); + spl.removeModule("Psychopump"); + spl.removeModule("Q"); + spl.removeModule("Qqqq"); + spl.removeModule("Quack"); + spl.removeModule("Quale"); + spl.removeModule("Rotatoes4"); + spl.removeModule("Smerge"); + spl.removeModule("Solomon16"); + spl.removeModule("Solomon4"); + spl.removeModule("Solomon8"); + spl.removeModule("Splirge"); + spl.removeModule("Splort"); + spl.removeModule("Undular"); + + } +} + +static void initStatic__AudibleInstruments() +{ + Plugin* const p = new Plugin; + pluginInstance__AudibleInstruments = p; + + const StaticPluginLoader spl(p, "AudibleInstruments"); + if (spl.ok()) + { + p->addModel(modelPlaits); + + spl.removeModule("Blinds"); + spl.removeModule("Braids"); + spl.removeModule("Branches"); + spl.removeModule("Clouds"); + spl.removeModule("Elements"); + spl.removeModule("Frames"); + spl.removeModule("Kinks"); + spl.removeModule("Links"); + spl.removeModule("Marbles"); + spl.removeModule("Rings"); + spl.removeModule("Ripples"); + spl.removeModule("Shades"); + spl.removeModule("Shelves"); + spl.removeModule("Stages"); + spl.removeModule("Streams"); + spl.removeModule("Tides"); + spl.removeModule("Tides2"); + spl.removeModule("Veils"); + spl.removeModule("Warps"); + } +} + +static void initStatic__BogaudioModules() +{ + Plugin* const p = new Plugin; + pluginInstance__BogaudioModules = p; + + const StaticPluginLoader spl(p, "BogaudioModules"); + if (spl.ok()) + { + // Make sure to use match Cardinal theme + Skins& skins(Skins::skins()); + skins._default = settings::darkMode ? "dark" : "light"; + + p->addModel(modelAD); + p->addModel(modelBogaudioLFO); + p->addModel(modelBogaudioNoise); + p->addModel(modelBogaudioVCA); + p->addModel(modelBogaudioVCF); + p->addModel(modelBogaudioVCO); + p->addModel(modelOffset); + p->addModel(modelSampleHold); + p->addModel(modelSwitch); + p->addModel(modelSwitch18); + p->addModel(modelUnison); + + // cat plugins/BogaudioModules/plugin.json | jq -r .modules[].slug - | sort + spl.removeModule("Bogaudio-Additator"); + spl.removeModule("Bogaudio-AddrSeq"); + spl.removeModule("Bogaudio-AddrSeqX"); + spl.removeModule("Bogaudio-ADSR"); + spl.removeModule("Bogaudio-AMRM"); + spl.removeModule("Bogaudio-Analyzer"); + spl.removeModule("Bogaudio-AnalyzerXL"); + spl.removeModule("Bogaudio-Arp"); + spl.removeModule("Bogaudio-ASR"); + spl.removeModule("Bogaudio-Assign"); + spl.removeModule("Bogaudio-Blank3"); + spl.removeModule("Bogaudio-Blank6"); + spl.removeModule("Bogaudio-Bool"); + spl.removeModule("Bogaudio-Chirp"); + spl.removeModule("Bogaudio-Clpr"); + spl.removeModule("Bogaudio-Cmp"); + spl.removeModule("Bogaudio-CmpDist"); + spl.removeModule("Bogaudio-CVD"); + spl.removeModule("Bogaudio-DADSRH"); + spl.removeModule("Bogaudio-DADSRHPlus"); + spl.removeModule("Bogaudio-Detune"); + spl.removeModule("Bogaudio-DGate"); + spl.removeModule("Bogaudio-Edge"); + spl.removeModule("Bogaudio-EightFO"); + spl.removeModule("Bogaudio-EightOne"); + spl.removeModule("Bogaudio-EQ"); + spl.removeModule("Bogaudio-EQS"); + spl.removeModule("Bogaudio-FFB"); + spl.removeModule("Bogaudio-FlipFlop"); + spl.removeModule("Bogaudio-FMOp"); + spl.removeModule("Bogaudio-Follow"); + spl.removeModule("Bogaudio-FourFO"); + spl.removeModule("Bogaudio-FourMan"); + spl.removeModule("Bogaudio-Inv"); + spl.removeModule("Bogaudio-Lgsw"); + spl.removeModule("Bogaudio-LLFO"); + spl.removeModule("Bogaudio-LLPG"); + spl.removeModule("Bogaudio-Lmtr"); + spl.removeModule("Bogaudio-LPG"); + spl.removeModule("Bogaudio-LVCF"); + spl.removeModule("Bogaudio-LVCO"); + spl.removeModule("Bogaudio-Manual"); + spl.removeModule("Bogaudio-Matrix18"); + spl.removeModule("Bogaudio-Matrix44"); + spl.removeModule("Bogaudio-Matrix44Cvm"); + spl.removeModule("Bogaudio-Matrix81"); + spl.removeModule("Bogaudio-Matrix88"); + spl.removeModule("Bogaudio-Matrix88Cv"); + spl.removeModule("Bogaudio-Matrix88M"); + spl.removeModule("Bogaudio-MegaGate"); + spl.removeModule("Bogaudio-Mix1"); + spl.removeModule("Bogaudio-Mix2"); + spl.removeModule("Bogaudio-Mix4"); + spl.removeModule("Bogaudio-Mix4x"); + spl.removeModule("Bogaudio-Mix8"); + spl.removeModule("Bogaudio-Mix8x"); + spl.removeModule("Bogaudio-Mono"); + spl.removeModule("Bogaudio-Mult"); + spl.removeModule("Bogaudio-Mumix"); + spl.removeModule("Bogaudio-Mute8"); + spl.removeModule("Bogaudio-Nsgt"); + spl.removeModule("Bogaudio-OneEight"); + spl.removeModule("Bogaudio-Pan"); + spl.removeModule("Bogaudio-PEQ"); + spl.removeModule("Bogaudio-PEQ14"); + spl.removeModule("Bogaudio-PEQ14XF"); + spl.removeModule("Bogaudio-PEQ6"); + spl.removeModule("Bogaudio-PEQ6XF"); + spl.removeModule("Bogaudio-Pgmr"); + spl.removeModule("Bogaudio-PgmrX"); + spl.removeModule("Bogaudio-PolyCon"); + spl.removeModule("Bogaudio-PolyCon8"); + spl.removeModule("Bogaudio-PolyMult"); + spl.removeModule("Bogaudio-PolyOff16"); + spl.removeModule("Bogaudio-PolyOff8"); + spl.removeModule("Bogaudio-Pressor"); + spl.removeModule("Bogaudio-Pulse"); + spl.removeModule("Bogaudio-Ranalyzer"); + spl.removeModule("Bogaudio-Reftone"); + spl.removeModule("Bogaudio-RGate"); + spl.removeModule("Bogaudio-Shaper"); + spl.removeModule("Bogaudio-ShaperPlus"); + spl.removeModule("Bogaudio-Sine"); + spl.removeModule("Bogaudio-Slew"); + spl.removeModule("Bogaudio-Stack"); + spl.removeModule("Bogaudio-Sums"); + spl.removeModule("Bogaudio-Switch1616"); + spl.removeModule("Bogaudio-Switch44"); + spl.removeModule("Bogaudio-Switch81"); + spl.removeModule("Bogaudio-Switch88"); + spl.removeModule("Bogaudio-UMix"); + spl.removeModule("Bogaudio-VCAmp"); + spl.removeModule("Bogaudio-VCM"); + spl.removeModule("Bogaudio-Velo"); + spl.removeModule("Bogaudio-Vish"); + spl.removeModule("Bogaudio-VU"); + spl.removeModule("Bogaudio-Walk"); + spl.removeModule("Bogaudio-Walk2"); + spl.removeModule("Bogaudio-XCO"); + spl.removeModule("Bogaudio-XFade"); + } +} + +static void initStatic__MockbaModular() +{ + Plugin* const p = new Plugin; + pluginInstance__MockbaModular = p; + + const StaticPluginLoader spl(p, "MockbaModular"); + if (spl.ok()) + { + p->addModel(modelCZOsc); + p->addModel(modelFiltah); + p->addModel(modelMaugOsc); + p->addModel(modelMixah); + p->addModel(modelPannah); + p->addModel(modelReVoltah); + p->addModel(modelShapah); + + spl.removeModule("Blank"); + spl.removeModule("Comparator"); + spl.removeModule("Countah"); + spl.removeModule("CZDblSine"); + spl.removeModule("CZPulse"); + spl.removeModule("CZReso1"); + spl.removeModule("CZReso2"); + spl.removeModule("CZReso3"); + spl.removeModule("CZSaw"); + spl.removeModule("CZSawPulse"); + spl.removeModule("CZSquare"); + spl.removeModule("Dividah"); + spl.removeModule("DualBUFFER"); + spl.removeModule("DualNOT"); + spl.removeModule("DualOR"); + spl.removeModule("DualNOR"); + spl.removeModule("DualAND"); + spl.removeModule("DualNAND"); + spl.removeModule("DualXOR"); + spl.removeModule("DualXNOR"); + spl.removeModule("Feidah"); + spl.removeModule("FeidahS"); + spl.removeModule("Holdah"); + spl.removeModule("MaugSaw"); + spl.removeModule("MaugSaw2"); + spl.removeModule("MaugShark"); + spl.removeModule("MaugSquare"); + spl.removeModule("MaugSquare2"); + spl.removeModule("MaugSquare3"); + spl.removeModule("MaugTriangle"); + spl.removeModule("Mixah3"); + spl.removeModule("PSelectah"); + spl.removeModule("Selectah"); + spl.removeModule("UDPClockMaster"); + spl.removeModule("UDPClockSlave"); + } +} + +static void initStatic__surgext() +{ + Plugin* const p = new Plugin; + pluginInstance__surgext = p; + + const StaticPluginLoader spl(p, "surgext"); + if (spl.ok()) + { + p->addModel(modelVCOModern); + p->addModel(modelVCOSine); + /* + p->addModel(modelVCOAlias); + p->addModel(modelVCOClassic); + p->addModel(modelVCOFM2); + p->addModel(modelVCOFM3); + p->addModel(modelVCOSHNoise); + p->addModel(modelVCOString); + p->addModel(modelVCOTwist); + p->addModel(modelVCOWavetable); + p->addModel(modelVCOWindow); + */ + spl.removeModule("SurgeXTOSCAlias"); + spl.removeModule("SurgeXTOSCClassic"); + spl.removeModule("SurgeXTOSCFM2"); + spl.removeModule("SurgeXTOSCFM3"); + spl.removeModule("SurgeXTOSCSHNoise"); + spl.removeModule("SurgeXTOSCString"); + spl.removeModule("SurgeXTOSCTwist"); + spl.removeModule("SurgeXTOSCWavetable"); + spl.removeModule("SurgeXTOSCWindow"); + + // Add the ported ones + p->addModel(modelSurgeLFO); + p->addModel(modelSurgeMixer); + p->addModel(modelSurgeModMatrix); + p->addModel(modelSurgeWaveshaper); + /* + p->addModel(modelSurgeDelay); + p->addModel(modelSurgeDelayLineByFreq); + p->addModel(modelSurgeDelayLineByFreqExpanded); + p->addModel(modelSurgeVCF); + */ + spl.removeModule("SurgeXTDelay"); + spl.removeModule("SurgeXTDelayLineByFreq"); + spl.removeModule("SurgeXTDelayLineByFreqExpanded"); + spl.removeModule("SurgeXTVCF"); + + spl.removeModule("SurgeXTFXChorus"); + spl.removeModule("SurgeXTFXChow"); + spl.removeModule("SurgeXTFXCombulator"); + spl.removeModule("SurgeXTFXDistortion"); + spl.removeModule("SurgeXTFXExciter"); + spl.removeModule("SurgeXTFXEnsemble"); + spl.removeModule("SurgeXTFXFlanger"); + spl.removeModule("SurgeXTFXFrequencyShifter"); + spl.removeModule("SurgeXTFXNeuron"); + spl.removeModule("SurgeXTFXPhaser"); + spl.removeModule("SurgeXTFXResonator"); + spl.removeModule("SurgeXTFXReverb"); + spl.removeModule("SurgeXTFXReverb2"); + spl.removeModule("SurgeXTFXRingMod"); + spl.removeModule("SurgeXTFXRotarySpeaker"); + spl.removeModule("SurgeXTFXSpringReverb"); + spl.removeModule("SurgeXTFXTreeMonster"); + spl.removeModule("SurgeXTFXVocoder"); + + /* + p->addModel(modelEGxVCA); + p->addModel(modelQuadAD); + p->addModel(modelQuadLFO); + */ + spl.removeModule("SurgeXTEGxVCA"); + spl.removeModule("SurgeXTQuadAD"); + spl.removeModule("SurgeXTQuadLFO"); + + surgext_rack_initialize(); + } +} + +/* +static void initStatic__ValleyAudio() +{ + Plugin* const p = new Plugin; + pluginInstance__ValleyAudio = p; + + const StaticPluginLoader spl(p, "ValleyAudio"); + if (spl.ok()) + { + p->addModel(modelDexter); + p->addModel(modelInterzone); + + spl.removeModule("Amalgam"); + spl.removeModule("Feline"); + spl.removeModule("Plateau"); + spl.removeModule("Terrorform"); + spl.removeModule("Topograph"); + spl.removeModule("uGraph"); + } +} +*/ + +void initStaticPlugins() +{ + initStatic__Cardinal(); + initStatic__Fundamental(); + initStatic__Aria(); + initStatic__AudibleInstruments(); + initStatic__BogaudioModules(); + initStatic__MockbaModular(); + initStatic__surgext(); + /* + initStatic__ValleyAudio(); + */ +} + +void destroyStaticPlugins() +{ + for (Plugin* p : plugins) + delete p; + plugins.clear(); +} + +void updateStaticPluginsDarkMode() +{ + const bool darkMode = settings::darkMode; + // bogaudio + { + Skins& skins(Skins::skins()); + skins._default = darkMode ? "dark" : "light"; + + std::lock_guard lock(skins._defaultSkinListenersLock); + for (auto listener : skins._defaultSkinListeners) { + listener->defaultSkinChanged(skins._default); + } + } + // surgext + { + surgext_rack_update_theme(); + } +} + +} +} diff --git a/plugins/plugins.cpp b/plugins/plugins.cpp index efdd1ba2..706efd49 100644 --- a/plugins/plugins.cpp +++ b/plugins/plugins.cpp @@ -26,8 +26,8 @@ // Fundamental (always enabled) #include "Fundamental/src/plugin.hpp" -// ZamAudio (always enabled) -#include "ZamAudio/src/plugin.hpp" +// ZamAudio (always enabled) - TODO +// #include "ZamAudio/src/plugin.hpp" #ifndef NOPLUGINS // 21kHz @@ -39,6 +39,13 @@ // Aaron Static #include "AaronStatic/src/plugin.hpp" +// Alef's Bits +#define modelSteps modelalefsbitsSteps +#define modelLogic modelalefsbitsLogic +#include "alefsbits/src/plugin.hpp" +#undef modelSteps +#undef modelLogic + // Algoritmarte #include "Algoritmarte/src/plugin.hpp" @@ -149,7 +156,7 @@ extern Model* modelChord; // Bidoo #include "Bidoo/src/plugin.hpp" -// BogaudioModules - force dark skin as default +// BogaudioModules - integrate theme/skin support #include #include #include @@ -309,10 +316,34 @@ extern Model* modelTestVCF; #include "ChowDSP/src/plugin.cpp" #undef init +// dBiz +#define DarkDefaultItem dBizDarkDefaultItem +#define OrangeLight dBizOrangeLight +#define darkPanelID dBizdarkPanelID +#define lightPanelID dBizlightPanelID +#define modelChord modeldBizChord +#define modelDivider modeldBizDivider +#define modelFourSeq modeldBizFourSeq +#define modelVCA4 modeldBizVCA4 +#include "dBiz/src/plugin.hpp" +#undef DarkDefaultItem +#undef OrangeLight +#undef darkPanelID +#undef lightPanelID +#undef modelChord +#undef modelDivider +#undef modelFourSeq +#undef modelVCA4 + // DrumKit #include "DrumKit/src/DrumKit.hpp" void setupSamples(); +// EnigmaCurry +#define modelPulse modelEnigmaCurryPulse +#include "EnigmaCurry/src/plugin.hpp" +#undef modelPulse + // ESeries #include "ESeries/src/plugin.hpp" @@ -342,6 +373,9 @@ void saveGtgPluginDefault(const char*, int) {} // GrandeModular #include "GrandeModular/src/plugin.hpp" +// H4N4 Modules +#include "h4n4-modules/src/plugin.hpp" + // Hampton Harmonics #define modelArp modelHamptonHarmonicsArp #define modelProgress modelHamptonHarmonicsProgress @@ -495,18 +529,25 @@ extern int panelTheme; /* NOTE too much noise in original include, do this a different way // #include "MindMeldModular/src/MindMeldModular.hpp" */ -extern Model* modelMixMasterJr; -extern Model* modelAuxExpanderJr; -extern Model* modelMixMaster; -extern Model* modelAuxExpander; -extern Model* modelMeld; -extern Model* modelUnmeld; -extern Model* modelMSMelder; -extern Model* modelEqMaster; -extern Model* modelEqExpander; -extern Model* modelBassMaster; -extern Model* modelBassMasterJr; -extern Model* modelShapeMaster; +extern Model *modelPatchMaster; +extern Model *modelPatchMasterBlank; +extern Model *modelRouteMasterMono5to1; +extern Model *modelRouteMasterStereo5to1; +extern Model *modelRouteMasterMono1to5; +extern Model *modelRouteMasterStereo1to5; +extern Model *modelMasterChannel; +extern Model *modelMeld; +extern Model *modelUnmeld; +extern Model *modelMSMelder; +extern Model *modelEqMaster; +extern Model *modelEqExpander; +extern Model *modelBassMaster; +extern Model *modelBassMasterJr; +extern Model *modelShapeMaster; +extern Model *modelMixMasterJr; +extern Model *modelAuxExpanderJr; +extern Model *modelMixMaster; +extern Model *modelAuxExpander; // ML_modules /* NOTE too much noise in original include, do this a different way @@ -554,6 +595,7 @@ extern Model* modelArpeggiator; #undef modelComparator #include "MockbaModular/src/MockbaModular.hpp" #undef min +#undef max #define saveBack ignoreMockbaModular1 #define loadBack ignoreMockbaModular2 #include "MockbaModular/src/MockbaModular.cpp" @@ -660,6 +702,15 @@ extern Model* modelBlankPanel; // rackwindows #include "rackwindows/src/plugin.hpp" +// RebelTech +#define BefacoInputPort BefacoInputPortRebelTech +#define BefacoOutputPort BefacoOutputPortRebelTech +#include "RebelTech/src/plugin.hpp" +#undef BefacoInputPort +#undef BefacoOutputPort +ModuleTheme defaultPanelTheme = DARK_THEME; +void addThemeMenuItems(Menu*, ModuleTheme*) {} + // repelzen #define modelBlank modelrepelzenBlank #define modelMixer modelrepelzenMixer @@ -671,6 +722,9 @@ extern Model* modelBlankPanel; #undef modelWerner #undef tanh_pade +// Sapphire +#include "Sapphire/src/plugin.hpp" + // sonusmodular #include "sonusmodular/src/sonusmodular.hpp" @@ -683,6 +737,25 @@ extern Model* modelBlankPanel; // stocaudio #include "stocaudio/src/plugin.hpp" +// stoermelder-packone +#include "stoermelder-packone/src/plugin.hpp" +Model* modelAudioInterface64; +Model* modelMidiCat; +Model* modelMidiCatCtx; +Model* modelMidiCatMem; +Model* modelMidiKey; +Model* modelMidiMon; +Model* modelMidiPlug; +Model* modelMidiStep; +StoermelderSettings pluginSettings; +void StoermelderSettings::saveToJson() {} +void StoermelderSettings::readFromJson() {} + +// surgext +#include "surgext/src/SurgeXT.h" +void surgext_rack_initialize(); +void surgext_rack_update_theme(); + // unless_modules #include "unless_modules/src/unless.hpp" @@ -713,22 +786,30 @@ extern Model* modelBlankPanel; // known terminal modules std::vector hostTerminalModels; -// stuff that reads config files, we dont want that +#ifndef NOPLUGINS +// stuff that reads config files, we don't want that int loadConsoleType() { return 0; } +bool loadDarkAsDefault() { return settings::darkMode; } +ModuleTheme loadDefaultTheme() { return settings::darkMode ? DARK_THEME : LIGHT_THEME; } int loadDirectOutMode() { return 0; } +void readDefaultTheme() { defaultPanelTheme = loadDefaultTheme(); } void saveConsoleType(int) {} void saveDarkAsDefault(bool) {} +void saveDefaultTheme(ModuleTheme) {} void saveDirectOutMode(bool) {} void saveHighQualityAsDefault(bool) {} +void writeDefaultTheme() {} +#endif // plugin instances Plugin* pluginInstance__Cardinal; Plugin* pluginInstance__Fundamental; -Plugin* pluginInstance__ZamAudio; +// Plugin* pluginInstance__ZamAudio; #ifndef NOPLUGINS Plugin* pluginInstance__21kHz; Plugin* pluginInstance__8Mode; extern Plugin* pluginInstance__AaronStatic; +Plugin* pluginInstance__alefsbits; Plugin* pluginInstance__Algoritmarte; Plugin* pluginInstance__AmalgamatedHarmonics; Plugin* pluginInstance__ArableInstruments; @@ -745,7 +826,9 @@ Plugin* pluginInstance__BogaudioModules; Plugin* pluginInstance__CatroModulo; Plugin* pluginInstance__cf; Plugin* pluginInstance__ChowDSP; +Plugin* pluginInstance__dBiz; extern Plugin* pluginInstance__DrumKit; +Plugin* pluginInstance__EnigmaCurry; Plugin* pluginInstance__ESeries; Plugin* pluginInstance__ExpertSleepersEncoders; Plugin* pluginInstance__Extratone; @@ -754,6 +837,7 @@ Plugin* pluginInstance__forsitan; Plugin* pluginInstance__GlueTheGiant; Plugin* pluginInstance__GoodSheperd; Plugin* pluginInstance__GrandeModular; +Plugin* pluginInstance__H4N4; Plugin* pluginInstance__HamptonHarmonics; Plugin* pluginInstance__HetrickCV; extern Plugin* pluginInstance__ImpromptuModular; @@ -780,10 +864,14 @@ Plugin* pluginInstance__PathSet; Plugin* pluginInstance__PinkTrombone; Plugin* pluginInstance__Prism; Plugin* pluginInstance__rackwindows; +Plugin* pluginInstance__RebelTech; Plugin* pluginInstance__repelzen; +Plugin* pluginInstance__sapphire; Plugin* pluginInstance__sonusmodular; Plugin* pluginInstance__StarlingVia; Plugin* pluginInstance__stocaudio; +extern Plugin* pluginInstance__stoermelder_p1; +Plugin* pluginInstance__surgext; Plugin* pluginInstance__unless_modules; Plugin* pluginInstance__ValleyAudio; Plugin* pluginInstance__Voxglitch; @@ -898,6 +986,7 @@ static void initStatic__Cardinal() const StaticPluginLoader spl(p, "Cardinal"); if (spl.ok()) { + p->addModel(modelAidaX); p->addModel(modelCardinalBlank); p->addModel(modelExpanderInputMIDI); p->addModel(modelExpanderOutputMIDI); @@ -919,15 +1008,15 @@ static void initStatic__Cardinal() #endif #ifndef STATIC_BUILD p->addModel(modelAudioFile); - p->addModel(modelIldaeil); #else spl.removeModule("AudioFile"); - spl.removeModule("Ildaeil"); #endif #if !(defined(DISTRHO_OS_WASM) || defined(STATIC_BUILD)) p->addModel(modelCarla); + p->addModel(modelIldaeil); #else spl.removeModule("Carla"); + spl.removeModule("Ildaeil"); #endif #ifndef HEADLESS p->addModel(modelSassyScope); @@ -997,6 +1086,7 @@ static void initStatic__Fundamental() } } +/* static void initStatic__ZamAudio() { Plugin* const p = new Plugin; @@ -1008,6 +1098,7 @@ static void initStatic__ZamAudio() p->addModel(modelZamComp); } } +*/ #ifndef NOPLUGINS static void initStatic__21kHz() @@ -1051,6 +1142,33 @@ static void initStatic__AaronStatic() } } +static void initStatic__alefsbits() +{ + Plugin* const p = new Plugin; + pluginInstance__alefsbits = p; + + const StaticPluginLoader spl(p, "alefsbits"); + if (spl.ok()) + { +#define modelSteps modelalefsbitsSteps +#define modelLogic modelalefsbitsLogic + p->addModel(modelSimplexandhold); + p->addModel(modelBlank6hp); + p->addModel(modelPolyrand); + p->addModel(modelNoize); + p->addModel(modelSteps); + p->addModel(modelFibb); + p->addModel(modelOctsclr); + p->addModel(modelShift); + p->addModel(modelMlt); + p->addModel(modelMath); + p->addModel(modelLogic); + p->addModel(modelProbablynot); +#undef modelSteps +#undef modelLogic + } +} + static void initStatic__Algoritmarte() { Plugin* const p = new Plugin; @@ -1326,23 +1444,16 @@ static void initStatic__Bacon() p->addModel(modelPolyGnome); p->addModel(modelQuantEyes); p->addModel(modelSampleDelay); -#ifdef BUILD_SORTACHORUS - p->addModel(modelSortaChorus); -#endif p->addModel(modelChipNoise); p->addModel(modelChipWaves); p->addModel(modelChipYourWave); p->addModel(modelOpen303); -#ifdef BUILD_GENERICLSFR - p->addModel(modelGenericLFSR); -#endif p->addModel(modelKarplusStrongPoly); p->addModel(modelALingADing); p->addModel(modelBitulator); -#ifdef BUILD_PHASER - p->addModel(modelPhaser); -#endif p->addModel(modelPolyGenerator); + p->addModel(modelLintBuddy); + p->addModel(modelLuckyHold); } } @@ -1375,6 +1486,8 @@ static void initStatic__Befaco() p->addModel(modelMex); p->addModel(modelNoisePlethora); p->addModel(modelChannelStrip); + p->addModel(modelPonyVCO); + p->addModel(modelMotionMTR); #undef modelADSR #undef modelMixer } @@ -1452,7 +1565,7 @@ static void initStatic__BogaudioModules() { // Make sure to use dark theme as default Skins& skins(Skins::skins()); - skins._default = "dark"; + skins._default = settings::darkMode ? "dark" : "light"; #define modelADSR modelBogaudioADSR #define modelLFO modelBogaudioLFO #define modelNoise modelBogaudioNoise @@ -1677,6 +1790,58 @@ static void initStatic__ChowDSP() } } +static void initStatic__dBiz() +{ + Plugin* const p = new Plugin; + pluginInstance__dBiz = p; + + const StaticPluginLoader spl(p, "dBiz"); + if (spl.ok()) + { +#define modelChord modeldBizChord +#define modelDivider modeldBizDivider +#define modelFourSeq modeldBizFourSeq +#define modelVCA4 modeldBizVCA4 + p->addModel(modelNavControl); + p->addModel(modelBench); + p->addModel(modelContorno); + //p->addModel(modelContornoMK2); + p->addModel(modelTranspose); + p->addModel(modelUtility); + p->addModel(modelChord); + p->addModel(modelBene); + p->addModel(modelBenePads); + p->addModel(modelPerfMixer); + p->addModel(modelDrMix); + p->addModel(modelPerfMixer4); + p->addModel(modelVCA4); + p->addModel(modelVCA530); + p->addModel(modelRemix); + p->addModel(modelSmixer); + p->addModel(modelVerbo); + p->addModel(modelDVCO); + p->addModel(modelDAOSC); + p->addModel(modelTROSC); + p->addModel(modelTROSCMK2); + p->addModel(modelSuHa); + p->addModel(modelSuHaMK2); + p->addModel(modelFourSeq); + p->addModel(modelDivider); + p->addModel(modelUtil2); + p->addModel(modelSmorph); + p->addModel(modelBigSmorph); + p->addModel(modelSPan); + p->addModel(modelQuePasa); + p->addModel(modelDualFilter); + p->addModel(modelOrder); + p->addModel(modelDualMatrix); +#undef modelChord +#undef modelDivider +#undef modelFourSeq +#undef modelVCA4 + } +} + static void initStatic__DrumKit() { Plugin* const p = new Plugin; @@ -1701,6 +1866,24 @@ static void initStatic__DrumKit() } } +static void initStatic__EnigmaCurry() +{ + Plugin* const p = new Plugin; + pluginInstance__EnigmaCurry = p; + + const StaticPluginLoader spl(p, "EnigmaCurry"); + if (spl.ok()) + { +#define modelPulse modelEnigmaCurryPulse + p->addModel(modelTransport); + p->addModel(modelLatch); + p->addModel(modelPulse); + p->addModel(modelRange); +#undef modelPulse + } +} + + static void initStatic__ESeries() { Plugin* const p = new Plugin; @@ -1840,6 +2023,7 @@ static void initStatic__GrandeModular() if (spl.ok()) { p->addModel(modelClip); + p->addModel(modelCompare3); p->addModel(modelLFO3); p->addModel(modelLFO4); p->addModel(modelLogic); @@ -1859,12 +2043,25 @@ static void initStatic__GrandeModular() p->addModel(modelScale); p->addModel(modelSplit8); p->addModel(modelTails); + p->addModel(modelTails4); p->addModel(modelVarSampleDelays); p->addModel(modelVCA3); p->addModel(modelVCA4); } } +static void initStatic__H4N4() +{ + Plugin* const p = new Plugin; + pluginInstance__H4N4 = p; + + const StaticPluginLoader spl(p, "h4n4-modules"); + if (spl.ok()) + { + p->addModel(modelXenQnt); + } +} + static void initStatic__HamptonHarmonics() { Plugin* const p = new Plugin; @@ -2166,10 +2363,13 @@ static void initStatic__MindMeld() const StaticPluginLoader spl(p, "MindMeldModular"); if (spl.ok()) { - p->addModel(modelMixMasterJr); - p->addModel(modelAuxExpanderJr); - p->addModel(modelMixMaster); - p->addModel(modelAuxExpander); + p->addModel(modelPatchMaster); + p->addModel(modelPatchMasterBlank); + p->addModel(modelRouteMasterMono5to1); + p->addModel(modelRouteMasterStereo5to1); + p->addModel(modelRouteMasterMono1to5); + p->addModel(modelRouteMasterStereo1to5); + p->addModel(modelMasterChannel); p->addModel(modelMeld); p->addModel(modelUnmeld); p->addModel(modelMSMelder); @@ -2178,6 +2378,10 @@ static void initStatic__MindMeld() p->addModel(modelBassMaster); p->addModel(modelBassMasterJr); p->addModel(modelShapeMaster); + p->addModel(modelMixMasterJr); + p->addModel(modelAuxExpanderJr); + p->addModel(modelMixMaster); + p->addModel(modelAuxExpander); } } @@ -2410,9 +2614,14 @@ static void initStatic__nonlinearcircuits() p->addModel(modelLetsSplosh); p->addModel(modelNeuron); p->addModel(modelNumberwang); + p->addModel(modelRouter); p->addModel(modelSegue); + p->addModel(modelSlothApathy); + p->addModel(modelSlothInertia); + p->addModel(modelSlothTorpor); p->addModel(modelSquidAxon); p->addModel(modelStatues); + p->addModel(modelTripleSloth); } } @@ -2456,7 +2665,9 @@ static void initStatic__PathSet() p->addModel(modelIceTray); p->addModel(modelAstroVibe); p->addModel(modelGlassPane); + p->addModel(modelPlusPane); p->addModel(modelNudge); + p->addModel(modelOneShot); } } @@ -2516,6 +2727,23 @@ static void initStatic__rackwindows() } } +static void initStatic__RebelTech() +{ + Plugin* const p = new Plugin; + pluginInstance__RebelTech = p; + + const StaticPluginLoader spl(p, "RebelTech"); + if (spl.ok()) + { + p->addModel(modelStoicheia); + p->addModel(modelTonic); + p->addModel(modelKlasmata); + p->addModel(modelCLK); + p->addModel(modelLogoi); + p->addModel(modelPhoreo); + } +} + static void initStatic__repelzen() { Plugin* const p = new Plugin; @@ -2539,6 +2767,20 @@ static void initStatic__repelzen() } } +static void initStatic__Sapphire() +{ + Plugin* const p = new Plugin; + pluginInstance__sapphire = p; + + const StaticPluginLoader spl(p, "Sapphire"); + if (spl.ok()) + { + p->addModel(modelElastika); + p->addModel(modelMoots); + p->addModel(modelTubeUnit); + } +} + static void initStatic__sonusmodular() { Plugin* const p = new Plugin; @@ -2614,6 +2856,128 @@ static void initStatic__stocaudio() } } +static void initStatic__stoermelder_p1() +{ + Plugin* const p = new Plugin; + pluginInstance__stoermelder_p1 = p; + + const StaticPluginLoader spl(p, "stoermelder-packone"); + if (spl.ok()) + { + p->addModel(modelCVMap); + p->addModel(modelCVMapCtx); + p->addModel(modelCVMapMicro); + p->addModel(modelCVPam); + p->addModel(modelRotorA); + p->addModel(modelReMoveLite); + p->addModel(modelBolt); + p->addModel(modelInfix); + p->addModel(modelInfixMicro); + p->addModel(modelEightFace); + p->addModel(modelEightFaceX2); + p->addModel(modelSipo); + p->addModel(modelFourRounds); + p->addModel(modelArena); + p->addModel(modelMaze); + p->addModel(modelHive); + p->addModel(modelIntermix); + p->addModel(modelIntermixGate); + p->addModel(modelIntermixEnv); + p->addModel(modelIntermixFade); + p->addModel(modelSail); + p->addModel(modelPile); + p->addModel(modelPilePoly); + p->addModel(modelMirror); + p->addModel(modelAffix); + p->addModel(modelAffixMicro); + p->addModel(modelGrip); + p->addModel(modelGlue); + p->addModel(modelGoto); + p->addModel(modelStroke); + p->addModel(modelSpin); + p->addModel(modelTransit); + p->addModel(modelTransitEx); + p->addModel(modelX4); + p->addModel(modelMacro); + p->addModel(modelOrbit); + p->addModel(modelEightFaceMk2); + p->addModel(modelEightFaceMk2Ex); + p->addModel(modelDirt); + p->addModel(modelMb); + p->addModel(modelMe); + p->addModel(modelRaw); + p->addModel(modelStrip); + p->addModel(modelStripBay4); + p->addModel(modelStripPp); + + spl.removeModule("AudioInterface64"); + spl.removeModule("MidiCat"); + spl.removeModule("MidiCatEx"); + spl.removeModule("MidiCatCtx"); + spl.removeModule("MidiKey"); + spl.removeModule("MidiMon"); + spl.removeModule("MidiPlug"); + spl.removeModule("MidiStep"); + } +} + +static void initStatic__surgext() +{ + Plugin* const p = new Plugin; + pluginInstance__surgext = p; + + const StaticPluginLoader spl(p, "surgext"); + if (spl.ok()) + { + p->addModel(modelVCOClassic); + p->addModel(modelVCOModern); + p->addModel(modelVCOWavetable); + p->addModel(modelVCOWindow); + p->addModel(modelVCOSine); + p->addModel(modelVCOFM2); + p->addModel(modelVCOFM3); + p->addModel(modelVCOSHNoise); + p->addModel(modelVCOAlias); + p->addModel(modelVCOString); + p->addModel(modelVCOTwist); + + // Add the ported ones + p->addModel(modelSurgeVCF); + p->addModel(modelSurgeDelay); + p->addModel(modelSurgeDelayLineByFreq); + p->addModel(modelSurgeDelayLineByFreqExpanded); + p->addModel(modelSurgeWaveshaper); + p->addModel(modelSurgeLFO); + p->addModel(modelSurgeMixer); + p->addModel(modelSurgeModMatrix); + + p->addModel(modelFXReverb); + p->addModel(modelFXPhaser); + p->addModel(modelFXRotarySpeaker); + p->addModel(modelFXDistortion); + p->addModel(modelFXFrequencyShifter); + p->addModel(modelFXChorus); + p->addModel(modelFXVocoder); + p->addModel(modelFXReverb2); + p->addModel(modelFXFlanger); + p->addModel(modelFXRingMod); + p->addModel(modelFXNeuron); + p->addModel(modelFXResonator); + p->addModel(modelFXChow); + p->addModel(modelFXExciter); + p->addModel(modelFXEnsemble); + p->addModel(modelFXCombulator); + p->addModel(modelFXSpringReverb); + p->addModel(modelFXTreeMonster); + + p->addModel(modelEGxVCA); + p->addModel(modelQuadAD); + p->addModel(modelQuadLFO); + + surgext_rack_initialize(); + } +} + static void initStatic__unless_modules() { Plugin* const p = new Plugin; @@ -2672,18 +3036,16 @@ static void initStatic__Voxglitch() p->addModel(modelDigitalSequencerXP); p->addModel(modelGlitchSequencer); p->addModel(modelGhosts); - p->addModel(modelGoblins); - p->addModel(modelGrainEngine); p->addModel(modelGrainEngineMK2); p->addModel(modelGrainEngineMK2Expander); p->addModel(modelGrainFx); + p->addModel(modelGrooveBox); + p->addModel(modelGrooveBoxExpander); p->addModel(modelHazumi); p->addModel(modelLooper); p->addModel(modelRepeater); p->addModel(modelSamplerX8); p->addModel(modelSatanonaut); - p->addModel(modelGrooveBox); - p->addModel(modelGrooveBoxExpander); p->addModel(modelWavBank); p->addModel(modelWavBankMC); p->addModel(modelXY); @@ -2751,11 +3113,12 @@ void initStaticPlugins() { initStatic__Cardinal(); initStatic__Fundamental(); - initStatic__ZamAudio(); + // initStatic__ZamAudio(); #ifndef NOPLUGINS initStatic__21kHz(); initStatic__8Mode(); initStatic__AaronStatic(); + initStatic__alefsbits(); initStatic__Algoritmarte(); initStatic__AmalgamatedHarmonics(); initStatic__AnimatedCircuits(); @@ -2772,7 +3135,9 @@ void initStaticPlugins() initStatic__CatroModulo(); initStatic__cf(); initStatic__ChowDSP(); + initStatic__dBiz(); initStatic__DrumKit(); + initStatic__EnigmaCurry(); initStatic__ESeries(); initStatic__ExpertSleepersEncoders(); initStatic__Extratone(); @@ -2781,6 +3146,7 @@ void initStaticPlugins() initStatic__GlueTheGiant(); initStatic__GoodSheperd(); initStatic__GrandeModular(); + initStatic__H4N4(); initStatic__HamptonHarmonics(); initStatic__HetrickCV(); initStatic__ImpromptuModular(); @@ -2807,10 +3173,14 @@ void initStaticPlugins() initStatic__PinkTrombone(); initStatic__Prism(); initStatic__rackwindows(); + initStatic__RebelTech(); initStatic__repelzen(); + initStatic__Sapphire(); initStatic__sonusmodular(); initStatic__StarlingVia(); initStatic__stocaudio(); + initStatic__stoermelder_p1(); + initStatic__surgext(); initStatic__unless_modules(); initStatic__ValleyAudio(); initStatic__Voxglitch(); @@ -2845,6 +3215,14 @@ void updateStaticPluginsDarkMode() { panelTheme = darkMode ? 1 : 0; } + // glue the giant + { + gtg_default_theme = darkMode ? 1 : 0; + } + // surgext + { + surgext_rack_update_theme(); + } #endif } diff --git a/plugins/stoermelder-packone b/plugins/stoermelder-packone new file mode 160000 index 00000000..ec3c0972 --- /dev/null +++ b/plugins/stoermelder-packone @@ -0,0 +1 @@ +Subproject commit ec3c0972440edddfb00d5e5ad189f345c68be471 diff --git a/plugins/surgext b/plugins/surgext new file mode 160000 index 00000000..f4420b19 --- /dev/null +++ b/plugins/surgext @@ -0,0 +1 @@ +Subproject commit f4420b19c7137d85c0390ef494bb880cc2726e74 diff --git a/plugins/surgext-helper/surgext-helper.cpp b/plugins/surgext-helper/surgext-helper.cpp new file mode 100644 index 00000000..c349e87b --- /dev/null +++ b/plugins/surgext-helper/surgext-helper.cpp @@ -0,0 +1,37 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021-2022 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the LICENSE file. + */ + +#include "../BaconPlugs/src/Style.hpp" +#include "../surgext/src/XTStyle.h" + +using namespace baconpaul::rackplugs; +using namespace sst::surgext_rack::style; + +void surgext_rack_initialize() +{ + BaconStyle::get()->activeStyle = rack::settings::darkMode ? BaconStyle::DARK : BaconStyle::LIGHT; + XTStyle::initialize(); +} + +void surgext_rack_update_theme() +{ + BaconStyle::get()->activeStyle = rack::settings::darkMode ? BaconStyle::DARK : BaconStyle::LIGHT; + BaconStyle::get()->notifyStyleListeners(); + + XTStyle::setGlobalStyle(rack::settings::darkMode ? XTStyle::Style::DARK : XTStyle::Style::LIGHT); + XTStyle::notifyStyleListeners(); +} diff --git a/plugins/todo.txt b/plugins/todo.txt index 2735250f..a2e8434a 100644 --- a/plugins/todo.txt +++ b/plugins/todo.txt @@ -8,15 +8,9 @@ VultModulesFree 61804.0 (not opensource?) NYSTHI 58494.0 (not opensource?) -ML_modules 55847.0 -https://github.com/martin-lueders/ML_modules/ - FrozenWasteland 53690.0 (GPL-3.0-only) https://github.com/almostEric/FrozenWasteland/ -ArableInstruments 48756.0 -https://github.com/adbrant/ArableInstruments/ - squinkylabs-plug1 48682.0 https://github.com/squinkylabs/SquinkyVCV @@ -28,14 +22,12 @@ https://github.com/MarcBoule/Geodesics Alikins 41798.0 https://github.com/alikins/Alikins-rack-plugins -dBiz 40849.0 RJModules 39972.0 DHE-Modules 39582.0 AlrightDevices 38307.0 SynthKit 38228.0 SubmarineFree 38146.0 Hora-treasureFree 37847.0 -ParableInstruments 37781.0 CountModula 37759.0 MSM 37337.0 CharredDesert 36813.0 @@ -45,10 +37,8 @@ Autinn 34990.0 trowaSoft 34946.0 Hora-VCO_VCF_VCA_Free 34770.0 moDllz 34368.0 -21kHz 34172.0 Ohmer 33950.0 modular80 33447.0 -Autodafe-DrumKit 33143.0 Koralfx-Modules 33035.0 alto777_LFSR 32872.0 StellareModular 32526.0 diff --git a/plugins/unless_modules b/plugins/unless_modules index 7c15142c..b91d953b 160000 --- a/plugins/unless_modules +++ b/plugins/unless_modules @@ -1 +1 @@ -Subproject commit 7c15142c4e7adb174f92d7ad54c819970ac4bda4 +Subproject commit b91d953ba545dd92220efd91f922759f18425c56 diff --git a/plugins/voxglitch b/plugins/voxglitch index e856cfb4..55186974 160000 --- a/plugins/voxglitch +++ b/plugins/voxglitch @@ -1 +1 @@ -Subproject commit e856cfb4dbc255165d22294e80e13957241d2c80 +Subproject commit 55186974eeb6c068f2687d7bb4f5c5e1884bf7da diff --git a/src/AsyncDialog.cpp b/src/AsyncDialog.cpp index 1009eace..49af49fd 100644 --- a/src/AsyncDialog.cpp +++ b/src/AsyncDialog.cpp @@ -220,6 +220,10 @@ struct AsyncTextInput : OpaqueWidget } TextField::onSelectKey(e); } + void step() override { + APP->event->setSelectedWidget(this); + TextField::step(); + } }; AsyncTextField* const textField = new AsyncTextField; textField->box.size.x = contentLayout->box.size.x - (label != nullptr ? label->box.size.x + margin : 0); diff --git a/src/Cardinal/CardinalRemote.cpp b/src/Cardinal/CardinalRemote.cpp new file mode 120000 index 00000000..23838232 --- /dev/null +++ b/src/Cardinal/CardinalRemote.cpp @@ -0,0 +1 @@ +../CardinalRemote.cpp \ No newline at end of file diff --git a/src/Cardinal/CardinalX11WindowIcon.cpp b/src/Cardinal/CardinalX11WindowIcon.cpp new file mode 120000 index 00000000..5d4fb7f7 --- /dev/null +++ b/src/Cardinal/CardinalX11WindowIcon.cpp @@ -0,0 +1 @@ +../CardinalX11WindowIcon.cpp \ No newline at end of file diff --git a/src/Cardinal/DistrhoPluginInfo.h b/src/Cardinal/DistrhoPluginInfo.h index f08793d0..bae1099d 100644 --- a/src/Cardinal/DistrhoPluginInfo.h +++ b/src/Cardinal/DistrhoPluginInfo.h @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -19,6 +19,7 @@ #define DISTRHO_PLUGIN_INFO_H_INCLUDED #define CARDINAL_VARIANT_MAIN 1 +#define CARDINAL_VARIANT_MINI 0 #define CARDINAL_VARIANT_FX 0 #define CARDINAL_VARIANT_NATIVE 0 #define CARDINAL_VARIANT_SYNTH 0 @@ -26,13 +27,15 @@ #define CARDINAL_NUM_AUDIO_INPUTS 8 #define CARDINAL_NUM_AUDIO_OUTPUTS 8 -#define DISTRHO_PLUGIN_BRAND "DISTRHO" -#define DISTRHO_PLUGIN_NAME "Cardinal" -#define DISTRHO_PLUGIN_LABEL "Cardinal" -#define DISTRHO_PLUGIN_URI "https://distrho.kx.studio/plugins/cardinal" +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_NAME "Cardinal" +#define DISTRHO_PLUGIN_LABEL "Cardinal" +#define DISTRHO_PLUGIN_URI "https://distrho.kx.studio/plugins/cardinal" +#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.cardinal" #ifdef HEADLESS #define DISTRHO_PLUGIN_HAS_UI 0 +#define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 0 #else #define DISTRHO_PLUGIN_HAS_UI 1 #define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 1 @@ -42,7 +45,7 @@ #define DISTRHO_UI_DEFAULT_WIDTH 1228 #define DISTRHO_UI_DEFAULT_HEIGHT 666 #endif -#define DISTRHO_PLUGIN_IS_SYNTH 0 +#define DISTRHO_PLUGIN_IS_SYNTH 1 #define DISTRHO_PLUGIN_NUM_INPUTS CARDINAL_NUM_AUDIO_INPUTS + 10 #define DISTRHO_PLUGIN_NUM_OUTPUTS CARDINAL_NUM_AUDIO_OUTPUTS + 10 #define DISTRHO_PLUGIN_WANT_MIDI_INPUT 1 @@ -50,7 +53,7 @@ #define DISTRHO_PLUGIN_WANT_FULL_STATE 1 #define DISTRHO_PLUGIN_WANT_STATE 1 #define DISTRHO_PLUGIN_WANT_TIMEPOS 1 -#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:UtilityPlugin" -#define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Generator" +#define DISTRHO_PLUGIN_USES_CUSTOM_MODGUI 1 +#define DISTRHO_PLUGIN_LV2_CATEGORY "mod:ControlVoltagePlugin, lv2:UtilityPlugin" #endif // DISTRHO_PLUGIN_INFO_H_INCLUDED diff --git a/src/Cardinal/MenuBar.cpp b/src/Cardinal/MenuBar.cpp new file mode 120000 index 00000000..8d1a35a5 --- /dev/null +++ b/src/Cardinal/MenuBar.cpp @@ -0,0 +1 @@ +../override/MenuBar.cpp \ No newline at end of file diff --git a/src/CardinalCommon.cpp b/src/CardinalCommon.cpp index 4329e046..8fdba7e3 100644 --- a/src/CardinalCommon.cpp +++ b/src/CardinalCommon.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -38,9 +38,19 @@ #include #include #include +#include #include +#include #include +#ifndef DISTRHO_PLUGIN_WANT_DIRECT_ACCESS +# error wrong build +#endif + +#if (defined(STATIC_BUILD) && !defined(__MOD_DEVICES__)) || CARDINAL_VARIANT_MINI +# undef CARDINAL_INIT_OSC_THREAD +#endif + #ifdef NDEBUG # undef DEBUG #endif @@ -53,17 +63,735 @@ # include #endif +#ifdef ARCH_LIN +# include +#endif + +#ifdef HAVE_LIBLO +# include +#endif + #ifdef DISTRHO_OS_WASM # include #endif -const std::string CARDINAL_VERSION = "22.09"; +#if defined(CARDINAL_COMMON_DSP_ONLY) || defined(HEADLESS) +# define HEADLESS_BEHAVIOUR +#endif + +#if CARDINAL_VARIANT_FX +# define CARDINAL_VARIANT_NAME "fx" +#elif CARDINAL_VARIANT_MINI +# define CARDINAL_VARIANT_NAME "mini" +#elif CARDINAL_VARIANT_NATIVE +# define CARDINAL_VARIANT_NAME "native" +#elif CARDINAL_VARIANT_SYNTH +# define CARDINAL_VARIANT_NAME "synth" +#else +# define CARDINAL_VARIANT_NAME "main" +#endif + +#ifdef DISTRHO_OS_WASM +# if CARDINAL_VARIANT_MINI +# define CARDINAL_WASM_WELCOME_TEMPLATE_FILENAME "welcome-wasm-mini" +# else +# define CARDINAL_WASM_WELCOME_TEMPLATE_FILENAME "welcome-wasm" +# endif +#endif namespace rack { +namespace asset { +std::string patchesPath(); +void destroy(); +} +namespace plugin { +void initStaticPlugins(); +void destroyStaticPlugins(); +} +} + +const std::string CARDINAL_VERSION = "23.10"; + +START_NAMESPACE_DISTRHO + +// ----------------------------------------------------------------------------------------------------------- + +#ifndef HEADLESS +void handleHostParameterDrag(const CardinalPluginContext* pcontext, uint index, bool started) +{ + DISTRHO_SAFE_ASSERT_RETURN(pcontext->ui != nullptr,); + + #ifndef CARDINAL_COMMON_DSP_ONLY + if (started) + { + pcontext->ui->editParameter(index, true); + pcontext->ui->setParameterValue(index, pcontext->parameters[index]); + } + else + { + pcontext->ui->editParameter(index, false); + } + #endif +} +#endif + +// -------------------------------------------------------------------------------------------------------------------- + +#ifndef HEADLESS +bool CardinalPluginContext::addIdleCallback(IdleCallback* const cb) const +{ + #ifndef CARDINAL_COMMON_DSP_ONLY + if (ui != nullptr) + { + ui->addIdleCallback(cb); + return true; + } + #else + // unused + (void)cb; + #endif + + return false; +} + +void CardinalPluginContext::removeIdleCallback(IdleCallback* const cb) const +{ + #ifndef CARDINAL_COMMON_DSP_ONLY + if (ui != nullptr) + ui->removeIdleCallback(cb); + #else + // unused + (void)cb; + #endif +} +#endif + +void CardinalPluginContext::writeMidiMessage(const rack::midi::Message& message, const uint8_t channel) +{ + if (bypassed) + return; + + const size_t size = message.bytes.size(); + DISTRHO_SAFE_ASSERT_RETURN(size > 0,); + DISTRHO_SAFE_ASSERT_RETURN(message.frame >= 0,); + + MidiEvent event; + event.frame = message.frame; + + switch (message.bytes[0] & 0xF0) + { + case 0x80: + case 0x90: + case 0xA0: + case 0xB0: + case 0xE0: + event.size = 3; + break; + case 0xC0: + case 0xD0: + event.size = 2; + break; + case 0xF0: + switch (message.bytes[0] & 0x0F) + { + case 0x0: + case 0x4: + case 0x5: + case 0x7: + case 0x9: + case 0xD: + // unsupported + return; + case 0x1: + case 0x2: + case 0x3: + case 0xE: + event.size = 3; + break; + case 0x6: + case 0x8: + case 0xA: + case 0xB: + case 0xC: + case 0xF: + event.size = 1; + break; + } + break; + default: + // invalid + return; + } + + DISTRHO_SAFE_ASSERT_RETURN(size >= event.size,); + + std::memcpy(event.data, message.bytes.data(), event.size); + + if (channel != 0 && event.data[0] < 0xF0) + event.data[0] |= channel & 0x0F; + + plugin->writeMidiEvent(event); +} + +// ----------------------------------------------------------------------------------------------------------- + +#ifdef HAVE_LIBLO +static void osc_error_handler(int num, const char* msg, const char* path) +{ + d_stderr("Cardinal OSC Error: code: %i, msg: \"%s\", path: \"%s\")", num, msg, path); +} + +static int osc_fallback_handler(const char* const path, const char* const types, lo_arg**, int, lo_message, void*) +{ + d_stderr("Cardinal OSC unhandled message \"%s\" with types \"%s\"", path, types); + return 0; +} + +static int osc_hello_handler(const char*, const char*, lo_arg**, int, const lo_message m, void* const self) +{ + d_stdout("Hello received from OSC, saying hello back to them o/"); + const lo_address source = lo_message_get_source(m); + const lo_server server = static_cast(self)->oscServer; + lo_send_from(source, server, LO_TT_IMMEDIATE, "/resp", "ss", "hello", "ok"); + return 0; +} + +static int osc_load_handler(const char*, const char* types, lo_arg** argv, int argc, const lo_message m, void* const self) +{ + d_debug("osc_load_handler()"); + DISTRHO_SAFE_ASSERT_RETURN(argc == 1, 0); + DISTRHO_SAFE_ASSERT_RETURN(types != nullptr && types[0] == 'b', 0); + + const int32_t size = argv[0]->blob.size; + DISTRHO_SAFE_ASSERT_RETURN(size > 4, 0); + + const uint8_t* const blob = (uint8_t*)(&argv[0]->blob.data); + DISTRHO_SAFE_ASSERT_RETURN(blob != nullptr, 0); + + bool ok = false; + + if (CardinalBasePlugin* const plugin = static_cast(self)->remotePluginInstance) + { + CardinalPluginContext* const context = plugin->context; + std::vector data(size); + std::memcpy(data.data(), blob, size); + + rack::contextSet(context); + rack::system::removeRecursively(context->patch->autosavePath); + rack::system::createDirectories(context->patch->autosavePath); + try { + rack::system::unarchiveToDirectory(data, context->patch->autosavePath); + context->patch->loadAutosave(); + ok = true; + } + catch (rack::Exception& e) { + WARN("%s", e.what()); + } + rack::contextSet(nullptr); + } + + const lo_address source = lo_message_get_source(m); + const lo_server server = static_cast(self)->oscServer; + lo_send_from(source, server, LO_TT_IMMEDIATE, "/resp", "ss", "load", ok ? "ok" : "fail"); + return 0; +} + +static int osc_param_handler(const char*, const char* types, lo_arg** argv, int argc, const lo_message m, void* const self) +{ + d_debug("osc_param_handler()"); + DISTRHO_SAFE_ASSERT_RETURN(argc == 3, 0); + DISTRHO_SAFE_ASSERT_RETURN(types != nullptr, 0); + DISTRHO_SAFE_ASSERT_RETURN(types[0] == 'h', 0); + DISTRHO_SAFE_ASSERT_RETURN(types[1] == 'i', 0); + DISTRHO_SAFE_ASSERT_RETURN(types[2] == 'f', 0); + + if (CardinalBasePlugin* const plugin = static_cast(self)->remotePluginInstance) + { + CardinalPluginContext* const context = plugin->context; + + const int64_t moduleId = argv[0]->h; + const int paramId = argv[1]->i; + const float paramValue = argv[2]->f; + + rack::engine::Module* const module = context->engine->getModule(moduleId); + DISTRHO_SAFE_ASSERT_RETURN(module != nullptr, 0); + + context->engine->setParamValue(module, paramId, paramValue); + } + + return 0; +} + +static int osc_host_param_handler(const char*, const char* types, lo_arg** argv, int argc, const lo_message m, void* const self) +{ + d_debug("osc_host_param_handler()"); + DISTRHO_SAFE_ASSERT_RETURN(argc == 2, 0); + DISTRHO_SAFE_ASSERT_RETURN(types != nullptr, 0); + DISTRHO_SAFE_ASSERT_RETURN(types[0] == 'i', 0); + DISTRHO_SAFE_ASSERT_RETURN(types[1] == 'f', 0); + + if (CardinalBasePlugin* const plugin = static_cast(self)->remotePluginInstance) + { + CardinalPluginContext* const context = plugin->context; + + const int paramId = argv[0]->i; + DISTRHO_SAFE_ASSERT_RETURN(paramId >= 0, 0); + + const uint uparamId = static_cast(paramId); + DISTRHO_SAFE_ASSERT_UINT2_RETURN(uparamId < kModuleParameterCount, uparamId, kModuleParameterCount, 0); + + const float paramValue = argv[1]->f; + + context->parameters[uparamId] = paramValue; + } + + return 0; +} + +# ifdef CARDINAL_INIT_OSC_THREAD +static int osc_screenshot_handler(const char*, const char* types, lo_arg** argv, int argc, const lo_message m, void* const self) +{ + d_debug("osc_screenshot_handler()"); + DISTRHO_SAFE_ASSERT_RETURN(argc == 1, 0); + DISTRHO_SAFE_ASSERT_RETURN(types != nullptr && types[0] == 'b', 0); + + const int32_t size = argv[0]->blob.size; + DISTRHO_SAFE_ASSERT_RETURN(size > 4, 0); + + const uint8_t* const blob = (uint8_t*)(&argv[0]->blob.data); + DISTRHO_SAFE_ASSERT_RETURN(blob != nullptr, 0); + + bool ok = false; + + if (CardinalBasePlugin* const plugin = static_cast(self)->remotePluginInstance) + { + if (char* const screenshot = String::asBase64(blob, size).getAndReleaseBuffer()) + { + ok = plugin->updateStateValue("screenshot", screenshot); + std::free(screenshot); + } + } + + const lo_address source = lo_message_get_source(m); + const lo_server server = static_cast(self)->oscServer; + lo_send_from(source, server, LO_TT_IMMEDIATE, "/resp", "ss", "screenshot", ok ? "ok" : "fail"); + return 0; +} +# endif +#endif + +// ----------------------------------------------------------------------------------------------------------- + +#if defined(DISTRHO_OS_WASM) && !defined(CARDINAL_COMMON_UI_ONLY) +static void WebBrowserDataLoaded(void* const data) +{ + static_cast(data)->loadSettings(true); +} +#endif + +// ----------------------------------------------------------------------------------------------------------- + +Initializer::Initializer(const CardinalBasePlugin* const plugin, const CardinalBaseUI* const ui) +{ + using namespace rack; + + // Cardinal default settings, potentially overriding VCV Rack ones + settings::allowCursorLock = false; + settings::tooltips = true; + settings::cableOpacity = 0.5f; + settings::cableTension = 0.75f; + settings::rackBrightness = 1.0f; + settings::haloBrightness = 0.25f; + settings::knobMode = settings::KNOB_MODE_LINEAR; + settings::knobScroll = false; + settings::knobScrollSensitivity = 0.001f; + settings::lockModules = false; + settings::browserSort = settings::BROWSER_SORT_UPDATED; + settings::browserZoom = -1.f; + settings::invertZoom = false; + settings::squeezeModules = true; + settings::darkMode = true; + settings::uiTheme = "dark"; + + // runtime behaviour + settings::devMode = true; + settings::isPlugin = true; + #ifdef HEADLESS_BEHAVIOUR + settings::headless = true; + #endif + + // copied from https://community.vcvrack.com/t/16-colour-cable-palette/15951 + settings::cableColors = { + color::fromHexString("#ff5252"), + color::fromHexString("#ff9352"), + color::fromHexString("#ffd452"), + color::fromHexString("#e8ff52"), + color::fromHexString("#a8ff52"), + color::fromHexString("#67ff52"), + color::fromHexString("#52ff7d"), + color::fromHexString("#52ffbe"), + color::fromHexString("#52ffff"), + color::fromHexString("#52beff"), + color::fromHexString("#527dff"), + color::fromHexString("#6752ff"), + color::fromHexString("#a852ff"), + color::fromHexString("#e952ff"), + color::fromHexString("#ff52d4"), + color::fromHexString("#ff5293"), + }; + + system::init(); + logger::init(); + random::init(); + ui::init(); + + #ifdef CARDINAL_COMMON_UI_ONLY + constexpr const bool isRealInstance = true; + #else + const bool isRealInstance = !plugin->isDummyInstance(); + #endif + + if (asset::systemDir.empty()) + { + if (const char* const bundlePath = (plugin != nullptr ? plugin->getBundlePath() : + #if DISTRHO_PLUGIN_HAS_UI + ui != nullptr ? ui->getBundlePath() : + #endif + nullptr)) + { + if (const char* const resourcePath = getResourcePath(bundlePath)) + { + asset::systemDir = resourcePath; + asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); + } + } + + if (asset::systemDir.empty() || ! system::exists(asset::systemDir) || ! system::exists(asset::bundlePath)) + { + #ifdef CARDINAL_PLUGIN_SOURCE_DIR + // Make system dir point to source code location as fallback + asset::systemDir = CARDINAL_PLUGIN_SOURCE_DIR DISTRHO_OS_SEP_STR "Rack"; + asset::bundlePath.clear(); + + // If source code dir does not exist use install target prefix as system dir + if (!system::exists(system::join(asset::systemDir, "res"))) + #endif + { + #if defined(DISTRHO_OS_WASM) + asset::systemDir = "/resources"; + #elif defined(ARCH_MAC) + asset::systemDir = "/Library/Application Support/Cardinal"; + #elif defined(ARCH_WIN) + asset::systemDir = system::join(getSpecialPath(kSpecialPathCommonProgramFiles), "Cardinal"); + #else + asset::systemDir = CARDINAL_PLUGIN_PREFIX "/share/cardinal"; + #endif + asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); + } + } + } + + if (asset::userDir.empty()) + { + #if defined(DISTRHO_OS_WASM) + asset::userDir = "/userfiles"; + #elif defined(ARCH_MAC) + asset::userDir = system::join(homeDir(), "Documents", "Cardinal"); + #elif defined(ARCH_WIN) + asset::userDir = system::join(getSpecialPath(kSpecialPathMyDocuments), "Cardinal"); + #else + std::string xdgConfigDir; + if (const char* const xdgEnv = getenv("XDG_CONFIG_HOME")) + xdgConfigDir = xdgEnv; + if (xdgConfigDir.empty()) + xdgConfigDir = system::join(homeDir(), ".config"); + + const std::string xdgDirsConfigPath(system::join(xdgConfigDir, "user-dirs.dirs")); + + if (system::exists(xdgDirsConfigPath)) + { + std::ifstream xdgDirsConfigFile(xdgDirsConfigPath, std::ios::in|std::ios::ate); + std::string xdgDirsConfig(xdgDirsConfigFile.tellg(), 0); + + xdgDirsConfigFile.seekg(0); + xdgDirsConfigFile.read(&xdgDirsConfig[0], xdgDirsConfig.size()); + + if (const char* const xdgDocsDir = std::strstr(xdgDirsConfig.c_str(), "XDG_DOCUMENTS_DIR=\"")) + { + if (const char* const xdgDocsDirNL = std::strstr(xdgDocsDir, "\"\n")) + { + asset::userDir = std::string(xdgDocsDir + 19, xdgDocsDirNL - xdgDocsDir - 19); + + if (string::startsWith(asset::userDir, "$HOME")) + asset::userDir.replace(asset::userDir.begin(), asset::userDir.begin() + 5, homeDir()); + + if (! system::exists(asset::userDir)) + asset::userDir.clear(); + } + } + } + + if (asset::userDir.empty()) + asset::userDir = system::join(homeDir(), "Documents", "Cardinal"); + #endif + + if (isRealInstance) + { + system::createDirectory(asset::userDir); + #if defined(DISTRHO_OS_WASM) && !defined(CARDINAL_COMMON_UI_ONLY) + EM_ASM({ + Module.FS.mount(Module.IDBFS, {}, '/userfiles'); + Module.FS.syncfs(true, function(err) { if (!err) { dynCall('vi', $0, [$1]) } }); + }, WebBrowserDataLoaded, this); + #endif + } + } + + #ifndef CARDINAL_COMMON_DSP_ONLY + if (asset::configDir.empty()) + { + #if defined(ARCH_MAC) || defined(ARCH_WIN) || defined(DISTRHO_OS_WASM) + asset::configDir = asset::userDir; + #else + if (const char* const xdgEnv = getenv("XDG_CONFIG_HOME")) + asset::configDir = system::join(xdgEnv, "Cardinal"); + else + asset::configDir = system::join(homeDir(), ".config", "Cardinal"); + + if (isRealInstance) + system::createDirectory(asset::configDir); + #endif + } + #endif + + if (settings::settingsPath.empty()) + settings::settingsPath = asset::config(CARDINAL_VARIANT_NAME ".json"); + + templatePath = asset::user("templates/" CARDINAL_VARIANT_NAME ".vcv"); + #ifdef DISTRHO_OS_WASM + factoryTemplatePath = system::join(asset::patchesPath(), CARDINAL_WASM_WELCOME_TEMPLATE_FILENAME ".vcv"); + #else + factoryTemplatePath = system::join(asset::patchesPath(), "templates/" CARDINAL_VARIANT_NAME ".vcv"); + #endif + + // Log environment + INFO("%s %s %s, compatible with Rack version %s", APP_NAME.c_str(), APP_EDITION.c_str(), CARDINAL_VERSION.c_str(), APP_VERSION.c_str()); + INFO("%s", system::getOperatingSystemInfo().c_str()); + INFO("Binary filename: %s", getBinaryFilename()); + if (plugin != nullptr) { + INFO("Bundle path: %s", plugin->getBundlePath()); + #if DISTRHO_PLUGIN_HAS_UI + } else if (ui != nullptr) { + INFO("Bundle path: %s", ui->getBundlePath()); + #endif + } + INFO("System directory: %s", asset::systemDir.c_str()); + INFO("User directory: %s", asset::userDir.c_str()); + INFO("Template patch: %s", templatePath.c_str()); + INFO("System template patch: %s", factoryTemplatePath.c_str()); + + // Report to user if something is wrong with the installation + if (asset::systemDir.empty()) + { + d_stderr2("Failed to locate Cardinal plugin bundle.\n" + "Install Cardinal with its bundle folder intact and try again."); + } + else if (! system::exists(asset::systemDir)) + { + d_stderr2("System directory \"%s\" does not exist.\n" + "Make sure Cardinal was downloaded and installed correctly.", asset::systemDir.c_str()); + } + + INFO("Initializing plugins"); + plugin::initStaticPlugins(); + + INFO("Initializing plugin browser DB"); + app::browserInit(); + + loadSettings(isRealInstance); + + #if defined(CARDINAL_INIT_OSC_THREAD) + INFO("Initializing OSC Remote control"); + const char* port; + if (const char* const portEnv = std::getenv("CARDINAL_REMOTE_HOST_PORT")) + port = portEnv; + else + port = CARDINAL_DEFAULT_REMOTE_PORT; + startRemoteServer(port); + #elif defined(HAVE_LIBLO) + if (isStandalone()) { + INFO("OSC Remote control is available on request"); + } else { + INFO("OSC Remote control is not available on plugin variants"); + } + #else + INFO("OSC Remote control is not enabled in this build"); + #endif +} + +Initializer::~Initializer() +{ + using namespace rack; + + #ifdef HAVE_LIBLO + stopRemoteServer(); + #endif + + if (shouldSaveSettings) + { + INFO("Save settings"); + settings::save(); + } + + INFO("Clearing asset paths"); + asset::bundlePath.clear(); + asset::systemDir.clear(); + asset::userDir.clear(); + + INFO("Destroying plugins"); + plugin::destroyStaticPlugins(); + + INFO("Destroying colourized assets"); + asset::destroy(); + + INFO("Destroying settings"); + settings::destroy(); + + INFO("Destroying logger"); + logger::destroy(); +} + +void Initializer::loadSettings(const bool isRealInstance) +{ + using namespace rack; + + if (isRealInstance) + { + INFO("Loading settings"); + settings::load(); + shouldSaveSettings = true; + } + + // enforce settings that do not make sense as anything else + settings::safeMode = false; + settings::token.clear(); + settings::windowMaximized = false; + settings::windowPos = math::Vec(0, 0); + settings::pixelRatio = 0.0; + settings::sampleRate = 0; + settings::threadCount = 1; + settings::autosaveInterval = 0; + settings::skipLoadOnLaunch = true; + settings::autoCheckUpdates = false; + settings::showTipsOnLaunch = false; + settings::tipIndex = -1; + + if (settings::uiTheme != "dark" && settings::uiTheme != "light") + { + settings::uiTheme = "dark"; + rack::ui::refreshTheme(); + } + + // reload dark/light mode as necessary + switchDarkMode(settings::uiTheme == "dark"); +} + +#ifdef HAVE_LIBLO +bool Initializer::startRemoteServer(const char* const port) +{ + #ifdef CARDINAL_INIT_OSC_THREAD + if (oscServerThread != nullptr) + return true; + + if ((oscServerThread = lo_server_thread_new_with_proto(port, LO_UDP, osc_error_handler)) == nullptr) + return false; + + oscServer = lo_server_thread_get_server(oscServerThread); + + lo_server_thread_add_method(oscServerThread, "/hello", "", osc_hello_handler, this); + lo_server_thread_add_method(oscServerThread, "/host-param", "if", osc_host_param_handler, this); + lo_server_thread_add_method(oscServerThread, "/load", "b", osc_load_handler, this); + lo_server_thread_add_method(oscServerThread, "/param", "hif", osc_param_handler, this); + lo_server_thread_add_method(oscServerThread, "/screenshot", "b", osc_screenshot_handler, this); + lo_server_thread_add_method(oscServerThread, nullptr, nullptr, osc_fallback_handler, nullptr); + lo_server_thread_start(oscServerThread); + #else + if (oscServer != nullptr) + return true; + + if ((oscServer = lo_server_new_with_proto(port, LO_UDP, osc_error_handler)) == nullptr) + return false; + + lo_server_add_method(oscServer, "/hello", "", osc_hello_handler, this); + lo_server_add_method(oscServer, "/host-param", "if", osc_host_param_handler, this); + lo_server_add_method(oscServer, "/load", "b", osc_load_handler, this); + lo_server_add_method(oscServer, "/param", "hif", osc_param_handler, this); + lo_server_add_method(oscServer, nullptr, nullptr, osc_fallback_handler, nullptr); + #endif + + return true; +} + +void Initializer::stopRemoteServer() +{ + DISTRHO_SAFE_ASSERT(remotePluginInstance == nullptr); + + #ifdef CARDINAL_INIT_OSC_THREAD + if (oscServerThread != nullptr) + { + lo_server_thread_stop(oscServerThread); + lo_server_thread_del_method(oscServerThread, nullptr, nullptr); + lo_server_thread_free(oscServerThread); + oscServerThread = oscServer = nullptr; + } + #else + if (oscServer != nullptr) + { + lo_server_del_method(oscServer, nullptr, nullptr); + lo_server_free(oscServer); + oscServer = nullptr; + } + #endif +} + +void Initializer::stepRemoteServer() +{ + DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(remotePluginInstance != nullptr,); + + #ifndef CARDINAL_INIT_OSC_THREAD + for (;;) + { + try { + if (lo_server_recv_noblock(oscServer, 0) == 0) + break; + } DISTRHO_SAFE_EXCEPTION_CONTINUE("stepRemoteServer") + } + #endif +} +#endif // HAVE_LIBLO + +// -------------------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO + +// -------------------------------------------------------------------------------------------------------------------- + +namespace rack { + +bool isMini() +{ +#if CARDINAL_VARIANT_MINI + return true; +#else + return false; +#endif +} bool isStandalone() { - return std::strstr(getPluginFormatName(), "Standalone") != nullptr; + static const bool standalone = std::strstr(getPluginFormatName(), "Standalone") != nullptr; + return standalone; } #ifdef ARCH_WIN @@ -84,13 +812,16 @@ std::string getSpecialPath(const SpecialPath type) case kSpecialPathAppData: csidl = CSIDL_APPDATA; break; + case kSpecialPathMyDocuments: + csidl = CSIDL_MYDOCUMENTS; + break; default: return {}; } - WCHAR path[MAX_PATH + 256]; + WCHAR path[MAX_PATH] = {}; - if (SHGetSpecialFolderPathW(nullptr, path, csidl, FALSE)) + if (SHGetFolderPathW(nullptr, csidl, nullptr, SHGFP_TYPE_CURRENT, path) == S_OK) return string::UTF16toUTF8(path); return {}; @@ -101,29 +832,42 @@ std::string getSpecialPath(const SpecialPath type) char* patchFromURL = nullptr; char* patchRemoteURL = nullptr; char* patchStorageSlug = nullptr; + +void syncfs() +{ + settings::save(); + + #ifndef CARDINAL_COMMON_UI_ONLY + EM_ASM({ + Module.FS.syncfs(false, function(){} ); + }); + #endif +} #endif std::string homeDir() { -# ifdef ARCH_WIN + #ifdef ARCH_WIN return getSpecialPath(kSpecialPathUserProfile); -# else + #else if (const char* const home = getenv("HOME")) return home; if (struct passwd* const pwd = getpwuid(getuid())) return pwd->pw_dir; -# endif + #endif return {}; } } // namespace rack +// -------------------------------------------------------------------------------------------------------------------- + namespace patchUtils { using namespace rack; -#ifndef HEADLESS +#ifndef HEADLESS_BEHAVIOUR static void promptClear(const char* const message, const std::function action) { if (APP->history->isSaved() || APP->scene->rack->hasModules()) @@ -135,7 +879,7 @@ static void promptClear(const char* const message, const std::function a void loadDialog() { -#ifndef HEADLESS +#ifndef HEADLESS_BEHAVIOUR promptClear("The current patch is unsaved. Clear it and open a new patch?", []() { std::string dir; if (! APP->patch->path.empty()) @@ -160,7 +904,7 @@ void loadDialog() void loadPathDialog(const std::string& path, const bool asTemplate) { -#ifndef HEADLESS +#ifndef HEADLESS_BEHAVIOUR promptClear("The current patch is unsaved. Clear it and open the new patch?", [path, asTemplate]() { APP->patch->loadAction(path); @@ -169,6 +913,14 @@ void loadPathDialog(const std::string& path, const bool asTemplate) APP->patch->path = ""; APP->history->setSaved(); } + + #ifdef DISTRHO_OS_WASM + syncfs(); + #endif + + if (remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote()) + if (remoteDetails->autoDeploy) + remoteUtils::sendFullPatchToRemote(remoteDetails); }); #endif } @@ -194,32 +946,79 @@ void loadSelectionDialog() } std::free(pathC); + + #ifdef DISTRHO_OS_WASM + syncfs(); + #endif + + if (remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote()) + if (remoteDetails->autoDeploy) + remoteUtils::sendFullPatchToRemote(remoteDetails); }); } -void loadTemplateDialog() +void loadTemplate(const bool factory) { -#ifndef HEADLESS - promptClear("The current patch is unsaved. Clear it and start a new patch?", []() { - APP->patch->loadTemplate(); + try { + APP->patch->load(factory ? APP->patch->factoryTemplatePath : APP->patch->templatePath); + } + catch (Exception& e) { + // if user template failed, try the factory one + if (!factory) + return loadTemplate(true); + + const std::string message = string::f("Could not load template patch, clearing rack: %s", e.what()); + asyncDialog::create(message.c_str()); + + APP->patch->clear(); + APP->patch->clearAutosave(); + } + + // load() sets the patch's original patch, but we don't want to use that. + APP->patch->path.clear(); + APP->history->setSaved(); + + #ifdef DISTRHO_OS_WASM + syncfs(); + #endif + + if (remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote()) + if (remoteDetails->autoDeploy) + remoteUtils::sendFullPatchToRemote(remoteDetails); +} + + +void loadTemplateDialog(const bool factory) +{ +#ifndef HEADLESS_BEHAVIOUR + promptClear("The current patch is unsaved. Clear it and start a new patch?", [factory]() { + loadTemplate(factory); }); #endif } void revertDialog() { -#ifndef HEADLESS +#ifndef HEADLESS_BEHAVIOUR if (APP->patch->path.empty()) return; promptClear("Revert patch to the last saved state?", []{ APP->patch->loadAction(APP->patch->path); + + #ifdef DISTRHO_OS_WASM + syncfs(); + #endif + + if (remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote()) + if (remoteDetails->autoDeploy) + remoteUtils::sendFullPatchToRemote(remoteDetails); }); #endif } void saveDialog(const std::string& path) { -#ifndef HEADLESS +#ifndef HEADLESS_BEHAVIOUR if (path.empty()) { return; } @@ -234,17 +1033,30 @@ void saveDialog(const std::string& path) asyncDialog::create(string::f("Could not save patch: %s", e.what()).c_str()); return; } + + APP->patch->pushRecentPath(path); + + #ifdef DISTRHO_OS_WASM + syncfs(); + #else + rack::settings::save(); + #endif #endif } -#ifndef HEADLESS +#ifndef HEADLESS_BEHAVIOUR static void saveAsDialog(const bool uncompressed) { std::string dir; if (! APP->patch->path.empty()) + { dir = system::getDirectory(APP->patch->path); + } else - dir = homeDir(); + { + dir = asset::user("patches"); + system::createDirectories(dir); + } CardinalPluginContext* const pcontext = static_cast(APP); DISTRHO_SAFE_ASSERT_RETURN(pcontext != nullptr,); @@ -264,18 +1076,37 @@ static void saveAsDialog(const bool uncompressed) void saveAsDialog() { -#ifndef HEADLESS +#ifndef HEADLESS_BEHAVIOUR saveAsDialog(false); #endif } void saveAsDialogUncompressed() { -#ifndef HEADLESS +#ifndef HEADLESS_BEHAVIOUR saveAsDialog(true); #endif } +void saveTemplateDialog() +{ + asyncDialog::create("Overwrite template patch?", []{ + rack::system::createDirectories(system::getDirectory(APP->patch->templatePath)); + + try { + APP->patch->save(APP->patch->templatePath); + } + catch (Exception& e) { + asyncDialog::create(string::f("Could not save template patch: %s", e.what()).c_str()); + return; + } + + #ifdef DISTRHO_OS_WASM + syncfs(); + #endif + }); +} + void openBrowser(const std::string& url) { #ifdef DISTRHO_OS_WASM @@ -289,13 +1120,15 @@ void openBrowser(const std::string& url) } +// -------------------------------------------------------------------------------------------------------------------- + void async_dialog_filebrowser(const bool saving, const char* const defaultName, const char* const startDir, const char* const title, const std::function action) { -#ifndef HEADLESS +#ifndef HEADLESS_BEHAVIOUR CardinalPluginContext* const pcontext = static_cast(APP); DISTRHO_SAFE_ASSERT_RETURN(pcontext != nullptr,); @@ -318,14 +1151,14 @@ void async_dialog_filebrowser(const bool saving, void async_dialog_message(const char* const message) { -#ifndef HEADLESS +#ifndef HEADLESS_BEHAVIOUR asyncDialog::create(message); #endif } void async_dialog_message(const char* const message, const std::function action) { -#ifndef HEADLESS +#ifndef HEADLESS_BEHAVIOUR asyncDialog::create(message, action); #endif } @@ -333,7 +1166,7 @@ void async_dialog_message(const char* const message, const std::function void async_dialog_text_input(const char* const message, const char* const text, const std::function action) { -#ifndef HEADLESS +#ifndef HEADLESS_BEHAVIOUR asyncDialog::textInput(message, text, action); #endif } diff --git a/src/CardinalCommon.hpp b/src/CardinalCommon.hpp index 188a454c..756f02dd 100644 --- a/src/CardinalCommon.hpp +++ b/src/CardinalCommon.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -15,26 +15,16 @@ * For a full copy of the GNU General Public License see the LICENSE file. */ -#include - #pragma once -#ifdef HAVE_LIBLO -// # define REMOTE_HOST "localhost" -# define REMOTE_HOST "192.168.51.1" -# define REMOTE_HOST_PORT "2228" -#endif +#include "DistrhoUtils.hpp" -#ifdef DISTRHO_OS_WASM -# ifdef STATIC_BUILD -# define CARDINAL_WASM_WELCOME_TEMPLATE_FILENAME "welcome-wasm-mini.vcv" -# else -# define CARDINAL_WASM_WELCOME_TEMPLATE_FILENAME "welcome-wasm.vcv" -# endif -#endif +#include extern const std::string CARDINAL_VERSION; +// ----------------------------------------------------------------------------------------------------------- + namespace rack { namespace ui { @@ -45,6 +35,7 @@ namespace window { void generateScreenshot(); } +bool isMini(); bool isStandalone(); #ifdef ARCH_WIN @@ -53,6 +44,7 @@ enum SpecialPath { kSpecialPathCommonProgramFiles, kSpecialPathProgramFiles, kSpecialPathAppData, + kSpecialPathMyDocuments, }; std::string getSpecialPath(SpecialPath type); #endif @@ -61,28 +53,76 @@ std::string getSpecialPath(SpecialPath type); extern char* patchFromURL; extern char* patchRemoteURL; extern char* patchStorageSlug; +void syncfs(); #endif +std::string homeDir(); + +void switchDarkMode(bool darkMode); + } // namespace rack +// ----------------------------------------------------------------------------------------------------------- + namespace patchUtils { void loadDialog(); void loadPathDialog(const std::string& path, bool asTemplate = false); void loadSelectionDialog(); -void loadTemplateDialog(); +void loadTemplate(bool factory); +void loadTemplateDialog(bool factory); void revertDialog(); void saveDialog(const std::string& path); void saveAsDialog(); void saveAsDialogUncompressed(); +void saveTemplateDialog(); void appendSelectionContextMenu(rack::ui::Menu* menu); void openBrowser(const std::string& url); -bool connectToRemote(); -bool isRemoteConnected(); -bool isRemoteAutoDeployed(); -void setRemoteAutoDeploy(bool autoDeploy); -void deployToRemote(); -void sendScreenshotToRemote(const char* screenshot); - } // namespace patchUtils + +// ----------------------------------------------------------------------------------------------------------- + +#if defined(HAVE_LIBLO) && defined(HEADLESS) +# define CARDINAL_INIT_OSC_THREAD +#endif + +typedef void* lo_server; +typedef void* lo_server_thread; + +START_NAMESPACE_DISTRHO + +class CardinalBasePlugin; +class CardinalBaseUI; +struct CardinalPluginContext; + +struct Initializer +{ + std::string templatePath; + std::string factoryTemplatePath; + bool shouldSaveSettings = false; + + Initializer(const CardinalBasePlugin* plugin, const CardinalBaseUI* ui); + ~Initializer(); + void loadSettings(bool isRealInstance); + + #ifdef HAVE_LIBLO + lo_server oscServer = nullptr; + #ifdef CARDINAL_INIT_OSC_THREAD + lo_server_thread oscServerThread = nullptr; + #endif + CardinalBasePlugin* remotePluginInstance = nullptr; + + bool startRemoteServer(const char* port); + void stopRemoteServer(); + void stepRemoteServer(); + #endif +}; + +#ifndef HEADLESS +void handleHostParameterDrag(const CardinalPluginContext* pcontext, uint index, bool started); +#endif + +END_NAMESPACE_DISTRHO + +// ----------------------------------------------------------------------------------------------------------- diff --git a/src/CardinalFX/CardinalRemote.cpp b/src/CardinalFX/CardinalRemote.cpp new file mode 120000 index 00000000..23838232 --- /dev/null +++ b/src/CardinalFX/CardinalRemote.cpp @@ -0,0 +1 @@ +../CardinalRemote.cpp \ No newline at end of file diff --git a/src/CardinalFX/CardinalX11WindowIcon.cpp b/src/CardinalFX/CardinalX11WindowIcon.cpp new file mode 120000 index 00000000..5d4fb7f7 --- /dev/null +++ b/src/CardinalFX/CardinalX11WindowIcon.cpp @@ -0,0 +1 @@ +../CardinalX11WindowIcon.cpp \ No newline at end of file diff --git a/src/CardinalFX/DistrhoPluginInfo.h b/src/CardinalFX/DistrhoPluginInfo.h index ca175203..906bbc6b 100644 --- a/src/CardinalFX/DistrhoPluginInfo.h +++ b/src/CardinalFX/DistrhoPluginInfo.h @@ -19,6 +19,7 @@ #define DISTRHO_PLUGIN_INFO_H_INCLUDED #define CARDINAL_VARIANT_MAIN 0 +#define CARDINAL_VARIANT_MINI 0 #define CARDINAL_VARIANT_FX 1 #define CARDINAL_VARIANT_NATIVE 0 #define CARDINAL_VARIANT_SYNTH 0 @@ -26,19 +27,16 @@ #define CARDINAL_NUM_AUDIO_INPUTS 2 #define CARDINAL_NUM_AUDIO_OUTPUTS 2 -#define DISTRHO_PLUGIN_BRAND "DISTRHO" -#define DISTRHO_PLUGIN_URI "https://distrho.kx.studio/plugins/cardinal#fx" +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_URI "https://distrho.kx.studio/plugins/cardinal#fx" +#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.cardinal#fx" -#if defined(__MOD_DEVICES__) -# define DISTRHO_PLUGIN_NAME "Cardinal Mini" -# define DISTRHO_PLUGIN_LABEL "CardinalMini" -#else -# define DISTRHO_PLUGIN_NAME "Cardinal FX" -# define DISTRHO_PLUGIN_LABEL "CardinalFX" -#endif +#define DISTRHO_PLUGIN_NAME "Cardinal FX" +#define DISTRHO_PLUGIN_LABEL "CardinalFX" #ifdef HEADLESS #define DISTRHO_PLUGIN_HAS_UI 0 +#define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 0 #else #define DISTRHO_PLUGIN_HAS_UI 1 #define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 1 @@ -56,6 +54,7 @@ #define DISTRHO_PLUGIN_WANT_FULL_STATE 1 #define DISTRHO_PLUGIN_WANT_STATE 1 #define DISTRHO_PLUGIN_WANT_TIMEPOS 1 +#define DISTRHO_PLUGIN_USES_CUSTOM_MODGUI 1 #define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:UtilityPlugin" #define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Generator" diff --git a/src/CardinalFX/MenuBar.cpp b/src/CardinalFX/MenuBar.cpp new file mode 120000 index 00000000..8d1a35a5 --- /dev/null +++ b/src/CardinalFX/MenuBar.cpp @@ -0,0 +1 @@ +../override/MenuBar.cpp \ No newline at end of file diff --git a/src/CardinalMini/CardinalCommon.cpp b/src/CardinalMini/CardinalCommon.cpp new file mode 120000 index 00000000..76b4b5f3 --- /dev/null +++ b/src/CardinalMini/CardinalCommon.cpp @@ -0,0 +1 @@ +../CardinalCommon.cpp \ No newline at end of file diff --git a/src/CardinalMini/CardinalPlugin.cpp b/src/CardinalMini/CardinalPlugin.cpp new file mode 120000 index 00000000..c0c7e71e --- /dev/null +++ b/src/CardinalMini/CardinalPlugin.cpp @@ -0,0 +1 @@ +../CardinalPlugin.cpp \ No newline at end of file diff --git a/src/CardinalMini/CardinalRemote.cpp b/src/CardinalMini/CardinalRemote.cpp new file mode 120000 index 00000000..23838232 --- /dev/null +++ b/src/CardinalMini/CardinalRemote.cpp @@ -0,0 +1 @@ +../CardinalRemote.cpp \ No newline at end of file diff --git a/src/CardinalMini/CardinalUI.cpp b/src/CardinalMini/CardinalUI.cpp new file mode 120000 index 00000000..5558256b --- /dev/null +++ b/src/CardinalMini/CardinalUI.cpp @@ -0,0 +1 @@ +../CardinalUI.cpp \ No newline at end of file diff --git a/src/CardinalMini/CardinalX11WindowIcon.cpp b/src/CardinalMini/CardinalX11WindowIcon.cpp new file mode 120000 index 00000000..5d4fb7f7 --- /dev/null +++ b/src/CardinalMini/CardinalX11WindowIcon.cpp @@ -0,0 +1 @@ +../CardinalX11WindowIcon.cpp \ No newline at end of file diff --git a/src/CardinalMini/DistrhoPluginInfo.h b/src/CardinalMini/DistrhoPluginInfo.h new file mode 100644 index 00000000..c98736aa --- /dev/null +++ b/src/CardinalMini/DistrhoPluginInfo.h @@ -0,0 +1,55 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021-2022 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the LICENSE file. + */ + +#ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED +#define DISTRHO_PLUGIN_INFO_H_INCLUDED + +#define CARDINAL_VARIANT_MAIN 0 +#define CARDINAL_VARIANT_MINI 1 +#define CARDINAL_VARIANT_FX 0 +#define CARDINAL_VARIANT_NATIVE 0 +#define CARDINAL_VARIANT_SYNTH 0 + +#define CARDINAL_NUM_AUDIO_INPUTS 2 +#define CARDINAL_NUM_AUDIO_OUTPUTS 2 + +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_URI "https://distrho.kx.studio/plugins/cardinal#mini" +#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.cardinal#mini" + +#define DISTRHO_PLUGIN_NAME "Cardinal Mini" +#define DISTRHO_PLUGIN_LABEL "CardinalMini" + +#define DISTRHO_PLUGIN_HAS_UI 1 +#define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 1 +#define DISTRHO_UI_FILE_BROWSER 1 +#define DISTRHO_UI_USE_NANOVG 1 +#define DISTRHO_UI_USER_RESIZABLE 1 +#define DISTRHO_UI_DEFAULT_WIDTH 1000 +#define DISTRHO_UI_DEFAULT_HEIGHT 600 +#define DISTRHO_PLUGIN_IS_SYNTH 0 +#define DISTRHO_PLUGIN_NUM_INPUTS CARDINAL_NUM_AUDIO_INPUTS + 5 +#define DISTRHO_PLUGIN_NUM_OUTPUTS CARDINAL_NUM_AUDIO_OUTPUTS + 5 +#define DISTRHO_PLUGIN_WANT_MIDI_INPUT 1 +#define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 1 +#define DISTRHO_PLUGIN_WANT_FULL_STATE 1 +#define DISTRHO_PLUGIN_WANT_STATE 1 +#define DISTRHO_PLUGIN_WANT_TIMEPOS 1 +#define DISTRHO_PLUGIN_LV2_CATEGORY "mod:ControlVoltagePlugin, lv2:UtilityPlugin" +#define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Generator" + +#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED diff --git a/src/CardinalMini/Makefile b/src/CardinalMini/Makefile new file mode 100644 index 00000000..24e50436 --- /dev/null +++ b/src/CardinalMini/Makefile @@ -0,0 +1,8 @@ +#!/usr/bin/make -f +# Makefile for DISTRHO Plugins # +# ---------------------------- # +# Created by falkTX +# + +NAME = CardinalMini +include ../Makefile.cardinal.mk diff --git a/src/CardinalMini/MenuBar.cpp b/src/CardinalMini/MenuBar.cpp new file mode 120000 index 00000000..8d1a35a5 --- /dev/null +++ b/src/CardinalMini/MenuBar.cpp @@ -0,0 +1 @@ +../override/MenuBar.cpp \ No newline at end of file diff --git a/src/CardinalMini/RemoteNanoVG.cpp b/src/CardinalMini/RemoteNanoVG.cpp new file mode 120000 index 00000000..a6394af3 --- /dev/null +++ b/src/CardinalMini/RemoteNanoVG.cpp @@ -0,0 +1 @@ +../custom/RemoteNanoVG.cpp \ No newline at end of file diff --git a/src/CardinalMini/RemoteWindow.cpp b/src/CardinalMini/RemoteWindow.cpp new file mode 120000 index 00000000..7e00fed5 --- /dev/null +++ b/src/CardinalMini/RemoteWindow.cpp @@ -0,0 +1 @@ +../custom/RemoteWindow.cpp \ No newline at end of file diff --git a/src/CardinalMini/Window.cpp b/src/CardinalMini/Window.cpp new file mode 120000 index 00000000..759f2728 --- /dev/null +++ b/src/CardinalMini/Window.cpp @@ -0,0 +1 @@ +../override/Window.cpp \ No newline at end of file diff --git a/src/CardinalMini/common.cpp b/src/CardinalMini/common.cpp new file mode 120000 index 00000000..915948e3 --- /dev/null +++ b/src/CardinalMini/common.cpp @@ -0,0 +1 @@ +../override/common.cpp \ No newline at end of file diff --git a/src/CardinalMini/glfw.cpp b/src/CardinalMini/glfw.cpp new file mode 120000 index 00000000..8c6a6e44 --- /dev/null +++ b/src/CardinalMini/glfw.cpp @@ -0,0 +1 @@ +../custom/glfw.cpp \ No newline at end of file diff --git a/include/mingw-compat/future b/src/CardinalMiniSep/CardinalCommon-UI.cpp similarity index 86% rename from include/mingw-compat/future rename to src/CardinalMiniSep/CardinalCommon-UI.cpp index b782903c..6c3feffa 100644 --- a/include/mingw-compat/future +++ b/src/CardinalMiniSep/CardinalCommon-UI.cpp @@ -15,11 +15,5 @@ * For a full copy of the GNU General Public License see the LICENSE file. */ -#pragma once -#include_next -#include "mingw.future.h" - -#undef IN -#undef OUT -#undef far -#undef near +#define CARDINAL_COMMON_UI_ONLY +#include "../CardinalCommon.cpp" diff --git a/include/mingw-compat/condition_variable b/src/CardinalMiniSep/CardinalCommon.cpp similarity index 76% rename from include/mingw-compat/condition_variable rename to src/CardinalMiniSep/CardinalCommon.cpp index 256734cf..24dffcde 100644 --- a/include/mingw-compat/condition_variable +++ b/src/CardinalMiniSep/CardinalCommon.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -15,11 +15,5 @@ * For a full copy of the GNU General Public License see the LICENSE file. */ -#pragma once -#include_next -#include "mingw.condition_variable.h" - -#undef IN -#undef OUT -#undef far -#undef near +#define CARDINAL_COMMON_DSP_ONLY +#include "../CardinalCommon.cpp" diff --git a/src/CardinalMiniSep/CardinalPlugin.cpp b/src/CardinalMiniSep/CardinalPlugin.cpp new file mode 120000 index 00000000..c0c7e71e --- /dev/null +++ b/src/CardinalMiniSep/CardinalPlugin.cpp @@ -0,0 +1 @@ +../CardinalPlugin.cpp \ No newline at end of file diff --git a/src/CardinalMiniSep/CardinalRemote.cpp b/src/CardinalMiniSep/CardinalRemote.cpp new file mode 120000 index 00000000..23838232 --- /dev/null +++ b/src/CardinalMiniSep/CardinalRemote.cpp @@ -0,0 +1 @@ +../CardinalRemote.cpp \ No newline at end of file diff --git a/src/CardinalMiniSep/CardinalUI.cpp b/src/CardinalMiniSep/CardinalUI.cpp new file mode 120000 index 00000000..5558256b --- /dev/null +++ b/src/CardinalMiniSep/CardinalUI.cpp @@ -0,0 +1 @@ +../CardinalUI.cpp \ No newline at end of file diff --git a/src/CardinalMiniSep/CardinalX11WindowIcon.cpp b/src/CardinalMiniSep/CardinalX11WindowIcon.cpp new file mode 120000 index 00000000..5d4fb7f7 --- /dev/null +++ b/src/CardinalMiniSep/CardinalX11WindowIcon.cpp @@ -0,0 +1 @@ +../CardinalX11WindowIcon.cpp \ No newline at end of file diff --git a/src/CardinalMiniSep/DistrhoPluginInfo.h b/src/CardinalMiniSep/DistrhoPluginInfo.h new file mode 100644 index 00000000..3593730e --- /dev/null +++ b/src/CardinalMiniSep/DistrhoPluginInfo.h @@ -0,0 +1,56 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021-2022 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the LICENSE file. + */ + +#ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED +#define DISTRHO_PLUGIN_INFO_H_INCLUDED + +#define CARDINAL_VARIANT_MAIN 0 +#define CARDINAL_VARIANT_MINI 1 +#define CARDINAL_VARIANT_FX 0 +#define CARDINAL_VARIANT_NATIVE 0 +#define CARDINAL_VARIANT_SYNTH 0 + +#define CARDINAL_NUM_AUDIO_INPUTS 2 +#define CARDINAL_NUM_AUDIO_OUTPUTS 2 + +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_URI "https://distrho.kx.studio/plugins/cardinal#mini" + +#define DISTRHO_PLUGIN_NAME "Cardinal Mini" +#define DISTRHO_PLUGIN_LABEL "CardinalMini" + +#define DISTRHO_PLUGIN_HAS_UI 1 +#define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 0 +#define DISTRHO_UI_FILE_BROWSER 1 +#define DISTRHO_UI_USE_NANOVG 1 +#define DISTRHO_UI_USER_RESIZABLE 1 +#define DISTRHO_UI_DEFAULT_WIDTH 1000 +#define DISTRHO_UI_DEFAULT_HEIGHT 600 +#define DISTRHO_PLUGIN_IS_SYNTH 0 +#define DISTRHO_PLUGIN_NUM_INPUTS CARDINAL_NUM_AUDIO_INPUTS + 5 +#define DISTRHO_PLUGIN_NUM_OUTPUTS CARDINAL_NUM_AUDIO_OUTPUTS + 5 +#define DISTRHO_PLUGIN_WANT_MIDI_INPUT 1 +#define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 1 +#define DISTRHO_PLUGIN_WANT_FULL_STATE 1 +#define DISTRHO_PLUGIN_WANT_STATE 1 +#define DISTRHO_PLUGIN_WANT_TIMEPOS 1 +#define DISTRHO_PLUGIN_USES_CUSTOM_MODGUI 0 +#define DISTRHO_PLUGIN_LV2_CATEGORY "mod:ControlVoltagePlugin, lv2:UtilityPlugin" + +#define DISTRHO_PLUGIN_USES_MODGUI 1 + +#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED diff --git a/src/CardinalMiniSep/Makefile b/src/CardinalMiniSep/Makefile new file mode 100644 index 00000000..1a97ebd7 --- /dev/null +++ b/src/CardinalMiniSep/Makefile @@ -0,0 +1,11 @@ +#!/usr/bin/make -f +# Makefile for DISTRHO Plugins # +# ---------------------------- # +# Created by falkTX +# + +NAME = CardinalMini +DPF_BUILD_DIR = ../../build/$(NAME)-sep +DSP_UI_SPLIT = true +MODGUI_CLASS_NAME = distrho_cardinal_mini +include ../Makefile.cardinal.mk diff --git a/src/CardinalMiniSep/MenuBar.cpp b/src/CardinalMiniSep/MenuBar.cpp new file mode 120000 index 00000000..8d1a35a5 --- /dev/null +++ b/src/CardinalMiniSep/MenuBar.cpp @@ -0,0 +1 @@ +../override/MenuBar.cpp \ No newline at end of file diff --git a/src/CardinalMiniSep/RemoteNanoVG.cpp b/src/CardinalMiniSep/RemoteNanoVG.cpp new file mode 120000 index 00000000..a6394af3 --- /dev/null +++ b/src/CardinalMiniSep/RemoteNanoVG.cpp @@ -0,0 +1 @@ +../custom/RemoteNanoVG.cpp \ No newline at end of file diff --git a/src/CardinalMiniSep/RemoteWindow.cpp b/src/CardinalMiniSep/RemoteWindow.cpp new file mode 120000 index 00000000..7e00fed5 --- /dev/null +++ b/src/CardinalMiniSep/RemoteWindow.cpp @@ -0,0 +1 @@ +../custom/RemoteWindow.cpp \ No newline at end of file diff --git a/src/CardinalMiniSep/Window.cpp b/src/CardinalMiniSep/Window.cpp new file mode 120000 index 00000000..759f2728 --- /dev/null +++ b/src/CardinalMiniSep/Window.cpp @@ -0,0 +1 @@ +../override/Window.cpp \ No newline at end of file diff --git a/src/CardinalMiniSep/common.cpp b/src/CardinalMiniSep/common.cpp new file mode 120000 index 00000000..915948e3 --- /dev/null +++ b/src/CardinalMiniSep/common.cpp @@ -0,0 +1 @@ +../override/common.cpp \ No newline at end of file diff --git a/src/CardinalMiniSep/glfw.cpp b/src/CardinalMiniSep/glfw.cpp new file mode 120000 index 00000000..8c6a6e44 --- /dev/null +++ b/src/CardinalMiniSep/glfw.cpp @@ -0,0 +1 @@ +../custom/glfw.cpp \ No newline at end of file diff --git a/src/CardinalModuleWidget.cpp b/src/CardinalModuleWidget.cpp index 39aa43ab..7adc2fc5 100644 --- a/src/CardinalModuleWidget.cpp +++ b/src/CardinalModuleWidget.cpp @@ -40,242 +40,11 @@ #include #include +#undef ModuleWidget + namespace rack { namespace app { -struct CardinalModuleWidget : ModuleWidget { - CardinalModuleWidget() : ModuleWidget() {} - DEPRECATED CardinalModuleWidget(engine::Module* module) : ModuleWidget() { - setModule(module); - } - void onButton(const ButtonEvent& e) override; -}; - -struct ModuleWidget::Internal { - math::Vec dragOffset; - math::Vec dragRackPos; - bool dragEnabled; - widget::Widget* panel; -}; - -static void CardinalModuleWidget__loadDialog(ModuleWidget* const w) -{ - std::string presetDir = w->model->getUserPresetDirectory(); - system::createDirectories(presetDir); - - WeakPtr weakThis = w; - - async_dialog_filebrowser(false, nullptr, presetDir.c_str(), "Load preset", [=](char* pathC) { - // Delete directories if empty - DEFER({ - try { - system::remove(presetDir); - system::remove(system::getDirectory(presetDir)); - } - catch (Exception& e) { - // Ignore exceptions if directory cannot be removed. - } - }); - - if (!weakThis) - return; - if (!pathC) - return; - - try { - weakThis->loadAction(pathC); - } - catch (Exception& e) { - async_dialog_message(e.what()); - } - - std::free(pathC); - }); -} - -void CardinalModuleWidget__saveDialog(ModuleWidget* const w) -{ - const std::string presetDir = w->model->getUserPresetDirectory(); - system::createDirectories(presetDir); - - WeakPtr weakThis = w; - - async_dialog_filebrowser(true, "preset.vcvm", presetDir.c_str(), "Save preset", [=](char* pathC) { - // Delete directories if empty - DEFER({ - try { - system::remove(presetDir); - system::remove(system::getDirectory(presetDir)); - } - catch (Exception& e) { - // Ignore exceptions if directory cannot be removed. - } - }); - - if (!weakThis) - return; - if (!pathC) - return; - - std::string path = pathC; - std::free(pathC); - - // Automatically append .vcvm extension - if (system::getExtension(path) != ".vcvm") - path += ".vcvm"; - - weakThis->save(path); - }); -} - -// Create ModulePresetPathItems for each patch in a directory. -static void appendPresetItems(ui::Menu* menu, WeakPtr moduleWidget, std::string presetDir) { - bool foundPresets = false; - - if (system::isDirectory(presetDir)) - { - // Note: This is not cached, so opening this menu each time might have a bit of latency. - std::vector entries = system::getEntries(presetDir); - std::sort(entries.begin(), entries.end()); - for (std::string path : entries) { - std::string name = system::getStem(path); - // Remove "1_", "42_", "001_", etc at the beginning of preset filenames - std::regex r("^\\d+_"); - name = std::regex_replace(name, r, ""); - - if (system::getExtension(path) == ".vcvm" && name != "template") - { - if (!foundPresets) - menu->addChild(new ui::MenuSeparator); - - foundPresets = true; - - menu->addChild(createMenuItem(name, "", [=]() { - if (!moduleWidget) - return; - try { - moduleWidget->loadAction(path); - } - catch (Exception& e) { - async_dialog_message(e.what()); - } - })); - } - } - } -}; - -static void CardinalModuleWidget__createContextMenu(ModuleWidget* const w, - plugin::Model* const model, - engine::Module* const module) { - DISTRHO_SAFE_ASSERT_RETURN(model != nullptr,); - - ui::Menu* menu = createMenu(); - - WeakPtr weakThis = w; - - // Brand and module name - menu->addChild(createMenuLabel(model->name)); - menu->addChild(createMenuLabel(model->plugin->brand)); - - // Info - menu->addChild(createSubmenuItem("Info", "", [model](ui::Menu* menu) { - model->appendContextMenu(menu); - })); - - // Preset - menu->addChild(createSubmenuItem("Preset", "", [weakThis](ui::Menu* menu) { - menu->addChild(createMenuItem("Copy", RACK_MOD_CTRL_NAME "+C", [weakThis]() { - if (!weakThis) - return; - weakThis->copyClipboard(); - })); - - menu->addChild(createMenuItem("Paste", RACK_MOD_CTRL_NAME "+V", [weakThis]() { - if (!weakThis) - return; - weakThis->pasteClipboardAction(); - })); - - menu->addChild(createMenuItem("Open", "", [weakThis]() { - if (!weakThis) - return; - CardinalModuleWidget__loadDialog(weakThis); - })); - - /* TODO requires setting up user dir - menu->addChild(createMenuItem("Save as", "", [weakThis]() { - if (!weakThis) - return; - CardinalModuleWidget__saveDialog(weakThis); - })); - - // Scan `/presets//` for presets. - menu->addChild(new ui::MenuSeparator); - menu->addChild(createMenuLabel("User presets")); - appendPresetItems(menu, weakThis, weakThis->model->getUserPresetDirectory()); - */ - - // Scan `/presets/` for presets. - appendPresetItems(menu, weakThis, weakThis->model->getFactoryPresetDirectory()); - })); - - // Initialize - menu->addChild(createMenuItem("Initialize", RACK_MOD_CTRL_NAME "+I", [weakThis]() { - if (!weakThis) - return; - weakThis->resetAction(); - })); - - // Randomize - menu->addChild(createMenuItem("Randomize", RACK_MOD_CTRL_NAME "+R", [weakThis]() { - if (!weakThis) - return; - weakThis->randomizeAction(); - })); - - // Disconnect cables - menu->addChild(createMenuItem("Disconnect cables", RACK_MOD_CTRL_NAME "+U", [weakThis]() { - if (!weakThis) - return; - weakThis->disconnectAction(); - })); - - // Bypass - std::string bypassText = RACK_MOD_CTRL_NAME "+E"; - bool bypassed = module && module->isBypassed(); - if (bypassed) - bypassText += " " CHECKMARK_STRING; - menu->addChild(createMenuItem("Bypass", bypassText, [weakThis, bypassed]() { - if (!weakThis) - return; - weakThis->bypassAction(!bypassed); - })); - - // Duplicate - menu->addChild(createMenuItem("Duplicate", RACK_MOD_CTRL_NAME "+D", [weakThis]() { - if (!weakThis) - return; - weakThis->cloneAction(false); - })); - - // Duplicate with cables - menu->addChild(createMenuItem("â”” with cables", RACK_MOD_SHIFT_NAME "+" RACK_MOD_CTRL_NAME "+D", [weakThis]() { - if (!weakThis) - return; - weakThis->cloneAction(true); - })); - - // Delete - menu->addChild(createMenuItem("Delete", "Backspace/Delete", [weakThis]() { - if (!weakThis) - return; - weakThis->removeAction(); - }, false, true)); - - w->appendContextMenu(menu); -} - static void CardinalModuleWidget__saveSelectionDialog(RackWidget* const w) { std::string selectionDir = asset::user("selections"); @@ -304,75 +73,6 @@ static void CardinalModuleWidget__saveSelectionDialog(RackWidget* const w) }); } -void CardinalModuleWidget::onButton(const ButtonEvent& e) -{ - const bool selected = APP->scene->rack->isSelected(this); - - if (selected) { - if (e.button == GLFW_MOUSE_BUTTON_RIGHT) { - if (e.action == GLFW_PRESS) { - // Open selection context menu on right-click - ui::Menu* menu = createMenu(); - patchUtils::appendSelectionContextMenu(menu); - } - e.consume(this); - } - - if (e.button == GLFW_MOUSE_BUTTON_LEFT) { - if (e.action == GLFW_PRESS) { - // Toggle selection on Shift-click - if ((e.mods & RACK_MOD_MASK) == GLFW_MOD_SHIFT) { - APP->scene->rack->select(this, false); - e.consume(NULL); - return; - } - - // If module positions are locked, don't consume left-click - if (settings::lockModules) { - return; - } - - internal->dragOffset = e.pos; - } - - e.consume(this); - } - - return; - } - - // Dispatch event to children - Widget::onButton(e); - e.stopPropagating(); - if (e.isConsumed()) - return; - - if (e.button == GLFW_MOUSE_BUTTON_LEFT) { - if (e.action == GLFW_PRESS) { - // Toggle selection on Shift-click - if ((e.mods & RACK_MOD_MASK) == GLFW_MOD_SHIFT) { - APP->scene->rack->select(this, true); - e.consume(NULL); - return; - } - - // If module positions are locked, don't consume left-click - if (settings::lockModules) { - return; - } - - internal->dragOffset = e.pos; - } - e.consume(this); - } - - // Open context menu on right-click - if (e.button == GLFW_MOUSE_BUTTON_RIGHT && e.action == GLFW_PRESS) { - CardinalModuleWidget__createContextMenu(this, model, module); - e.consume(this); - } -} - } } diff --git a/src/CardinalNative/CardinalRemote.cpp b/src/CardinalNative/CardinalRemote.cpp new file mode 120000 index 00000000..23838232 --- /dev/null +++ b/src/CardinalNative/CardinalRemote.cpp @@ -0,0 +1 @@ +../CardinalRemote.cpp \ No newline at end of file diff --git a/src/CardinalNative/CardinalX11WindowIcon.cpp b/src/CardinalNative/CardinalX11WindowIcon.cpp new file mode 120000 index 00000000..5d4fb7f7 --- /dev/null +++ b/src/CardinalNative/CardinalX11WindowIcon.cpp @@ -0,0 +1 @@ +../CardinalX11WindowIcon.cpp \ No newline at end of file diff --git a/src/CardinalNative/DistrhoPluginInfo.h b/src/CardinalNative/DistrhoPluginInfo.h index b820481a..3b8081d7 100644 --- a/src/CardinalNative/DistrhoPluginInfo.h +++ b/src/CardinalNative/DistrhoPluginInfo.h @@ -19,6 +19,7 @@ #define DISTRHO_PLUGIN_INFO_H_INCLUDED #define CARDINAL_VARIANT_MAIN 0 +#define CARDINAL_VARIANT_MINI 0 #define CARDINAL_VARIANT_FX 0 #define CARDINAL_VARIANT_NATIVE 1 #define CARDINAL_VARIANT_SYNTH 0 @@ -39,6 +40,7 @@ #ifdef HEADLESS #define DISTRHO_PLUGIN_HAS_UI 0 +#define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 0 #else #define DISTRHO_PLUGIN_HAS_UI 1 #define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 1 diff --git a/src/CardinalNative/MenuBar.cpp b/src/CardinalNative/MenuBar.cpp new file mode 120000 index 00000000..8d1a35a5 --- /dev/null +++ b/src/CardinalNative/MenuBar.cpp @@ -0,0 +1 @@ +../override/MenuBar.cpp \ No newline at end of file diff --git a/src/CardinalPlugin.cpp b/src/CardinalPlugin.cpp index d7e6f750..9e7414b1 100644 --- a/src/CardinalPlugin.cpp +++ b/src/CardinalPlugin.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -15,7 +15,6 @@ * For a full copy of the GNU General Public License see the LICENSE file. */ -#include #include #include #include @@ -24,10 +23,10 @@ #include #include -#include #include #include #include +#include #include #ifdef NDEBUG @@ -39,12 +38,15 @@ # include "extra/Thread.hpp" #endif +#include #include #include "CardinalCommon.hpp" #include "DistrhoPluginUtils.hpp" #include "PluginContext.hpp" #include "extra/Base64.hpp" +#include "extra/ScopedDenormalDisable.hpp" +#include "extra/ScopedSafeLocale.hpp" #ifdef DISTRHO_OS_WASM # include @@ -52,44 +54,26 @@ # include "extra/SharedResourcePointer.hpp" #endif -#if CARDINAL_VARIANT_FX -# define CARDINAL_TEMPLATE_NAME "init/fx.vcv" -#elif CARDINAL_VARIANT_NATIVE -# define CARDINAL_TEMPLATE_NAME "init/native.vcv" -#elif CARDINAL_VARIANT_SYNTH -# define CARDINAL_TEMPLATE_NAME "init/synth.vcv" -#else -# define CARDINAL_TEMPLATE_NAME "init/main.vcv" -#endif - -static const constexpr uint kCardinalStateBaseCount = 3; // patch, screenshot, comment - -#ifndef HEADLESS +#if CARDINAL_VARIANT_MINI || !defined(HEADLESS) # include "extra/ScopedValueSetter.hpp" -# include "WindowParameters.hpp" -static const constexpr uint kCardinalStateCount = kCardinalStateBaseCount + 2; // moduleInfos, windowSize -#else -# define kWindowParameterCount 0 -static const constexpr uint kCardinalStateCount = kCardinalStateBaseCount; #endif +extern const std::string CARDINAL_VERSION; + namespace rack { +#if (CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS) || defined(HEADLESS) +namespace app { +rack::widget::Widget* createMenuBar() { return new rack::widget::Widget; } +} +#endif +#ifdef DISTRHO_OS_WASM namespace asset { std::string patchesPath(); -void destroy(); } +#endif namespace engine { void Engine_setAboutToClose(Engine*); } -namespace plugin { -void initStaticPlugins(); -void destroyStaticPlugins(); -} -#ifndef HEADLESS -namespace window { -void WindowInit(Window* window, DISTRHO_NAMESPACE::Plugin* plugin); -} -#endif } START_NAMESPACE_DISTRHO @@ -101,6 +85,11 @@ bool d_isDiffHigherThanLimit(const T& v1, const T& v2, const T& limit) return v1 != v2 ? (v1 > v2 ? v1 - v2 : v2 - v1) > limit : false; } +#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS +const char* UI::getBundlePath() const noexcept { return nullptr; } +void UI::setState(const char*, const char*) {} +#endif + // ----------------------------------------------------------------------------------------------------------- #ifdef DISTRHO_OS_WASM @@ -144,356 +133,25 @@ static char* getPatchStorageSlug() { }; #endif -// ----------------------------------------------------------------------------------------------------------- - -struct Initializer -#if defined(HAVE_LIBLO) && defined(HEADLESS) -: public Thread -#endif +#if CARDINAL_VARIANT_MINI || !defined(HEADLESS) +float RackKnobModeToFloat(const rack::settings::KnobMode knobMode) noexcept { -#if defined(HAVE_LIBLO) && defined(HEADLESS) - lo_server oscServer = nullptr; - CardinalBasePlugin* oscPlugin = nullptr; -#endif - std::string templatePath; - std::string factoryTemplatePath; - - Initializer(const CardinalBasePlugin* const plugin) - { - using namespace rack; - -#ifdef DISTRHO_OS_WASM - settings::allowCursorLock = true; -#else - settings::allowCursorLock = false; -#endif - settings::autoCheckUpdates = false; - settings::autosaveInterval = 0; - settings::devMode = true; - settings::isPlugin = true; - settings::skipLoadOnLaunch = true; - settings::showTipsOnLaunch = false; - settings::windowPos = math::Vec(0, 0); -#ifdef HEADLESS - settings::headless = true; -#endif - - // copied from https://community.vcvrack.com/t/16-colour-cable-palette/15951 - settings::cableColors = { - color::fromHexString("#ff5252"), - color::fromHexString("#ff9352"), - color::fromHexString("#ffd452"), - color::fromHexString("#e8ff52"), - color::fromHexString("#a8ff52"), - color::fromHexString("#67ff52"), - color::fromHexString("#52ff7d"), - color::fromHexString("#52ffbe"), - color::fromHexString("#52ffff"), - color::fromHexString("#52beff"), - color::fromHexString("#527dff"), - color::fromHexString("#6752ff"), - color::fromHexString("#a852ff"), - color::fromHexString("#e952ff"), - color::fromHexString("#ff52d4"), - color::fromHexString("#ff5293"), - }; - - system::init(); - logger::init(); - random::init(); - ui::init(); - - if (asset::systemDir.empty()) - { - if (const char* const bundlePath = plugin->getBundlePath()) - { - if (const char* const resourcePath = getResourcePath(bundlePath)) - { - asset::systemDir = resourcePath; - asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); - } - } - - if (asset::systemDir.empty() || ! system::exists(asset::systemDir) || ! system::exists(asset::bundlePath)) - { - #ifdef CARDINAL_PLUGIN_SOURCE_DIR - // Make system dir point to source code location as fallback - asset::systemDir = CARDINAL_PLUGIN_SOURCE_DIR DISTRHO_OS_SEP_STR "Rack"; - asset::bundlePath.clear(); - - // If source code dir does not exist use install target prefix as system dir - if (!system::exists(system::join(asset::systemDir, "res"))) - #endif - { - #if defined(DISTRHO_OS_WASM) - asset::systemDir = "/resources"; - #elif defined(ARCH_MAC) - asset::systemDir = "/Library/Application Support/Cardinal"; - #elif defined(ARCH_WIN) - const std::string commonprogfiles = getSpecialPath(kSpecialPathCommonProgramFiles); - if (! commonprogfiles.empty()) - asset::systemDir = system::join(commonprogfiles, "Cardinal"); - #else - asset::systemDir = CARDINAL_PLUGIN_PREFIX "/share/cardinal"; - #endif - - asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); - } - } - - asset::userDir = asset::systemDir; - } - - const std::string patchesPath = asset::patchesPath(); - #ifdef DISTRHO_OS_WASM - templatePath = system::join(patchesPath, CARDINAL_WASM_WELCOME_TEMPLATE_FILENAME); - #else - templatePath = system::join(patchesPath, CARDINAL_TEMPLATE_NAME); - #endif - factoryTemplatePath = system::join(patchesPath, CARDINAL_TEMPLATE_NAME); - - // Log environment - INFO("%s %s v%s", APP_NAME.c_str(), APP_EDITION.c_str(), APP_VERSION.c_str()); - INFO("%s", system::getOperatingSystemInfo().c_str()); - INFO("Binary filename: %s", getBinaryFilename()); - INFO("Bundle path: %s", plugin->getBundlePath()); - INFO("System directory: %s", asset::systemDir.c_str()); - INFO("User directory: %s", asset::userDir.c_str()); - INFO("Template patch: %s", templatePath.c_str()); - INFO("System template patch: %s", factoryTemplatePath.c_str()); - - // Report to user if something is wrong with the installation - if (asset::systemDir.empty()) - { - d_stderr2("Failed to locate Cardinal plugin bundle.\n" - "Install Cardinal with its bundle folder intact and try again."); - } - else if (! system::exists(asset::systemDir)) - { - d_stderr2("System directory \"%s\" does not exist.\n" - "Make sure Cardinal was downloaded and installed correctly.", asset::systemDir.c_str()); - } - - INFO("Initializing plugins"); - plugin::initStaticPlugins(); - - INFO("Initializing plugin browser DB"); - app::browserInit(); - -#if defined(HAVE_LIBLO) && defined(HEADLESS) - INFO("Initializing OSC Remote control"); - oscServer = lo_server_new_with_proto(REMOTE_HOST_PORT, LO_UDP, osc_error_handler); - DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr,); - - lo_server_add_method(oscServer, "/hello", "", osc_hello_handler, this); - lo_server_add_method(oscServer, "/load", "b", osc_load_handler, this); - lo_server_add_method(oscServer, "/screenshot", "b", osc_screenshot_handler, this); - lo_server_add_method(oscServer, nullptr, nullptr, osc_fallback_handler, nullptr); - - startThread(); -#elif defined(HEADLESS) - INFO("OSC Remote control is not enabled in this build"); -#endif - } - - ~Initializer() + switch (knobMode) { - using namespace rack; - -#if defined(HAVE_LIBLO) && defined(HEADLESS) - if (oscServer != nullptr) - { - stopThread(5000); - lo_server_del_method(oscServer, nullptr, nullptr); - lo_server_free(oscServer); - oscServer = nullptr; - } -#endif - - INFO("Clearing asset paths"); - asset::bundlePath.clear(); - asset::systemDir.clear(); - asset::userDir.clear(); - - INFO("Destroying plugins"); - plugin::destroyStaticPlugins(); - - INFO("Destroying colourized assets"); - asset::destroy(); - - INFO("Destroying settings"); - settings::destroy(); - - INFO("Destroying logger"); - logger::destroy(); - } - -#if defined(HAVE_LIBLO) && defined(HEADLESS) - void run() override - { - INFO("OSC Thread Listening for remote commands"); - - while (! shouldThreadExit()) - { - d_msleep(200); - while (lo_server_recv_noblock(oscServer, 0) != 0) {} - } - - INFO("OSC Thread Closed"); - } - - static void osc_error_handler(int num, const char* msg, const char* path) - { - d_stderr("Cardinal OSC Error: code: %i, msg: \"%s\", path: \"%s\")", num, msg, path); - } - - static int osc_fallback_handler(const char* const path, const char* const types, lo_arg**, int, lo_message, void*) - { - d_stderr("Cardinal OSC unhandled message \"%s\" with types \"%s\"", path, types); - return 0; - } - - static int osc_hello_handler(const char*, const char*, lo_arg**, int, const lo_message m, void* const self) - { - d_stdout("osc_hello_handler()"); - const lo_address source = lo_message_get_source(m); - lo_send_from(source, static_cast(self)->oscServer, LO_TT_IMMEDIATE, "/resp", "ss", "hello", "ok"); - return 0; - } - - static int osc_load_handler(const char*, const char* types, lo_arg** argv, int argc, const lo_message m, void* const self) - { - d_stdout("osc_load_handler()"); - DISTRHO_SAFE_ASSERT_RETURN(argc == 1, 0); - DISTRHO_SAFE_ASSERT_RETURN(types != nullptr && types[0] == 'b', 0); - - const int32_t size = argv[0]->blob.size; - DISTRHO_SAFE_ASSERT_RETURN(size > 4, 0); - - const uint8_t* const blob = (uint8_t*)(&argv[0]->blob.data); - DISTRHO_SAFE_ASSERT_RETURN(blob != nullptr, 0); - - bool ok = false; - - if (CardinalBasePlugin* const plugin = static_cast(self)->oscPlugin) - { - CardinalPluginContext* const context = plugin->context; - std::vector data(size); - std::memcpy(data.data(), blob, size); - - rack::contextSet(context); - rack::system::removeRecursively(context->patch->autosavePath); - rack::system::createDirectories(context->patch->autosavePath); - try { - rack::system::unarchiveToDirectory(data, context->patch->autosavePath); - context->patch->loadAutosave(); - ok = true; - } - catch (rack::Exception& e) { - WARN("%s", e.what()); - } - rack::contextSet(nullptr); - } - - const lo_address source = lo_message_get_source(m); - lo_send_from(source, static_cast(self)->oscServer, - LO_TT_IMMEDIATE, "/resp", "ss", "load", ok ? "ok" : "fail"); - return 0; - } - - static int osc_screenshot_handler(const char*, const char* types, lo_arg** argv, int argc, const lo_message m, void* const self) - { - d_stdout("osc_screenshot_handler()"); - DISTRHO_SAFE_ASSERT_RETURN(argc == 1, 0); - DISTRHO_SAFE_ASSERT_RETURN(types != nullptr && types[0] == 'b', 0); - - const int32_t size = argv[0]->blob.size; - DISTRHO_SAFE_ASSERT_RETURN(size > 4, 0); - - const uint8_t* const blob = (uint8_t*)(&argv[0]->blob.data); - DISTRHO_SAFE_ASSERT_RETURN(blob != nullptr, 0); - - bool ok = false; - - if (CardinalBasePlugin* const plugin = static_cast(self)->oscPlugin) - ok = plugin->updateStateValue("screenshot", String::asBase64(blob, size).buffer()); - - const lo_address source = lo_message_get_source(m); - lo_send_from(source, static_cast(self)->oscServer, - LO_TT_IMMEDIATE, "/resp", "ss", "screenshot", ok ? "ok" : "fail"); - return 0; - } -#endif -}; - -// ----------------------------------------------------------------------------------------------------------- - -void CardinalPluginContext::writeMidiMessage(const rack::midi::Message& message, const uint8_t channel) -{ - if (bypassed) - return; - - const size_t size = message.bytes.size(); - DISTRHO_SAFE_ASSERT_RETURN(size > 0,); - DISTRHO_SAFE_ASSERT_RETURN(message.frame >= 0,); - - MidiEvent event; - event.frame = message.frame; - - switch (message.bytes[0] & 0xF0) - { - case 0x80: - case 0x90: - case 0xA0: - case 0xB0: - case 0xE0: - event.size = 3; - break; - case 0xC0: - case 0xD0: - event.size = 2; + case rack::settings::KNOB_MODE_LINEAR: + return 0.f; + case rack::settings::KNOB_MODE_ROTARY_ABSOLUTE: + return 1.f; + case rack::settings::KNOB_MODE_ROTARY_RELATIVE: + return 2.f; + // unused in Rack + case rack::settings::KNOB_MODE_SCALED_LINEAR: break; - case 0xF0: - switch (message.bytes[0] & 0x0F) - { - case 0x0: - case 0x4: - case 0x5: - case 0x7: - case 0x9: - case 0xD: - // unsupported - return; - case 0x1: - case 0x2: - case 0x3: - case 0xE: - event.size = 3; - break; - case 0x6: - case 0x8: - case 0xA: - case 0xB: - case 0xC: - case 0xF: - event.size = 1; - break; - } - break; - default: - // invalid - return; } - DISTRHO_SAFE_ASSERT_RETURN(size >= event.size,); - - std::memcpy(event.data, message.bytes.data(), event.size); - - if (channel != 0 && event.data[0] < 0xF0) - event.data[0] |= channel & 0x0F; - - plugin->writeMidiEvent(event); + return 0.f; } +#endif // ----------------------------------------------------------------------------------------------------------- @@ -509,7 +167,6 @@ struct ScopedContext { } }; - // ----------------------------------------------------------------------------------------------------------- class CardinalPlugin : public CardinalBasePlugin @@ -533,7 +190,7 @@ class CardinalPlugin : public CardinalBasePlugin struct { String comment; String screenshot; - #ifndef HEADLESS + #if CARDINAL_VARIANT_MINI || !defined(HEADLESS) String windowSize; #endif } fState; @@ -542,18 +199,21 @@ class CardinalPlugin : public CardinalBasePlugin bool fWasBypassed; MidiEvent bypassMidiEvents[16]; - #ifndef HEADLESS + #if CARDINAL_VARIANT_MINI || !defined(HEADLESS) // real values, not VCV interpreted ones float fWindowParameters[kWindowParameterCount]; #endif + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + float fMiniReportValues[kCardinalParameterCountAtMini - kCardinalParameterStartMini]; + #endif public: CardinalPlugin() - : CardinalBasePlugin(kModuleParameters + kWindowParameterCount + 1, 0, kCardinalStateCount), + : CardinalBasePlugin(kCardinalParameterCount, 0, kCardinalStateCount), #ifdef DISTRHO_OS_WASM - fInitializer(new Initializer(this)), + fInitializer(new Initializer(this, static_cast(nullptr))), #else - fInitializer(this), + fInitializer(this, static_cast(nullptr)), #endif #if DISTRHO_PLUGIN_NUM_INPUTS != 0 fAudioBufferCopy(nullptr), @@ -561,21 +221,36 @@ class CardinalPlugin : public CardinalBasePlugin fNextExpectedFrame(0), fWasBypassed(false) { - #ifndef HEADLESS - fWindowParameters[kWindowParameterShowTooltips] = 1.0f; - fWindowParameters[kWindowParameterCableOpacity] = 50.0f; - fWindowParameters[kWindowParameterCableTension] = 75.0f; - fWindowParameters[kWindowParameterRackBrightness] = 100.0f; - fWindowParameters[kWindowParameterHaloBrightness] = 25.0f; - fWindowParameters[kWindowParameterKnobMode] = 0.0f; - fWindowParameters[kWindowParameterWheelKnobControl] = 0.0f; - fWindowParameters[kWindowParameterWheelSensitivity] = 1.0f; - fWindowParameters[kWindowParameterLockModulePositions] = 0.0f; + // check if first time loading a real instance + if (!fInitializer->shouldSaveSettings && !isDummyInstance()) + fInitializer->loadSettings(true); + + #if CARDINAL_VARIANT_MINI || !defined(HEADLESS) + fWindowParameters[kWindowParameterShowTooltips] = rack::settings::tooltips ? 1.f : 0.f; + fWindowParameters[kWindowParameterCableOpacity] = std::min(100.f, std::max(0.f, rack::settings::cableOpacity * 100)); + fWindowParameters[kWindowParameterCableTension] = std::min(100.f, std::max(0.f, rack::settings::cableTension * 100)); + fWindowParameters[kWindowParameterRackBrightness] = std::min(100.f, std::max(0.f, rack::settings::rackBrightness * 100)); + fWindowParameters[kWindowParameterHaloBrightness] = std::min(100.f, std::max(0.f, rack::settings::haloBrightness * 100)); + fWindowParameters[kWindowParameterKnobMode] = RackKnobModeToFloat(rack::settings::knobMode); + fWindowParameters[kWindowParameterWheelKnobControl] = rack::settings::knobScroll ? 1.f : 0.f; + fWindowParameters[kWindowParameterWheelSensitivity] = std::min(10.f, std::max(0.1f, rack::settings::knobScrollSensitivity * 1000)); + fWindowParameters[kWindowParameterLockModulePositions] = rack::settings::lockModules ? 1.f : 0.f; + fWindowParameters[kWindowParameterBrowserSort] = std::min(rack::settings::BROWSER_SORT_RANDOM, + std::max(rack::settings::BROWSER_SORT_UPDATED, + rack::settings::browserSort)); + fWindowParameters[kWindowParameterBrowserZoom] = std::min(200.f, std::max(25.f, std::pow(2.f, rack::settings::browserZoom) * 100.0f)); + fWindowParameters[kWindowParameterInvertZoom] = rack::settings::invertZoom ? 1.f : 0.f; + fWindowParameters[kWindowParameterSqueezeModulePositions] = rack::settings::squeezeModules ? 1.f : 0.f; + // not saved fWindowParameters[kWindowParameterUpdateRateLimit] = 0.0f; - fWindowParameters[kWindowParameterBrowserSort] = 3.0f; - fWindowParameters[kWindowParameterBrowserZoom] = 50.0f; - fWindowParameters[kWindowParameterInvertZoom] = 0.0f; - fWindowParameters[kWindowParameterSqueezeModulePositions] = 1.0f; + #endif + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + std::memset(fMiniReportValues, 0, sizeof(fMiniReportValues)); + fMiniReportValues[kCardinalParameterMiniTimeBar - kCardinalParameterStartMini] = 1; + fMiniReportValues[kCardinalParameterMiniTimeBeat - kCardinalParameterStartMini] = 1; + fMiniReportValues[kCardinalParameterMiniTimeBeatsPerBar - kCardinalParameterStartMini] = 4; + fMiniReportValues[kCardinalParameterMiniTimeBeatType - kCardinalParameterStartMini] = 4; + fMiniReportValues[kCardinalParameterMiniTimeBeatsPerMinute - kCardinalParameterStartMini] = 120; #endif // create unique temporary path for this instance @@ -639,19 +314,18 @@ class CardinalPlugin : public CardinalBasePlugin { context->patch->loadTemplate(); context->scene->rackScroll->reset(); - // swap to factory template after first load - context->patch->templatePath = context->patch->factoryTemplatePath; } - #if defined(HAVE_LIBLO) && defined(HEADLESS) - fInitializer->oscPlugin = this; + #ifdef CARDINAL_INIT_OSC_THREAD + fInitializer->remotePluginInstance = this; #endif } ~CardinalPlugin() override { - #if defined(HAVE_LIBLO) && defined(HEADLESS) - fInitializer->oscPlugin = nullptr; + #ifdef HAVE_LIBLO + if (fInitializer->remotePluginInstance == this) + fInitializer->remotePluginInstance = nullptr; #endif { @@ -659,7 +333,7 @@ class CardinalPlugin : public CardinalBasePlugin context->patch->clear(); // do a little dance to prevent context scene deletion from saving to temp dir - #ifndef HEADLESS + #if CARDINAL_VARIANT_MINI || !defined(HEADLESS) const ScopedValueSetter svs(rack::settings::headless, true); #endif Engine_setAboutToClose(context->engine); @@ -675,6 +349,37 @@ class CardinalPlugin : public CardinalBasePlugin return context; } + #ifdef HAVE_LIBLO + bool startRemoteServer(const char* const port) override + { + if (fInitializer->remotePluginInstance != nullptr) + return false; + + if (fInitializer->startRemoteServer(port)) + { + fInitializer->remotePluginInstance = this; + return true; + } + + return false; + } + + void stopRemoteServer() override + { + DISTRHO_SAFE_ASSERT_RETURN(fInitializer->remotePluginInstance == this,); + + fInitializer->remotePluginInstance = nullptr; + fInitializer->stopRemoteServer(); + } + + void stepRemoteServer() override + { + DISTRHO_SAFE_ASSERT_RETURN(fInitializer->remotePluginInstance == this,); + + fInitializer->stepRemoteServer(); + } + #endif + protected: /* -------------------------------------------------------------------------------------------------------- * Information */ @@ -712,13 +417,15 @@ class CardinalPlugin : public CardinalBasePlugin uint32_t getVersion() const override { - return d_version(0, 22, 9); + return d_version(0, 23, 10); } int64_t getUniqueId() const override { #if CARDINAL_VARIANT_MAIN || CARDINAL_VARIANT_NATIVE return d_cconst('d', 'C', 'd', 'n'); + #elif CARDINAL_VARIANT_MINI + return d_cconst('d', 'C', 'd', 'M'); #elif CARDINAL_VARIANT_FX return d_cconst('d', 'C', 'n', 'F'); #elif CARDINAL_VARIANT_SYNTH @@ -733,17 +440,23 @@ class CardinalPlugin : public CardinalBasePlugin void initAudioPort(const bool input, uint32_t index, AudioPort& port) override { - #if CARDINAL_VARIANT_MAIN - if (index < 8) + #if CARDINAL_VARIANT_MAIN || CARDINAL_VARIANT_MINI + static_assert(CARDINAL_NUM_AUDIO_INPUTS == CARDINAL_NUM_AUDIO_OUTPUTS, "inputs == outputs"); + + if (index < CARDINAL_NUM_AUDIO_INPUTS) { + #if CARDINAL_VARIANT_MINI + port.groupId = kPortGroupStereo; + #else port.groupId = index / 2; + #endif } else { - port.hints = kAudioPortIsCV | kCVPortHasPositiveUnipolarRange | kCVPortHasScaledRange; - index -= 8; + port.hints = kAudioPortIsCV | kCVPortHasPositiveUnipolarRange | kCVPortHasScaledRange | kCVPortIsOptional; + index -= CARDINAL_NUM_AUDIO_INPUTS; } - #elif CARDINAL_VARIANT_FX || CARDINAL_VARIANT_NATIVE || CARDINAL_VARIANT_SYNTH + #elif CARDINAL_VARIANT_NATIVE || CARDINAL_VARIANT_FX || CARDINAL_VARIANT_SYNTH if (index < 2) port.groupId = kPortGroupStereo; #endif @@ -778,7 +491,7 @@ class CardinalPlugin : public CardinalBasePlugin void initParameter(const uint32_t index, Parameter& parameter) override { - if (index < kModuleParameters) + if (index < kCardinalParameterCountAtModules) { parameter.name = "Parameter "; parameter.name += String(index + 1); @@ -792,181 +505,370 @@ class CardinalPlugin : public CardinalBasePlugin return; } - if (index == kModuleParameters) + if (index == kCardinalParameterBypass) { parameter.initDesignation(kParameterDesignationBypass); return; } - #ifndef HEADLESS - switch (index - kModuleParameters - 1) + #if CARDINAL_VARIANT_MINI || !defined(HEADLESS) + if (index < kCardinalParameterCountAtWindow) { - case kWindowParameterShowTooltips: - parameter.name = "Show tooltips"; - parameter.symbol = "tooltips"; - parameter.hints = kParameterIsAutomatable|kParameterIsInteger|kParameterIsBoolean; - parameter.ranges.def = 1.0f; + switch (index - kCardinalParameterStartWindow) + { + case kWindowParameterShowTooltips: + parameter.name = "Show tooltips"; + parameter.symbol = "tooltips"; + parameter.hints = kParameterIsAutomatable|kParameterIsInteger|kParameterIsBoolean; + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + parameter.hints |= kParameterIsHidden; + #endif + parameter.ranges.def = rack::settings::tooltips ? 1.f : 0.f; + parameter.ranges.min = 0.0f; + parameter.ranges.max = 1.0f; + break; + case kWindowParameterCableOpacity: + parameter.name = "Cable opacity"; + parameter.symbol = "cableOpacity"; + parameter.unit = "%"; + parameter.hints = kParameterIsAutomatable; + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + parameter.hints |= kParameterIsHidden; + #endif + parameter.ranges.def = std::min(100.f, std::max(0.f, rack::settings::cableOpacity * 100)); + parameter.ranges.min = 0.0f; + parameter.ranges.max = 100.0f; + break; + case kWindowParameterCableTension: + parameter.name = "Cable tension"; + parameter.symbol = "cableTension"; + parameter.unit = "%"; + parameter.hints = kParameterIsAutomatable; + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + parameter.hints |= kParameterIsHidden; + #endif + parameter.ranges.def = std::min(100.f, std::max(0.f, rack::settings::cableTension * 100)); + parameter.ranges.min = 0.0f; + parameter.ranges.max = 100.0f; + break; + case kWindowParameterRackBrightness: + parameter.name = "Room brightness"; + parameter.symbol = "rackBrightness"; + parameter.unit = "%"; + parameter.hints = kParameterIsAutomatable; + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + parameter.hints |= kParameterIsHidden; + #endif + parameter.ranges.def = std::min(100.f, std::max(0.f, rack::settings::rackBrightness * 100)); + parameter.ranges.min = 0.0f; + parameter.ranges.max = 100.0f; + break; + case kWindowParameterHaloBrightness: + parameter.name = "Light Bloom"; + parameter.symbol = "haloBrightness"; + parameter.unit = "%"; + parameter.hints = kParameterIsAutomatable; + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + parameter.hints |= kParameterIsHidden; + #endif + parameter.ranges.def = std::min(100.f, std::max(0.f, rack::settings::haloBrightness * 100)); + parameter.ranges.min = 0.0f; + parameter.ranges.max = 100.0f; + break; + case kWindowParameterKnobMode: + parameter.name = "Knob mode"; + parameter.symbol = "knobMode"; + parameter.hints = kParameterIsAutomatable|kParameterIsInteger; + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + parameter.hints |= kParameterIsHidden; + #endif + parameter.ranges.def = RackKnobModeToFloat(rack::settings::knobMode); + parameter.ranges.min = 0.0f; + parameter.ranges.max = 2.0f; + parameter.enumValues.count = 3; + parameter.enumValues.restrictedMode = true; + parameter.enumValues.values = new ParameterEnumerationValue[3]; + parameter.enumValues.values[0].label = "Linear"; + parameter.enumValues.values[0].value = 0.0f; + parameter.enumValues.values[1].label = "Absolute rotary"; + parameter.enumValues.values[1].value = 1.0f; + parameter.enumValues.values[2].label = "Relative rotary"; + parameter.enumValues.values[2].value = 2.0f; + break; + case kWindowParameterWheelKnobControl: + parameter.name = "Scroll wheel knob control"; + parameter.symbol = "knobScroll"; + parameter.hints = kParameterIsAutomatable|kParameterIsInteger|kParameterIsBoolean; + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + parameter.hints |= kParameterIsHidden; + #endif + parameter.ranges.def = rack::settings::knobScroll ? 1.f : 0.f; + parameter.ranges.min = 0.0f; + parameter.ranges.max = 1.0f; + break; + case kWindowParameterWheelSensitivity: + parameter.name = "Scroll wheel knob sensitivity"; + parameter.symbol = "knobScrollSensitivity"; + parameter.hints = kParameterIsAutomatable|kParameterIsLogarithmic; + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + parameter.hints |= kParameterIsHidden; + #endif + parameter.ranges.def = std::min(10.f, std::max(0.1f, rack::settings::knobScrollSensitivity * 1000)); + parameter.ranges.min = 0.1f; + parameter.ranges.max = 10.0f; + break; + case kWindowParameterLockModulePositions: + parameter.name = "Lock module positions"; + parameter.symbol = "lockModules"; + parameter.hints = kParameterIsAutomatable|kParameterIsInteger|kParameterIsBoolean; + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + parameter.hints |= kParameterIsHidden; + #endif + parameter.ranges.def = rack::settings::lockModules ? 1.f : 0.f; + parameter.ranges.min = 0.0f; + parameter.ranges.max = 1.0f; + break; + case kWindowParameterUpdateRateLimit: + parameter.name = "Update rate limit"; + parameter.symbol = "rateLimit"; + parameter.hints = kParameterIsAutomatable|kParameterIsInteger; + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + parameter.hints |= kParameterIsHidden; + #endif + parameter.ranges.def = 0.0f; + parameter.ranges.min = 0.0f; + parameter.ranges.max = 2.0f; + parameter.enumValues.count = 3; + parameter.enumValues.restrictedMode = true; + parameter.enumValues.values = new ParameterEnumerationValue[3]; + parameter.enumValues.values[0].label = "None"; + parameter.enumValues.values[0].value = 0.0f; + parameter.enumValues.values[1].label = "2x"; + parameter.enumValues.values[1].value = 1.0f; + parameter.enumValues.values[2].label = "4x"; + parameter.enumValues.values[2].value = 2.0f; + break; + case kWindowParameterBrowserSort: + parameter.name = "Browser sort"; + parameter.symbol = "browserSort"; + parameter.hints = kParameterIsAutomatable|kParameterIsInteger; + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + parameter.hints |= kParameterIsHidden; + #endif + parameter.ranges.def = std::min(rack::settings::BROWSER_SORT_RANDOM, + std::max(rack::settings::BROWSER_SORT_UPDATED, + rack::settings::browserSort)); + parameter.ranges.min = rack::settings::BROWSER_SORT_UPDATED; + parameter.ranges.max = rack::settings::BROWSER_SORT_RANDOM; + parameter.enumValues.count = 6; + parameter.enumValues.restrictedMode = true; + parameter.enumValues.values = new ParameterEnumerationValue[6]; + parameter.enumValues.values[0].label = "Updated"; + parameter.enumValues.values[0].value = rack::settings::BROWSER_SORT_UPDATED; + parameter.enumValues.values[1].label = "Last used"; + parameter.enumValues.values[1].value = rack::settings::BROWSER_SORT_LAST_USED; + parameter.enumValues.values[2].label = "Most used"; + parameter.enumValues.values[2].value = rack::settings::BROWSER_SORT_MOST_USED; + parameter.enumValues.values[3].label = "Brand"; + parameter.enumValues.values[3].value = rack::settings::BROWSER_SORT_BRAND; + parameter.enumValues.values[4].label = "Name"; + parameter.enumValues.values[4].value = rack::settings::BROWSER_SORT_NAME; + parameter.enumValues.values[5].label = "Random"; + parameter.enumValues.values[5].value = rack::settings::BROWSER_SORT_RANDOM; + break; + case kWindowParameterBrowserZoom: + parameter.name = "Browser zoom"; + parameter.symbol = "browserZoom"; + parameter.hints = kParameterIsAutomatable; + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + parameter.hints |= kParameterIsHidden; + #endif + parameter.unit = "%"; + parameter.ranges.def = std::min(200.f, std::max(25.f, std::pow(2.f, rack::settings::browserZoom) * 100.0f)); + parameter.ranges.min = 25.0f; + parameter.ranges.max = 200.0f; + parameter.enumValues.count = 7; + parameter.enumValues.restrictedMode = true; + parameter.enumValues.values = new ParameterEnumerationValue[7]; + parameter.enumValues.values[0].label = "25"; + parameter.enumValues.values[0].value = 25.0f; + parameter.enumValues.values[1].label = "35"; + parameter.enumValues.values[1].value = 35.0f; + parameter.enumValues.values[2].label = "50"; + parameter.enumValues.values[2].value = 50.0f; + parameter.enumValues.values[3].label = "71"; + parameter.enumValues.values[3].value = 71.0f; + parameter.enumValues.values[4].label = "100"; + parameter.enumValues.values[4].value = 100.0f; + parameter.enumValues.values[5].label = "141"; + parameter.enumValues.values[5].value = 141.0f; + parameter.enumValues.values[6].label = "200"; + parameter.enumValues.values[6].value = 200.0f; + break; + case kWindowParameterInvertZoom: + parameter.name = "Invert zoom"; + parameter.symbol = "invertZoom"; + parameter.hints = kParameterIsAutomatable|kParameterIsInteger|kParameterIsBoolean; + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + parameter.hints |= kParameterIsHidden; + #endif + parameter.ranges.def = rack::settings::invertZoom ? 1.f : 0.f; + parameter.ranges.min = 0.0f; + parameter.ranges.max = 1.0f; + break; + case kWindowParameterSqueezeModulePositions: + parameter.name = "Auto-squeeze module positions"; + parameter.symbol = "squeezeModules"; + parameter.hints = kParameterIsAutomatable|kParameterIsInteger|kParameterIsBoolean; + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + parameter.hints |= kParameterIsHidden; + #endif + parameter.ranges.def = rack::settings::squeezeModules ? 1.f : 0.f; + parameter.ranges.min = 0.0f; + parameter.ranges.max = 1.0f; + break; + } + } + #endif + + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + switch (index) + { + case kCardinalParameterMiniAudioIn1: + parameter.name = "Report Audio Input 1"; + parameter.symbol = "r_audio_in_1"; + parameter.hints = kParameterIsAutomatable|kParameterIsOutput; + parameter.ranges.def = 0.0f; parameter.ranges.min = 0.0f; parameter.ranges.max = 1.0f; break; - case kWindowParameterCableOpacity: - parameter.name = "Cable opacity"; - parameter.symbol = "cableOpacity"; - parameter.unit = "%"; - parameter.hints = kParameterIsAutomatable; - parameter.ranges.def = 50.0f; + case kCardinalParameterMiniAudioIn2: + parameter.name = "Report Audio Input 2"; + parameter.symbol = "r_audio_in_2"; + parameter.hints = kParameterIsAutomatable|kParameterIsOutput; + parameter.ranges.def = 0.0f; parameter.ranges.min = 0.0f; - parameter.ranges.max = 100.0f; + parameter.ranges.max = 1.0f; break; - case kWindowParameterCableTension: - parameter.name = "Cable tension"; - parameter.symbol = "cableTension"; - parameter.unit = "%"; - parameter.hints = kParameterIsAutomatable; - parameter.ranges.def = 75.0f; + case kCardinalParameterMiniCVIn1: + parameter.name = "Report CV Input 1"; + parameter.symbol = "r_cv_in_1"; + parameter.hints = kParameterIsAutomatable|kParameterIsOutput; + parameter.ranges.def = -10.0f; parameter.ranges.min = 0.0f; - parameter.ranges.max = 100.0f; + parameter.ranges.max = 10.0f; break; - case kWindowParameterRackBrightness: - parameter.name = "Room brightness"; - parameter.symbol = "rackBrightness"; - parameter.unit = "%"; - parameter.hints = kParameterIsAutomatable; - parameter.ranges.def = 100.0f; + case kCardinalParameterMiniCVIn2: + parameter.name = "Report CV Input 2"; + parameter.symbol = "r_cv_in_2"; + parameter.hints = kParameterIsAutomatable|kParameterIsOutput; + parameter.ranges.def = -10.0f; parameter.ranges.min = 0.0f; - parameter.ranges.max = 100.0f; + parameter.ranges.max = 10.0f; break; - case kWindowParameterHaloBrightness: - parameter.name = "Light Bloom"; - parameter.symbol = "haloBrightness"; - parameter.unit = "%"; - parameter.hints = kParameterIsAutomatable; - parameter.ranges.def = 25.0f; + case kCardinalParameterMiniCVIn3: + parameter.name = "Report CV Input 3"; + parameter.symbol = "r_cv_in_3"; + parameter.hints = kParameterIsAutomatable|kParameterIsOutput; + parameter.ranges.def = -10.0f; parameter.ranges.min = 0.0f; - parameter.ranges.max = 100.0f; + parameter.ranges.max = 10.0f; break; - case kWindowParameterKnobMode: - parameter.name = "Knob mode"; - parameter.symbol = "knobMode"; - parameter.hints = kParameterIsAutomatable|kParameterIsInteger; - parameter.ranges.def = 0.0f; + case kCardinalParameterMiniCVIn4: + parameter.name = "Report CV Input 4"; + parameter.symbol = "r_cv_in_4"; + parameter.hints = kParameterIsAutomatable|kParameterIsOutput; + parameter.ranges.def = -10.0f; parameter.ranges.min = 0.0f; - parameter.ranges.max = 2.0f; - parameter.enumValues.count = 3; - parameter.enumValues.restrictedMode = true; - parameter.enumValues.values = new ParameterEnumerationValue[3]; - parameter.enumValues.values[0].label = "Linear"; - parameter.enumValues.values[0].value = 0.0f; - parameter.enumValues.values[1].label = "Absolute rotary"; - parameter.enumValues.values[1].value = 1.0f; - parameter.enumValues.values[2].label = "Relative rotary"; - parameter.enumValues.values[2].value = 2.0f; + parameter.ranges.max = 10.0f; break; - case kWindowParameterWheelKnobControl: - parameter.name = "Scroll wheel knob control"; - parameter.symbol = "knobScroll"; - parameter.hints = kParameterIsAutomatable|kParameterIsInteger|kParameterIsBoolean; - parameter.ranges.def = 0.0f; + case kCardinalParameterMiniCVIn5: + parameter.name = "Report CV Input 5"; + parameter.symbol = "r_cv_in_5"; + parameter.hints = kParameterIsAutomatable|kParameterIsOutput; + parameter.ranges.def = -10.0f; parameter.ranges.min = 0.0f; - parameter.ranges.max = 1.0f; + parameter.ranges.max = 10.0f; + break; + case kCardinalParameterMiniTimeFlags: + parameter.name = "Report Time Flags"; + parameter.symbol = "r_time_flags"; + parameter.hints = kParameterIsAutomatable|kParameterIsOutput; + parameter.ranges.def = 0x0; + parameter.ranges.min = 0x0; + parameter.ranges.max = 0x7; break; - case kWindowParameterWheelSensitivity: - parameter.name = "Scroll wheel knob sensitivity"; - parameter.symbol = "knobScrollSensitivity"; - parameter.hints = kParameterIsAutomatable|kParameterIsLogarithmic; + case kCardinalParameterMiniTimeBar: + parameter.name = "Report Time Bar"; + parameter.symbol = "r_time_bar"; + parameter.hints = kParameterIsAutomatable|kParameterIsOutput; parameter.ranges.def = 1.0f; - parameter.ranges.min = 0.1f; - parameter.ranges.max = 10.0f; + parameter.ranges.min = 1.0f; + parameter.ranges.max = FLT_MAX; break; - case kWindowParameterLockModulePositions: - parameter.name = "Lock module positions"; - parameter.symbol = "lockModules"; - parameter.hints = kParameterIsAutomatable|kParameterIsInteger|kParameterIsBoolean; - parameter.ranges.def = 0.0f; + case kCardinalParameterMiniTimeBeat: + parameter.name = "Report Time Beat"; + parameter.symbol = "r_time_beat"; + parameter.hints = kParameterIsAutomatable|kParameterIsOutput; + parameter.ranges.def = 1.0f; + parameter.ranges.min = 1.0f; + parameter.ranges.max = 128.0f; + break; + case kCardinalParameterMiniTimeBeatsPerBar: + parameter.name = "Report Time Beats Per Bar"; + parameter.symbol = "r_time_beatsPerBar"; + parameter.hints = kParameterIsAutomatable|kParameterIsOutput; + parameter.ranges.def = 4.0f; parameter.ranges.min = 0.0f; - parameter.ranges.max = 1.0f; + parameter.ranges.max = 128.0f; + break; + case kCardinalParameterMiniTimeBeatType: + parameter.name = "Report Time Beat Type"; + parameter.symbol = "r_time_beatType"; + parameter.hints = kParameterIsAutomatable|kParameterIsOutput; + parameter.ranges.def = 4.0f; + parameter.ranges.min = 0.0f; + parameter.ranges.max = 128.0f; break; - case kWindowParameterUpdateRateLimit: - parameter.name = "Update rate limit"; - parameter.symbol = "rateLimit"; - parameter.hints = kParameterIsAutomatable|kParameterIsInteger; + case kCardinalParameterMiniTimeFrame: + parameter.name = "Report Time Frame"; + parameter.symbol = "r_time_frame"; + parameter.hints = kParameterIsAutomatable|kParameterIsOutput; parameter.ranges.def = 0.0f; parameter.ranges.min = 0.0f; - parameter.ranges.max = 2.0f; - parameter.enumValues.count = 3; - parameter.enumValues.restrictedMode = true; - parameter.enumValues.values = new ParameterEnumerationValue[3]; - parameter.enumValues.values[0].label = "None"; - parameter.enumValues.values[0].value = 0.0f; - parameter.enumValues.values[1].label = "2x"; - parameter.enumValues.values[1].value = 1.0f; - parameter.enumValues.values[2].label = "4x"; - parameter.enumValues.values[2].value = 2.0f; + parameter.ranges.max = FLT_MAX; break; - case kWindowParameterBrowserSort: - parameter.name = "Browser sort"; - parameter.symbol = "browserSort"; - parameter.hints = kParameterIsAutomatable|kParameterIsInteger; - parameter.ranges.def = 3.0f; + case kCardinalParameterMiniTimeBarStartTick: + parameter.name = "Report Time BarStartTick"; + parameter.symbol = "r_time_barStartTick"; + parameter.hints = kParameterIsAutomatable|kParameterIsOutput; + parameter.ranges.def = 0.0f; parameter.ranges.min = 0.0f; - parameter.ranges.max = 5.0f; - parameter.enumValues.count = 6; - parameter.enumValues.restrictedMode = true; - parameter.enumValues.values = new ParameterEnumerationValue[6]; - parameter.enumValues.values[0].label = "Updated"; - parameter.enumValues.values[0].value = 0.0f; - parameter.enumValues.values[1].label = "Last used"; - parameter.enumValues.values[1].value = 1.0f; - parameter.enumValues.values[2].label = "Most used"; - parameter.enumValues.values[2].value = 2.0f; - parameter.enumValues.values[3].label = "Brand"; - parameter.enumValues.values[3].value = 3.0f; - parameter.enumValues.values[4].label = "Name"; - parameter.enumValues.values[4].value = 4.0f; - parameter.enumValues.values[5].label = "Random"; - parameter.enumValues.values[5].value = 5.0f; + parameter.ranges.max = FLT_MAX; break; - case kWindowParameterBrowserZoom: - parameter.name = "Browser zoom"; - parameter.symbol = "browserZoom"; - parameter.hints = kParameterIsAutomatable; - parameter.unit = "%"; - parameter.ranges.def = 50.0f; - parameter.ranges.min = 25.0f; - parameter.ranges.max = 200.0f; - parameter.enumValues.count = 7; - parameter.enumValues.restrictedMode = true; - parameter.enumValues.values = new ParameterEnumerationValue[7]; - parameter.enumValues.values[0].label = "25"; - parameter.enumValues.values[0].value = 25.0f; - parameter.enumValues.values[1].label = "35"; - parameter.enumValues.values[1].value = 35.0f; - parameter.enumValues.values[2].label = "50"; - parameter.enumValues.values[2].value = 50.0f; - parameter.enumValues.values[3].label = "71"; - parameter.enumValues.values[3].value = 71.0f; - parameter.enumValues.values[4].label = "100"; - parameter.enumValues.values[4].value = 100.0f; - parameter.enumValues.values[5].label = "141"; - parameter.enumValues.values[5].value = 141.0f; - parameter.enumValues.values[6].label = "200"; - parameter.enumValues.values[6].value = 200.0f; + case kCardinalParameterMiniTimeBeatsPerMinute: + parameter.name = "Report Time Beats Per Minute"; + parameter.symbol = "r_time_bpm"; + parameter.hints = kParameterIsAutomatable|kParameterIsOutput; + parameter.ranges.def = 20.0f; + parameter.ranges.min = 120.0f; + parameter.ranges.max = 999.0f; break; - case kWindowParameterInvertZoom: - parameter.name = "Invert zoom"; - parameter.symbol = "invertZoom"; - parameter.hints = kParameterIsAutomatable|kParameterIsInteger|kParameterIsBoolean; + case kCardinalParameterMiniTimeTick: + parameter.name = "Report Time Tick"; + parameter.symbol = "r_time_tick"; + parameter.hints = kParameterIsAutomatable|kParameterIsOutput; parameter.ranges.def = 0.0f; parameter.ranges.min = 0.0f; - parameter.ranges.max = 1.0f; + parameter.ranges.max = 8192.0f; break; - case kWindowParameterSqueezeModulePositions: - parameter.name = "Auto-squeeze module positions"; - parameter.symbol = "squeezeModules"; - parameter.hints = kParameterIsAutomatable|kParameterIsInteger|kParameterIsBoolean; - parameter.ranges.def = 1.0f; + case kCardinalParameterMiniTimeTicksPerBeat: + parameter.name = "Report Time Ticks Per Beat"; + parameter.symbol = "r_time_ticksPerBeat"; + parameter.hints = kParameterIsAutomatable|kParameterIsOutput; + parameter.ranges.def = 0.0f; parameter.ranges.min = 0.0f; - parameter.ranges.max = 1.0f; + parameter.ranges.max = 8192.0f; break; } #endif @@ -976,31 +878,62 @@ class CardinalPlugin : public CardinalBasePlugin { switch (index) { - case 0: - state.hints = kStateIsBase64Blob | kStateIsOnlyForDSP; + case kCardinalStatePatch: + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + state.hints = kStateIsHostReadable; + #else + state.hints = kStateIsOnlyForDSP | kStateIsBase64Blob; + #endif + if (FILE* const f = std::fopen(context->patch->factoryTemplatePath.c_str(), "r")) + { + std::fseek(f, 0, SEEK_END); + if (const long fileSize = std::ftell(f)) + { + std::fseek(f, 0, SEEK_SET); + char* const fileContent = new char[fileSize+1]; + + if (std::fread(fileContent, fileSize, 1, f) == 1) + { + fileContent[fileSize] = '\0'; + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + state.defaultValue = fileContent; + #else + state.defaultValue = String::asBase64(fileContent, fileSize); + #endif + } + + delete[] fileContent; + } + std::fclose(f); + } state.key = "patch"; state.label = "Patch"; break; - case 1: + case kCardinalStateScreenshot: state.hints = kStateIsHostReadable | kStateIsBase64Blob; state.key = "screenshot"; state.label = "Screenshot"; break; - case 2: + case kCardinalStateComment: state.hints = kStateIsHostWritable; state.key = "comment"; state.label = "Comment"; break; - case 3: - state.hints = kStateIsOnlyForUI; - state.key = "moduleInfos"; - state.label = "moduleInfos"; - break; - case 4: + #if CARDINAL_VARIANT_MINI || !defined(HEADLESS) + case kCardinalStateWindowSize: state.hints = kStateIsOnlyForUI; + // state.defaultValue = String("%d:%d", DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT); state.key = "windowSize"; state.label = "Window size"; break; + #endif + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + case kCardinalStateParamChange: + state.hints = kStateIsHostReadable | kStateIsOnlyForDSP; + state.key = "param"; + state.label = "ParamChange"; + break; + #endif } } @@ -1010,19 +943,21 @@ class CardinalPlugin : public CardinalBasePlugin float getParameterValue(uint32_t index) const override { // host mapped parameters - if (index < kModuleParameters) + if (index < kCardinalParameterCountAtModules) return context->parameters[index]; // bypass - if (index == kModuleParameters) + if (index == kCardinalParameterBypass) return context->bypassed ? 1.0f : 0.0f; - #ifndef HEADLESS - // window related parameters - index -= kModuleParameters + 1; + #if CARDINAL_VARIANT_MINI || !defined(HEADLESS) + if (index < kCardinalParameterCountAtWindow) + return fWindowParameters[index - kCardinalParameterStartWindow]; + #endif - if (index < kWindowParameterCount) - return fWindowParameters[index]; + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + if (index < kCardinalParameterCountAtMini) + return fMiniReportValues[index - kCardinalParameterStartMini]; #endif return 0.0f; @@ -1031,26 +966,23 @@ class CardinalPlugin : public CardinalBasePlugin void setParameterValue(uint32_t index, float value) override { // host mapped parameters - if (index < kModuleParameters) + if (index < kCardinalParameterCountAtModules) { context->parameters[index] = value; return; } // bypass - if (index == kModuleParameters) + if (index == kCardinalParameterBypass) { context->bypassed = value > 0.5f; return; } - #ifndef HEADLESS - // window related parameters - index -= kModuleParameters + 1; - - if (index < kWindowParameterCount) + #if CARDINAL_VARIANT_MINI || !defined(HEADLESS) + if (index < kCardinalParameterCountAtWindow) { - fWindowParameters[index] = value; + fWindowParameters[index - kCardinalParameterStartWindow] = value; return; } #endif @@ -1058,50 +990,7 @@ class CardinalPlugin : public CardinalBasePlugin String getState(const char* const key) const override { - #ifndef HEADLESS - if (std::strcmp(key, "moduleInfos") == 0) - { - json_t* const rootJ = json_object(); - DISTRHO_SAFE_ASSERT_RETURN(rootJ != nullptr, String()); - - for (const auto& pluginPair : rack::settings::moduleInfos) - { - json_t* const pluginJ = json_object(); - DISTRHO_SAFE_ASSERT_CONTINUE(pluginJ != nullptr); - - for (const auto& modulePair : pluginPair.second) - { - json_t* const moduleJ = json_object(); - DISTRHO_SAFE_ASSERT_CONTINUE(moduleJ != nullptr); - - const rack::settings::ModuleInfo& m(modulePair.second); - - // To make setting.json smaller, only set properties if not default values. - if (m.favorite) - json_object_set_new(moduleJ, "favorite", json_boolean(m.favorite)); - if (m.added > 0) - json_object_set_new(moduleJ, "added", json_integer(m.added)); - if (std::isfinite(m.lastAdded)) - json_object_set_new(moduleJ, "lastAdded", json_real(m.lastAdded)); - - if (json_object_size(moduleJ)) - json_object_set_new(pluginJ, modulePair.first.c_str(), moduleJ); - else - json_decref(moduleJ); - } - - if (json_object_size(pluginJ)) - json_object_set_new(rootJ, pluginPair.first.c_str(), pluginJ); - else - json_decref(pluginJ); - } - - const String info(json_dumps(rootJ, JSON_COMPACT), false); - json_decref(rootJ); - - return info; - } - + #if CARDINAL_VARIANT_MINI || !defined(HEADLESS) if (std::strcmp(key, "windowSize") == 0) return fState.windowSize; #endif @@ -1126,9 +1015,30 @@ class CardinalPlugin : public CardinalBasePlugin context->patch->cleanAutosave(); // context->history->setSaved(); + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + FILE* const f = std::fopen(rack::system::join(context->patch->autosavePath, "patch.json").c_str(), "r"); + DISTRHO_SAFE_ASSERT_RETURN(f != nullptr, String()); + + DEFER({ + std::fclose(f); + }); + + std::fseek(f, 0, SEEK_END); + const long fileSize = std::ftell(f); + DISTRHO_SAFE_ASSERT_RETURN(fileSize > 0, String()); + + std::fseek(f, 0, SEEK_SET); + char* const fileContent = static_cast(std::malloc(fileSize+1)); + + DISTRHO_SAFE_ASSERT_RETURN(std::fread(fileContent, fileSize, 1, f) == 1, String()); + fileContent[fileSize] = '\0'; + + return String(fileContent, false); + #else try { data = rack::system::archiveDirectory(fAutosavePath, 1); } DISTRHO_SAFE_EXCEPTION_RETURN("getState archiveDirectory", String()); + #endif } return String::asBase64(data.data(), data.size()); @@ -1136,41 +1046,26 @@ class CardinalPlugin : public CardinalBasePlugin void setState(const char* const key, const char* const value) override { - #ifndef HEADLESS - if (std::strcmp(key, "moduleInfos") == 0) + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + if (std::strcmp(key, "param") == 0) { - json_error_t error; - json_t* const rootJ = json_loads(value, 0, &error); - DISTRHO_SAFE_ASSERT_RETURN(rootJ != nullptr,); - - const char* pluginSlug; - json_t* pluginJ; - - json_object_foreach(rootJ, pluginSlug, pluginJ) + long long moduleId = 0; + int paramId = 0; + float paramValue = 0.f; { - const char* moduleSlug; - json_t* moduleJ; - - json_object_foreach(pluginJ, moduleSlug, moduleJ) - { - rack::settings::ModuleInfo m; - - if (json_t* const favoriteJ = json_object_get(moduleJ, "favorite")) - m.favorite = json_boolean_value(favoriteJ); - - if (json_t* const addedJ = json_object_get(moduleJ, "added")) - m.added = json_integer_value(addedJ); - - if (json_t* const lastAddedJ = json_object_get(moduleJ, "lastAdded")) - m.lastAdded = json_number_value(lastAddedJ); - - rack::settings::moduleInfos[pluginSlug][moduleSlug] = m; - } + const ScopedSafeLocale cssl; + std::sscanf(value, "%lld:%d:%f", &moduleId, ¶mId, ¶mValue); } - json_decref(rootJ); + rack::engine::Module* const module = context->engine->getModule(moduleId); + DISTRHO_SAFE_ASSERT_RETURN(module != nullptr,); + + context->engine->setParamValue(module, paramId, paramValue); return; } + #endif + + #if CARDINAL_VARIANT_MINI || !defined(HEADLESS) if (std::strcmp(key, "windowSize") == 0) { fState.windowSize = value; @@ -1187,9 +1082,6 @@ class CardinalPlugin : public CardinalBasePlugin if (std::strcmp(key, "screenshot") == 0) { fState.screenshot = value; - #if defined(HAVE_LIBLO) && !defined(HEADLESS) - patchUtils::sendScreenshotToRemote(value); - #endif return; } @@ -1198,12 +1090,20 @@ class CardinalPlugin : public CardinalBasePlugin if (fAutosavePath.empty()) return; + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + rack::system::removeRecursively(fAutosavePath); + rack::system::createDirectories(fAutosavePath); + + FILE* const f = std::fopen(rack::system::join(fAutosavePath, "patch.json").c_str(), "w"); + DISTRHO_SAFE_ASSERT_RETURN(f != nullptr,); + + std::fwrite(value, std::strlen(value), 1, f); + std::fclose(f); + #else const std::vector data(d_getChunkFromBase64String(value)); DISTRHO_SAFE_ASSERT_RETURN(data.size() >= 4,); - const ScopedContext sc(this); - rack::system::removeRecursively(fAutosavePath); rack::system::createDirectories(fAutosavePath); @@ -1223,9 +1123,14 @@ class CardinalPlugin : public CardinalBasePlugin rack::system::unarchiveToDirectory(data, fAutosavePath); } DISTRHO_SAFE_EXCEPTION_RETURN("setState unarchiveToDirectory",); } + #endif + + const ScopedContext sc(this); try { context->patch->loadAutosave(); + } catch(const rack::Exception& e) { + d_stderr(e.what()); } DISTRHO_SAFE_EXCEPTION_RETURN("setState loadAutosave",); // context->history->setSaved(); @@ -1263,6 +1168,8 @@ class CardinalPlugin : public CardinalBasePlugin void run(const float** const inputs, float** const outputs, const uint32_t frames, const MidiEvent* const midiEvents, const uint32_t midiEventCount) override { + const ScopedDenormalDisable sdd; + rack::contextSet(context); const bool bypassed = context->bypassed; @@ -1270,7 +1177,11 @@ class CardinalPlugin : public CardinalBasePlugin { const TimePosition& timePos(getTimePosition()); - const bool reset = timePos.playing && (timePos.frame == 0 || d_isDiffHigherThanLimit(fNextExpectedFrame, timePos.frame, (uint64_t)2)); + bool reset = timePos.playing && (timePos.frame == 0 || d_isDiffHigherThanLimit(fNextExpectedFrame, timePos.frame, (uint64_t)2)); + + // ignore hosts which cannot supply time frame position + if (context->playing == timePos.playing && timePos.frame == 0 && context->frame == 0) + reset = false; context->playing = timePos.playing; context->bbtValid = timePos.bbt.valid; @@ -1292,10 +1203,28 @@ class CardinalPlugin : public CardinalBasePlugin context->ticksPerClock = timePos.bbt.ticksPerBeat / timePos.bbt.beatType; context->ticksPerFrame = 1.0 / samplesPerTick; context->tickClock = std::fmod(timePos.bbt.tick, context->ticksPerClock); + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + fMiniReportValues[kCardinalParameterMiniTimeBar - kCardinalParameterStartMini] = timePos.bbt.bar; + fMiniReportValues[kCardinalParameterMiniTimeBeat - kCardinalParameterStartMini] = timePos.bbt.beat; + fMiniReportValues[kCardinalParameterMiniTimeBeatsPerBar - kCardinalParameterStartMini] = timePos.bbt.beatsPerBar; + fMiniReportValues[kCardinalParameterMiniTimeBeatType - kCardinalParameterStartMini] = timePos.bbt.beatType; + fMiniReportValues[kCardinalParameterMiniTimeBarStartTick - kCardinalParameterStartMini] = timePos.bbt.barStartTick; + fMiniReportValues[kCardinalParameterMiniTimeBeatsPerMinute - kCardinalParameterStartMini] = timePos.bbt.beatsPerMinute; + fMiniReportValues[kCardinalParameterMiniTimeTick - kCardinalParameterStartMini] = timePos.bbt.tick; + fMiniReportValues[kCardinalParameterMiniTimeTicksPerBeat - kCardinalParameterStartMini] = timePos.bbt.ticksPerBeat; + #endif } context->reset = reset; fNextExpectedFrame = timePos.playing ? timePos.frame + frames : 0; + + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + const int flags = (timePos.playing ? 0x1 : 0x0) + | (timePos.bbt.valid ? 0x2 : 0x0) + | (reset ? 0x4 : 0x0); + fMiniReportValues[kCardinalParameterMiniTimeFlags - kCardinalParameterStartMini] = flags; + fMiniReportValues[kCardinalParameterMiniTimeFrame - kCardinalParameterStartMini] = timePos.frame / getSampleRate(); + #endif } // separate buffers, use them @@ -1310,8 +1239,8 @@ class CardinalPlugin : public CardinalBasePlugin #if DISTRHO_PLUGIN_NUM_INPUTS != 0 for (int i=0; idataIns[i][0]; + #endif + if (bypassed) { if (fWasBypassed != bypassed) @@ -1387,6 +1321,6 @@ Plugin* createPlugin() return new CardinalPlugin(); } -// ----------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- END_NAMESPACE_DISTRHO diff --git a/src/CardinalRemote.cpp b/src/CardinalRemote.cpp new file mode 100644 index 00000000..c7951379 --- /dev/null +++ b/src/CardinalRemote.cpp @@ -0,0 +1,246 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021-2022 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the LICENSE file. + */ + +#include +#include +#include + +#ifdef NDEBUG +# undef DEBUG +#endif + +#include "CardinalRemote.hpp" +#include "PluginContext.hpp" +#include "extra/Base64.hpp" +#include "extra/ScopedSafeLocale.hpp" + +#if defined(STATIC_BUILD) || ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS +# undef HAVE_LIBLO +#endif + +#if (defined(HAVE_LIBLO) || ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS) && !defined(HEADLESS) +# define CARDINAL_REMOTE_ENABLED +#endif + +#ifdef HAVE_LIBLO +# include +#endif + +// ----------------------------------------------------------------------------------------------------------- + +namespace remoteUtils { + +#ifdef HAVE_LIBLO +static int osc_handler(const char* const path, const char* const types, lo_arg** argv, const int argc, lo_message, void* const self) +{ + d_stdout("osc_handler(\"%s\", \"%s\", %p, %i)", path, types, argv, argc); + + if (std::strcmp(path, "/resp") == 0 && argc == 2 && types[0] == 's' && types[1] == 's') + { + d_stdout("osc_handler(\"%s\", ...) - got resp | '%s' '%s'", path, &argv[0]->s, &argv[1]->s); + + if (std::strcmp(&argv[0]->s, "hello") == 0 && std::strcmp(&argv[1]->s, "ok") == 0) + static_cast(self)->connected = true; + } + return 0; +} +#endif + +RemoteDetails* getRemote() +{ +#ifdef CARDINAL_REMOTE_ENABLED + CardinalPluginContext* const context = static_cast(APP); + DISTRHO_SAFE_ASSERT_RETURN(context != nullptr, nullptr); + + CardinalBaseUI* const ui = static_cast(context->ui); + DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, nullptr); + + return ui->remoteDetails; +#else + return nullptr; +#endif +} + +bool connectToRemote(const char* const url) +{ +#ifdef CARDINAL_REMOTE_ENABLED + CardinalPluginContext* const context = static_cast(APP); + DISTRHO_SAFE_ASSERT_RETURN(context != nullptr, false); + + CardinalBaseUI* const ui = static_cast(context->ui); + DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, false); + + RemoteDetails* remoteDetails = ui->remoteDetails; + + #if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + if (remoteDetails == nullptr) + { + ui->remoteDetails = remoteDetails = new RemoteDetails; + remoteDetails->handle = ui; + remoteDetails->url = strdup(url); + remoteDetails->connected = true; + remoteDetails->autoDeploy = true; + } + #elif defined(HAVE_LIBLO) + const lo_address addr = lo_address_new_from_url(url); + DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr, false); + + if (remoteDetails == nullptr) + { + const lo_server oscServer = lo_server_new_with_proto(nullptr, LO_UDP, nullptr); + DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr, false); + + ui->remoteDetails = remoteDetails = new RemoteDetails; + remoteDetails->handle = oscServer; + remoteDetails->url = strdup(url); + remoteDetails->connected = false; + remoteDetails->autoDeploy = false; + + lo_server_add_method(oscServer, "/resp", nullptr, osc_handler, remoteDetails); + } + else if (std::strcmp(remoteDetails->url, url) != 0) + { + ui->remoteDetails = nullptr; + disconnectFromRemote(remoteDetails); + return connectToRemote(url); + } + + lo_send(addr, "/hello", ""); + lo_address_free(addr); + #endif + + return remoteDetails != nullptr; +#else + return false; +#endif +} + +void disconnectFromRemote(RemoteDetails* const remote) +{ + if (remote != nullptr) + { + #ifdef HAVE_LIBLO + lo_server_free(static_cast(remote->handle)); + #endif + std::free(const_cast(remote->url)); + delete remote; + } +} + +void idleRemote(RemoteDetails* const remote) +{ + DISTRHO_SAFE_ASSERT_RETURN(remote != nullptr,); +#ifdef HAVE_LIBLO + while (lo_server_recv_noblock(static_cast(remote->handle), 0) != 0) {} +#endif +} + +void sendParamChangeToRemote(RemoteDetails* const remote, int64_t moduleId, int paramId, float value) +{ +#ifdef CARDINAL_REMOTE_ENABLED +#if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + char paramBuf[512] = {}; + { + const ScopedSafeLocale cssl; + std::snprintf(paramBuf, sizeof(paramBuf), "%lld:%d:%f", (long long)moduleId, paramId, value); + } + static_cast(remote->handle)->setState("param", paramBuf); +#elif defined(HAVE_LIBLO) + const lo_address addr = lo_address_new_from_url(remote->url); + DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,); + + lo_send(addr, "/param", "hif", moduleId, paramId, value); + + lo_address_free(addr); +#endif +#endif +} + +void sendFullPatchToRemote(RemoteDetails* const remote) +{ +#ifdef CARDINAL_REMOTE_ENABLED + CardinalPluginContext* const context = static_cast(APP); + DISTRHO_SAFE_ASSERT_RETURN(context != nullptr,); + + context->engine->prepareSave(); + context->patch->saveAutosave(); + context->patch->cleanAutosave(); + + std::vector data; + using namespace rack::system; + + #if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + FILE* const f = std::fopen(join(context->patch->autosavePath, "patch.json").c_str(), "r"); + DISTRHO_SAFE_ASSERT_RETURN(f != nullptr,); + + DEFER({ + std::fclose(f); + }); + + std::fseek(f, 0, SEEK_END); + const long fileSize = std::ftell(f); + DISTRHO_SAFE_ASSERT_RETURN(fileSize > 0,); + + std::fseek(f, 0, SEEK_SET); + char* const fileContent = new char[fileSize+1]; + + DISTRHO_SAFE_ASSERT_RETURN(std::fread(fileContent, fileSize, 1, f) == 1,); + fileContent[fileSize] = '\0'; + static_cast(remote->handle)->setState("patch", fileContent); + delete[] fileContent; + #elif defined(HAVE_LIBLO) + try { + data = archiveDirectory(context->patch->autosavePath, 1); + } DISTRHO_SAFE_EXCEPTION_RETURN("sendFullPatchToRemote",); + + DISTRHO_SAFE_ASSERT_RETURN(data.size() >= 4,); + + const lo_address addr = lo_address_new_from_url(remote->url); + DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,); + + if (const lo_blob blob = lo_blob_new(data.size(), data.data())) + { + lo_send(addr, "/load", "b", blob); + lo_blob_free(blob); + } + + lo_address_free(addr); + #endif +#endif +} + +void sendScreenshotToRemote(RemoteDetails* const remote, const char* const screenshot) +{ +#if defined(HAVE_LIBLO) && DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + const lo_address addr = lo_address_new_from_url(remote->url); + DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,); + + std::vector data(d_getChunkFromBase64String(screenshot)); + + if (const lo_blob blob = lo_blob_new(data.size(), data.data())) + { + lo_send(addr, "/screenshot", "b", blob); + lo_blob_free(blob); + } + + lo_address_free(addr); +#endif +} + +} + +// ----------------------------------------------------------------------------------------------------------- diff --git a/src/CardinalRemote.hpp b/src/CardinalRemote.hpp new file mode 100644 index 00000000..991c9950 --- /dev/null +++ b/src/CardinalRemote.hpp @@ -0,0 +1,44 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the LICENSE file. + */ + +#pragma once + +#define CARDINAL_DEFAULT_REMOTE_PORT "2228" +#define CARDINAL_DEFAULT_REMOTE_URL "osc.udp://192.168.51.1:2228" + +// ----------------------------------------------------------------------------------------------------------- + +namespace remoteUtils { + +struct RemoteDetails { + void* handle; + const char* url; + bool connected; + bool autoDeploy; +}; + +RemoteDetails* getRemote(); +bool connectToRemote(const char* url); +void disconnectFromRemote(RemoteDetails* remote); +void idleRemote(RemoteDetails* remote); +void sendParamChangeToRemote(RemoteDetails* remote, int64_t moduleId, int paramId, float value); +void sendFullPatchToRemote(RemoteDetails* remote); +void sendScreenshotToRemote(RemoteDetails* remote, const char* screenshot); + +} + +// ----------------------------------------------------------------------------------------------------------- diff --git a/src/CardinalRemote/CardinalX11WindowIcon.cpp b/src/CardinalRemote/CardinalX11WindowIcon.cpp new file mode 120000 index 00000000..5d4fb7f7 --- /dev/null +++ b/src/CardinalRemote/CardinalX11WindowIcon.cpp @@ -0,0 +1 @@ +../CardinalX11WindowIcon.cpp \ No newline at end of file diff --git a/src/CardinalRemote/Makefile b/src/CardinalRemote/Makefile index 8c0666f1..8c891642 100644 --- a/src/CardinalRemote/Makefile +++ b/src/CardinalRemote/Makefile @@ -7,8 +7,11 @@ # -------------------------------------------------------------- # Carla stuff -CWD = ../../carla/source +ifneq ($(STATIC_BUILD),true) + STATIC_PLUGIN_TARGET = true + +CWD = ../../carla/source include $(CWD)/Makefile.deps.mk CARLA_BUILD_DIR = ../../carla/build @@ -23,7 +26,9 @@ CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/carla_engine_ CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/carla_plugin.a CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/native-plugins.a CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/audio_decoder.a +ifneq ($(WASM),true) CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/jackbridge.min.a +endif CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/lilv.a CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/rtmempool.a CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/sfzero.a @@ -31,10 +36,17 @@ CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/water.a CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/ysfx.a CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/zita-resampler.a +endif # STATIC_BUILD + # -------------------------------------------------------------- # Import base definitions +DISTRHO_NAMESPACE = CardinalDISTRHO +DGL_NAMESPACE = CardinalDGL +NVG_DISABLE_SKIPPING_WHITESPACE = true +NVG_FONT_TEXTURE_FLAGS = NVG_IMAGE_NEAREST USE_NANOVG_FBO = true +WASM_EXCEPTIONS = true include ../../dpf/Makefile.base.mk # -------------------------------------------------------------- @@ -57,7 +69,11 @@ endif # -------------------------------------------------------------- # Extra libraries to link against +ifeq ($(NOPLUGINS),true) +RACK_EXTRA_LIBS = ../../plugins/noplugins.a +else RACK_EXTRA_LIBS = ../../plugins/plugins.a +endif RACK_EXTRA_LIBS += ../rack.a RACK_EXTRA_LIBS += $(DEP_LIB_PATH)/libquickjs.a @@ -74,22 +90,51 @@ RACK_EXTRA_LIBS += $(DEP_LIB_PATH)/libzstd.a endif # -------------------------------------------------------------- +# surgext libraries + +ifneq ($(NOPLUGINS),true) +SURGE_DEP_PATH = $(abspath ../../deps/surge-build) +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/src/common/libsurge-common.a +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/src/common/libjuce_dsp_rack_sub.a +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/airwindows/libairwindows.a +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/eurorack/libeurorack.a +ifeq ($(DEBUG),true) +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/fmt/libfmtd.a +else +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/fmt/libfmt.a +endif +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sqlite-3.23.3/libsqlite.a +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sst/sst-plugininfra/libsst-plugininfra.a +ifneq ($(WINDOWS),true) +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sst/sst-plugininfra/libs/filesystem/libfilesystem.a +endif +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sst/sst-plugininfra/libs/strnatcmp/libstrnatcmp.a +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sst/sst-plugininfra/libs/tinyxml/libtinyxml.a +endif + +# -------------------------------------------------------------- + +# FIXME +ifeq ($(CIBUILD)$(WASM),truetrue) +ifneq ($(STATIC_BUILD),true) +STATIC_CARLA_PLUGIN_LIBS = -lsndfile -lopus -lFLAC -lvorbisenc -lvorbis -logg -lm +endif +endif EXTRA_DEPENDENCIES = $(RACK_EXTRA_LIBS) $(CARLA_EXTRA_LIBS) EXTRA_LIBS = $(RACK_EXTRA_LIBS) $(CARLA_EXTRA_LIBS) $(STATIC_CARLA_PLUGIN_LIBS) -ifeq ($(shell pkg-config --exists fftw3f && echo true),true) +ifeq ($(shell $(PKG_CONFIG) --exists fftw3f && echo true),true) EXTRA_DEPENDENCIES += ../../deps/aubio/libaubio.a EXTRA_LIBS += ../../deps/aubio/libaubio.a EXTRA_LIBS += $(shell $(PKG_CONFIG) --libs fftw3f) endif -# -------------------------------------------------------------- -# Extra flags for liblo - -BASE_FLAGS += -DHAVE_LIBLO -BASE_FLAGS += $(LIBLO_FLAGS) -LINK_FLAGS += $(LIBLO_LIBS) +ifneq ($(NOPLUGINS),true) +ifeq ($(MACOS),true) +EXTRA_LIBS += -framework Accelerate +endif +endif # -------------------------------------------------------------- # Extra flags for VCV stuff @@ -106,11 +151,11 @@ BASE_FLAGS += -DPRIVATE= BASE_FLAGS += -I.. BASE_FLAGS += -I../../dpf/dgl/src/nanovg BASE_FLAGS += -I../../include -BASE_FLAGS += -I../../include/neon-compat +BASE_FLAGS += -I../../include/simd-compat BASE_FLAGS += -I../Rack/include ifeq ($(SYSDEPS),true) BASE_FLAGS += -DCARDINAL_SYSDEPS -BASE_FLAGS += $(shell pkg-config --cflags jansson libarchive samplerate speexdsp) +BASE_FLAGS += $(shell $(PKG_CONFIG) --cflags jansson libarchive samplerate speexdsp) else BASE_FLAGS += -DZSTDLIB_VISIBILITY= BASE_FLAGS += -I../Rack/dep/include @@ -119,18 +164,31 @@ BASE_FLAGS += -I../Rack/dep/glfw/include BASE_FLAGS += -I../Rack/dep/nanosvg/src BASE_FLAGS += -I../Rack/dep/oui-blendish -ifeq ($(WASM),true) -BASE_FLAGS += -DNANOVG_GLES2=1 -BASE_FLAGS += -msse -msse2 -msse3 -msimd128 -else ifneq ($(HAIKU),true) +ifeq ($(HEADLESS),true) +BASE_FLAGS += -DHEADLESS +endif + +ifeq ($(MOD_BUILD),true) +BASE_FLAGS += -DDISTRHO_PLUGIN_USES_MODGUI=1 -DDISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE=0xffff +endif + +ifneq ($(WASM),true) +ifneq ($(HAIKU),true) BASE_FLAGS += -pthread endif +endif ifeq ($(WINDOWS),true) BASE_FLAGS += -D_USE_MATH_DEFINES BASE_FLAGS += -DWIN32_LEAN_AND_MEAN +BASE_FLAGS += -D_WIN32_WINNT=0x0600 BASE_FLAGS += -I../../include/mingw-compat -BASE_FLAGS += -I../../include/mingw-std-threads +endif + +ifeq ($(USE_GLES2),true) +BASE_FLAGS += -DNANOVG_GLES2_FORCED +else ifeq ($(USE_GLES3),true) +BASE_FLAGS += -DNANOVG_GLES3_FORCED endif BUILD_C_FLAGS += -std=gnu11 @@ -139,21 +197,64 @@ BUILD_CXX_FLAGS += -fno-finite-math-only -fno-strict-aliasing ifneq ($(MACOS),true) BUILD_CXX_FLAGS += -faligned-new -Wno-abi +ifeq ($(MOD_BUILD),true) +BUILD_CXX_FLAGS += -std=gnu++17 +endif endif # Rack code is not tested for this flag, unset it BUILD_CXX_FLAGS += -U_GLIBCXX_ASSERTIONS -Wp,-U_GLIBCXX_ASSERTIONS +# Ignore bad behaviour from Rack API +BUILD_CXX_FLAGS += -Wno-format-security + # -------------------------------------------------------------- # FIXME lots of warnings from VCV side BASE_FLAGS += -Wno-unused-parameter BASE_FLAGS += -Wno-unused-variable -# -------------------------------------------------------------- -# extra linker flags - -ifeq ($(HAIKU),true) +ifeq ($(WASM),true) +ifneq ($(STATIC_BUILD),true) +LINK_FLAGS += --use-preload-plugins +LINK_FLAGS += --preload-file=./jsfx +LINK_FLAGS += --preload-file=./lv2 +endif +LINK_FLAGS += --preload-file=../../bin/CardinalNative.lv2/resources@/resources +LINK_FLAGS += --use-preload-cache +ifneq ($(NOPLUGINS),true) +SYMLINKED_DIRS_RESOURCES = +# find . -type l | grep -v svg | grep -v ttf | grep -v art | grep -v json | grep -v png | grep -v otf | sort +SYMLINKED_DIRS_RESOURCES += BaconPlugs/res/midi/chopin +SYMLINKED_DIRS_RESOURCES += BaconPlugs/res/midi/debussy +SYMLINKED_DIRS_RESOURCES += BaconPlugs/res/midi/goldberg +SYMLINKED_DIRS_RESOURCES += cf/playeroscs +SYMLINKED_DIRS_RESOURCES += DrumKit/res/samples +SYMLINKED_DIRS_RESOURCES += Fundamental/presets +SYMLINKED_DIRS_RESOURCES += GrandeModular/presets +SYMLINKED_DIRS_RESOURCES += LyraeModules/presets +SYMLINKED_DIRS_RESOURCES += Meander/res +SYMLINKED_DIRS_RESOURCES += MindMeldModular/presets +SYMLINKED_DIRS_RESOURCES += MindMeldModular/res/ShapeMaster/CommunityPresets +SYMLINKED_DIRS_RESOURCES += MindMeldModular/res/ShapeMaster/CommunityShapes +SYMLINKED_DIRS_RESOURCES += MindMeldModular/res/ShapeMaster/MindMeldPresets +SYMLINKED_DIRS_RESOURCES += MindMeldModular/res/ShapeMaster/MindMeldShapes +SYMLINKED_DIRS_RESOURCES += Mog/res +SYMLINKED_DIRS_RESOURCES += nonlinearcircuits/res +SYMLINKED_DIRS_RESOURCES += Orbits/presets +SYMLINKED_DIRS_RESOURCES += stoermelder-packone/presets +SYMLINKED_DIRS_RESOURCES += surgext/build/surge-data/fx_presets +SYMLINKED_DIRS_RESOURCES += surgext/build/surge-data/wavetables +SYMLINKED_DIRS_RESOURCES += surgext/patches +SYMLINKED_DIRS_RESOURCES += surgext/presets +LINK_FLAGS += $(foreach d,$(SYMLINKED_DIRS_RESOURCES),--preload-file=../../bin/CardinalNative.lv2/resources/$(d)@/resources/$(d)) +endif +LINK_FLAGS += -sALLOW_MEMORY_GROWTH +LINK_FLAGS += -sINITIAL_MEMORY=64Mb +LINK_FLAGS += -sLZ4=1 +LINK_FLAGS += --shell-file=../emscripten/shell.html +LINK_FLAGS += -O3 +else ifeq ($(HAIKU),true) LINK_FLAGS += -lpthread else LINK_FLAGS += -pthread @@ -181,7 +282,7 @@ EXTRA_LIBS += -lws2_32 -lwinmm endif ifeq ($(SYSDEPS),true) -EXTRA_LIBS += $(shell pkg-config --libs jansson libarchive samplerate speexdsp) +EXTRA_LIBS += $(shell $(PKG_CONFIG) --libs jansson libarchive samplerate speexdsp) endif ifeq ($(WITH_LTO),true) @@ -193,6 +294,13 @@ LINK_FLAGS += -Wno-stringop-overflow endif endif +# -------------------------------------------------------------- +# Extra flags for liblo + +BASE_FLAGS += -DHAVE_LIBLO +BASE_FLAGS += $(LIBLO_FLAGS) +LINK_FLAGS += $(LIBLO_LIBS) + # -------------------------------------------------------------- # fallback path to resource files @@ -221,8 +329,10 @@ BUILD_CXX_FLAGS += -DCARDINAL_PLUGIN_PREFIX='"$(PREFIX)"' FILES = main.cpp FILES += RemoteUI.cpp FILES += CardinalCommon.cpp +FILES += CardinalRemote.cpp FILES += common.cpp FILES += glfw.cpp +FILES += MenuBar.cpp FILES += Window.cpp ifeq ($(WINDOWS),true) diff --git a/src/CardinalRemote/MenuBar.cpp b/src/CardinalRemote/MenuBar.cpp new file mode 120000 index 00000000..8d1a35a5 --- /dev/null +++ b/src/CardinalRemote/MenuBar.cpp @@ -0,0 +1 @@ +../override/MenuBar.cpp \ No newline at end of file diff --git a/src/CardinalRemote/RemoteUI.cpp b/src/CardinalRemote/RemoteUI.cpp index 1295f13c..41362307 100644 --- a/src/CardinalRemote/RemoteUI.cpp +++ b/src/CardinalRemote/RemoteUI.cpp @@ -17,7 +17,7 @@ #include "RemoteUI.hpp" -// #include +#include // #include #include #include @@ -26,66 +26,368 @@ #include #include +#include "AsyncDialog.hpp" + +// -------------------------------------------------------------------------------------------------------------------- + CardinalRemoteUI::CardinalRemoteUI(Window& window, const std::string& templatePath) - : NanoTopLevelWidget(window), - context(nullptr) + : NanoTopLevelWidget(window) { - // create unique temporary path for this instance - try { - char uidBuf[24]; - const std::string tmp = rack::system::getTempDirectory(); + CardinalPluginContext* const context = static_cast(rack::contextGet()); + context->nativeWindowId = window.getNativeWindowHandle(); + context->tlw = this; - for (int i=1;; ++i) - { - std::snprintf(uidBuf, sizeof(uidBuf), "CardinalRemote.%04d", i); - const std::string trypath = rack::system::join(tmp, uidBuf); - - if (! rack::system::exists(trypath)) - { - if (rack::system::createDirectories(trypath)) - autosavePath = trypath; - break; - } - } - } DISTRHO_SAFE_EXCEPTION("create unique temporary path"); + // -------------------------------------------------------------------------- + + rack::window::WindowSetPluginRemote(context->window, this); - rack::contextSet(&context); + // hide "Browse VCV Library" button + rack::widget::Widget* const browser = context->scene->browser->children.back(); + rack::widget::Widget* const headerLayout = browser->children.front(); + rack::widget::Widget* const libraryButton = headerLayout->children.back(); + libraryButton->hide(); - context.bufferSize = 512; - rack::settings::sampleRate = context.sampleRate = 48000; + // Report to user if something is wrong with the installation + std::string errorMessage; - context.engine = new rack::engine::Engine; - context.engine->setSampleRate(context.sampleRate); + if (rack::asset::systemDir.empty()) + { + errorMessage = "Failed to locate Cardinal plugin bundle.\n" + "Install Cardinal with its plugin bundle folder intact and try again."; + } + else if (! rack::system::exists(rack::asset::systemDir)) + { + errorMessage = rack::string::f("System directory \"%s\" does not exist. " + "Make sure Cardinal was downloaded and installed correctly.", + rack::asset::systemDir.c_str()); + } - context.history = new rack::history::State; - context.patch = new rack::patch::Manager; - context.patch->autosavePath = autosavePath; - context.patch->templatePath = templatePath; + if (! errorMessage.empty()) + asyncDialog::create(errorMessage.c_str()); - context.event = new rack::widget::EventState; - context.scene = new rack::app::Scene; - context.event->rootWidget = context.scene; - context.window = new rack::window::Window; + context->window->step(); - context.patch->loadTemplate(); - context.scene->rackScroll->reset(); + WindowParametersSetCallback(context->window, this); - context.nativeWindowId = getWindow().getNativeWindowHandle(); + // -------------------------------------------------------------------------- + + addIdleCallback(this); } CardinalRemoteUI::~CardinalRemoteUI() { - rack::contextSet(&context); + removeIdleCallback(this); + + // -------------------------------------------------------------------------- - context.nativeWindowId = 0; - context.patch->clear(); + CardinalPluginContext* const context = static_cast(rack::contextGet()); - if (! autosavePath.empty()) - rack::system::removeRecursively(autosavePath); + context->nativeWindowId = 0; + + rack::window::WindowSetPluginRemote(context->window, nullptr); } void CardinalRemoteUI::onNanoDisplay() { - rack::contextSet(&context); - context.window->step(); + CardinalPluginContext* const context = static_cast(rack::contextGet()); + const ScopedContext sc(context); + context->window->step(); +} + +void CardinalRemoteUI::idleCallback() +{ + /* + if (filebrowserhandle != nullptr && fileBrowserIdle(filebrowserhandle)) + { + { + const char* const path = fileBrowserGetPath(filebrowserhandle); + + const ScopedContext sc(this); + filebrowseraction(path != nullptr ? strdup(path) : nullptr); + } + + fileBrowserClose(filebrowserhandle); + filebrowseraction = nullptr; + filebrowserhandle = nullptr; + } + */ + + if (windowParameters.rateLimit != 0 && ++rateLimitStep % (windowParameters.rateLimit * 2)) + return; + + rateLimitStep = 0; + repaint(); } + +void CardinalRemoteUI::WindowParametersChanged(const WindowParameterList param, float value) +{ + float mult = 1.0f; + + switch (param) + { + case kWindowParameterShowTooltips: + windowParameters.tooltips = value > 0.5f; + break; + case kWindowParameterCableOpacity: + mult = 100.0f; + windowParameters.cableOpacity = value; + break; + case kWindowParameterCableTension: + mult = 100.0f; + windowParameters.cableTension = value; + break; + case kWindowParameterRackBrightness: + mult = 100.0f; + windowParameters.rackBrightness = value; + break; + case kWindowParameterHaloBrightness: + mult = 100.0f; + windowParameters.haloBrightness = value; + break; + case kWindowParameterKnobMode: + switch (static_cast(value + 0.5f)) + { + case rack::settings::KNOB_MODE_LINEAR: + value = 0; + windowParameters.knobMode = rack::settings::KNOB_MODE_LINEAR; + break; + case rack::settings::KNOB_MODE_ROTARY_ABSOLUTE: + value = 1; + windowParameters.knobMode = rack::settings::KNOB_MODE_ROTARY_ABSOLUTE; + break; + case rack::settings::KNOB_MODE_ROTARY_RELATIVE: + value = 2; + windowParameters.knobMode = rack::settings::KNOB_MODE_ROTARY_RELATIVE; + break; + } + break; + case kWindowParameterWheelKnobControl: + windowParameters.knobScroll = value > 0.5f; + break; + case kWindowParameterWheelSensitivity: + mult = 1000.0f; + windowParameters.knobScrollSensitivity = value; + break; + case kWindowParameterLockModulePositions: + windowParameters.lockModules = value > 0.5f; + break; + case kWindowParameterUpdateRateLimit: + windowParameters.rateLimit = static_cast(value + 0.5f); + rateLimitStep = 0; + break; + case kWindowParameterBrowserSort: + windowParameters.browserSort = static_cast(value + 0.5f); + break; + case kWindowParameterBrowserZoom: + windowParameters.browserZoom = value; + value = std::pow(2.f, value) * 100.0f; + break; + case kWindowParameterInvertZoom: + windowParameters.invertZoom = value > 0.5f; + break; + case kWindowParameterSqueezeModulePositions: + windowParameters.squeezeModules = value > 0.5f; + break; + default: + return; + } + + // setParameterValue(kModuleParameters + param + 1, value * mult); +} + +// -------------------------------------------------------------------------------------------------------------------- + +static int glfwMods(const uint mod) noexcept +{ + int mods = 0; + + if (mod & kModifierControl) + mods |= GLFW_MOD_CONTROL; + if (mod & kModifierShift) + mods |= GLFW_MOD_SHIFT; + if (mod & kModifierAlt) + mods |= GLFW_MOD_ALT; + if (mod & kModifierSuper) + mods |= GLFW_MOD_SUPER; + + /* + if (glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS) + mods |= GLFW_MOD_SHIFT; + if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) + mods |= GLFW_MOD_CONTROL; + if (glfwGetKey(win, GLFW_KEY_LEFT_ALT) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS) + mods |= GLFW_MOD_ALT; + if (glfwGetKey(win, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS) + mods |= GLFW_MOD_SUPER; + */ + + return mods; +} + +bool CardinalRemoteUI::onMouse(const MouseEvent& ev) +{ + if (ev.press) + getWindow().focus(); + + const int action = ev.press ? GLFW_PRESS : GLFW_RELEASE; + int mods = glfwMods(ev.mod); + + int button; + + switch (ev.button) + { + case 1: button = GLFW_MOUSE_BUTTON_LEFT; break; + case 2: button = GLFW_MOUSE_BUTTON_RIGHT; break; + case 3: button = GLFW_MOUSE_BUTTON_MIDDLE; break; + default: + button = ev.button; + break; + } + + #ifdef DISTRHO_OS_MAC + // Remap Ctrl-left click to right click on macOS + if (button == GLFW_MOUSE_BUTTON_LEFT && (mods & RACK_MOD_MASK) == GLFW_MOD_CONTROL) { + button = GLFW_MOUSE_BUTTON_RIGHT; + mods &= ~GLFW_MOD_CONTROL; + } + // Remap Ctrl-shift-left click to middle click on macOS + if (button == GLFW_MOUSE_BUTTON_LEFT && (mods & RACK_MOD_MASK) == (GLFW_MOD_CONTROL | GLFW_MOD_SHIFT)) { + button = GLFW_MOUSE_BUTTON_MIDDLE; + mods &= ~(GLFW_MOD_CONTROL | GLFW_MOD_SHIFT); + } + #endif + + CardinalPluginContext* context = static_cast(rack::contextGet()); + const ScopedContext sc(context, mods); + return context->event->handleButton(lastMousePos, button, action, mods); +} + +bool CardinalRemoteUI::onMotion(const MotionEvent& ev) +{ + const rack::math::Vec mousePos = rack::math::Vec(ev.pos.getX(), ev.pos.getY()).div(getScaleFactor()).round(); + const rack::math::Vec mouseDelta = mousePos.minus(lastMousePos); + + lastMousePos = mousePos; + + CardinalPluginContext* context = static_cast(rack::contextGet()); + const ScopedContext sc(context); + return context->event->handleHover(mousePos, mouseDelta); +} + +bool CardinalRemoteUI::onScroll(const ScrollEvent& ev) +{ + rack::math::Vec scrollDelta = rack::math::Vec(ev.delta.getX(), ev.delta.getY()); + #ifndef DISTRHO_OS_MAC + scrollDelta = scrollDelta.mult(50.0); + #endif + + const int mods = glfwMods(ev.mod); + + CardinalPluginContext* context = static_cast(rack::contextGet()); + const ScopedContext sc(context, mods); + return context->event->handleScroll(lastMousePos, scrollDelta); +} + +bool CardinalRemoteUI::onCharacterInput(const CharacterInputEvent& ev) +{ + if (ev.character < ' ' || ev.character >= kKeyDelete) + return false; + + const int mods = glfwMods(ev.mod); + + CardinalPluginContext* context = static_cast(rack::contextGet()); + const ScopedContext sc(context, mods); + return context->event->handleText(lastMousePos, ev.character); +} + +bool CardinalRemoteUI::onKeyboard(const KeyboardEvent& ev) +{ + const int action = ev.press ? GLFW_PRESS : GLFW_RELEASE; + const int mods = glfwMods(ev.mod); + + /* These are unsupported in pugl right now + #define GLFW_KEY_KP_0 320 + #define GLFW_KEY_KP_1 321 + #define GLFW_KEY_KP_2 322 + #define GLFW_KEY_KP_3 323 + #define GLFW_KEY_KP_4 324 + #define GLFW_KEY_KP_5 325 + #define GLFW_KEY_KP_6 326 + #define GLFW_KEY_KP_7 327 + #define GLFW_KEY_KP_8 328 + #define GLFW_KEY_KP_9 329 + #define GLFW_KEY_KP_DECIMAL 330 + #define GLFW_KEY_KP_DIVIDE 331 + #define GLFW_KEY_KP_MULTIPLY 332 + #define GLFW_KEY_KP_SUBTRACT 333 + #define GLFW_KEY_KP_ADD 334 + #define GLFW_KEY_KP_ENTER 335 + #define GLFW_KEY_KP_EQUAL 336 + */ + + int key; + switch (ev.key) + { + case '\r': key = GLFW_KEY_ENTER; break; + case '\t': key = GLFW_KEY_TAB; break; + case kKeyBackspace: key = GLFW_KEY_BACKSPACE; break; + case kKeyEscape: key = GLFW_KEY_ESCAPE; break; + case kKeyDelete: key = GLFW_KEY_DELETE; break; + case kKeyF1: key = GLFW_KEY_F1; break; + case kKeyF2: key = GLFW_KEY_F2; break; + case kKeyF3: key = GLFW_KEY_F3; break; + case kKeyF4: key = GLFW_KEY_F4; break; + case kKeyF5: key = GLFW_KEY_F5; break; + case kKeyF6: key = GLFW_KEY_F6; break; + case kKeyF7: key = GLFW_KEY_F7; break; + case kKeyF8: key = GLFW_KEY_F8; break; + case kKeyF9: key = GLFW_KEY_F9; break; + case kKeyF10: key = GLFW_KEY_F10; break; + case kKeyF11: key = GLFW_KEY_F11; break; + case kKeyF12: key = GLFW_KEY_F12; break; + case kKeyLeft: key = GLFW_KEY_LEFT; break; + case kKeyUp: key = GLFW_KEY_UP; break; + case kKeyRight: key = GLFW_KEY_RIGHT; break; + case kKeyDown: key = GLFW_KEY_DOWN; break; + case kKeyPageUp: key = GLFW_KEY_PAGE_UP; break; + case kKeyPageDown: key = GLFW_KEY_PAGE_DOWN; break; + case kKeyHome: key = GLFW_KEY_HOME; break; + case kKeyEnd: key = GLFW_KEY_END; break; + case kKeyInsert: key = GLFW_KEY_INSERT; break; + case kKeyShiftL: key = GLFW_KEY_LEFT_SHIFT; break; + case kKeyShiftR: key = GLFW_KEY_RIGHT_SHIFT; break; + case kKeyControlL: key = GLFW_KEY_LEFT_CONTROL; break; + case kKeyControlR: key = GLFW_KEY_RIGHT_CONTROL; break; + case kKeyAltL: key = GLFW_KEY_LEFT_ALT; break; + case kKeyAltR: key = GLFW_KEY_RIGHT_ALT; break; + case kKeySuperL: key = GLFW_KEY_LEFT_SUPER; break; + case kKeySuperR: key = GLFW_KEY_RIGHT_SUPER; break; + case kKeyMenu: key = GLFW_KEY_MENU; break; + case kKeyCapsLock: key = GLFW_KEY_CAPS_LOCK; break; + case kKeyScrollLock: key = GLFW_KEY_SCROLL_LOCK; break; + case kKeyNumLock: key = GLFW_KEY_NUM_LOCK; break; + case kKeyPrintScreen: key = GLFW_KEY_PRINT_SCREEN; break; + case kKeyPause: key = GLFW_KEY_PAUSE; break; + default: + // glfw expects uppercase + if (ev.key >= 'a' && ev.key <= 'z') + key = ev.key - ('a' - 'A'); + else + key = ev.key; + break; + } + + CardinalPluginContext* context = static_cast(rack::contextGet()); + const ScopedContext sc(context, mods); + return context->event->handleKey(lastMousePos, key, ev.keycode, action, mods); +} + +void CardinalRemoteUI::onResize(const ResizeEvent& ev) +{ + NanoTopLevelWidget::onResize(ev); + + CardinalPluginContext* context = static_cast(rack::contextGet()); + WindowSetInternalSize(context->window, rack::math::Vec(ev.size.getWidth(), ev.size.getHeight())); +} + +// -------------------------------------------------------------------------------------------------------------------- diff --git a/src/CardinalRemote/RemoteUI.hpp b/src/CardinalRemote/RemoteUI.hpp index 1ed46965..15b1c902 100644 --- a/src/CardinalRemote/RemoteUI.hpp +++ b/src/CardinalRemote/RemoteUI.hpp @@ -19,11 +19,51 @@ #include "NanoVG.hpp" #include "PluginContext.hpp" +#include "WindowParameters.hpp" -class CardinalRemoteUI : public NanoTopLevelWidget +#include + +// -------------------------------------------------------------------------------------------------------------------- + +namespace rack { +namespace window { +void WindowSetPluginRemote(Window* window, NanoTopLevelWidget* tlw); +void WindowSetMods(Window* window, int mods); +void WindowSetInternalSize(rack::window::Window* window, math::Vec size); +} +} + +// -------------------------------------------------------------------------------------------------------------------- + +class CardinalRemoteUI : public NanoTopLevelWidget, + public IdleCallback, + public WindowParametersCallback { - CardinalPluginContext context; - std::string autosavePath; + rack::math::Vec lastMousePos; + WindowParameters windowParameters; + int rateLimitStep = 0; + + struct ScopedContext { + CardinalPluginContext* const context; + + ScopedContext(CardinalPluginContext* const c) + : context(c) + { + WindowParametersRestore(context->window); + } + + ScopedContext(CardinalPluginContext* const c, const int mods) + : context(c) + { + rack::window::WindowSetMods(context->window, mods); + WindowParametersRestore(context->window); + } + + ~ScopedContext() + { + WindowParametersSave(context->window); + } + }; public: explicit CardinalRemoteUI(Window& window, const std::string& templatePath); @@ -31,6 +71,16 @@ class CardinalRemoteUI : public NanoTopLevelWidget protected: void onNanoDisplay() override; + void idleCallback() override; + void WindowParametersChanged(const WindowParameterList param, float value) override; + bool onMouse(const MouseEvent& ev) override; + bool onMotion(const MotionEvent& ev) override; + bool onScroll(const ScrollEvent& ev) override; + bool onCharacterInput(const CharacterInputEvent& ev) override; + bool onKeyboard(const KeyboardEvent& ev) override; + void onResize(const ResizeEvent& ev) override; DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CardinalRemoteUI) }; + +// -------------------------------------------------------------------------------------------------------------------- diff --git a/src/CardinalRemote/main.cpp b/src/CardinalRemote/main.cpp index 4ac0be22..381b086d 100644 --- a/src/CardinalRemote/main.cpp +++ b/src/CardinalRemote/main.cpp @@ -20,29 +20,80 @@ #include "RemoteUI.hpp" #include +#include #include #include #include #include +#include +#include #include +#include "PluginContext.hpp" +#include "extra/ScopedValueSetter.hpp" + +#define CARDINAL_TEMPLATE_NAME "init/main.vcv" + +extern const std::string CARDINAL_VERSION; + namespace rack { +namespace asset { +std::string patchesPath(); +void destroy(); +} +namespace engine { +void Engine_setAboutToClose(Engine*); +} namespace plugin { - void initStaticPlugins(); - void destroyStaticPlugins(); +void initStaticPlugins(); +void destroyStaticPlugins(); } } +START_NAMESPACE_DISTRHO + +bool isUsingNativeAudio() noexcept { return false; } +bool supportsAudioInput() { return false; } +bool supportsBufferSizeChanges() { return false; } +bool supportsMIDI() { return false; } +bool isAudioInputEnabled() { return false; } +bool isMIDIEnabled() { return false; } +uint getBufferSize() { return 0; } +bool requestAudioInput() { return false; } +bool requestBufferSizeChange(uint) { return false; } +bool requestMIDI() { return false; } +const char* getPluginFormatName() noexcept { return "Remote"; } + +FileBrowserHandle fileBrowserCreate(bool, ulong, double, const FileBrowserOptions&) { return nullptr; } + +uint32_t Plugin::getBufferSize() const noexcept { return 128; } +double Plugin::getSampleRate() const noexcept { return 48000; } +bool Plugin::writeMidiEvent(const MidiEvent&) noexcept { return false; } + +void UI::editParameter(uint, bool) {} +void UI::setParameterValue(uint, float) {} +void UI::setState(const char*, const char*) {} +bool UI::openFileBrowser(const FileBrowserOptions&) { return false; } + +END_NAMESPACE_DISTRHO + int main(const int argc, const char* argv[]) { using namespace rack; + std::string templatePath, factoryTemplatePath; + + // -------------------------------------------------------------------------- + + #ifdef DISTRHO_OS_WASM + settings::allowCursorLock = true; + #else settings::allowCursorLock = false; + #endif settings::autoCheckUpdates = false; settings::autosaveInterval = 0; settings::devMode = true; - settings::discordUpdateActivity = false; settings::isPlugin = true; settings::skipLoadOnLaunch = true; settings::showTipsOnLaunch = false; @@ -73,20 +124,18 @@ int main(const int argc, const char* argv[]) random::init(); ui::init(); - std::string templatePath; #ifdef CARDINAL_PLUGIN_SOURCE_DIR // Make system dir point to source code location as fallback asset::systemDir = CARDINAL_PLUGIN_SOURCE_DIR DISTRHO_OS_SEP_STR "Rack"; + asset::bundlePath.clear(); - if (system::exists(system::join(asset::systemDir, "res"))) - { - templatePath = CARDINAL_PLUGIN_SOURCE_DIR DISTRHO_OS_SEP_STR "template.vcv"; - } // If source code dir does not exist use install target prefix as system dir - else + if (!system::exists(system::join(asset::systemDir, "res"))) #endif { - #if defined(ARCH_MAC) + #if defined(DISTRHO_OS_WASM) + asset::systemDir = "/resources"; + #elif defined(ARCH_MAC) asset::systemDir = "/Library/Application Support/Cardinal"; #elif defined(ARCH_WIN) const std::string commonprogfiles = getSpecialPath(kSpecialPathCommonProgramFiles); @@ -96,33 +145,37 @@ int main(const int argc, const char* argv[]) asset::systemDir = CARDINAL_PLUGIN_PREFIX "/share/cardinal"; #endif - if (! asset::systemDir.empty()) - { - asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); - templatePath = system::join(asset::systemDir, "template.vcv"); - } + asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); } - + asset::userDir = asset::systemDir; + const std::string patchesPath = asset::patchesPath(); + #ifdef DISTRHO_OS_WASM + templatePath = system::join(patchesPath, CARDINAL_WASM_WELCOME_TEMPLATE_FILENAME); + #else + templatePath = system::join(patchesPath, CARDINAL_TEMPLATE_NAME); + #endif + factoryTemplatePath = system::join(patchesPath, CARDINAL_TEMPLATE_NAME); + // Log environment - INFO("%s %s v%s", APP_NAME.c_str(), APP_EDITION.c_str(), APP_VERSION.c_str()); + INFO("%s %s %s, compatible with Rack version %s", APP_NAME.c_str(), APP_EDITION.c_str(), CARDINAL_VERSION.c_str(), APP_VERSION.c_str()); INFO("%s", system::getOperatingSystemInfo().c_str()); -// INFO("Binary filename: %s", getBinaryFilename()); INFO("System directory: %s", asset::systemDir.c_str()); INFO("User directory: %s", asset::userDir.c_str()); INFO("Template patch: %s", templatePath.c_str()); + INFO("System template patch: %s", factoryTemplatePath.c_str()); // Report to user if something is wrong with the installation if (asset::systemDir.empty()) { d_stderr2("Failed to locate Cardinal plugin bundle.\n" - "Install Cardinal with its bundle folder intact and try again."); + "Install Cardinal with its bundle folder intact and try again."); } else if (! system::exists(asset::systemDir)) { d_stderr2("System directory \"%s\" does not exist.\n" - "Make sure Cardinal was downloaded and installed correctly.", asset::systemDir.c_str()); + "Make sure Cardinal was downloaded and installed correctly.", asset::systemDir.c_str()); } INFO("Initializing plugins"); @@ -131,17 +184,104 @@ int main(const int argc, const char* argv[]) INFO("Initializing plugin browser DB"); app::browserInit(); + // -------------------------------------------------------------------------- + + // create unique temporary path for this instance + std::string fAutosavePath; + + try { + char uidBuf[24]; + const std::string tmp = rack::system::getTempDirectory(); + + for (int i=1;; ++i) + { + std::snprintf(uidBuf, sizeof(uidBuf), "Cardinal.%04d", i); + const std::string trypath = rack::system::join(tmp, uidBuf); + + if (! rack::system::exists(trypath)) + { + if (rack::system::createDirectories(trypath)) + fAutosavePath = trypath; + break; + } + } + } DISTRHO_SAFE_EXCEPTION("create unique temporary path"); + + CardinalPluginContext* const context = new CardinalPluginContext(nullptr); + rack::contextSet(context); + + const float sampleRate = 48000; + rack::settings::sampleRate = sampleRate; + + context->bufferSize = 512; + context->sampleRate = sampleRate; + + context->engine = new rack::engine::Engine; + context->engine->setSampleRate(sampleRate); + + context->history = new rack::history::State; + context->patch = new rack::patch::Manager; + context->patch->autosavePath = fAutosavePath; + context->patch->templatePath = templatePath; + context->patch->factoryTemplatePath = factoryTemplatePath; + + context->event = new rack::widget::EventState; + context->scene = new rack::app::Scene; + context->event->rootWidget = context->scene; + + context->window = new rack::window::Window; + + context->patch->loadTemplate(); + context->scene->rackScroll->reset(); + // swap to factory template after first load + context->patch->templatePath = context->patch->factoryTemplatePath; + + // -------------------------------------------------------------------------- + Application app; - Window win(app); - win.setTitle("CardinalRemote"); + Window window(app); + window.setIgnoringKeyRepeat(true); + window.setResizable(true); + window.setTitle("CardinalRemote"); + + // -------------------------------------------------------------------------- + + const double scaleFactor = window.getScaleFactor(); + + window.setGeometryConstraints(648 * scaleFactor, 538 * scaleFactor); + + if (scaleFactor != 1.0) + window.setSize(DISTRHO_UI_DEFAULT_WIDTH * scaleFactor, + DISTRHO_UI_DEFAULT_HEIGHT * scaleFactor); + + // -------------------------------------------------------------------------- + ScopedPointer remoteUI; - + { - remoteUI = new CardinalRemoteUI(win, templatePath); + const Window::ScopedGraphicsContext sgc(window); + remoteUI = new CardinalRemoteUI(window, templatePath); } + window.show(); app.exec(); + // -------------------------------------------------------------------------- + + { + context->patch->clear(); + + // do a little dance to prevent context scene deletion from saving to temp dir + const ScopedValueSetter svs(rack::settings::headless, true); + Engine_setAboutToClose(context->engine); + delete context; + } + + if (! fAutosavePath.empty()) + rack::system::removeRecursively(fAutosavePath); + + // -------------------------------------------------------------------------- + INFO("Clearing asset paths"); asset::bundlePath.clear(); asset::systemDir.clear(); @@ -150,11 +290,16 @@ int main(const int argc, const char* argv[]) INFO("Destroying plugins"); plugin::destroyStaticPlugins(); + INFO("Destroying colourized assets"); + asset::destroy(); + INFO("Destroying settings"); settings::destroy(); INFO("Destroying logger"); logger::destroy(); + // -------------------------------------------------------------------------- + return 0; } diff --git a/src/CardinalSynth/CardinalRemote.cpp b/src/CardinalSynth/CardinalRemote.cpp new file mode 120000 index 00000000..23838232 --- /dev/null +++ b/src/CardinalSynth/CardinalRemote.cpp @@ -0,0 +1 @@ +../CardinalRemote.cpp \ No newline at end of file diff --git a/src/CardinalSynth/CardinalX11WindowIcon.cpp b/src/CardinalSynth/CardinalX11WindowIcon.cpp new file mode 120000 index 00000000..5d4fb7f7 --- /dev/null +++ b/src/CardinalSynth/CardinalX11WindowIcon.cpp @@ -0,0 +1 @@ +../CardinalX11WindowIcon.cpp \ No newline at end of file diff --git a/src/CardinalSynth/DistrhoPluginInfo.h b/src/CardinalSynth/DistrhoPluginInfo.h index 1d1ac1fc..5147667c 100644 --- a/src/CardinalSynth/DistrhoPluginInfo.h +++ b/src/CardinalSynth/DistrhoPluginInfo.h @@ -26,13 +26,15 @@ #define CARDINAL_NUM_AUDIO_INPUTS 0 #define CARDINAL_NUM_AUDIO_OUTPUTS 2 -#define DISTRHO_PLUGIN_BRAND "DISTRHO" -#define DISTRHO_PLUGIN_NAME "Cardinal Synth" -#define DISTRHO_PLUGIN_LABEL "CardinalSynth" -#define DISTRHO_PLUGIN_URI "https://distrho.kx.studio/plugins/cardinal#synth" +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_NAME "Cardinal Synth" +#define DISTRHO_PLUGIN_LABEL "CardinalSynth" +#define DISTRHO_PLUGIN_URI "https://distrho.kx.studio/plugins/cardinal#synth" +#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.cardinal#synth" #ifdef HEADLESS #define DISTRHO_PLUGIN_HAS_UI 0 +#define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 0 #else #define DISTRHO_PLUGIN_HAS_UI 1 #define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 1 diff --git a/src/CardinalSynth/MenuBar.cpp b/src/CardinalSynth/MenuBar.cpp new file mode 120000 index 00000000..8d1a35a5 --- /dev/null +++ b/src/CardinalSynth/MenuBar.cpp @@ -0,0 +1 @@ +../override/MenuBar.cpp \ No newline at end of file diff --git a/src/CardinalUI.cpp b/src/CardinalUI.cpp index 5b1496e2..27373cd4 100644 --- a/src/CardinalUI.cpp +++ b/src/CardinalUI.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -39,7 +39,6 @@ # include # include # include -# include "CardinalCommon.hpp" # include #endif @@ -47,17 +46,33 @@ # undef DEBUG #endif -#include +#include "Application.hpp" #include "AsyncDialog.hpp" +#include "CardinalCommon.hpp" #include "PluginContext.hpp" #include "WindowParameters.hpp" +#include "extra/Base64.hpp" + +#ifndef DISTRHO_OS_WASM +# include "extra/SharedResourcePointer.hpp" +#endif + +#ifndef HEADLESS +# include "extra/ScopedValueSetter.hpp" +#endif namespace rack { -namespace app { - widget::Widget* createMenuBar(bool isStandalone); +#ifdef DISTRHO_OS_WASM +namespace asset { +std::string patchesPath(); +} +#endif +namespace engine { +void Engine_setAboutToClose(Engine*); +void Engine_setRemoteDetails(Engine*, remoteUtils::RemoteDetails*); } namespace window { - void WindowSetPluginUI(Window* window, DISTRHO_NAMESPACE::UI* ui); + void WindowSetPluginUI(Window* window, CardinalBaseUI* ui); void WindowSetMods(Window* window, int mods); void WindowSetInternalSize(rack::window::Window* window, math::Vec size); } @@ -65,43 +80,19 @@ namespace window { START_NAMESPACE_DISTRHO -// ----------------------------------------------------------------------------------------------------------- - -bool CardinalPluginContext::addIdleCallback(IdleCallback* const cb) const -{ - if (ui == nullptr) - return false; +// -------------------------------------------------------------------------------------------------------------------- - ui->addIdleCallback(cb); - return true; -} - -void CardinalPluginContext::removeIdleCallback(IdleCallback* const cb) const -{ - if (ui == nullptr) - return; - - ui->removeIdleCallback(cb); -} - -void handleHostParameterDrag(const CardinalPluginContext* pcontext, uint index, bool started) -{ - DISTRHO_SAFE_ASSERT_RETURN(pcontext->ui != nullptr,); - - if (started) - { - pcontext->ui->editParameter(index, true); - pcontext->ui->setParameterValue(index, pcontext->parameters[index]); - } - else - { - pcontext->ui->editParameter(index, false); - } -} +#if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS +uint32_t Plugin::getBufferSize() const noexcept { return 0; } +double Plugin::getSampleRate() const noexcept { return 0.0; } +const char* Plugin::getBundlePath() const noexcept { return nullptr; } +bool Plugin::isSelfTestInstance() const noexcept { return false; } +bool Plugin::writeMidiEvent(const MidiEvent&) noexcept { return false; } +#endif -// ----------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- -#ifdef DISTRHO_OS_WASM +#if defined(DISTRHO_OS_WASM) && ! CARDINAL_VARIANT_MINI struct WasmWelcomeDialog : rack::widget::OpaqueWidget { static const constexpr float margin = 10; @@ -260,7 +251,7 @@ static void downloadRemotePatchFailed(const char* const filename) } using namespace rack; - context->patch->templatePath = system::join(asset::systemDir, "init/wasm.vcv"); // FIXME + context->patch->templatePath = rack::system::join(asset::patchesPath(), "templates/main.vcv"); context->patch->loadTemplate(); context->scene->rackScroll->reset(); } @@ -291,8 +282,8 @@ static void downloadRemotePatchSucceeded(const char* const filename) return; } + context->patch->path.clear(); context->scene->rackScroll->reset(); - context->patch->path = ""; context->history->setSaved(); } #endif @@ -302,10 +293,19 @@ static void downloadRemotePatchSucceeded(const char* const filename) class CardinalUI : public CardinalBaseUI, public WindowParametersCallback { + #if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + #ifdef DISTRHO_OS_WASM + ScopedPointer fInitializer; + #else + SharedResourcePointer fInitializer; + #endif + std::string fAutosavePath; + #endif + rack::math::Vec lastMousePos; WindowParameters windowParameters; int rateLimitStep = 0; - #ifdef DISTRHO_OS_WASM + #if defined(DISTRHO_OS_WASM) && ! CARDINAL_VARIANT_MINI int8_t counterForFirstIdlePoint = 0; #endif #ifdef DPF_RUNTIME_TESTING @@ -339,8 +339,78 @@ class CardinalUI : public CardinalBaseUI, public: CardinalUI() - : CardinalBaseUI(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT) + : CardinalBaseUI(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT), + #if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + #ifdef DISTRHO_OS_WASM + fInitializer(new Initializer(static_cast(nullptr), this)), + #else + fInitializer(static_cast(nullptr), this), + #endif + #endif + lastMousePos() { + rack::contextSet(context); + + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + // create unique temporary path for this instance + try { + char uidBuf[24]; + const std::string tmp = rack::system::getTempDirectory(); + + for (int i=1;; ++i) + { + std::snprintf(uidBuf, sizeof(uidBuf), "Cardinal.%04d", i); + const std::string trypath = rack::system::join(tmp, uidBuf); + + if (! rack::system::exists(trypath)) + { + if (rack::system::createDirectories(trypath)) + fAutosavePath = trypath; + break; + } + } + } DISTRHO_SAFE_EXCEPTION("create unique temporary path"); + + const float sampleRate = 60; // fake audio running at 60 fps + rack::settings::sampleRate = sampleRate; + + context->dataIns = new const float*[DISTRHO_PLUGIN_NUM_INPUTS]; + context->dataOuts = new float*[DISTRHO_PLUGIN_NUM_OUTPUTS]; + + for (uint32_t i=0; i(&context->dataIns[i]); + *bufferptr = new float[1]; + (*bufferptr)[0] = 0.f; + } + for (uint32_t i=0; idataOuts[i] = new float[1]; + + context->bufferSize = 1; + context->sampleRate = sampleRate; + + context->engine = new rack::engine::Engine; + context->engine->setSampleRate(sampleRate); + + context->history = new rack::history::State; + context->patch = new rack::patch::Manager; + context->patch->autosavePath = fAutosavePath; + context->patch->templatePath = context->patch->factoryTemplatePath = fInitializer->factoryTemplatePath; + + context->event = new rack::widget::EventState; + context->scene = new rack::app::Scene; + context->event->rootWidget = context->scene; + + context->window = new rack::window::Window; + + context->patch->loadTemplate(); + context->scene->rackScroll->reset(); + + DISTRHO_SAFE_ASSERT(remoteUtils::connectToRemote(CARDINAL_DEFAULT_REMOTE_URL)); + + Engine_setRemoteDetails(context->engine, remoteDetails); + #endif + Window& window(getWindow()); window.setIgnoringKeyRepeat(true); @@ -350,22 +420,23 @@ class CardinalUI : public CardinalBaseUI, setGeometryConstraints(648 * scaleFactor, 538 * scaleFactor); - if (scaleFactor != 1.0) + if (rack::isStandalone() && rack::system::exists(rack::settings::settingsPath)) + { + const double width = std::max(648.f, rack::settings::windowSize.x) * scaleFactor; + const double height = std::max(538.f, rack::settings::windowSize.y) * scaleFactor; + setSize(width, height); + } + else if (scaleFactor != 1.0) + { setSize(DISTRHO_UI_DEFAULT_WIDTH * scaleFactor, DISTRHO_UI_DEFAULT_HEIGHT * scaleFactor); + } - rack::contextSet(context); + #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + const DGL_NAMESPACE::Window::ScopedGraphicsContext sgc(window); + #endif rack::window::WindowSetPluginUI(context->window, this); - if (rack::widget::Widget* const menuBar = context->scene->menuBar) - { - context->scene->removeChild(menuBar); - delete menuBar; - } - - context->scene->menuBar = rack::app::createMenuBar(getApp().isStandalone()); - context->scene->addChildBelow(context->scene->menuBar, context->scene->rackScroll); - // hide "Browse VCV Library" button rack::widget::Widget* const browser = context->scene->browser->children.back(); rack::widget::Widget* const headerLayout = browser->children.front(); @@ -398,7 +469,7 @@ class CardinalUI : public CardinalBaseUI, } } - #ifdef DISTRHO_OS_WASM + #if defined(DISTRHO_OS_WASM) && ! CARDINAL_VARIANT_MINI if (rack::patchStorageSlug != nullptr) { psDialog = new WasmRemotePatchLoadingDialog(true); @@ -431,16 +502,33 @@ class CardinalUI : public CardinalBaseUI, context->nativeWindowId = 0; - if (rack::widget::Widget* const menuBar = context->scene->menuBar) + rack::window::WindowSetPluginUI(context->window, nullptr); + + context->tlw = nullptr; + context->ui = nullptr; + + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS { - context->scene->removeChild(menuBar); - delete menuBar; + const ScopedContext sc(this); + context->patch->clear(); + + // do a little dance to prevent context scene deletion from saving to temp dir + const ScopedValueSetter svs(rack::settings::headless, true); + Engine_setAboutToClose(context->engine); + delete context; } - context->scene->menuBar = rack::app::createMenuBar(); - context->scene->addChildBelow(context->scene->menuBar, context->scene->rackScroll); + if (! fAutosavePath.empty()) + rack::system::removeRecursively(fAutosavePath); + #endif - rack::window::WindowSetPluginUI(context->window, nullptr); + #if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + if (fInitializer->shouldSaveSettings) + { + INFO("Save settings"); + rack::settings::save(); + } + #endif rack::contextSet(nullptr); } @@ -515,7 +603,7 @@ class CardinalUI : public CardinalBaseUI, } #endif - #ifdef DISTRHO_OS_WASM + #if defined(DISTRHO_OS_WASM) && ! CARDINAL_VARIANT_MINI if (counterForFirstIdlePoint >= 0 && ++counterForFirstIdlePoint == 30) { counterForFirstIdlePoint = -1; @@ -557,6 +645,16 @@ class CardinalUI : public CardinalBaseUI, filebrowserhandle = nullptr; } + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + { + const ScopedContext sc(this); + for (uint32_t i=0; idataOuts[i][0] = 0.f; + ++context->processCounter; + context->engine->stepBlock(1); + } + #endif + if (windowParameters.rateLimit != 0 && ++rateLimitStep % (windowParameters.rateLimit * 2)) return; @@ -637,7 +735,7 @@ class CardinalUI : public CardinalBaseUI, return; } - setParameterValue(kModuleParameters + param + 1, value * mult); + setParameterValue(kCardinalParameterStartWindow + param, value * mult); } protected: @@ -650,108 +748,209 @@ class CardinalUI : public CardinalBaseUI, */ void parameterChanged(const uint32_t index, const float value) override { - // host mapped parameters + bypass - if (index <= kModuleParameters) + // host mapped parameters + if (index < kCardinalParameterCountAtModules) + { + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + context->parameters[index] = value; + #endif return; + } - switch (index - kModuleParameters - 1) + // bypass + if (index == kCardinalParameterBypass) { - case kWindowParameterShowTooltips: - windowParameters.tooltips = value > 0.5f; - break; - case kWindowParameterCableOpacity: - windowParameters.cableOpacity = value / 100.0f; - break; - case kWindowParameterCableTension: - windowParameters.cableTension = value / 100.0f; - break; - case kWindowParameterRackBrightness: - windowParameters.rackBrightness = value / 100.0f; - break; - case kWindowParameterHaloBrightness: - windowParameters.haloBrightness = value / 100.0f; - break; - case kWindowParameterKnobMode: - switch (static_cast(value + 0.5f)) + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + context->bypassed = value > 0.5f; + #endif + return; + } + + if (index < kCardinalParameterCountAtWindow) + { + switch (index - kCardinalParameterStartWindow) { - case 0: - windowParameters.knobMode = rack::settings::KNOB_MODE_LINEAR; + case kWindowParameterShowTooltips: + windowParameters.tooltips = value > 0.5f; break; - case 1: - windowParameters.knobMode = rack::settings::KNOB_MODE_ROTARY_ABSOLUTE; + case kWindowParameterCableOpacity: + windowParameters.cableOpacity = value / 100.0f; break; - case 2: - windowParameters.knobMode = rack::settings::KNOB_MODE_ROTARY_RELATIVE; + case kWindowParameterCableTension: + windowParameters.cableTension = value / 100.0f; + break; + case kWindowParameterRackBrightness: + windowParameters.rackBrightness = value / 100.0f; break; + case kWindowParameterHaloBrightness: + windowParameters.haloBrightness = value / 100.0f; + break; + case kWindowParameterKnobMode: + switch (static_cast(value + 0.5f)) + { + case 0: + windowParameters.knobMode = rack::settings::KNOB_MODE_LINEAR; + break; + case 1: + windowParameters.knobMode = rack::settings::KNOB_MODE_ROTARY_ABSOLUTE; + break; + case 2: + windowParameters.knobMode = rack::settings::KNOB_MODE_ROTARY_RELATIVE; + break; + } + break; + case kWindowParameterWheelKnobControl: + windowParameters.knobScroll = value > 0.5f; + break; + case kWindowParameterWheelSensitivity: + windowParameters.knobScrollSensitivity = value / 1000.0f; + break; + case kWindowParameterLockModulePositions: + windowParameters.lockModules = value > 0.5f; + break; + case kWindowParameterUpdateRateLimit: + windowParameters.rateLimit = static_cast(value + 0.5f); + rateLimitStep = 0; + break; + case kWindowParameterBrowserSort: + windowParameters.browserSort = static_cast(value + 0.5f); + break; + case kWindowParameterBrowserZoom: + // round up to nearest valid value + { + float rvalue = value - 1.0f; + + if (rvalue <= 25.0f) + rvalue = -2.0f; + else if (rvalue <= 35.0f) + rvalue = -1.5f; + else if (rvalue <= 50.0f) + rvalue = -1.0f; + else if (rvalue <= 71.0f) + rvalue = -0.5f; + else if (rvalue <= 100.0f) + rvalue = 0.0f; + else if (rvalue <= 141.0f) + rvalue = 0.5f; + else if (rvalue <= 200.0f) + rvalue = 1.0f; + else + rvalue = 0.0f; + + windowParameters.browserZoom = rvalue; + } + break; + case kWindowParameterInvertZoom: + windowParameters.invertZoom = value > 0.5f; + break; + case kWindowParameterSqueezeModulePositions: + windowParameters.squeezeModules = value > 0.5f; + break; + default: + return; } - break; - case kWindowParameterWheelKnobControl: - windowParameters.knobScroll = value > 0.5f; - break; - case kWindowParameterWheelSensitivity: - windowParameters.knobScrollSensitivity = value / 1000.0f; - break; - case kWindowParameterLockModulePositions: - windowParameters.lockModules = value > 0.5f; - break; - case kWindowParameterUpdateRateLimit: - windowParameters.rateLimit = static_cast(value + 0.5f); - rateLimitStep = 0; - break; - case kWindowParameterBrowserSort: - windowParameters.browserSort = static_cast(value + 0.5f); - break; - case kWindowParameterBrowserZoom: - // round up to nearest valid value - { - float rvalue = value - 1.0f; - - if (rvalue <= 25.0f) - rvalue = -2.0f; - else if (rvalue <= 35.0f) - rvalue = -1.5f; - else if (rvalue <= 50.0f) - rvalue = -1.0f; - else if (rvalue <= 71.0f) - rvalue = -0.5f; - else if (rvalue <= 100.0f) - rvalue = 0.0f; - else if (rvalue <= 141.0f) - rvalue = 0.5f; - else if (rvalue <= 200.0f) - rvalue = 1.0f; - else - rvalue = 0.0f; - windowParameters.browserZoom = rvalue; - } - break; - case kWindowParameterInvertZoom: - windowParameters.invertZoom = value > 0.5f; - break; - case kWindowParameterSqueezeModulePositions: - windowParameters.squeezeModules = value > 0.5f; - break; - default: + WindowParametersSetValues(context->window, windowParameters); return; } - WindowParametersSetValues(context->window, windowParameters); + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + if (index < kCardinalParameterCountAtMiniBuffers) + { + float* const buffer = *const_cast(&context->dataIns[index - kCardinalParameterStartMiniBuffers]); + buffer[0] = value; + return; + } + + switch (index) + { + case kCardinalParameterMiniTimeFlags: { + const int32_t flags = static_cast(value + 0.5f); + context->playing = flags & 0x1; + context->bbtValid = flags & 0x2; + context->reset = flags & 0x4; + return; + } + case kCardinalParameterMiniTimeBar: + context->bar = static_cast(value + 0.5f); + return; + case kCardinalParameterMiniTimeBeat: + context->beat = static_cast(value + 0.5f); + return; + case kCardinalParameterMiniTimeBeatsPerBar: + context->beatsPerBar = static_cast(value + 0.5f); + return; + case kCardinalParameterMiniTimeBeatType: + context->beatType = static_cast(value + 0.5f); + context->ticksPerClock = context->ticksPerBeat / context->beatType; + context->tickClock = std::fmod(context->tick, context->ticksPerClock); + return; + case kCardinalParameterMiniTimeFrame: + context->frame = static_cast(value * context->sampleRate + 0.5f); + return; + case kCardinalParameterMiniTimeBarStartTick: + context->barStartTick = value; + return; + case kCardinalParameterMiniTimeBeatsPerMinute: + context->beatsPerMinute = value; + context->ticksPerFrame = 1.0 / (60.0 * context->sampleRate / context->beatsPerMinute / context->ticksPerBeat); + return; + case kCardinalParameterMiniTimeTick: + context->tick = value; + context->tickClock = std::fmod(context->tick, context->ticksPerClock); + return; + case kCardinalParameterMiniTimeTicksPerBeat: + context->ticksPerBeat = value; + context->ticksPerClock = context->ticksPerBeat / context->beatType; + context->ticksPerFrame = 1.0 / (60.0 * context->sampleRate / context->beatsPerMinute / context->ticksPerBeat); + context->tickClock = std::fmod(context->tick, context->ticksPerClock); + return; + } + #endif } void stateChanged(const char* const key, const char* const value) override { - if (std::strcmp(key, "windowSize") != 0) - return; + #if CARDINAL_VARIANT_MINI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + if (std::strcmp(key, "patch") == 0) + { + if (fAutosavePath.empty()) + return; - int width = 0; - int height = 0; - std::sscanf(value, "%i:%i", &width, &height); + rack::system::removeRecursively(fAutosavePath); + rack::system::createDirectories(fAutosavePath); - if (width > 0 && height > 0) + FILE* const f = std::fopen(rack::system::join(fAutosavePath, "patch.json").c_str(), "w"); + DISTRHO_SAFE_ASSERT_RETURN(f != nullptr,); + + std::fwrite(value, std::strlen(value), 1, f); + std::fclose(f); + + const ScopedContext sc(this); + + try { + context->patch->loadAutosave(); + } catch(const rack::Exception& e) { + d_stderr(e.what()); + } DISTRHO_SAFE_EXCEPTION_RETURN("setState loadAutosave",); + + return; + } + #endif + + if (std::strcmp(key, "windowSize") == 0) { - const double scaleFactor = getScaleFactor(); - setSize(width * scaleFactor, height * scaleFactor); + int width = 0; + int height = 0; + std::sscanf(value, "%d:%d", &width, &height); + + if (width > 0 && height > 0) + { + const double scaleFactor = getScaleFactor(); + setSize(width * scaleFactor, height * scaleFactor); + } + + return; } } @@ -800,9 +999,9 @@ class CardinalUI : public CardinalBaseUI, switch (ev.button) { - case 1: button = GLFW_MOUSE_BUTTON_LEFT; break; - case 2: button = GLFW_MOUSE_BUTTON_RIGHT; break; - case 3: button = GLFW_MOUSE_BUTTON_MIDDLE; break; + case kMouseButtonLeft: button = GLFW_MOUSE_BUTTON_LEFT; break; + case kMouseButtonRight: button = GLFW_MOUSE_BUTTON_RIGHT; break; + case kMouseButtonMiddle: button = GLFW_MOUSE_BUTTON_MIDDLE; break; default: button = ev.button; break; @@ -846,10 +1045,10 @@ class CardinalUI : public CardinalBaseUI, if (inSelfTest) return false; #endif - rack::math::Vec scrollDelta = rack::math::Vec(ev.delta.getX(), ev.delta.getY()); -#ifndef DISTRHO_OS_MAC + rack::math::Vec scrollDelta = rack::math::Vec(-ev.delta.getX(), ev.delta.getY()); + #ifndef DISTRHO_OS_MAC scrollDelta = scrollDelta.mult(50.0); -#endif + #endif const int mods = glfwMods(ev.mod); const ScopedContext sc(this, mods); @@ -879,34 +1078,15 @@ class CardinalUI : public CardinalBaseUI, const int action = ev.press ? GLFW_PRESS : GLFW_RELEASE; const int mods = glfwMods(ev.mod); - /* These are unsupported in pugl right now - #define GLFW_KEY_KP_0 320 - #define GLFW_KEY_KP_1 321 - #define GLFW_KEY_KP_2 322 - #define GLFW_KEY_KP_3 323 - #define GLFW_KEY_KP_4 324 - #define GLFW_KEY_KP_5 325 - #define GLFW_KEY_KP_6 326 - #define GLFW_KEY_KP_7 327 - #define GLFW_KEY_KP_8 328 - #define GLFW_KEY_KP_9 329 - #define GLFW_KEY_KP_DECIMAL 330 - #define GLFW_KEY_KP_DIVIDE 331 - #define GLFW_KEY_KP_MULTIPLY 332 - #define GLFW_KEY_KP_SUBTRACT 333 - #define GLFW_KEY_KP_ADD 334 - #define GLFW_KEY_KP_ENTER 335 - #define GLFW_KEY_KP_EQUAL 336 - */ - int key; switch (ev.key) { - case '\r': key = GLFW_KEY_ENTER; break; case '\t': key = GLFW_KEY_TAB; break; case kKeyBackspace: key = GLFW_KEY_BACKSPACE; break; + case kKeyEnter: key = GLFW_KEY_ENTER; break; case kKeyEscape: key = GLFW_KEY_ESCAPE; break; case kKeyDelete: key = GLFW_KEY_DELETE; break; + case kKeySpace: key = GLFW_KEY_SPACE; break; case kKeyF1: key = GLFW_KEY_F1; break; case kKeyF2: key = GLFW_KEY_F2; break; case kKeyF3: key = GLFW_KEY_F3; break; @@ -919,15 +1099,21 @@ class CardinalUI : public CardinalBaseUI, case kKeyF10: key = GLFW_KEY_F10; break; case kKeyF11: key = GLFW_KEY_F11; break; case kKeyF12: key = GLFW_KEY_F12; break; + case kKeyPageUp: key = GLFW_KEY_PAGE_UP; break; + case kKeyPageDown: key = GLFW_KEY_PAGE_DOWN; break; + case kKeyEnd: key = GLFW_KEY_END; break; + case kKeyHome: key = GLFW_KEY_HOME; break; case kKeyLeft: key = GLFW_KEY_LEFT; break; case kKeyUp: key = GLFW_KEY_UP; break; case kKeyRight: key = GLFW_KEY_RIGHT; break; case kKeyDown: key = GLFW_KEY_DOWN; break; - case kKeyPageUp: key = GLFW_KEY_PAGE_UP; break; - case kKeyPageDown: key = GLFW_KEY_PAGE_DOWN; break; - case kKeyHome: key = GLFW_KEY_HOME; break; - case kKeyEnd: key = GLFW_KEY_END; break; + case kKeyPrintScreen: key = GLFW_KEY_PRINT_SCREEN; break; case kKeyInsert: key = GLFW_KEY_INSERT; break; + case kKeyPause: key = GLFW_KEY_PAUSE; break; + case kKeyMenu: key = GLFW_KEY_MENU; break; + case kKeyNumLock: key = GLFW_KEY_NUM_LOCK; break; + case kKeyScrollLock: key = GLFW_KEY_SCROLL_LOCK; break; + case kKeyCapsLock: key = GLFW_KEY_CAPS_LOCK; break; case kKeyShiftL: key = GLFW_KEY_LEFT_SHIFT; break; case kKeyShiftR: key = GLFW_KEY_RIGHT_SHIFT; break; case kKeyControlL: key = GLFW_KEY_LEFT_CONTROL; break; @@ -936,12 +1122,39 @@ class CardinalUI : public CardinalBaseUI, case kKeyAltR: key = GLFW_KEY_RIGHT_ALT; break; case kKeySuperL: key = GLFW_KEY_LEFT_SUPER; break; case kKeySuperR: key = GLFW_KEY_RIGHT_SUPER; break; - case kKeyMenu: key = GLFW_KEY_MENU; break; - case kKeyCapsLock: key = GLFW_KEY_CAPS_LOCK; break; - case kKeyScrollLock: key = GLFW_KEY_SCROLL_LOCK; break; - case kKeyNumLock: key = GLFW_KEY_NUM_LOCK; break; - case kKeyPrintScreen: key = GLFW_KEY_PRINT_SCREEN; break; - case kKeyPause: key = GLFW_KEY_PAUSE; break; + case kKeyPad0: key = GLFW_KEY_KP_0; break; + case kKeyPad1: key = GLFW_KEY_KP_1; break; + case kKeyPad2: key = GLFW_KEY_KP_2; break; + case kKeyPad3: key = GLFW_KEY_KP_3; break; + case kKeyPad4: key = GLFW_KEY_KP_4; break; + case kKeyPad5: key = GLFW_KEY_KP_5; break; + case kKeyPad6: key = GLFW_KEY_KP_6; break; + case kKeyPad7: key = GLFW_KEY_KP_7; break; + case kKeyPad8: key = GLFW_KEY_KP_8; break; + case kKeyPad9: key = GLFW_KEY_KP_9; break; + case kKeyPadEnter: key = GLFW_KEY_KP_ENTER; break; + /* undefined in glfw + case kKeyPadPageUp: + case kKeyPadPageDown: + case kKeyPadEnd: + case kKeyPadHome: + case kKeyPadLeft: + case kKeyPadUp: + case kKeyPadRight: + case kKeyPadDown: + case kKeyPadClear: + case kKeyPadInsert: + case kKeyPadDelete: + */ + case kKeyPadEqual: key = GLFW_KEY_KP_EQUAL; break; + case kKeyPadMultiply: key = GLFW_KEY_KP_MULTIPLY; break; + case kKeyPadAdd: key = GLFW_KEY_KP_ADD; break; + /* undefined in glfw + case kKeyPadSeparator: + */ + case kKeyPadSubtract: key = GLFW_KEY_KP_SUBTRACT; break; + case kKeyPadDecimal: key = GLFW_KEY_KP_DECIMAL; break; + case kKeyPadDivide: key = GLFW_KEY_KP_DIVIDE; break; default: // glfw expects uppercase if (ev.key >= 'a' && ev.key <= 'z') @@ -963,10 +1176,15 @@ class CardinalUI : public CardinalBaseUI, WindowSetInternalSize(context->window, rack::math::Vec(ev.size.getWidth(), ev.size.getHeight())); const double scaleFactor = getScaleFactor(); - char sizeString[64]; - std::snprintf(sizeString, sizeof(sizeString), "%d:%d", - (int)(ev.size.getWidth() / scaleFactor), (int)(ev.size.getHeight() / scaleFactor)); + const int width = static_cast(ev.size.getWidth() / scaleFactor + 0.5); + const int height = static_cast(ev.size.getHeight() / scaleFactor + 0.5); + + char sizeString[64] = {}; + std::snprintf(sizeString, sizeof(sizeString), "%d:%d", width, height); setState("windowSize", sizeString); + + if (rack::isStandalone()) + rack::settings::windowSize = rack::math::Vec(width, height); } void uiFocus(const bool focus, CrossingMode) override @@ -1038,7 +1256,14 @@ class CardinalUI : public CardinalBaseUI, } context->patch->path = sfilename; + context->patch->pushRecentPath(sfilename); context->history->setSaved(); + + #ifdef DISTRHO_OS_WASM + rack::syncfs(); + #else + rack::settings::save(); + #endif } #if 0 diff --git a/src/CardinalX11WindowIcon.cpp b/src/CardinalX11WindowIcon.cpp new file mode 100644 index 00000000..d7d3fe37 --- /dev/null +++ b/src/CardinalX11WindowIcon.cpp @@ -0,0 +1,1221 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the LICENSE file. + */ + +#include + +static constexpr const unsigned long sCardinalX11Icon[] = { + // 16x16 + 16, 16, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x2dffffff, 0x91ffffff, 0xd5ffffff, 0xf4ffffff, 0xf4ffffff, 0xd5ffffff, 0x91ffffff, 0x2dffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x003e3e3e, 0x06ffffff, 0x96ffffff, 0xfdffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfdffffff, 0x95ffffff, 0x06ffffff, 0x003e3e3e, 0x00ffffff, + 0x00ffffff, 0x06ffffff, 0xbdffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfbffffff, 0xfbffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xbdffffff, 0x06ffffff, 0x00ffffff, + 0x00ffffff, 0x96ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa1ffffff, 0x32ffffff, 0x02ffffff, 0x02ffffff, 0x32ffffff, 0xa2ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x93ffffff, 0x00ffffff, + 0x2dffffff, 0xfdffffff, 0xffffffff, 0xffffffff, 0x65ffffff, 0x003b3b3b, 0x00535353, 0x10ffffff, 0x11ffffff, 0x004f4f4f, 0x003e4d61, 0x67ffffff, 0xffffffff, 0xffffffff, 0xfcffffff, 0x2bffffff, + 0x91ffffff, 0xffffffff, 0xffffffff, 0xa1ffffff, 0x00763d3d, 0x18ffffff, 0xb8ffffff, 0xffffffff, 0xffffffff, 0xb7ffffff, 0x17ffffff, 0x00394a62, 0xa3ffffff, 0xffffffff, 0xffffffff, 0x8fffffff, + 0xd5ffffff, 0xffffffff, 0xffffffff, 0x31ffffff, 0x001a1a1a, 0xb9ffffff, 0xeeffffff, 0x6fffffff, 0x70ffffff, 0xefffffff, 0xb7ffffff, 0x003d567a, 0x33ffffff, 0xffffffff, 0xffffffff, 0xd4ffffff, + 0xf3ffffff, 0xffffffff, 0xfbffffff, 0x02ffffff, 0x11ffffff, 0xfeffffff, 0x6fffffff, 0x00393535, 0x00393535, 0x70ffffff, 0xfeffffff, 0x10ffffff, 0x03ffffff, 0xfbffffff, 0xffffffff, 0xf3ffffff, + 0xf3ffffff, 0xffffffff, 0xfcffffff, 0x03ffffff, 0x11ffffff, 0xfeffffff, 0x70ffffff, 0x00363333, 0x00363333, 0x71ffffff, 0xfeffffff, 0x10ffffff, 0x03ffffff, 0xfcffffff, 0xffffffff, 0xf1ffffff, + 0xd6ffffff, 0xffffffff, 0xffffffff, 0x32ffffff, 0x001a1a1a, 0xb7ffffff, 0xefffffff, 0x71ffffff, 0x71ffffff, 0xefffffff, 0xb5ffffff, 0x003e5b83, 0x33ffffff, 0xffffffff, 0xffffffff, 0xd4ffffff, + 0x91ffffff, 0xffffffff, 0xffffffff, 0xa1ffffff, 0x00783f3f, 0x18ffffff, 0xb7ffffff, 0xfeffffff, 0xfeffffff, 0xb5ffffff, 0x17ffffff, 0x003c5477, 0xa4ffffff, 0xffffffff, 0xffffffff, 0x8effffff, + 0x2dffffff, 0xfcffffff, 0xffffffff, 0xffffffff, 0x67ffffff, 0x00363636, 0x004f4f4f, 0x10ffffff, 0x10ffffff, 0x00464646, 0x003d4c5f, 0x68ffffff, 0xffffffff, 0xffffffff, 0xfcffffff, 0x2bffffff, + 0x00ffffff, 0x94ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa3ffffff, 0x32ffffff, 0x02ffffff, 0x03ffffff, 0x34ffffff, 0xa4ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x92ffffff, 0x00ffffff, + 0x00ffffff, 0x06ffffff, 0xbdffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfbffffff, 0xfcffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xbcffffff, 0x06ffffff, 0x00ffffff, + 0x00ffffff, 0x003e3e3e, 0x06ffffff, 0x93ffffff, 0xfcffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfcffffff, 0x91ffffff, 0x06ffffff, 0x003e3e3e, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x2bffffff, 0x8effffff, 0xd3ffffff, 0xf3ffffff, 0xf3ffffff, 0xd3ffffff, 0x8effffff, 0x2bffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + + // 48x48 + 48, 48, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00333333, 0x002b2b2b, 0x002b2b2b, 0x002b2b2b, 0x002b2b2b, 0x002b2b2b, 0x002b2b2b, + 0x002b2b2b, 0x18ffffff, 0x58ffffff, 0x90ffffff, 0xb8ffffff, 0xd9ffffff, 0xeeffffff, 0xf9ffffff, 0xf9ffffff, 0xeeffffff, 0xd9ffffff, 0xb7ffffff, 0x8fffffff, 0x57ffffff, 0x17ffffff, 0x002b2b2b, + 0x002b2b2b, 0x002b2b2b, 0x002b2b2b, 0x002b2b2b, 0x002b2b2b, 0x002b2b2b, 0x00333333, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x002b2b2b, 0x001a1a1a, 0x00222222, 0x001a1a1a, 0x00181818, 0x00212121, 0x00212121, 0x00212121, 0x00212121, 0x13ffffff, 0x6dffffff, + 0xcaffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc9ffffff, + 0x6cffffff, 0x13ffffff, 0x00212121, 0x00212121, 0x00212121, 0x00212121, 0x00181818, 0x001a1a1a, 0x00222222, 0x001a1a1a, 0x002b2b2b, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x001a1a1a, 0x00181818, 0x001e1e1e, 0x001b1b1b, 0x001b1b1b, 0x001d1d1d, 0x001c1c1c, 0x001b1b1b, 0x1bffffff, 0x90ffffff, 0xf5ffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xf4ffffff, 0x8effffff, 0x1affffff, 0x001b1b1b, 0x001c1c1c, 0x001d1d1d, 0x001b1b1b, 0x001b1b1b, 0x001e1e1e, 0x00181818, 0x001a1a1a, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00000000, 0x00000000, 0x00151515, 0x001a1a1a, 0x001d1d1d, 0x003b3017, 0x00785a14, 0x00997715, 0x00966f12, 0x05ffffff, 0x6fffffff, 0xf3ffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xf5ffffff, 0x80ffffff, 0x06ffffff, 0x00815206, 0x007c5106, 0x006b490b, 0x003a2c14, 0x001d1d1d, 0x001a1a1a, 0x00151515, 0x00000000, 0x00000000, 0x00ffffff, + 0x00000000, 0x00000000, 0x001a1a1a, 0x001a1a1a, 0x001d1d1d, 0x005f4110, 0x00a76f0d, 0x00bc7d0f, 0x00cc6d0e, 0x27ffffff, 0xd0ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xceffffff, 0x25ffffff, 0x00984a00, 0x00a06100, 0x00a26601, 0x006e4c0f, 0x001d1d1d, 0x001a1a1a, 0x001a1a1a, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00181818, 0x001d1d1d, 0x0056360d, 0x00996008, 0x00c13a06, 0x00d10200, 0x52ffffff, 0xf3ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf2ffffff, 0x50ffffff, 0x00820200, 0x00933600, 0x00ac7408, 0x00775f20, 0x001d1d1d, 0x00181818, 0x00000000, 0x00000000, + 0x00000000, 0x001a1a1a, 0x001e1e1e, 0x002e2015, 0x00854a05, 0x00b93104, 0x00d00000, 0x60ffffff, 0xfbffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfcffffff, 0x68ffffff, 0x007e0000, 0x00953b05, 0x00bb9025, 0x00443b22, 0x001e1e1e, 0x001a1a1a, 0x00000000, + 0x00000000, 0x00222222, 0x001b1b1b, 0x004e2d0b, 0x008c4a05, 0x00cf0200, 0x67ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x66ffffff, 0x007b0200, 0x00bd8f26, 0x00897732, 0x001b1b1b, 0x00222222, 0x00000000, + 0x00333333, 0x001b1b1b, 0x001b1b1b, 0x005e3308, 0x009a3b05, 0x53ffffff, 0xfcffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe9ffffff, 0xddffffff, 0xddffffff, 0xe9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfcffffff, 0x50ffffff, 0x00ae711f, 0x00a38e39, 0x001b1b1b, 0x001a1a1a, 0x00333333, + 0x00333333, 0x00242424, 0x001d1d1d, 0x00643507, 0x27ffffff, 0xf3ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xddffffff, 0x85ffffff, 0x3fffffff, 0x0effffff, 0x00262626, 0x00262626, 0x00262626, 0x00262626, 0x0effffff, 0x40ffffff, 0x86ffffff, 0xdfffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf2ffffff, 0x25ffffff, 0x00ad973c, 0x001d1d1d, 0x00242424, 0x00333333, + 0x002b2b2b, 0x00232323, 0x001c1c1c, 0x06ffffff, 0xd0ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xceffffff, 0x4effffff, 0x01ffffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x00303030, 0x00303f30, 0x01ffffff, 0x4fffffff, 0xd0ffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xcfffffff, 0x05ffffff, 0x001c1c1c, 0x00212121, 0x002b2b2b, + 0x002b2b2b, 0x00212121, 0x001b1b1b, 0x78ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf8ffffff, 0x72ffffff, + 0x03ffffff, 0x002c2c2c, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x00303030, 0x00294929, 0x0000ff00, 0x0000ff00, 0x04ffffff, + 0x75ffffff, 0xf9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x75ffffff, 0x001b1b1b, 0x00212121, 0x002b2b2b, + 0x002b2b2b, 0x00212121, 0x1bffffff, 0xf4ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe9ffffff, 0x36ffffff, 0x001a1a1a, + 0x001a1a1a, 0x002c2c2c, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x00303030, 0x002a462a, 0x0000e000, 0x0000e000, 0x0000e000, + 0x0000e000, 0x39ffffff, 0xebffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf3ffffff, 0x19ffffff, 0x00212121, 0x002b2b2b, + 0x002b2b2b, 0x00212121, 0x90ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xeaffffff, 0x28ffffff, 0x00895151, 0x00433333, + 0x001a1a1a, 0x002c2c2c, 0x00424242, 0x00797979, 0x00575757, 0x005f5f5f, 0x003f3f3f, 0x005a5a5a, 0x006b6b6b, 0x005d5d5d, 0x003f3f3f, 0x00303030, 0x002a452a, 0x0000d800, 0x0000d800, 0x0000d800, + 0x0000d800, 0x0000d100, 0x2affffff, 0xebffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x8dffffff, 0x00212121, 0x002b2b2b, + 0x002b2b2b, 0x14ffffff, 0xf5ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf8ffffff, 0x36ffffff, 0x009f9f9f, 0x00b7b1b1, 0x007b3e3e, + 0x00272525, 0x002c2c2c, 0x00616161, 0x00505050, 0x003c3c3c, 0x1dffffff, 0x56ffffff, 0x6fffffff, 0x6fffffff, 0x56ffffff, 0x1cffffff, 0x00303030, 0x00294929, 0x0000ff00, 0x0000ff00, 0x0000ff00, + 0x0000ff00, 0x0000f800, 0x00000000, 0x38ffffff, 0xf9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf4ffffff, 0x13ffffff, 0x002b2b2b, + 0x002b2b2b, 0x6effffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x72ffffff, 0x00767676, 0x00727272, 0x00a2a2a2, 0x00936262, + 0x00463939, 0x002c2c2c, 0x003c3c3c, 0x4cffffff, 0xc9ffffff, 0xfeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfeffffff, 0xc8ffffff, 0x4cffffff, 0x00108810, 0x00108810, 0x00108810, + 0x00108810, 0x00118511, 0x001f1f1f, 0x001f1f1f, 0x74ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x6bffffff, 0x002b2b2b, + 0x002b2b2b, 0xcbffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xceffffff, 0x03ffffff, 0x007d7d7d, 0x00787878, 0x00a5a5a5, 0x00864e4e, + 0x00413737, 0x0dffffff, 0xb0ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xaeffffff, 0x0cffffff, 0x0002816b, + 0x00030303, 0x00030303, 0x00030303, 0x00030303, 0x04ffffff, 0xd1ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc8ffffff, 0x002b2b2b, + 0x16ffffff, 0xfeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x4dffffff, 0x00ab9292, 0x00adadad, 0x00aaaaaa, 0x00907e7e, 0x006d3939, + 0x0dffffff, 0xcfffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xceffffff, 0x0dffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00161616, 0x51ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfeffffff, 0x17ffffff, + 0x58ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xdeffffff, 0x01ffffff, 0x00653b3b, 0x00864f4f, 0x00804c4c, 0x006b3d3d, 0x00372e2e, + 0xb0ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfaffffff, 0xfaffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xaeffffff, + 0x00005042, 0x00005042, 0x00005042, 0x0000483b, 0x00161616, 0x02ffffff, 0xe0ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x56ffffff, + 0x90ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x85ffffff, 0x001a1a1a, 0x001b1b1b, 0x002b2929, 0x002f2c2c, 0x001c1c1c, 0x4dffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfeffffff, 0x9effffff, 0x30ffffff, 0x003b3b3b, 0x01ffffff, 0x30ffffff, 0xa0ffffff, 0xfeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x4affffff, 0x0000ffd2, 0x0000ffd2, 0x0000e8bf, 0x00161616, 0x00262626, 0x88ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x8effffff, + 0xb7ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x40ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0xc8ffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xfeffffff, 0x61ffffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x64ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xc7ffffff, 0x0000ffd2, 0x0000ffd2, 0x0000e8bf, 0x00161616, 0x00262626, 0x42ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb6ffffff, + 0xdbffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0effffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x1dffffff, 0xfeffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0x9effffff, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x002a2a2a, 0xa0ffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xfeffffff, 0x1cffffff, 0x00333333, 0x00333333, 0x00333333, 0x00232323, 0x10ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xdaffffff, + 0xecffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xeaffffff, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x55ffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0x2fffffff, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x31ffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0x53ffffff, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x00533a3a, 0xecffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xebffffff, + 0xf9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xdbffffff, 0x00494141, 0x004a4141, 0x004a4141, 0x004a4141, 0x004a4141, 0x6fffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xfaffffff, 0x02ffffff, 0x004a4141, 0x004a4141, 0x004a4141, 0x004a4141, 0x004a4141, 0x004a4141, 0x004a4141, 0x004a4141, 0x02ffffff, 0xfaffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0x6effffff, 0x004a4141, 0x004a4141, 0x00494141, 0x00494141, 0x00504343, 0xdcffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf8ffffff, + 0xf9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xdbffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x6fffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xfaffffff, 0x02ffffff, 0x00232323, 0x00232323, 0x00232323, 0x00232323, 0x00232323, 0x00232323, 0x00232323, 0x001e1e1e, 0x02ffffff, 0xfaffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0x6effffff, 0x001f1f1f, 0x001f1f1f, 0x001f1f1f, 0x001b1b1b, 0x00523939, 0xdcffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf8ffffff, + 0xecffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xeaffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x55ffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0x30ffffff, 0x003c3c3c, 0x003c3c3c, 0x003c3c3c, 0x003c3c3c, 0x003c3c3c, 0x003c3c3c, 0x003c3c3c, 0x00313131, 0x32ffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0x53ffffff, 0x00232323, 0x00232323, 0x002d2d2d, 0x00262626, 0x00523939, 0xecffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xebffffff, + 0xdbffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0effffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x1dffffff, 0xfeffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0x9fffffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x00303030, 0xa2ffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xfeffffff, 0x1bffffff, 0x00000000, 0x00000000, 0x00161616, 0x00262626, 0x10ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd9ffffff, + 0xb7ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x41ffffff, 0x001a1a1a, 0x00212020, 0x003d3030, 0x00403232, 0x00262424, 0xc8ffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xfeffffff, 0x64ffffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x66ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xc6ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00161616, 0x00262626, 0x43ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb5ffffff, + 0x8fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x86ffffff, 0x00342929, 0x00835050, 0x00c49696, 0x00bd9090, 0x00844e4e, 0x4bffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfeffffff, 0xa0ffffff, 0x31ffffff, 0x01ffffff, 0x01ffffff, 0x32ffffff, 0xa2ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x4affffff, 0x0000c900, 0x00000000, 0x00000000, 0x00161616, 0x00262626, 0x89ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x8effffff, + 0x57ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xdeffffff, 0x01ffffff, 0x00d2c4c4, 0x00a3a3a3, 0x00a0a0a0, 0x00b7b0b0, 0x00793c3c, + 0xaeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfaffffff, 0xfaffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xadffffff, + 0x0000ff00, 0x0000f800, 0x00000000, 0x00000000, 0x00161616, 0x02ffffff, 0xe0ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x55ffffff, + 0x16ffffff, 0xfeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x4fffffff, 0x00adadad, 0x00777777, 0x00737373, 0x00a2a2a2, 0x00946262, + 0x0dffffff, 0xceffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xcdffffff, 0x0cffffff, + 0x000e8e0e, 0x000f8b0f, 0x001d1d1d, 0x001d1d1d, 0x00282828, 0x53ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfeffffff, 0x15ffffff, + 0x002b2b2b, 0xc9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd0ffffff, 0x04ffffff, 0x007c7c7c, 0x00777777, 0x00a5a5a5, 0x00874f4f, + 0x00423838, 0x0dffffff, 0xaeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xacffffff, 0x0cffffff, 0x00037e68, + 0x00050505, 0x00050505, 0x00050505, 0x00050505, 0x04ffffff, 0xd3ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc7ffffff, 0x002b2b2b, + 0x002b2b2b, 0x6cffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x75ffffff, 0x00acacac, 0x00a9a9a9, 0x00928282, 0x006e3939, + 0x00222222, 0x002c2c2c, 0x00696969, 0x4affffff, 0xc7ffffff, 0xfeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfeffffff, 0xc6ffffff, 0x49ffffff, 0x0000ffd2, 0x0000ffd2, 0x00008870, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x77ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x69ffffff, 0x002b2b2b, + 0x002b2b2b, 0x13ffffff, 0xf4ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf9ffffff, 0x38ffffff, 0x00835050, 0x006b3b3b, 0x00392f2f, + 0x001a1a1a, 0x002c2c2c, 0x00838383, 0x008e8e8e, 0x00545454, 0x1bffffff, 0x53ffffff, 0x6effffff, 0x6effffff, 0x53ffffff, 0x1bffffff, 0x002f2f2f, 0x002b423e, 0x0000977d, 0x0000977d, 0x00007661, + 0x00005042, 0x00005042, 0x00005042, 0x3affffff, 0xfaffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf3ffffff, 0x12ffffff, 0x002b2b2b, + 0x002b2b2b, 0x00212121, 0x8effffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xebffffff, 0x2affffff, 0x001d1d1d, 0x001a1a1a, + 0x001a1a1a, 0x002c2c2c, 0x00474747, 0x004e4e4e, 0x003b3b3b, 0x00454545, 0x004f4f4f, 0x003a3a3a, 0x00424242, 0x00515151, 0x003b3b3b, 0x00303030, 0x00294943, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, + 0x0000ffd2, 0x0000ffd2, 0x2affffff, 0xebffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x8bffffff, 0x00212121, 0x002b2b2b, + 0x002b2b2b, 0x00212121, 0x1affffff, 0xf3ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xebffffff, 0x39ffffff, 0x001a1a1a, + 0x001a1a1a, 0x002c2c2c, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x00303030, 0x00294943, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, + 0x0000ffd2, 0x3affffff, 0xecffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf2ffffff, 0x18ffffff, 0x00212121, 0x002b2b2b, + 0x002b2b2b, 0x00212121, 0x001b1b1b, 0x75ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf9ffffff, 0x74ffffff, + 0x04ffffff, 0x00282828, 0x00353535, 0x00353535, 0x00353535, 0x00353535, 0x00353535, 0x00353535, 0x00353535, 0x00353535, 0x00353535, 0x002a2a2a, 0x00303131, 0x00313938, 0x00313938, 0x04ffffff, + 0x77ffffff, 0xfaffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x73ffffff, 0x001b1b1b, 0x00212121, 0x002b2b2b, + 0x002b2b2b, 0x00232323, 0x001c1c1c, 0x05ffffff, 0xceffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xd1ffffff, 0x50ffffff, 0x01ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x02ffffff, 0x52ffffff, 0xd3ffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xcdffffff, 0x05ffffff, 0x001c1c1c, 0x00212121, 0x002b2b2b, + 0x00333333, 0x00242424, 0x001d1d1d, 0x0081580d, 0x25ffffff, 0xf1ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xdfffffff, 0x87ffffff, 0x42ffffff, 0x10ffffff, 0x005a3838, 0x005a3838, 0x005a3838, 0x005a3838, 0x10ffffff, 0x43ffffff, 0x89ffffff, 0xe1ffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf0ffffff, 0x24ffffff, 0x00c7c262, 0x001d1d1d, 0x00242424, 0x00333333, + 0x00333333, 0x001b1b1b, 0x001b1b1b, 0x007b540e, 0x00a45c0b, 0x4fffffff, 0xfcffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xecffffff, 0xddffffff, 0xddffffff, 0xecffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfbffffff, 0x4dffffff, 0x00baa54b, 0x00bbb55d, 0x001b1b1b, 0x001a1a1a, 0x00333333, + 0x00000000, 0x00222222, 0x001b1b1b, 0x00674811, 0x00b0770e, 0x007f0300, 0x65ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfeffffff, 0x63ffffff, 0x00300502, 0x00e1d361, 0x009b964f, 0x001b1b1b, 0x00222222, 0x00000000, + 0x00000000, 0x001a1a1a, 0x001e1e1e, 0x00372c18, 0x00af7c0f, 0x00a24a09, 0x007a0000, 0x60ffffff, 0xfbffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfcffffff, 0x67ffffff, 0x002b0000, 0x00856428, 0x00e3d764, 0x0049462d, 0x001e1e1e, 0x001a1a1a, 0x00000000, + 0x00000000, 0x00000000, 0x00181818, 0x001d1d1d, 0x00715614, 0x00c69413, 0x009a4408, 0x00770200, 0x51ffffff, 0xf2ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf0ffffff, 0x4dffffff, 0x002d0200, 0x007a541b, 0x00ddc550, 0x00928c48, 0x001d1d1d, 0x00181818, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x001a1a1a, 0x001a1a1a, 0x001e1e1e, 0x007a6016, 0x00b38110, 0x00a56d0b, 0x008e4706, 0x26ffffff, 0xcfffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xcdffffff, 0x24ffffff, 0x00875000, 0x00b1831b, 0x00c3a134, 0x008a7d3b, 0x001e1e1e, 0x001a1a1a, 0x001a1a1a, 0x00000000, 0x00000000, + 0x00ffffff, 0x00000000, 0x00000000, 0x00151515, 0x001b1b1b, 0x001d1d1d, 0x003a3118, 0x006c4d12, 0x00764d0b, 0x006f4107, 0x04ffffff, 0x6fffffff, 0xf2ffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xf4ffffff, 0x80ffffff, 0x06ffffff, 0x00875906, 0x00835808, 0x00765b1c, 0x003f3920, 0x001d1d1d, 0x001b1b1b, 0x00151515, 0x00000000, 0x00000000, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x001a1a1a, 0x00181818, 0x001e1e1e, 0x001b1b1b, 0x001b1b1b, 0x001d1d1d, 0x001c1c1c, 0x001b1b1b, 0x19ffffff, 0x8dffffff, 0xf4ffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xf3ffffff, 0x8bffffff, 0x18ffffff, 0x001b1b1b, 0x001c1c1c, 0x001d1d1d, 0x001b1b1b, 0x001b1b1b, 0x001e1e1e, 0x00181818, 0x001a1a1a, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x002b2b2b, 0x001a1a1a, 0x00222222, 0x001b1b1b, 0x00181818, 0x00212121, 0x00212121, 0x00212121, 0x00212121, 0x12ffffff, 0x6bffffff, + 0xc8ffffff, 0xfeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfeffffff, 0xc7ffffff, + 0x6affffff, 0x12ffffff, 0x00212121, 0x00212121, 0x00212121, 0x00212121, 0x00181818, 0x001b1b1b, 0x00222222, 0x001a1a1a, 0x002b2b2b, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00333333, 0x002b2b2b, 0x002b2b2b, 0x002b2b2b, 0x002b2b2b, 0x002b2b2b, 0x002b2b2b, + 0x002b2b2b, 0x16ffffff, 0x56ffffff, 0x8effffff, 0xb6ffffff, 0xd8ffffff, 0xecffffff, 0xf9ffffff, 0xf8ffffff, 0xecffffff, 0xd8ffffff, 0xb5ffffff, 0x8dffffff, 0x55ffffff, 0x15ffffff, 0x002b2b2b, + 0x002b2b2b, 0x002b2b2b, 0x002b2b2b, 0x002b2b2b, 0x002b2b2b, 0x002b2b2b, 0x00333333, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + + // 128x128 + 128, 128, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11ffffff, 0x37ffffff, 0x5fffffff, 0x86ffffff, 0xa7ffffff, 0xbbffffff, 0xc7ffffff, 0xd2ffffff, 0xddffffff, 0xeeffffff, 0xf9ffffff, + 0xf9ffffff, 0xeeffffff, 0xddffffff, 0xd1ffffff, 0xc6ffffff, 0xbbffffff, 0xa6ffffff, 0x86ffffff, 0x5fffffff, 0x37ffffff, 0x10ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, + 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, + 0x0cffffff, 0x49ffffff, 0x8bffffff, 0xc1ffffff, 0xe9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe9ffffff, 0xc0ffffff, 0x8affffff, 0x48ffffff, 0x0cffffff, + 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, + 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x002b2b2b, 0x00242424, 0x00242424, 0x00202020, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x06ffffff, 0x43ffffff, 0x84ffffff, 0xc5ffffff, + 0xfbffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfaffffff, + 0xc4ffffff, 0x83ffffff, 0x41ffffff, 0x06ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x00202020, 0x00242424, 0x00242424, 0x002b2b2b, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00333333, + 0x002b2b2b, 0x00202020, 0x001c1c1c, 0x00171717, 0x00151515, 0x00121212, 0x00111111, 0x00202020, 0x00202020, 0x001e1e1e, 0x001e1e1e, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, + 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x33ffffff, 0x91ffffff, 0xeaffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeffffff, 0x99ffffff, 0x3cffffff, 0x01ffffff, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, + 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001e1e1e, 0x001e1e1e, 0x00202020, 0x00202020, 0x00111111, 0x00121212, 0x00151515, 0x00171717, 0x001c1c1c, 0x00202020, 0x002b2b2b, + 0x00333333, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00333333, 0x00242424, 0x001c1c1c, + 0x00171717, 0x00121212, 0x00202020, 0x001b1b1b, 0x00181818, 0x00161616, 0x001f1f1f, 0x001d1d1d, 0x001c1c1c, 0x001b1b1b, 0x001b1b1b, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x1cffffff, 0x77ffffff, 0xd9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd8ffffff, 0x80ffffff, 0x23ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001b1b1b, 0x001b1b1b, 0x001c1c1c, 0x001d1d1d, 0x001f1f1f, 0x00161616, 0x00181818, 0x001b1b1b, 0x00202020, 0x00121212, 0x00171717, + 0x001c1c1c, 0x00242424, 0x00333333, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x002b2b2b, 0x001c1c1c, 0x00151515, 0x00222222, + 0x001b1b1b, 0x00171717, 0x001d1d1d, 0x001a1a1a, 0x00171717, 0x001c1c1c, 0x001b1b1b, 0x001a1a1a, 0x00181818, 0x00181818, 0x00171717, 0x001d1d1d, 0x001d1d1d, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, + 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x30ffffff, 0xa2ffffff, 0xfdffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfeffffff, 0xb3ffffff, 0x37ffffff, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, + 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001d1d1d, 0x001d1d1d, 0x00171717, 0x00181818, 0x00181818, 0x001a1a1a, 0x001b1b1b, 0x001c1c1c, 0x00171717, 0x001a1a1a, 0x001d1d1d, 0x00171717, 0x001b1b1b, + 0x00222222, 0x00151515, 0x001c1c1c, 0x002b2b2b, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00333333, 0x00242424, 0x00171717, 0x00121212, 0x001b1b1b, 0x00151515, + 0x001a1a1a, 0x001e1e1e, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00181818, 0x001b1b1b, 0x001a1a1a, 0x00191919, 0x00191919, 0x00181818, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, + 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x3cffffff, 0xb3ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc4ffffff, 0x4dffffff, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, + 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x00181818, 0x00191919, 0x00191919, 0x001a1a1a, 0x001b1b1b, 0x00181818, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001e1e1e, 0x001a1a1a, + 0x00151515, 0x001b1b1b, 0x00121212, 0x00171717, 0x00202020, 0x00333333, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x002b2b2b, 0x00202020, 0x00151515, 0x001e1e1e, 0x00171717, 0x001a1a1a, 0x001d1d1d, + 0x00181818, 0x001a1a1a, 0x001b1b1b, 0x00181818, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00191919, 0x001b1b1b, 0x001b1b1b, 0x001b1b1b, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x46ffffff, 0xc4ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc2ffffff, 0x44ffffff, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001b1b1b, 0x001b1b1b, 0x001b1b1b, 0x00191919, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00181818, 0x001b1b1b, 0x001a1a1a, 0x00181818, + 0x001d1d1d, 0x001a1a1a, 0x00171717, 0x001e1e1e, 0x00151515, 0x00202020, 0x002b2b2b, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x002b2b2b, 0x001c1c1c, 0x00141414, 0x001c1c1c, 0x001f1f1f, 0x00171717, 0x00191919, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001b1b1b, 0x00191919, 0x001a1a1a, 0x001b1b1b, 0x001d1c1a, 0x00262219, 0x00242118, 0x00242018, 0x0025221a, 0x0025211a, 0x0024211a, 0x0024201a, 0x1bffffff, + 0xa2ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb3ffffff, + 0x1fffffff, 0x0025221a, 0x0025211a, 0x00242019, 0x00242019, 0x00231e17, 0x00231e17, 0x00242018, 0x001d1b19, 0x001b1b1b, 0x001a1a1a, 0x00191919, 0x001b1b1b, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x00191919, 0x00171717, 0x001f1f1f, 0x001b1b1b, 0x00141414, 0x001c1c1c, 0x002b2b2b, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x002b2b2b, 0x001c1c1c, 0x00141414, 0x001b1b1b, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001b1b1b, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x00232018, 0x00674e15, 0x00987213, 0x00b28713, 0x00c19415, 0x00c39412, 0x00bf8e11, 0x00b8860f, 0x00b17f0d, 0x00ac780c, 0x00a5700a, 0x05ffffff, 0x6fffffff, 0xf2ffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xf5ffffff, 0x80ffffff, 0x06ffffff, 0x009c6000, 0x009d6100, 0x009e6200, 0x009f6300, 0x00a06400, 0x00a06500, 0x009a6101, 0x00945e03, 0x00845606, 0x005f410d, 0x00231f17, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001b1b1b, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001b1b1b, 0x00141414, 0x001c1c1c, 0x002b2b2b, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00202020, 0x00141414, 0x001b1b1b, 0x001b1b1b, 0x001c1c1c, 0x001a1a1a, 0x00191919, 0x001b1b1b, 0x001a1a1a, + 0x001f1c18, 0x007d5911, 0x00ad7c0f, 0x00b6840f, 0x00bd8d11, 0x00c49312, 0x00ca9914, 0x00c59212, 0x00c08c11, 0x00b8840f, 0x00b37d0d, 0x00ab750b, 0x40ffffff, 0xd5ffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xd4ffffff, 0x3effffff, 0x009d6100, 0x009e6200, 0x009f6300, 0x00a06400, 0x00a16500, 0x00a26600, 0x00a26600, 0x00a36700, 0x00a46800, 0x00a26701, 0x007c5208, 0x001f1c18, + 0x001a1a1a, 0x001b1b1b, 0x00191919, 0x001a1a1a, 0x001c1c1c, 0x001b1b1b, 0x001b1b1b, 0x00141414, 0x00202020, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00242424, 0x00151515, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001b1b1b, 0x00443315, + 0x0095650d, 0x00aa760c, 0x00b17d0e, 0x00bb8410, 0x00c28910, 0x00ca8f11, 0x00cf9513, 0x00c98f11, 0x00c2880f, 0x00bc820e, 0x05ffffff, 0x8bffffff, 0xfeffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xfeffffff, 0x88ffffff, 0x04ffffff, 0x009f6300, 0x00a06400, 0x00a16500, 0x00a26600, 0x00a36700, 0x00a36700, 0x00a46800, 0x00a56900, 0x00a66a00, 0x00986303, + 0x00493511, 0x001b1b1b, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x00151515, 0x00202020, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x002b2b2b, 0x00171717, 0x001e1e1e, 0x001f1f1f, 0x001c1c1c, 0x001a1a1a, 0x00181818, 0x001a1a1a, 0x001c1b1a, 0x006c480f, 0x009b6609, + 0x00a36f0b, 0x00ac750c, 0x00b67c0d, 0x00bd830f, 0x00c5780e, 0x00cd550b, 0x00d04308, 0x00cd3106, 0x00cb2604, 0x1dffffff, 0xc4ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc9ffffff, 0x21ffffff, 0x008d1c00, 0x008e2100, 0x00922d00, 0x00963d00, 0x009f5a00, 0x00a46800, 0x00a56900, 0x00a66a00, 0x00a76b00, + 0x00a66b00, 0x007c570e, 0x001d1c1a, 0x001a1a1a, 0x00181818, 0x001a1a1a, 0x001c1c1c, 0x001f1f1f, 0x001e1e1e, 0x00171717, 0x002b2b2b, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x001c1c1c, 0x00121212, 0x00171717, 0x00171717, 0x001c1c1c, 0x00191919, 0x001a1a1a, 0x001c1b1a, 0x00805009, 0x00965f08, 0x009e6709, + 0x00a76d0b, 0x00af730c, 0x00bb670b, 0x00cd1e04, 0x00d10000, 0x00d00000, 0x00cf0000, 0x00ce0000, 0x4dffffff, 0xedffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xecffffff, 0x4bffffff, 0x00850000, 0x00840000, 0x00830000, 0x00830000, 0x00891700, 0x009f5600, 0x00a66a00, 0x00a76b00, + 0x00a86c00, 0x00ad7508, 0x00a17414, 0x001d1c1a, 0x001a1a1a, 0x00191919, 0x001c1c1c, 0x00171717, 0x00171717, 0x00121212, 0x001c1c1c, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00242424, 0x00151515, 0x001b1b1b, 0x001b1b1b, 0x00191919, 0x001b1b1b, 0x001b1b1b, 0x001b1b1b, 0x00643e0d, 0x00905806, 0x00986108, 0x00a16609, + 0x00a86c0a, 0x00c13f07, 0x00d10300, 0x00d10000, 0x00d00000, 0x00cf0000, 0x02ffffff, 0x8bffffff, 0xfeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfeffffff, 0x88ffffff, 0x02ffffff, 0x00830000, 0x00820000, 0x00810000, 0x00820200, 0x00943700, 0x00a76a00, + 0x00a86c00, 0x00af770a, 0x00b58213, 0x0087681d, 0x001b1b1b, 0x001b1b1b, 0x001b1b1b, 0x00191919, 0x001a1a1a, 0x001b1b1b, 0x00151515, 0x00242424, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, + 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x001c1c1c, 0x00111111, 0x00151515, 0x001d1d1d, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x003a2813, 0x00875005, 0x00905806, 0x009a6008, 0x00a85908, + 0x00ca1702, 0x00d20000, 0x00d10000, 0x00d00000, 0x00cf0000, 0x06ffffff, 0xa8ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xadffffff, 0x08ffffff, 0x00810000, 0x00800000, 0x00800000, 0x007f0000, 0x00871600, + 0x00a35f00, 0x00af770a, 0x00b68415, 0x00bb8c1e, 0x0052441f, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001d1d1d, 0x00151515, 0x00111111, 0x001c1c1c, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, + 0x00ffffff, 0x00000000, 0x00000000, 0x002b2b2b, 0x00171717, 0x001b1b1b, 0x001a1a1a, 0x00181818, 0x001a1a1a, 0x001a1a1a, 0x001b1a19, 0x00764306, 0x00895105, 0x00935807, 0x009b5f08, 0x00c91602, + 0x00d20000, 0x00d10000, 0x00d00000, 0x00cf0000, 0x0cffffff, 0xb9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xbdffffff, 0x0effffff, 0x00800000, 0x007f0000, 0x007e0000, 0x007e0000, + 0x00861700, 0x00af780c, 0x00b68415, 0x00bd8e1e, 0x00b28e28, 0x00201f1a, 0x001a1a1a, 0x001a1a1a, 0x00181818, 0x001a1a1a, 0x001b1b1b, 0x00171717, 0x002b2b2b, 0x00000000, 0x00000000, 0x00ffffff, + 0x00000000, 0x00000000, 0x00000000, 0x00202020, 0x00121212, 0x00171717, 0x001e1e1e, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x005c350a, 0x00824903, 0x008b5205, 0x00935807, 0x00b53304, 0x00d20000, + 0x00d10000, 0x00d00000, 0x00d00000, 0x13ffffff, 0xc7ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xccffffff, 0x16ffffff, 0x007f0000, 0x007e0000, 0x007d0000, + 0x007c0000, 0x00984106, 0x00b68415, 0x00be9020, 0x00c49b2a, 0x00967d2d, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001e1e1e, 0x00171717, 0x00121212, 0x00202020, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00333333, 0x001c1c1c, 0x00202020, 0x001d1d1d, 0x001a1a1a, 0x001b1b1b, 0x001a1a1a, 0x00211c18, 0x007a4103, 0x00854b04, 0x008c5205, 0x009f4b06, 0x00d10300, 0x00d10000, + 0x00d00000, 0x00cf0000, 0x20ffffff, 0xdaffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd9ffffff, 0x1fffffff, 0x007d0000, 0x007c0000, + 0x007c0000, 0x007c0300, 0x00ad7013, 0x00be9020, 0x00c59d2b, 0x00c8a534, 0x0026241c, 0x001a1a1a, 0x001b1b1b, 0x001a1a1a, 0x001d1d1d, 0x00202020, 0x001c1c1c, 0x00333333, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x002b2b2b, 0x00171717, 0x001b1b1b, 0x001a1a1a, 0x001c1c1c, 0x00181818, 0x001b1b1b, 0x00482a0d, 0x007e4302, 0x00854a04, 0x008e5305, 0x00c31602, 0x00d10000, 0x00d00000, + 0x00cf0000, 0x15ffffff, 0xd8ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xdcffffff, 0x17ffffff, 0x007c0000, + 0x007b0000, 0x007a0000, 0x00892106, 0x00bf9222, 0x00c59d2b, 0x00cdaa37, 0x0076672d, 0x001b1b1b, 0x00181818, 0x001c1c1c, 0x001a1a1a, 0x001b1b1b, 0x00171717, 0x002b2b2b, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00242424, 0x00151515, 0x00181818, 0x00171717, 0x001a1a1a, 0x001a1a1a, 0x001c1c1c, 0x00623407, 0x007e4302, 0x00874c04, 0x00964a04, 0x00d10000, 0x00d00000, 0x00cf0000, + 0x0dffffff, 0xcdffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xcbffffff, 0x0dffffff, + 0x007a0000, 0x007a0000, 0x00790100, 0x00b7821e, 0x00c79f2d, 0x00cdaa37, 0x00aa9238, 0x001c1c1c, 0x001a1a1a, 0x001a1a1a, 0x00171717, 0x00181818, 0x00151515, 0x00242424, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00242424, 0x00121212, 0x00161616, 0x001c1c1c, 0x001d1d1d, 0x001c1c1c, 0x001a1a1a, 0x006d3804, 0x007e4302, 0x00874c04, 0x00a93103, 0x00d00000, 0x00cf0000, 0x06ffffff, + 0xb9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xbeffffff, + 0x07ffffff, 0x00790000, 0x00780000, 0x00a25614, 0x00c79f2d, 0x00cdaa37, 0x00c1a53e, 0x001a1a1a, 0x001c1c1c, 0x001d1d1d, 0x001c1c1c, 0x00161616, 0x00121212, 0x00242424, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00202020, 0x00222222, 0x001f1f1f, 0x001b1b1b, 0x001b1b1b, 0x001a1a1a, 0x001b1b1b, 0x00723a02, 0x007f4502, 0x00874c04, 0x00b32603, 0x00cf0000, 0x02ffffff, 0xaaffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xa7ffffff, 0x02ffffff, 0x00770000, 0x00984310, 0x00c79f2d, 0x00ceac39, 0x00cbae40, 0x001b1b1b, 0x001a1a1a, 0x001b1b1b, 0x001b1b1b, 0x001f1f1f, 0x00222222, 0x00202020, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x001c1c1c, 0x00202020, 0x001d1d1d, 0x001a1a1a, 0x001a1a1a, 0x00191919, 0x001c1b1a, 0x00783d01, 0x007f4502, 0x00884d04, 0x00b81e02, 0x00cd0000, 0x8bffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf7ffffff, 0xd1ffffff, 0xbbffffff, 0xaeffffff, 0xa3ffffff, 0x98ffffff, + 0x98ffffff, 0xa2ffffff, 0xadffffff, 0xbbffffff, 0xd1ffffff, 0xf7ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0x87ffffff, 0x00770000, 0x0090350d, 0x00c8a12f, 0x00ceac39, 0x00d5b844, 0x001e1d1b, 0x00191919, 0x001a1a1a, 0x001a1a1a, 0x001d1d1d, 0x00202020, 0x001c1c1c, 0x00000000, 0x00000000, + 0x00000000, 0x00333333, 0x001c1c1c, 0x001e1e1e, 0x001c1c1c, 0x00181818, 0x001a1a1a, 0x001c1c1c, 0x00211c18, 0x00793d01, 0x00814603, 0x00884d04, 0x00ba1b02, 0x4dffffff, 0xfeffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf4ffffff, 0xb8ffffff, 0x77ffffff, 0x46ffffff, 0x20ffffff, 0x02ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x02ffffff, 0x20ffffff, 0x47ffffff, 0x78ffffff, 0xb9ffffff, 0xf4ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xfeffffff, 0x4affffff, 0x008d2f0c, 0x00c8a12f, 0x00d0ae3a, 0x00d6b944, 0x0028271e, 0x001c1c1c, 0x001a1a1a, 0x00181818, 0x001c1c1c, 0x001e1e1e, 0x001c1c1c, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001c1c1c, 0x001e1e1e, 0x001b1b1b, 0x001e1e1e, 0x001d1d1d, 0x001b1b1b, 0x00221d19, 0x007a3f01, 0x00814603, 0x00884d04, 0x1effffff, 0xedffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xe5ffffff, 0x8affffff, 0x3cffffff, 0x05ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x06ffffff, 0x3dffffff, 0x8cffffff, 0xe6ffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xebffffff, 0x1cffffff, 0x00c8a12f, 0x00d0ae3a, 0x00d6b944, 0x0029271f, 0x001b1b1b, 0x001d1d1d, 0x001e1e1e, 0x001b1b1b, 0x001e1e1e, 0x001c1c1c, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001e1e1e, 0x001b1b1b, 0x001d1d1d, 0x001c1c1c, 0x001b1b1b, 0x00221d19, 0x007a3f01, 0x00814603, 0x05ffffff, 0xc6ffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfaffffff, + 0xa5ffffff, 0x47ffffff, 0x03ffffff, 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, + 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00414141, 0x00292929, 0x001a1a1a, 0x00303030, 0x003c3c3c, 0x03ffffff, 0x48ffffff, 0xa6ffffff, + 0xfaffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xc3ffffff, 0x04ffffff, 0x00d0ae3a, 0x00d7bb46, 0x0029271f, 0x001b1b1b, 0x001c1c1c, 0x001d1d1d, 0x001b1b1b, 0x001e1e1e, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001d1d1d, 0x001c1c1c, 0x001a1a1a, 0x00221d19, 0x007a3f01, 0x00824803, 0x8bffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf8ffffff, 0xa2ffffff, 0x23ffffff, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x1effffff, 0x91ffffff, 0xf6ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x86ffffff, 0x00d1b03c, 0x00d7bb46, 0x0029271f, 0x001a1a1a, 0x001c1c1c, 0x001d1d1d, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x00221d19, 0x007b4002, 0x41ffffff, 0xfeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfbffffff, 0x91ffffff, 0x17ffffff, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00363d36, 0x0001e101, 0x0001e101, 0x0001e101, + 0x0001e101, 0x0001e101, 0x18ffffff, 0x93ffffff, 0xfcffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfdffffff, 0x3dffffff, 0x00d8bd48, 0x0029271f, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x00211d19, 0x06ffffff, 0xd6ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xcbffffff, 0x35ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00363e36, 0x0000ff00, 0x0000ff00, 0x0000ff00, + 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x2fffffff, 0xc5ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd4ffffff, 0x05ffffff, 0x0029271f, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x00211d19, 0x78ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf4ffffff, 0x65ffffff, 0x01ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00363e36, 0x0000ff00, 0x0000ff00, 0x0000ff00, + 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x02ffffff, 0x67ffffff, 0xf5ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x73ffffff, 0x0029271f, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x1dffffff, 0xf3ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd7ffffff, 0x2dffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00363e36, 0x0000ff00, 0x0000ff00, 0x0000ff00, + 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x28ffffff, 0xd2ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf2ffffff, 0x1cffffff, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0xaeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x9fffffff, 0x0affffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00363e36, 0x0000ff00, 0x0000ff00, 0x0000ff00, + 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000f800, 0x0bffffff, 0xa1ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xaaffffff, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x46ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7effffff, 0x001c1c1c, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00363e36, 0x0000ff00, 0x0000ff00, 0x0000ff00, + 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000f800, 0x00000000, 0x00000000, 0x80ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x42ffffff, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0xc3ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xfcffffff, 0x68ffffff, 0x005d5959, 0x005a5757, 0x002d2d2d, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x00424242, 0x003f3f3f, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00383a38, 0x00005000, 0x00005000, 0x00005000, + 0x00005000, 0x00005000, 0x00005000, 0x00005000, 0x00005000, 0x00005000, 0x00005000, 0x00004d00, 0x00000000, 0x00000000, 0x00000000, 0x61ffffff, 0xfbffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc0ffffff, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x3fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xfcffffff, 0x57ffffff, 0x00ad6d6d, 0x00993a3a, 0x007a2f2f, 0x00615d5d, 0x00474444, 0x001d1d1d, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x003a3a3a, 0x00484848, 0x00b1b1b1, 0x00d1d1d1, 0x00c5c5c5, 0x008f8f8f, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x008d8d8d, 0x007a7a7a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00363d36, 0x0000e800, 0x0000e800, 0x0000e800, + 0x0000e800, 0x0000e800, 0x0000e800, 0x0000e800, 0x0000e800, 0x0000e800, 0x0000e800, 0x0000e800, 0x0000e800, 0x0000e800, 0x00008200, 0x00000000, 0x58ffffff, 0xfcffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3cffffff, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0xbbffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x6effffff, 0x00d4d4d4, 0x00d0cece, 0x00bbb4b4, 0x00a78080, 0x00892121, 0x00695151, 0x004e4b4b, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x003a3a3a, 0x00c2c2c2, 0x00898989, 0x003c3c3c, 0x003a3a3a, 0x00616161, 0x003a3a3a, 0x00646464, 0x00828282, 0x00505050, 0x003a3a3a, 0x003a3a3a, 0x00686868, 0x005a5a5a, 0x00757575, + 0x008d8d8d, 0x007a7a7a, 0x003b3b3b, 0x006d6d6d, 0x00808080, 0x004a4a4a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00363e36, 0x0000ff00, 0x0000ff00, 0x0000ff00, + 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x00009000, 0x00000000, 0x00000000, 0x67ffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb7ffffff, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x36ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0x7dffffff, 0x00bababa, 0x00bababa, 0x00c2c2c2, 0x00cdcdcd, 0x00c0bcbc, 0x009d9191, 0x00891f1f, 0x00666060, 0x00343434, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x003f3f3f, 0x00f2f2f2, 0x003d3d3d, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x00868686, 0x006f6f6f, 0x00bcbcbc, 0x00686868, 0x003a3a3a, 0x00e1e1e1, 0x00a5a5a5, 0x00686868, + 0x008d8d8d, 0x007a7a7a, 0x003f3f3f, 0x00878787, 0x00717171, 0x00cacaca, 0x004f4f4f, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00363e36, 0x0000ff00, 0x0000ff00, 0x0000ff00, + 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x00009000, 0x00000000, 0x00000000, 0x00000000, 0x80ffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x34ffffff, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0xb0ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x9fffffff, 0x00a3a3a3, 0x009f9f9f, 0x00a0a0a0, 0x00a6a6a6, 0x00b5b5b5, 0x00c8c8c8, 0x00b7b4b4, 0x008c6767, 0x007f2f2f, 0x00666363, 0x00202020, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x00484848, 0x00e2e2e2, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x006f6f6f, 0x00a5a5a5, 0x00c0c0c0, 0x00a1a1a1, 0x07ffffff, 0x28ffffff, 0x33ffffff, 0x44ffffff, + 0x44ffffff, 0x34ffffff, 0x27ffffff, 0x07ffffff, 0x00a9a9a9, 0x00cbcbcb, 0x00868686, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00363e36, 0x0000ff00, 0x0000ff00, 0x0000ff00, + 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x00009000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xa2ffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xaeffffff, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x20ffffff, 0xfeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd4ffffff, + 0x0affffff, 0x00909090, 0x008a8a8a, 0x008b8b8b, 0x00939393, 0x00a0a0a0, 0x00b4b4b4, 0x00cdcdcd, 0x008d8686, 0x00862929, 0x006c5959, 0x00373737, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x003a3a3a, 0x00e9e9e9, 0x00525252, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x004d4d4d, 0x26ffffff, 0x6bffffff, 0xabffffff, 0xddffffff, 0xfcffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xfcffffff, 0xdcffffff, 0xabffffff, 0x6affffff, 0x26ffffff, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00363e36, 0x0000ff00, 0x0000ff00, 0x0000ff00, + 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x00009000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0bffffff, + 0xd6ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfdffffff, 0x1fffffff, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x7effffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf4ffffff, 0x2affffff, + 0x008d8d8d, 0x007e7e7e, 0x00777777, 0x00787878, 0x00828282, 0x00929292, 0x00a5a5a5, 0x00c0c0c0, 0x00b0afaf, 0x007d4646, 0x00784545, 0x004a4949, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x003a3a3a, 0x00757575, 0x00d9d9d9, 0x00979797, 0x0effffff, 0x6effffff, 0xccffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xcbffffff, 0x6dffffff, 0x0dffffff, 0x003b3b3b, 0x00363e36, 0x0000ff00, 0x0000ff00, 0x0000ff00, + 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x00009000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x2bffffff, 0xf5ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7affffff, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x01ffffff, 0xdaffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x66ffffff, 0x00979797, + 0x00838383, 0x00737373, 0x00696969, 0x006c6c6c, 0x00767676, 0x00898989, 0x009e9e9e, 0x00b8b8b8, 0x00bdbdbd, 0x00735959, 0x00803232, 0x00615b5b, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x10ffffff, 0x83ffffff, 0xefffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xeeffffff, 0x80ffffff, 0x10ffffff, 0x001e661e, 0x001e661e, 0x001e661e, + 0x001e661e, 0x001e661e, 0x001e661e, 0x001e661e, 0x001e661e, 0x001e661e, 0x001e661e, 0x001e661e, 0x001e661e, 0x001e661e, 0x00234b23, 0x002a2a2a, 0x002a2a2a, 0x002a2a2a, 0x002a2a2a, 0x002a2a2a, + 0x002a2a2a, 0x69ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd7ffffff, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x39ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xcaffffff, 0x02ffffff, 0x00959595, + 0x00808080, 0x00707070, 0x005f5f5f, 0x00666666, 0x00747474, 0x00868686, 0x009c9c9c, 0x00b6b6b6, 0x00c7c7c7, 0x00645757, 0x00842727, 0x006b6767, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x01ffffff, 0x5dffffff, 0xe8ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe7ffffff, 0x5cffffff, 0x01ffffff, 0x0026564e, + 0x0026564e, 0x0026564e, 0x0026564e, 0x0026564e, 0x002e3231, 0x002f2f2f, 0x002f2f2f, 0x002f2f2f, 0x002f2f2f, 0x002f2f2f, 0x002f2f2f, 0x002f2f2f, 0x002f2f2f, 0x002f2f2f, 0x002f2f2f, 0x002f2f2f, + 0x002f2f2f, 0x02ffffff, 0xc7ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x35ffffff, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x96ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfcffffff, 0x31ffffff, 0x00b1b1b1, 0x00999999, + 0x00858585, 0x00757575, 0x006d6d6d, 0x006f6f6f, 0x00787878, 0x008b8b8b, 0x009f9f9f, 0x00bababa, 0x00b3b3b3, 0x00674646, 0x00803838, 0x005e5959, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x13ffffff, 0xb3ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb1ffffff, 0x12ffffff, + 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x00001814, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x32ffffff, 0xfcffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x92ffffff, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x07ffffff, 0xedffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x91ffffff, 0x00d1d1d1, 0x00bbbbbb, 0x00a2a2a2, + 0x00919191, 0x00838383, 0x007b7b7b, 0x007c7c7c, 0x00878787, 0x00969696, 0x00a8a8a8, 0x00c4c4c4, 0x00969494, 0x00692929, 0x00784c4c, 0x00484848, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x33ffffff, + 0xe3ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe1ffffff, + 0x31ffffff, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x00001814, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x00444444, 0x95ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xebffffff, 0x05ffffff, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x44ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf7ffffff, 0x19ffffff, 0x00b8b2b2, 0x00cbcbcb, 0x00b2b2b2, + 0x00a0a0a0, 0x00959595, 0x00909090, 0x00919191, 0x00989898, 0x00a4a4a4, 0x00bababa, 0x00c7c7c7, 0x004e4848, 0x00801717, 0x00716666, 0x00363636, 0x001a1a1a, 0x001a1a1a, 0x43ffffff, 0xf2ffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xf1ffffff, 0x41ffffff, 0x0000ffd2, 0x0000ffd2, 0x00001814, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x00444444, 0x18ffffff, 0xf6ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3fffffff, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x85ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x92ffffff, 0x00822222, 0x00a18888, 0x00c3c2c2, 0x00c8c8c8, + 0x00b7b7b7, 0x00aaaaaa, 0x00a5a5a5, 0x00a5a5a5, 0x00adadad, 0x00bcbcbc, 0x00cecece, 0x00726c6c, 0x00672828, 0x007d4343, 0x00666262, 0x001b1b1b, 0x001a1a1a, 0x43ffffff, 0xf8ffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xf7ffffff, 0x40ffffff, 0x0000ffd2, 0x00001814, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x96ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x80ffffff, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0xc6ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfaffffff, 0x1fffffff, 0x00665858, 0x008c2323, 0x00918383, 0x00a9a5a5, + 0x00cecece, 0x00c7c7c7, 0x00c2c2c2, 0x00c3c3c3, 0x00cacaca, 0x00c3c3c3, 0x00635c5c, 0x005a3636, 0x00862424, 0x00737171, 0x002b2b2b, 0x001a1a1a, 0x34ffffff, 0xf2ffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xf0ffffff, 0x30ffffff, 0x00001814, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x1effffff, 0xf9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc2ffffff, 0x00333333, 0x00000000, + 0x00000000, 0x0dffffff, 0xfaffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa5ffffff, 0x001b1b1b, 0x00585454, 0x00695757, 0x00852222, 0x00855353, + 0x00787272, 0x00898080, 0x00a09e9e, 0x00928d8d, 0x006b6262, 0x004b4444, 0x006e1f1f, 0x00833333, 0x00736e6e, 0x00464545, 0x001a1a1a, 0x13ffffff, 0xe2ffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xe0ffffff, 0x11ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0xa7ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf9ffffff, 0x0bffffff, 0x00000000, + 0x00000000, 0x4affffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x46ffffff, 0x001a1a1a, 0x001c1c1c, 0x00444242, 0x00686666, 0x007a3d3d, + 0x00842424, 0x007f2424, 0x00713030, 0x00702626, 0x007b1a1a, 0x00842424, 0x00775454, 0x006f6c6c, 0x00363636, 0x001a1a1a, 0x01ffffff, 0xb3ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb0ffffff, 0x0000382e, 0x0000382e, 0x0000382e, 0x0000382e, 0x0000382e, 0x0000382e, 0x0000382e, 0x0000382e, 0x0000382e, 0x0000382e, 0x00002821, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0x4affffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x47ffffff, 0x00000000, + 0x00000000, 0x8bffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe5ffffff, 0x03ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x002b2b2b, 0x005d5858, + 0x006c6b6b, 0x006e6c6c, 0x00715d5d, 0x00716262, 0x00727171, 0x00706d6d, 0x00565353, 0x00212121, 0x001a1a1a, 0x001a1a1a, 0x5effffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf2ffffff, 0xbbffffff, 0x95ffffff, 0x86ffffff, + 0x87ffffff, 0x95ffffff, 0xbbffffff, 0xf2ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x59ffffff, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000b898, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0x04ffffff, 0xe7ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x88ffffff, 0x00000000, + 0x00000000, 0xc1ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x8bffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001c1c1c, 0x002b2b2b, 0x003b3b3b, 0x00383838, 0x00252525, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x11ffffff, 0xe9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfdffffff, 0xabffffff, 0x45ffffff, 0x04ffffff, 0x00545454, 0x00353535, 0x00393939, + 0x003a3a3a, 0x003b3b3b, 0x00545454, 0x04ffffff, 0x46ffffff, 0xacffffff, 0xfdffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe6ffffff, 0x0fffffff, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000b898, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0x00242424, 0x8dffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xbfffffff, 0x00000000, + 0x00000000, 0xe9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3cffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x82ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc2ffffff, 0x2cffffff, 0x00393939, 0x00393939, 0x00383838, 0x00363636, 0x00393939, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x00383838, 0x00393939, 0x003a3a3a, 0x00353535, 0x2effffff, 0xc4ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7fffffff, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000b898, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0x00242424, 0x3fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe6ffffff, 0x00000000, + 0x10ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf5ffffff, 0x06ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x0dffffff, 0xeeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfeffffff, 0x82ffffff, 0x02ffffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x03ffffff, 0x85ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xedffffff, 0x0dffffff, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000b898, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0x00242424, 0x06ffffff, 0xf4ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x10ffffff, + 0x38ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb7ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x6dffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfeffffff, 0x6affffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x6dffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x6bffffff, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000b898, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0x00242424, 0x004d4d4d, 0xbaffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x35ffffff, + 0x5fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x77ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0xccffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x82ffffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x86ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc9ffffff, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000b898, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0x00242424, 0x004d4d4d, 0x79ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x5dffffff, + 0x86ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x46ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x27ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc3ffffff, 0x02ffffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x03ffffff, 0xc5ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x23ffffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x00444444, 0x00212121, 0x001a1a1a, 0x00242424, 0x004d4d4d, 0x49ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x83ffffff, + 0xa9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x20ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x6bffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xfcffffff, 0x2cffffff, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, + 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x00404040, 0x00292929, 0x001a1a1a, 0x2fffffff, 0xfdffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x67ffffff, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, + 0x003f3f3f, 0x003f3f3f, 0x00434343, 0x001f1f1f, 0x001a1a1a, 0x00242424, 0x004d4d4d, 0x22ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa7ffffff, + 0xb9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf6ffffff, 0x02ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0xacffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xaaffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0xadffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa9ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00242424, 0x004d4d4d, 0x02ffffff, 0xf7ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb7ffffff, + 0xc5ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd1ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0xddffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0x45ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x48ffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xdbffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00242424, 0x004d4d4d, 0x00673535, 0xd3ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc4ffffff, + 0xd3ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xbbffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x07ffffff, 0xfcffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xf1ffffff, 0x04ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x05ffffff, 0xf3ffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfcffffff, 0x06ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00242424, 0x004d4d4d, 0x00673535, 0xbeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd1ffffff, + 0xe0ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xaeffffff, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, + 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x27ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xbbffffff, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, + 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0xbeffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x25ffffff, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, + 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00454545, 0x00474747, 0x004d4d4d, 0x00623a3a, 0xb1ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xdeffffff, + 0xedffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa2ffffff, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, + 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x36ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x96ffffff, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, + 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x98ffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x34ffffff, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, + 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x00554545, 0xa4ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xebffffff, + 0xf9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x95ffffff, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, + 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x43ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x85ffffff, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, + 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x85ffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x42ffffff, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, + 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x00373737, 0x003b3b3b, 0x004d4d4d, 0x00653636, 0x96ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf8ffffff, + 0xf9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x95ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x42ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x84ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x85ffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x42ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00242424, 0x004d4d4d, 0x00663535, 0x96ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf8ffffff, + 0xedffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa2ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x35ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x96ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x98ffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x34ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00242424, 0x004d4d4d, 0x00663535, 0xa4ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xebffffff, + 0xe0ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xafffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x27ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xbcffffff, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, + 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003e3e3e, 0x00262626, 0x001a1a1a, 0x002f2f2f, 0x003d3d3d, 0xbeffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x25ffffff, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, 0x003d3d3d, + 0x003d3d3d, 0x003d3d3d, 0x00404040, 0x001e1e1e, 0x001a1a1a, 0x00242424, 0x004d4d4d, 0x00663535, 0xb1ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xdeffffff, + 0xd3ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xbcffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x07ffffff, 0xfcffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xf2ffffff, 0x04ffffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x06ffffff, 0xf4ffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfbffffff, 0x06ffffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x00444444, 0x00212121, 0x001a1a1a, 0x00242424, 0x004d4d4d, 0x00663535, 0xbeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd1ffffff, + 0xc6ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd2ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0xddffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0x46ffffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x49ffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xdaffffff, 0x000b0b0b, 0x000b0b0b, 0x000b0b0b, 0x000b0b0b, 0x000b0b0b, 0x000b0b0b, 0x000b0b0b, + 0x000b0b0b, 0x001b1b1b, 0x00444444, 0x00212121, 0x001a1a1a, 0x00242424, 0x004d4d4d, 0x00663535, 0xd4ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc4ffffff, + 0xbaffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf6ffffff, 0x02ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0xabffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xabffffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0xafffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa8ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0x00242424, 0x004d4d4d, 0x02ffffff, 0xf7ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb6ffffff, + 0xa9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x20ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x6affffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xfdffffff, 0x2dffffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x31ffffff, 0xfeffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x67ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0x00242424, 0x004d4d4d, 0x22ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa7ffffff, + 0x86ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x46ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x26ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc4ffffff, 0x03ffffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x04ffffff, 0xc7ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfeffffff, 0x22ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0x00242424, 0x004d4d4d, 0x49ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x83ffffff, + 0x5effffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x77ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0xcaffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x85ffffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x89ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc7ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0x00242424, 0x004d4d4d, 0x79ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x5cffffff, + 0x38ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb8ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001b1b1b, + 0x00262626, 0x00323232, 0x00413f3f, 0x003d3c3c, 0x00303030, 0x00222222, 0x001a1a1a, 0x001a1a1a, 0x6cffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x6dffffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x6fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x6affffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0x00242424, 0x004d4d4d, 0xbbffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x35ffffff, + 0x10ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf5ffffff, 0x07ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00313131, 0x00555252, + 0x00575555, 0x005f4949, 0x006e3939, 0x006b3e3e, 0x00605050, 0x005d5d5d, 0x00565252, 0x00282828, 0x0dffffff, 0xedffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x86ffffff, 0x03ffffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x04ffffff, 0x8affffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xecffffff, 0x0dffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0x00242424, 0x07ffffff, 0xf6ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0effffff, + 0x00000000, 0xe9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3dffffff, 0x001a1a1a, 0x001a1a1a, 0x00202020, 0x00484444, 0x00584e4e, 0x007c2525, + 0x00a74d4d, 0x00bb7b7b, 0x00cdadad, 0x00c09898, 0x00a85f5f, 0x00943131, 0x00753636, 0x00615e5e, 0x00413f3f, 0x80ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc6ffffff, 0x2fffffff, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x00808080, 0x00707070, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x30ffffff, 0xc7ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7dffffff, 0x0000d800, 0x0000d800, 0x0000d800, 0x00007900, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0x00242424, 0x40ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe6ffffff, 0x00000000, + 0x00000000, 0xc1ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x8cffffff, 0x001a1a1a, 0x001c1c1c, 0x00514d4d, 0x00673c3c, 0x00972e2e, 0x00dfc6c6, + 0x00e3dcdc, 0x00dddbdb, 0x00d9d9d9, 0x00d5d5d5, 0x00cdc9c9, 0x00bbb5b5, 0x00a47070, 0x00852121, 0x00675555, 0x0fffffff, 0xe7ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfdffffff, 0xadffffff, 0x48ffffff, 0x05ffffff, 0x00434343, 0x003c3c3c, 0x004e4e4e, + 0x008d8d8d, 0x007a7a7a, 0x003a3a3a, 0x05ffffff, 0x49ffffff, 0xaeffffff, 0xfdffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe5ffffff, 0x0effffff, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x00009000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0x00242424, 0x8fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xbfffffff, 0x00000000, + 0x00000000, 0x8affffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe8ffffff, 0x04ffffff, 0x003f3d3d, 0x00604444, 0x00a64444, 0x00ece5e5, 0x00e0dfdf, + 0x00cccccc, 0x00c1c1c1, 0x00bcbcbc, 0x00bdbdbd, 0x00c4c4c4, 0x00cfcfcf, 0x00bab5b5, 0x009d8d8d, 0x00892020, 0x00666262, 0x5bffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf3ffffff, 0xbdffffff, 0x97ffffff, 0x87ffffff, + 0x86ffffff, 0x97ffffff, 0xbeffffff, 0xf4ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x58ffffff, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x00009000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0x04ffffff, 0xe7ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x87ffffff, 0x00000000, + 0x00000000, 0x49ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x48ffffff, 0x00565353, 0x00891f1f, 0x00e6d9d9, 0x00dcdcdc, 0x00c4c4c4, + 0x00b2b2b2, 0x00a5a5a5, 0x00a0a0a0, 0x00a1a1a1, 0x00a8a8a8, 0x00b7b7b7, 0x00cacaca, 0x00b4b0b0, 0x008d6161, 0x007d3232, 0x01ffffff, 0xb2ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xadffffff, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x00009000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0x4bffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x46ffffff, 0x00000000, + 0x00000000, 0x0cffffff, 0xfaffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa6ffffff, 0x00703434, 0x00c68f8f, 0x00e1dddd, 0x00c7c7c7, 0x00aeaeae, + 0x009d9d9d, 0x00929292, 0x008b8b8b, 0x008d8d8d, 0x00949494, 0x00a1a1a1, 0x00b6b6b6, 0x00cdcdcd, 0x008a8484, 0x00872626, 0x006c5b5b, 0x12ffffff, 0xe1ffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xddffffff, 0x10ffffff, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x00009000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x001a1a1a, 0xa8ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf9ffffff, 0x0affffff, 0x00000000, + 0x00000000, 0x00333333, 0xc5ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfaffffff, 0x20ffffff, 0x00ded0d0, 0x00d6d6d6, 0x00b9b9b9, 0x00a0a0a0, + 0x008e8e8e, 0x007f7f7f, 0x00777777, 0x00797979, 0x00838383, 0x00939393, 0x00a6a6a6, 0x00c1c1c1, 0x00afaeae, 0x007d4444, 0x00774646, 0x00494949, 0x31ffffff, 0xf1ffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xefffffff, 0x2dffffff, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x00009000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x00444444, 0x00212121, 0x1effffff, 0xfaffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc1ffffff, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x83ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x94ffffff, 0x00dbd6d6, 0x00cdcdcd, 0x00afafaf, 0x00989898, + 0x00838383, 0x00737373, 0x006a6a6a, 0x006c6c6c, 0x00777777, 0x008a8a8a, 0x009e9e9e, 0x00b9b9b9, 0x00bcbcbc, 0x00745959, 0x00803434, 0x005f5a5a, 0x001a1a1a, 0x40ffffff, 0xf7ffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xf7ffffff, 0x3fffffff, 0x00197119, 0x00197119, 0x00197119, 0x00197119, 0x00197119, 0x00197119, 0x00197119, 0x001f501f, 0x00262626, 0x00262626, 0x00262626, 0x00262626, 0x00262626, + 0x00262626, 0x002d2d2d, 0x00444444, 0x00212121, 0x98ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x80ffffff, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x42ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf7ffffff, 0x1affffff, 0x00cbcbcb, 0x00adadad, 0x00959595, + 0x00808080, 0x006f6f6f, 0x005e5e5e, 0x00666666, 0x00747474, 0x00868686, 0x009c9c9c, 0x00b6b6b6, 0x00c7c7c7, 0x00635757, 0x00842727, 0x006c6868, 0x001a1a1a, 0x001a1a1a, 0x41ffffff, 0xf1ffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xefffffff, 0x3fffffff, 0x00304844, 0x00304844, 0x00353737, 0x00353535, 0x00353535, 0x00353535, 0x00353535, 0x00353535, 0x00353535, 0x00353535, 0x00353535, 0x00353535, 0x00353535, 0x00353535, + 0x00353535, 0x00373737, 0x00444444, 0x19ffffff, 0xf7ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3effffff, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x06ffffff, 0xecffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x93ffffff, 0x00cecece, 0x00b0b0b0, 0x00989898, + 0x00848484, 0x00747474, 0x006c6c6c, 0x006e6e6e, 0x00787878, 0x008a8a8a, 0x009f9f9f, 0x00b9b9b9, 0x00b4b4b4, 0x00664747, 0x00803737, 0x00605b5b, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x31ffffff, + 0xe0ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xdeffffff, + 0x2effffff, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x00001814, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x00444444, 0x97ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xeaffffff, 0x05ffffff, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x95ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfcffffff, 0x31ffffff, 0x00bababa, 0x00a1a1a1, + 0x00909090, 0x00818181, 0x00797979, 0x007b7b7b, 0x00858585, 0x00959595, 0x00a7a7a7, 0x00c3c3c3, 0x00999898, 0x00692b2b, 0x00794b4b, 0x004a4949, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x11ffffff, 0xb0ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xaeffffff, 0x10ffffff, + 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x00001814, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00141414, 0x33ffffff, 0xfcffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x91ffffff, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x38ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xcaffffff, 0x02ffffff, 0x00b1b1b1, + 0x009f9f9f, 0x00949494, 0x008e8e8e, 0x008f8f8f, 0x00979797, 0x00a3a3a3, 0x00b8b8b8, 0x00c9c9c9, 0x00514b4b, 0x007d1717, 0x00716565, 0x00383838, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x00393939, 0x5affffff, 0xe6ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe5ffffff, 0x57ffffff, 0x0000ffd2, 0x0000ffd2, + 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x00001814, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x02ffffff, 0xc8ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x34ffffff, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0xd8ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x68ffffff, 0x00c7c7c7, + 0x00b5b5b5, 0x00a8a8a8, 0x00a3a3a3, 0x00a4a4a4, 0x00ababab, 0x00bababa, 0x00cdcdcd, 0x00797575, 0x00652c2c, 0x007f3f3f, 0x00696565, 0x001d1d1d, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x00393939, 0x00626262, 0x00d7d7d7, 0x0fffffff, 0x7effffff, 0xedffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xecffffff, 0x7cffffff, 0x0dffffff, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, + 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x00001814, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x6bffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd6ffffff, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x7cffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf7ffffff, 0x2fffffff, + 0x00cecece, 0x00c5c5c5, 0x00c0c0c0, 0x00c1c1c1, 0x00c8c8c8, 0x00c6c6c6, 0x006c6666, 0x00573b3b, 0x00862020, 0x00737171, 0x002d2d2d, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x004c4c4c, 0x00848484, 0x00ababab, 0x00bebebe, 0x00aeaeae, 0x0dffffff, 0x6bffffff, 0xc8ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc6ffffff, 0x6affffff, 0x0cffffff, 0x003b3b3b, 0x00363e3d, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, + 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x00001814, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x2cffffff, 0xf5ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x79ffffff, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x1fffffff, 0xfdffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd5ffffff, + 0x0bffffff, 0x00938d8d, 0x00a8a8a8, 0x009b9a9a, 0x00766f6f, 0x004d4747, 0x006a2525, 0x00842b2b, 0x00736a6a, 0x004b4a4a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x005d5d5d, 0x00cbcbcb, 0x00737373, 0x008b8b8b, 0x009d9d9d, 0x008d8d8d, 0x007d7d7d, 0x003c3c3c, 0x23ffffff, 0x68ffffff, 0xa9ffffff, 0xdbffffff, 0xfbffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xfbffffff, 0xdbffffff, 0xa8ffffff, 0x66ffffff, 0x22ffffff, 0x003b3b3b, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00363e3d, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, + 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x00001814, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0cffffff, + 0xd8ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfdffffff, 0x1effffff, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0xaeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xa2ffffff, 0x007b2828, 0x00713c3c, 0x006e2e2e, 0x00761c1c, 0x00822020, 0x007a4d4d, 0x00716f6f, 0x003e3e3e, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x00565656, 0x00bdbdbd, 0x00adadad, 0x009d9d9d, 0x008c8c8c, 0x007c7c7c, 0x006c6c6c, 0x00383838, 0x00464646, 0x00bebebe, 0x00b1b1b1, 0x00a1a1a1, 0x06ffffff, 0x24ffffff, 0x33ffffff, 0x44ffffff, + 0x43ffffff, 0x33ffffff, 0x24ffffff, 0x06ffffff, 0x00959595, 0x00848484, 0x00747474, 0x00494949, 0x003b3b3b, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00383939, 0x0000352b, 0x0000352b, 0x0000352b, + 0x0000352b, 0x0000352b, 0x0000352b, 0x0000352b, 0x0000221c, 0x0000201a, 0x0000201a, 0x0000201a, 0x0000201a, 0x0000201a, 0x0000201a, 0x0000201a, 0x0000201a, 0x0000201a, 0x01ffffff, 0xa6ffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xacffffff, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x31ffffff, 0xfeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0x80ffffff, 0x00745353, 0x00735959, 0x00716d6d, 0x00727171, 0x005d5959, 0x00242424, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x00424242, 0x009a9a9a, 0x009c9c9c, 0x008c8c8c, 0x007b7b7b, 0x006b6b6b, 0x004d4d4d, 0x00353535, 0x003a3a3a, 0x00797979, 0x00a0a0a0, 0x00909090, 0x007f7f7f, 0x006f6f6f, 0x005b5b5b, 0x00353535, + 0x00393939, 0x005b5b5b, 0x00a4a4a4, 0x00949494, 0x00848484, 0x00737373, 0x00636363, 0x00363636, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00363e3d, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, + 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x84ffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x34ffffff, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0xb9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x6effffff, 0x003f3f3f, 0x002c2c2c, 0x001d1d1d, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x00424242, 0x007a7a7a, 0x007b7b7b, 0x006b6b6b, 0x004e4e4e, 0x00353535, 0x003a3a3a, 0x003a3a3a, 0x003f3f3f, 0x006d6d6d, 0x007f7f7f, 0x006f6f6f, 0x00585858, 0x00363636, 0x00393939, + 0x003a3a3a, 0x003b3b3b, 0x005c5c5c, 0x00828282, 0x00737373, 0x00606060, 0x003b3b3b, 0x00383838, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00363e3d, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, + 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x68ffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb5ffffff, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x3effffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xfcffffff, 0x58ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x003a3a3a, 0x00393939, 0x003b3b3b, 0x00393939, 0x00363636, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x00393939, 0x003b3b3b, 0x00393939, 0x00353535, 0x00393939, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x00393939, 0x003b3b3b, 0x003b3b3b, 0x00353535, 0x00383838, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00363e3d, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, + 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x59ffffff, 0xfdffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3affffff, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0xc2ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xfcffffff, 0x69ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00363e3d, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, + 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x6bffffff, 0xfdffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xbeffffff, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x44ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x80ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00363e3d, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, + 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x01ffffff, 0x84ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x40ffffff, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0xacffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa2ffffff, 0x0bffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x00363e3d, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, + 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2, 0x0cffffff, 0xa5ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa8ffffff, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x1cffffff, 0xf3ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd8ffffff, 0x2effffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00444444, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, + 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003a3a3a, 0x003e3e3e, 0x00303030, 0x001a1a1a, 0x003b3b3b, 0x003a3a3a, 0x00334340, 0x00334340, 0x00334340, + 0x00334340, 0x00334340, 0x00334340, 0x00334340, 0x00334340, 0x00334340, 0x00334340, 0x2affffff, 0xd4ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf2ffffff, 0x1bffffff, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x0024201a, 0x75ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf6ffffff, 0x6affffff, 0x02ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00474747, + 0x00434343, 0x00434343, 0x00434343, 0x00434343, 0x00434343, 0x00434343, 0x00434343, 0x00434343, 0x00434343, 0x00434343, 0x00434343, 0x00434343, 0x00434343, 0x00434343, 0x00434343, 0x00434343, + 0x00434343, 0x00434343, 0x00434343, 0x00434343, 0x00434343, 0x00434343, 0x00434343, 0x00434343, 0x00454545, 0x002b2b2b, 0x001a1a1a, 0x00373737, 0x00414141, 0x00414141, 0x00414141, 0x00414141, + 0x00414141, 0x00414141, 0x00414141, 0x00414141, 0x00414141, 0x02ffffff, 0x6cffffff, 0xf6ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x71ffffff, 0x002b2a21, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x0024201a, 0x04ffffff, 0xd1ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xcdffffff, 0x37ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x31ffffff, 0xc7ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd3ffffff, 0x05ffffff, 0x002a2a21, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x0024201a, 0x009f6a0a, 0x3fffffff, 0xfeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfcffffff, 0x95ffffff, 0x19ffffff, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x1affffff, 0x97ffffff, 0xfdffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfdffffff, 0x3bffffff, 0x00fbf67a, 0x002b2a21, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x001d1d1d, 0x001c1c1c, 0x001a1a1a, 0x0024201a, 0x009f6a0a, 0x00a7710b, 0x89ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf9ffffff, 0xa2ffffff, 0x25ffffff, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x1fffffff, 0x91ffffff, 0xf6ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x84ffffff, 0x00f4eb71, 0x00fcf77c, 0x002b2a21, 0x001a1a1a, 0x001c1c1c, 0x001d1d1d, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001a1a1a, 0x001e1e1e, 0x001b1b1b, 0x001d1d1d, 0x001c1c1c, 0x001b1b1b, 0x0024201a, 0x009f6a0a, 0x00a7710b, 0x04ffffff, 0xc4ffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfaffffff, + 0xa7ffffff, 0x49ffffff, 0x03ffffff, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, + 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x003f3f3f, 0x04ffffff, 0x4bffffff, 0xa9ffffff, + 0xfbffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xc1ffffff, 0x04ffffff, 0x00f6ed73, 0x00fcf77c, 0x002b2a21, 0x001b1b1b, 0x001c1c1c, 0x001d1d1d, 0x001b1b1b, 0x001e1e1e, 0x001a1a1a, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001c1c1c, 0x001e1e1e, 0x001b1b1b, 0x001e1e1e, 0x001d1d1d, 0x001b1b1b, 0x0024201a, 0x00a06b0a, 0x00a7710b, 0x00af780c, 0x1dffffff, 0xecffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xe7ffffff, 0x8effffff, 0x3fffffff, 0x07ffffff, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, + 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x004d4d4d, 0x07ffffff, 0x40ffffff, 0x8fffffff, 0xe8ffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xeaffffff, 0x1bffffff, 0x00efe369, 0x00f6ed73, 0x00faf57a, 0x002b2a21, 0x001b1b1b, 0x001d1d1d, 0x001e1e1e, 0x001b1b1b, 0x001e1e1e, 0x001c1c1c, 0x00333333, 0x00000000, + 0x00000000, 0x00333333, 0x001c1c1c, 0x001e1e1e, 0x001c1c1c, 0x00181818, 0x001a1a1a, 0x001c1c1c, 0x00231f19, 0x00a06b0a, 0x00a8720c, 0x00af780c, 0x00922804, 0x4bffffff, 0xfeffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf5ffffff, 0xbaffffff, 0x79ffffff, 0x48ffffff, 0x22ffffff, 0x03ffffff, 0x008f0c0c, 0x008f0c0c, 0x008e0c0c, 0x008e0c0c, 0x008d0c0c, + 0x008d0c0c, 0x008d0c0c, 0x008c0c0c, 0x008b0c0c, 0x008b0c0c, 0x03ffffff, 0x22ffffff, 0x48ffffff, 0x7affffff, 0xbbffffff, 0xf6ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xfdffffff, 0x48ffffff, 0x0069441e, 0x00efe369, 0x00f7f075, 0x00faf57a, 0x002a2920, 0x001c1c1c, 0x001a1a1a, 0x00181818, 0x001c1c1c, 0x001e1e1e, 0x001c1c1c, 0x00333333, 0x00000000, + 0x00000000, 0x00000000, 0x001c1c1c, 0x00202020, 0x001d1d1d, 0x001a1a1a, 0x001a1a1a, 0x00191919, 0x001c1b1a, 0x00a16c0a, 0x00a8720c, 0x00b0790d, 0x00942e05, 0x00810000, 0x88ffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf8ffffff, 0xd4ffffff, 0xbbffffff, 0xafffffff, 0xa3ffffff, 0x98ffffff, + 0x98ffffff, 0xa3ffffff, 0xafffffff, 0xbbffffff, 0xd5ffffff, 0xf8ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0x84ffffff, 0x002f0000, 0x00714d22, 0x00f1e56b, 0x00f7f075, 0x00f9f479, 0x001e1e1c, 0x00191919, 0x001a1a1a, 0x001a1a1a, 0x001d1d1d, 0x00202020, 0x001c1c1c, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00202020, 0x00222222, 0x001f1f1f, 0x001b1b1b, 0x001b1b1b, 0x001a1a1a, 0x001b1b1b, 0x009b680b, 0x00a7730c, 0x00b0790d, 0x00993a06, 0x00800000, 0x01ffffff, 0xa1ffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xa6ffffff, 0x02ffffff, 0x002e0000, 0x0081612b, 0x00f1e56b, 0x00f7f075, 0x00ece773, 0x001b1b1b, 0x001a1a1a, 0x001b1b1b, 0x001b1b1b, 0x001f1f1f, 0x00222222, 0x00202020, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00242424, 0x00121212, 0x00161616, 0x001c1c1c, 0x001d1d1d, 0x001c1c1c, 0x001a1a1a, 0x0093640c, 0x00a9750c, 0x00b0790d, 0x00a14d09, 0x007f0000, 0x007f0000, 0x05ffffff, + 0xb8ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xbdffffff, + 0x07ffffff, 0x002d0000, 0x002c0000, 0x009d823a, 0x00f1e56b, 0x00f8f276, 0x00e0db6e, 0x001a1a1a, 0x001c1c1c, 0x001d1d1d, 0x001c1c1c, 0x00161616, 0x00121212, 0x00242424, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00242424, 0x00151515, 0x00181818, 0x00171717, 0x001a1a1a, 0x001a1a1a, 0x001c1c1c, 0x00845b0f, 0x00a9750c, 0x00b17b0e, 0x00b1730d, 0x007f0100, 0x007e0000, 0x007d0000, + 0x0affffff, 0xc6ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xcbffffff, 0x0cffffff, + 0x002d0000, 0x002c0000, 0x002c0100, 0x00d6c358, 0x00f2e76d, 0x00f8f276, 0x00c5bf61, 0x001c1c1c, 0x001a1a1a, 0x001a1a1a, 0x00171717, 0x00181818, 0x00151515, 0x00242424, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x002b2b2b, 0x00171717, 0x001b1b1b, 0x001a1a1a, 0x001c1c1c, 0x00181818, 0x001b1b1b, 0x005e4313, 0x00aa760c, 0x00b17c0e, 0x00b9830f, 0x008f2404, 0x007d0000, 0x007c0000, + 0x007c0000, 0x14ffffff, 0xd7ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xdbffffff, 0x17ffffff, 0x002d0000, + 0x002c0000, 0x002b0000, 0x005b3717, 0x00ecdd64, 0x00f2e76d, 0x00f9f478, 0x00888448, 0x001b1b1b, 0x00181818, 0x001c1c1c, 0x001a1a1a, 0x001b1b1b, 0x00171717, 0x002b2b2b, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00333333, 0x001c1c1c, 0x00202020, 0x001d1d1d, 0x001a1a1a, 0x001b1b1b, 0x001a1a1a, 0x00242019, 0x00a7740d, 0x00b17e0e, 0x00b9830f, 0x00b4740e, 0x007e0501, 0x007c0000, + 0x007b0000, 0x007a0000, 0x1fffffff, 0xd9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd9ffffff, 0x1fffffff, 0x002d0000, 0x002c0000, + 0x002b0000, 0x00300602, 0x00c9b34d, 0x00ecdd64, 0x00f2e76d, 0x00f4ef76, 0x00292820, 0x001a1a1a, 0x001b1b1b, 0x001a1a1a, 0x001d1d1d, 0x00202020, 0x001c1c1c, 0x00333333, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00202020, 0x00121212, 0x00171717, 0x001e1e1e, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x007b5811, 0x00b27f0e, 0x00b88410, 0x00c08a10, 0x00a44e0a, 0x007b0000, + 0x007a0000, 0x007a0000, 0x00790000, 0x12ffffff, 0xc6ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xcbffffff, 0x16ffffff, 0x002d0000, 0x002c0000, 0x002b0000, + 0x002a0000, 0x008c6c2c, 0x00e5d25a, 0x00ecdd64, 0x00f3e96f, 0x00b5b25c, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001e1e1e, 0x00171717, 0x00121212, 0x00202020, 0x00000000, 0x00000000, 0x00000000, + 0x00ffffff, 0x00000000, 0x00000000, 0x002b2b2b, 0x00171717, 0x001b1b1b, 0x001a1a1a, 0x00181818, 0x001a1a1a, 0x001a1a1a, 0x001c1b19, 0x00a07310, 0x00b88710, 0x00c08b10, 0x00c79112, 0x008b2104, + 0x007a0000, 0x00790000, 0x00780000, 0x00780000, 0x0bffffff, 0xb7ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xbdffffff, 0x0effffff, 0x002d0000, 0x002c0000, 0x002b0000, 0x002a0000, + 0x004e290f, 0x00dec550, 0x00e5d25a, 0x00eddf66, 0x00dcd466, 0x0022221d, 0x001a1a1a, 0x001a1a1a, 0x00181818, 0x001a1a1a, 0x001b1b1b, 0x00171717, 0x002b2b2b, 0x00000000, 0x00000000, 0x00ffffff, + 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x001c1c1c, 0x00111111, 0x00151515, 0x001d1d1d, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x00493916, 0x00b68510, 0x00c08f12, 0x00c79212, 0x00c08310, + 0x008b2204, 0x00780000, 0x00780000, 0x00770000, 0x00760000, 0x06ffffff, 0xa6ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa5ffffff, 0x06ffffff, 0x002d0000, 0x002c0000, 0x002b0000, 0x00290000, 0x00502a0e, + 0x00c3a740, 0x00dfc751, 0x00e6d45c, 0x00eadc65, 0x00625f37, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001d1d1d, 0x00151515, 0x00111111, 0x001c1c1c, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, + 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00242424, 0x00151515, 0x001b1b1b, 0x001b1b1b, 0x00191919, 0x001b1b1b, 0x001c1c1c, 0x001b1b1b, 0x00846414, 0x00c09012, 0x00c69513, 0x00c89312, + 0x00c18c11, 0x009e4b09, 0x00790400, 0x00760000, 0x00760000, 0x00750000, 0x02ffffff, 0x87ffffff, 0xfeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfdffffff, 0x84ffffff, 0x01ffffff, 0x002d0000, 0x002c0000, 0x002b0000, 0x002e0501, 0x00825c1c, 0x00d1b13e, + 0x00d8bd48, 0x00e0c953, 0x00e6d45c, 0x00a79f4e, 0x001b1b1b, 0x001b1b1b, 0x001b1b1b, 0x00191919, 0x001a1a1a, 0x001b1b1b, 0x00151515, 0x00242424, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x001c1c1c, 0x00121212, 0x00171717, 0x00171717, 0x001c1c1c, 0x00191919, 0x001a1a1a, 0x001d1c1a, 0x00a97f13, 0x00c89913, 0x00c79713, + 0x00c08d10, 0x00bb850f, 0x00ab6c0b, 0x00852003, 0x00750000, 0x00740000, 0x00740000, 0x00730000, 0x44ffffff, 0xe8ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xebffffff, 0x49ffffff, 0x002e0000, 0x002d0000, 0x002c0000, 0x002a0000, 0x004e2408, 0x00ac8323, 0x00cca835, 0x00d2b23e, + 0x00dabf49, 0x00e0c953, 0x00ccbc55, 0x001f1e1c, 0x001a1a1a, 0x00191919, 0x001c1c1c, 0x00171717, 0x00171717, 0x00121212, 0x001c1c1c, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x002b2b2b, 0x001a1a1a, 0x001e1e1e, 0x001f1f1f, 0x001d1d1d, 0x001b1b1b, 0x00181818, 0x001a1a1a, 0x001e1d1a, 0x008c6e16, 0x00c39513, + 0x00c09011, 0x00ba860f, 0x00b47e0d, 0x00af780c, 0x00a36409, 0x008f3f05, 0x00852d03, 0x007f2202, 0x007a1a01, 0x1cffffff, 0xc3ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc1ffffff, 0x1bffffff, 0x00532100, 0x00592600, 0x00643201, 0x00794707, 0x00a77714, 0x00be9020, 0x00c59d2b, 0x00cca835, 0x00d3b440, + 0x00d7bc48, 0x009e9041, 0x001e1e1b, 0x001a1a1a, 0x00181818, 0x001a1a1a, 0x001c1c1c, 0x001f1f1f, 0x001e1e1e, 0x00171717, 0x002b2b2b, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00242424, 0x00151515, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x00181818, 0x001a1a1a, 0x001b1b1b, 0x004e4018, + 0x00ad8312, 0x00ba880f, 0x00b3810e, 0x00ad770c, 0x00a8710a, 0x00a16809, 0x009b6207, 0x00945b05, 0x008e5304, 0x00874c02, 0x04ffffff, 0x87ffffff, 0xfeffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xfdffffff, 0x85ffffff, 0x04ffffff, 0x00a66a00, 0x00a66a00, 0x00a76b00, 0x00aa6f02, 0x00b17b0d, 0x00b78617, 0x00bf9222, 0x00c59d2b, 0x00cdaa37, 0x00bea23c, + 0x00564d29, 0x001b1b1b, 0x001a1a1a, 0x00181818, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x00151515, 0x00202020, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00202020, 0x00141414, 0x001b1b1b, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x00191919, 0x001c1c1c, 0x001a1a1a, + 0x001c1b19, 0x00856413, 0x00af7d0f, 0x00ad790c, 0x00a6720a, 0x00a06a09, 0x009a6207, 0x00945b05, 0x008d5304, 0x00874c02, 0x00814500, 0x00874c02, 0x3dffffff, 0xd3ffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xd1ffffff, 0x3cffffff, 0x00a46800, 0x00a56900, 0x00a66a00, 0x00a76b00, 0x00a76b00, 0x00ab7104, 0x00b17b0d, 0x00b98819, 0x00bf9222, 0x00c39c2d, 0x00927b2e, 0x001d1c1a, + 0x001a1a1a, 0x001b1b1b, 0x00191919, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001b1b1b, 0x00141414, 0x00202020, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00333333, 0x001c1c1c, 0x00141414, 0x001b1b1b, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001b1b1b, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x00252119, 0x00624913, 0x00865e0e, 0x0091600a, 0x00935e08, 0x00935b05, 0x008c5303, 0x00874c02, 0x00814500, 0x00874c02, 0x008f5404, 0x04ffffff, 0x6fffffff, 0xf1ffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xf4ffffff, 0x80ffffff, 0x06ffffff, 0x00a36700, 0x00a46800, 0x00a56900, 0x00a66a00, 0x00a76b00, 0x00a76c00, 0x00a36c05, 0x00a27210, 0x00956f19, 0x006c561e, 0x0026241b, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001b1b1b, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001b1b1b, 0x00141414, 0x001c1c1c, 0x002b2b2b, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x002b2b2b, 0x001c1c1c, 0x00141414, 0x001c1c1c, 0x00141414, 0x00171717, 0x00191919, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001b1b1b, 0x00191919, 0x001a1a1a, 0x001b1b1b, 0x001c1b1a, 0x00231e18, 0x00211d17, 0x00211c17, 0x00231f19, 0x00231f19, 0x00242019, 0x0024201a, 0x1affffff, + 0xa2ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb3ffffff, + 0x1effffff, 0x00252019, 0x00252019, 0x00252019, 0x00252119, 0x00231f17, 0x00231f17, 0x00252018, 0x001d1c19, 0x001b1b1b, 0x001a1a1a, 0x00191919, 0x001b1b1b, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x00191919, 0x00171717, 0x00141414, 0x001c1c1c, 0x00141414, 0x001c1c1c, 0x002b2b2b, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00333333, 0x00202020, 0x00151515, 0x001e1e1e, 0x00171717, 0x001b1b1b, 0x001d1d1d, + 0x00181818, 0x001a1a1a, 0x001b1b1b, 0x00181818, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00191919, 0x001b1b1b, 0x001b1b1b, 0x001b1b1b, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x42ffffff, 0xc1ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xbeffffff, 0x40ffffff, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001b1b1b, 0x001b1b1b, 0x001b1b1b, 0x00191919, 0x001a1a1a, 0x001c1c1c, 0x001a1a1a, 0x00181818, 0x001b1b1b, 0x001a1a1a, 0x00181818, + 0x001d1d1d, 0x001a1a1a, 0x00171717, 0x001e1e1e, 0x00151515, 0x00202020, 0x00333333, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00333333, 0x00242424, 0x00171717, 0x00121212, 0x001b1b1b, 0x00151515, + 0x001a1a1a, 0x001e1e1e, 0x001a1a1a, 0x001d1d1d, 0x001a1a1a, 0x00181818, 0x001b1b1b, 0x001a1a1a, 0x00191919, 0x00191919, 0x00181818, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, + 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x3bffffff, 0xb3ffffff, 0xfeffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc4ffffff, 0x42ffffff, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, + 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x00181818, 0x00191919, 0x00191919, 0x001a1a1a, 0x001b1b1b, 0x00181818, 0x001a1a1a, 0x001d1d1d, 0x001a1a1a, 0x001e1e1e, 0x001a1a1a, + 0x00151515, 0x001b1b1b, 0x00121212, 0x00171717, 0x00242424, 0x00333333, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x002b2b2b, 0x001c1c1c, 0x00151515, 0x00222222, + 0x001c1c1c, 0x00171717, 0x001d1d1d, 0x001a1a1a, 0x00171717, 0x001c1c1c, 0x001b1b1b, 0x001a1a1a, 0x00181818, 0x00181818, 0x00171717, 0x001d1d1d, 0x001d1d1d, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, + 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x33ffffff, 0xaeffffff, 0xfdffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfdffffff, 0xacffffff, 0x31ffffff, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, + 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001d1d1d, 0x001d1d1d, 0x00171717, 0x00181818, 0x00181818, 0x001a1a1a, 0x001b1b1b, 0x001c1c1c, 0x00171717, 0x001a1a1a, 0x001d1d1d, 0x00171717, 0x001b1b1b, + 0x00222222, 0x00151515, 0x001c1c1c, 0x002b2b2b, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00333333, 0x00242424, 0x001c1c1c, + 0x00171717, 0x00121212, 0x00202020, 0x001b1b1b, 0x00181818, 0x00161616, 0x001f1f1f, 0x001d1d1d, 0x001c1c1c, 0x001b1b1b, 0x001b1b1b, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x1cffffff, 0x6fffffff, 0xd0ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd7ffffff, 0x80ffffff, 0x22ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001b1b1b, 0x001b1b1b, 0x001c1c1c, 0x001d1d1d, 0x001f1f1f, 0x00161616, 0x00181818, 0x001b1b1b, 0x00202020, 0x00121212, 0x00171717, + 0x001c1c1c, 0x00242424, 0x00333333, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00333333, + 0x002b2b2b, 0x00202020, 0x001c1c1c, 0x00171717, 0x00151515, 0x00121212, 0x00111111, 0x00202020, 0x00202020, 0x001e1e1e, 0x001e1e1e, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, + 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x2bffffff, 0x88ffffff, 0xe9ffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeffffff, 0x99ffffff, 0x3cffffff, 0x01ffffff, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, + 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001e1e1e, 0x001e1e1e, 0x00202020, 0x00202020, 0x00111111, 0x00121212, 0x00151515, 0x00171717, 0x001c1c1c, 0x00202020, 0x002b2b2b, + 0x00333333, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x002b2b2b, 0x00242424, 0x00242424, 0x00202020, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x06ffffff, 0x40ffffff, 0x81ffffff, 0xc3ffffff, + 0xfaffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf9ffffff, + 0xc2ffffff, 0x80ffffff, 0x3fffffff, 0x05ffffff, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, + 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001a1a1a, 0x001c1c1c, 0x001c1c1c, 0x001c1c1c, 0x00202020, 0x00242424, 0x00242424, 0x002b2b2b, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, + 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, + 0x0bffffff, 0x47ffffff, 0x88ffffff, 0xbfffffff, 0xe7ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe6ffffff, 0xbfffffff, 0x88ffffff, 0x46ffffff, 0x0bffffff, + 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, + 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00333333, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0fffffff, 0x35ffffff, 0x5dffffff, 0x84ffffff, 0xa6ffffff, 0xb8ffffff, 0xc4ffffff, 0xd0ffffff, 0xddffffff, 0xedffffff, 0xf9ffffff, + 0xf9ffffff, 0xedffffff, 0xddffffff, 0xd0ffffff, 0xc4ffffff, 0xb8ffffff, 0xa5ffffff, 0x84ffffff, 0x5cffffff, 0x35ffffff, 0x0fffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, +}; + +static constexpr const uint32_t sCardinalX11IconSize = 2 + 16 * 16 + 2 + 48 * 48 + 2 + 128 * 128; + +// declaration first, ensuring extern/visiblity status is respected +extern const unsigned long* gCardinalX11Icon; + +// definition afterwards +const unsigned long* gCardinalX11Icon = sCardinalX11Icon; diff --git a/src/MOD/Cardinal.lv2/modgui/stylesheet.css b/src/MOD/Cardinal.lv2/modgui/stylesheet.css index 6065621e..8b373a1e 100644 --- a/src/MOD/Cardinal.lv2/modgui/stylesheet.css +++ b/src/MOD/Cardinal.lv2/modgui/stylesheet.css @@ -73,6 +73,7 @@ align-items: center; justify-content: space-evenly; justify-content: space-between; + white-space: nowrap; } .cardinal-main.mod-pedal .visibility-buttons span { diff --git a/src/MOD/CardinalFX.lv2/modgui/icon.html b/src/MOD/CardinalFX.lv2/modgui/icon.html index f5062704..0138ac96 100644 --- a/src/MOD/CardinalFX.lv2/modgui/icon.html +++ b/src/MOD/CardinalFX.lv2/modgui/icon.html @@ -5,7 +5,7 @@
-
DISTRHO Cardinal - Mini -
+
DISTRHO Cardinal - FX -
diff --git a/src/MOD/CardinalMini.lv2/modgui/screenshot.png b/src/MOD/CardinalMini.lv2/modgui/screenshot.png new file mode 100644 index 00000000..8b92b9e2 Binary files /dev/null and b/src/MOD/CardinalMini.lv2/modgui/screenshot.png differ diff --git a/src/MOD/CardinalMini.lv2/modgui/thumbnail.png b/src/MOD/CardinalMini.lv2/modgui/thumbnail.png new file mode 100644 index 00000000..0fd025ae Binary files /dev/null and b/src/MOD/CardinalMini.lv2/modgui/thumbnail.png differ diff --git a/src/Makefile b/src/Makefile index 9b1c3d03..805cdfec 100644 --- a/src/Makefile +++ b/src/Makefile @@ -4,125 +4,30 @@ # Created by falkTX # -# -------------------------------------------------------------- -# Import base definitions - -DISTRHO_NAMESPACE = CardinalDISTRHO -DGL_NAMESPACE = CardinalDGL -USE_NANOVG_FBO = true -WASM_EXCEPTIONS = true -include ../dpf/Makefile.base.mk - -# -------------------------------------------------------------- -# Build config - -ifeq ($(BSD),true) -SYSDEPS ?= true -else -SYSDEPS ?= false -endif +BUILDING_RACK = true +ROOT = .. +include $(ROOT)/Makefile.base.mk # -------------------------------------------------------------- # Build setup -BUILD_DIR = ../build/rack - -ifeq ($(MACOS),true) -BASE_FLAGS += -DARCH_MAC -else ifeq ($(WINDOWS),true) -BASE_FLAGS += -DARCH_WIN +ifeq ($(HEADLESS),true) +BUILD_DIR = ../build-headless/rack else -BASE_FLAGS += -DARCH_LIN -endif - -ifeq ($(HAIKU),true) -BASE_FLAGS += -I../include/linux-compat -else ifeq ($(WASM),true) -BASE_FLAGS += -I../include/linux-compat +BUILD_DIR = ../build/rack endif BASE_FLAGS += -DPRIVATE= -BASE_FLAGS += -I../dpf/dgl/src/nanovg -BASE_FLAGS += -I../dpf/distrho -BASE_FLAGS += -I../include -BASE_FLAGS += -I../include/simd-compat -BASE_FLAGS += -IRack/include -ifeq ($(SYSDEPS),true) -BASE_FLAGS += -DCARDINAL_SYSDEPS -BASE_FLAGS += $(shell pkg-config --cflags jansson libarchive samplerate speexdsp) -else -BASE_FLAGS += -DZSTDLIB_VISIBILITY= -BASE_FLAGS += -IRack/dep/include -endif -BASE_FLAGS += -IRack/dep/filesystem/include -BASE_FLAGS += -IRack/dep/fuzzysearchdatabase/src -BASE_FLAGS += -IRack/dep/glfw/include -BASE_FLAGS += -IRack/dep/nanosvg/src -BASE_FLAGS += -IRack/dep/osdialog -BASE_FLAGS += -IRack/dep/oui-blendish -BASE_FLAGS += -IRack/dep/pffft - -ifeq ($(DEBUG),true) -BASE_FLAGS += -UDEBUG -ifeq ($(WASM),true) -# SSE must always be enabled on wasm, even in debug builds -BASE_FLAGS += -msse -msse2 -msse3 -msimd128 -endif -endif +BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/dep/osdialog) ifeq ($(HAVE_LIBLO),true) BASE_FLAGS += -DHAVE_LIBLO $(LIBLO_FLAGS) endif -ifeq ($(HEADLESS),true) -BASE_FLAGS += -DHEADLESS -endif - -ifeq ($(BSD),true) -BASE_FLAGS += -DCLOCK_MONOTONIC_RAW=CLOCK_MONOTONIC_PRECISE -endif - -ifeq ($(HAIKU),true) -BASE_FLAGS += -DCLOCK_MONOTONIC_RAW=CLOCK_MONOTONIC -endif - -ifneq ($(WASM),true) -ifneq ($(HAIKU),true) -BASE_FLAGS += -pthread -endif -endif - -ifeq ($(WINDOWS),true) -BASE_FLAGS += -D_USE_MATH_DEFINES -BASE_FLAGS += -DWIN32_LEAN_AND_MEAN -BASE_FLAGS += -I../include/mingw-compat -BASE_FLAGS += -I../include/mingw-std-threads -endif - -ifeq ($(USE_GLES2),true) -BASE_FLAGS += -DNANOVG_GLES2_FORCED -else ifeq ($(USE_GLES3),true) -BASE_FLAGS += -DNANOVG_GLES3_FORCED -endif - -BUILD_C_FLAGS += -std=gnu11 -BUILD_C_FLAGS += -fno-finite-math-only -fno-strict-aliasing -BUILD_CXX_FLAGS += -fno-finite-math-only -fno-strict-aliasing - -ifneq ($(MACOS),true) -BUILD_CXX_FLAGS += -faligned-new -Wno-abi -endif - # use our custom function to invert some colors BUILD_CXX_FLAGS += -DnsvgDelete=nsvgDeleteCardinal BUILD_CXX_FLAGS += -DnsvgParseFromFile=nsvgParseFromFileCardinal -# Rack code is not tested for this flag, unset it -BUILD_CXX_FLAGS += -U_GLIBCXX_ASSERTIONS -Wp,-U_GLIBCXX_ASSERTIONS - -# Ignore bad behaviour from Rack API -BUILD_CXX_FLAGS += -Wno-format-security - # -------------------------------------------------------------- # Rack files to build @@ -138,8 +43,8 @@ RACK_FILES += override/context.cpp RACK_FILES += override/minblep.cpp RACK_FILES += override/plugin.cpp RACK_FILES += override/Engine.cpp -RACK_FILES += override/MenuBar.cpp RACK_FILES += override/Model.cpp +RACK_FILES += override/ModuleWidget.cpp RACK_FILES += override/OpenGlWidget.cpp RACK_FILES += override/Scene.cpp @@ -157,6 +62,7 @@ IGNORED_FILES += Rack/src/gamepad.cpp IGNORED_FILES += Rack/src/keyboard.cpp IGNORED_FILES += Rack/src/library.cpp IGNORED_FILES += Rack/src/midi.cpp +IGNORED_FILES += Rack/src/midiloopback.cpp IGNORED_FILES += Rack/src/network.cpp IGNORED_FILES += Rack/src/plugin.cpp IGNORED_FILES += Rack/src/rtaudio.cpp @@ -164,6 +70,7 @@ IGNORED_FILES += Rack/src/rtmidi.cpp IGNORED_FILES += Rack/src/app/AudioDisplay.cpp IGNORED_FILES += Rack/src/app/MenuBar.cpp IGNORED_FILES += Rack/src/app/MidiDisplay.cpp +IGNORED_FILES += Rack/src/app/ModuleWidget.cpp IGNORED_FILES += Rack/src/app/Scene.cpp IGNORED_FILES += Rack/src/app/TipWindow.cpp IGNORED_FILES += Rack/src/dsp/minblep.cpp @@ -173,6 +80,7 @@ IGNORED_FILES += Rack/src/widget/OpenGlWidget.cpp IGNORED_FILES += Rack/src/window/Window.cpp IGNORED_FILES += $(wildcard Rack/src/core/*.cpp) +RACK_FILES += Rack/dep/tinyexpr/tinyexpr.c RACK_FILES += $(wildcard Rack/src/*.c) RACK_FILES += $(wildcard Rack/src/*/*.c) RACK_FILES += $(filter-out $(IGNORED_FILES),$(wildcard Rack/src/*.cpp)) @@ -197,51 +105,64 @@ endif # -------------------------------------------------------------- # Build targets -TARGET = rack.a +ifeq ($(HEADLESS),true) +TARGET_SUFFIX = -headless +endif + +TARGETS = rack$(TARGET_SUFFIX).a rack-headless.a ifneq ($(MACOS),true) CARDINAL_FX_ARGS = VST2_FILENAME=Cardinal.vst/CardinalFX$(LIB_EXT) CLAP_FILENAME=Cardinal.clap/CardinalFX.clap CARDINAL_SYNTH_ARGS = VST2_FILENAME=Cardinal.vst/CardinalSynth$(LIB_EXT) CLAP_FILENAME=Cardinal.clap/CardinalSynth.clap endif -all: $(TARGET) +all: $(TARGETS) ifeq ($(MOD_BUILD),true) $(MAKE) -C Cardinal lv2 $(MAKE) -C CardinalFX lv2 + $(MAKE) -C CardinalMiniSep lv2_sep else ifeq ($(WASM),true) $(MAKE) -C CardinalNative + $(MAKE) -C CardinalMini else $(MAKE) -C Cardinal + $(MAKE) -C CardinalMini + $(MAKE) -C CardinalMiniSep $(MAKE) -C CardinalNative $(MAKE) -C CardinalFX $(CARDINAL_FX_ARGS) $(MAKE) -C CardinalSynth $(CARDINAL_SYNTH_ARGS) endif -jack: $(TARGET) +jack: $(TARGETS) $(MAKE) jack -C Cardinal -native: $(TARGET) +native: $(TARGETS) $(MAKE) jack -C CardinalNative -lv2: $(TARGET) +mini: $(TARGETS) + $(MAKE) jack -C CardinalMini + +lv2: $(TARGETS) $(MAKE) lv2 -C Cardinal $(MAKE) lv2 -C CardinalFX $(CARDINAL_FX_ARGS) $(MAKE) lv2 -C CardinalSynth $(CARDINAL_SYNTH_ARGS) + $(MAKE) lv2_sep -C CardinalMiniSep -vst2: $(TARGET) +vst2: $(TARGETS) $(MAKE) vst2 -C CardinalFX $(CARDINAL_FX_ARGS) $(MAKE) vst2 -C CardinalSynth $(CARDINAL_SYNTH_ARGS) -vst3: $(TARGET) +vst3: $(TARGETS) $(MAKE) vst3 -C Cardinal $(MAKE) vst3 -C CardinalFX $(CARDINAL_FX_ARGS) $(MAKE) vst3 -C CardinalSynth $(CARDINAL_SYNTH_ARGS) -clap: $(TARGET) +clap: $(TARGETS) $(MAKE) clap -C CardinalFX $(CARDINAL_FX_ARGS) + $(MAKE) clap -C CardinalSynth $(CARDINAL_SYNTH_ARGS) clean: - rm -f $(TARGET) + rm -f *.a rm -rf $(BUILD_DIR) $(MAKE) clean -C Cardinal $(MAKE) clean -C CardinalFX $(CARDINAL_FX_ARGS) @@ -252,11 +173,16 @@ clean: RACK_OBJS = $(RACK_FILES:%=$(BUILD_DIR)/%.o) -$(TARGET): $(RACK_OBJS) +rack$(TARGET_SUFFIX).a: $(RACK_OBJS) @echo "Creating $@" $(SILENT)rm -f $@ $(SILENT)$(AR) crs $@ $^ +ifneq ($(HEADLESS),true) +rack-headless.a: + $(MAKE) HEADLESS=true $@ +endif + $(BUILD_DIR)/%.c.o: %.c -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" @@ -269,6 +195,8 @@ $(BUILD_DIR)/%.cpp.o: %.cpp $(BUILD_DIR)/emscripten/WasmUtils.cpp.o: BUILD_CXX_FLAGS += -fno-exceptions +$(BUILD_DIR)/Rack/dep/tinyexpr/tinyexpr.c.o: BUILD_C_FLAGS += -DTE_POW_FROM_RIGHT -DTE_NAT_LOG + # -------------------------------------------------------------- -include $(RACK_OBJS:%.o=%.d) diff --git a/src/Makefile.cardinal.mk b/src/Makefile.cardinal.mk index a03f2680..31b3b4c3 100644 --- a/src/Makefile.cardinal.mk +++ b/src/Makefile.cardinal.mk @@ -4,10 +4,17 @@ # Created by falkTX # -# Must have NAME defined +# ----------------------------------------------------------------------------- +# Set variant to build + +ifeq ($(NAME),) +$(error invalid usage) +endif ifeq ($(NAME),Cardinal) CARDINAL_VARIANT = main +else ifeq ($(NAME),CardinalMini) +CARDINAL_VARIANT = mini else ifeq ($(NAME),CardinalFX) CARDINAL_VARIANT = fx else ifeq ($(NAME),CardinalNative) @@ -19,10 +26,11 @@ endif # -------------------------------------------------------------- # Carla stuff +ifneq ($(CARDINAL_VARIANT),mini) ifneq ($(STATIC_BUILD),true) -CWD = ../../carla/source -include $(CWD)/Makefile.deps.mk +STATIC_PLUGIN_TARGET = true +include ../../carla/source/Makefile.deps.mk CARLA_BUILD_DIR = ../../carla/build ifeq ($(DEBUG),true) @@ -30,74 +38,61 @@ CARLA_BUILD_TYPE = Debug else CARLA_BUILD_TYPE = Release endif - CARLA_EXTRA_LIBS = $(CARLA_BUILD_DIR)/plugin/$(CARLA_BUILD_TYPE)/carla-host-plugin.cpp.o CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/carla_engine_plugin.a CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/carla_plugin.a CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/native-plugins.a CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/audio_decoder.a -ifneq ($(WASM),true) CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/jackbridge.min.a -endif CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/lilv.a CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/rtmempool.a -CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/sfzero.a CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/water.a CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/ysfx.a CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/zita-resampler.a endif # STATIC_BUILD +endif # CARDINAL_VARIANT mini # -------------------------------------------------------------- # Import base definitions -DISTRHO_NAMESPACE = CardinalDISTRHO -DGL_NAMESPACE = CardinalDGL -NVG_DISABLE_SKIPPING_WHITESPACE = true -NVG_FONT_TEXTURE_FLAGS = NVG_IMAGE_NEAREST -USE_NANOVG_FBO = true -WASM_EXCEPTIONS = true - ifeq ($(CARDINAL_VARIANT),main) # main variant should not use rtaudio/sdl2 fallback (it has CV ports) SKIP_NATIVE_AUDIO_FALLBACK = true -else -# fx and synth variants should only use rtaudio/sdl2 fallbacks +else ifneq ($(CARDINAL_VARIANT),mini) +# other variants should only use rtaudio/sdl2 fallbacks FORCE_NATIVE_AUDIO_FALLBACK = true endif -include ../../dpf/Makefile.base.mk +BUILDING_RACK = true +ROOT = ../.. +include $(ROOT)/Makefile.base.mk # -------------------------------------------------------------- # Build config PREFIX ?= /usr/local -ifeq ($(BSD),true) -SYSDEPS ?= true -else -SYSDEPS ?= false -endif - -ifeq ($(SYSDEPS),true) -DEP_LIB_PATH = $(abspath ../../deps/sysroot/lib) -else -DEP_LIB_PATH = $(abspath ../Rack/dep/lib) -endif +DEP_LIB_PATH = $(RACK_DEP_PATH)/lib # -------------------------------------------------------------- # Files to build (DPF stuff) FILES_DSP = CardinalPlugin.cpp FILES_DSP += CardinalCommon.cpp +FILES_DSP += CardinalRemote.cpp FILES_DSP += common.cpp -ifeq ($(HEADLESS),true) +ifeq ($(DSP_UI_SPLIT),true) +FILES_DSP += RemoteNanoVG.cpp +FILES_DSP += RemoteWindow.cpp +else ifeq ($(HEADLESS),true) FILES_DSP += RemoteNanoVG.cpp FILES_DSP += RemoteWindow.cpp else FILES_UI = CardinalUI.cpp FILES_UI += glfw.cpp +FILES_UI += MenuBar.cpp FILES_UI += Window.cpp endif @@ -105,12 +100,58 @@ ifeq ($(WINDOWS),true) FILES_UI += distrho.rc endif +ifneq ($(HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS),true) +FILES_UI += CardinalX11WindowIcon.cpp +endif + +# -------------------------------------------------------------- +# Rack and plugin libs + +ifeq ($(DSP_UI_SPLIT),true) +TARGET_SUFFIX = -headless +else ifeq ($(HEADLESS),true) +TARGET_SUFFIX = -headless +endif + +ifeq ($(CARDINAL_VARIANT),mini) +RACK_EXTRA_LIBS = ../../plugins/plugins-mini$(TARGET_SUFFIX).a +else +RACK_EXTRA_LIBS = ../../plugins/plugins$(TARGET_SUFFIX).a +endif + +ifeq ($(CARDINAL_VARIANT),mini) +RACK_EXTRA_LIBS += ../rack$(TARGET_SUFFIX).a +else +RACK_EXTRA_LIBS += ../rack$(TARGET_SUFFIX).a +endif + +# -------------------------------------------------------------- +# surgext libraries + +SURGE_DEP_PATH = $(abspath ../../deps/surge-build) +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/src/common/libsurge-common.a +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/src/common/libjuce_dsp_rack_sub.a +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/airwindows/libairwindows.a +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/eurorack/libeurorack.a +ifeq ($(DEBUG),true) +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/fmt/libfmtd.a +else +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/fmt/libfmt.a +endif +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sqlite-3.23.3/libsqlite.a +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sst/sst-plugininfra/libsst-plugininfra.a +ifneq ($(MACOS)$(WINDOWS),true) +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sst/sst-plugininfra/libs/filesystem/libfilesystem.a +endif +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sst/sst-plugininfra/libs/strnatcmp/libstrnatcmp.a +RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sst/sst-plugininfra/libs/tinyxml/libtinyxml.a + # -------------------------------------------------------------- # Extra libraries to link against -RACK_EXTRA_LIBS = ../../plugins/plugins.a -RACK_EXTRA_LIBS += ../rack.a +ifneq ($(CARDINAL_VARIANT),mini) RACK_EXTRA_LIBS += $(DEP_LIB_PATH)/libquickjs.a +endif ifneq ($(SYSDEPS),true) RACK_EXTRA_LIBS += $(DEP_LIB_PATH)/libjansson.a @@ -127,62 +168,103 @@ endif # -------------------------------------------------------------- # FIXME -ifeq ($(WASM),true) -ifneq ($(STATIC_BUILD),true) +ifeq ($(CARDINAL_VARIANT)$(WASM),nativetrue) +ifneq ($(OLD_PATH),) STATIC_CARLA_PLUGIN_LIBS = -lsndfile -lopus -lFLAC -lvorbisenc -lvorbis -logg -lm endif endif -EXTRA_DEPENDENCIES = $(RACK_EXTRA_LIBS) $(CARLA_EXTRA_LIBS) -EXTRA_LIBS = $(RACK_EXTRA_LIBS) $(CARLA_EXTRA_LIBS) $(STATIC_CARLA_PLUGIN_LIBS) +EXTRA_DSP_DEPENDENCIES = $(RACK_EXTRA_LIBS) $(CARLA_EXTRA_LIBS) +EXTRA_DSP_LIBS = $(RACK_EXTRA_LIBS) $(CARLA_EXTRA_LIBS) $(STATIC_CARLA_PLUGIN_LIBS) +ifneq ($(CARDINAL_VARIANT),mini) ifeq ($(shell $(PKG_CONFIG) --exists fftw3f && echo true),true) -EXTRA_DEPENDENCIES += ../../deps/aubio/libaubio.a -EXTRA_LIBS += ../../deps/aubio/libaubio.a -EXTRA_LIBS += $(shell $(PKG_CONFIG) --libs fftw3f) +EXTRA_DSP_DEPENDENCIES += ../../deps/aubio/libaubio.a +EXTRA_DSP_LIBS += ../../deps/aubio/libaubio.a +EXTRA_DSP_LIBS += $(filter-out -lpthread,$(shell $(PKG_CONFIG) --libs fftw3f)) +endif +endif + +ifeq ($(MACOS),true) +EXTRA_DSP_LIBS += -framework Accelerate -framework AppKit +else ifeq ($(WINDOWS),true) +EXTRA_DSP_LIBS += -lole32 -lshlwapi -luuid -lversion endif # -------------------------------------------------------------- # Setup resources -CORE_RESOURCES = patches -CORE_RESOURCES += $(subst ../Rack/res/,,$(wildcard ../Rack/res/ComponentLibrary/*.svg ../Rack/res/fonts/*.ttf)) +CORE_RESOURCES = $(subst ../Rack/res/,,$(wildcard ../Rack/res/ComponentLibrary/*.svg ../Rack/res/fonts/*.ttf)) +# ifneq ($(CARDINAL_VARIANT),mini) +CORE_RESOURCES += patches +# endif LV2_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).lv2/resources/%) VST3_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst3/Contents/Resources/%) +ifeq ($(MACOS),true) +CLAP_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).clap/Contents/Resources/%) +else +CLAP_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/Cardinal.clap/resources/%) +endif + # Install modgui resources if MOD build ifeq ($(MOD_BUILD),true) +ifneq ($(CARDINAL_VARIANT),mini) LV2_RESOURCES += $(TARGET_DIR)/$(NAME).lv2/Plateau_Reverb.ttl LV2_RESOURCES += $(TARGET_DIR)/$(NAME).lv2/modgui.ttl LV2_RESOURCES += $(TARGET_DIR)/$(NAME).lv2/modgui/documentation.pdf LV2_RESOURCES += $(TARGET_DIR)/$(NAME).lv2/modgui endif +endif + +ifeq ($(CARDINAL_VARIANT),mini) +LV2_RESOURCES += $(TARGET_DIR)/$(NAME).lv2/modgui/screenshot.png +LV2_RESOURCES += $(TARGET_DIR)/$(NAME).lv2/modgui/thumbnail.png +endif # Cardinal main variant is not available as VST2 due to lack of CV ports ifneq ($(CARDINAL_VARIANT),main) ifeq ($(MACOS),true) VST2_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst/Contents/Resources/%) -CLAP_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).clap/Contents/Resources/%) else VST2_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/Cardinal.vst/resources/%) -CLAP_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/Cardinal.clap/resources/%) endif endif ifeq ($(WASM),true) -WASM_RESOURCES = $(LV2_RESOURCES) +WASM_RESOURCES = $(TARGET_DIR)/$(NAME).html $(LV2_RESOURCES) -ifneq ($(STATIC_BUILD),true) -WASM_RESOURCES += $(CURDIR)/lv2 +EXTRA_DSP_DEPENDENCIES += $(WASM_RESOURCES) endif -EXTRA_DEPENDENCIES += $(WASM_RESOURCES) +# -------------------------------------------------------------- +# mini variant UI + +ifeq ($(DSP_UI_SPLIT),true) +ifneq ($(HEADLESS),true) +FILES_UI = CardinalUI.cpp +FILES_UI += CardinalCommon-UI.cpp +FILES_UI += CardinalRemote.cpp +FILES_UI += common.cpp +FILES_UI += glfw.cpp +FILES_UI += MenuBar.cpp +FILES_UI += Window.cpp +ifneq ($(HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS),true) +FILES_UI += CardinalX11WindowIcon.cpp +endif +EXTRA_UI_DEPENDENCIES = $(subst -headless,,$(EXTRA_DSP_DEPENDENCIES)) +EXTRA_UI_LIBS += $(subst -headless,,$(EXTRA_DSP_LIBS)) +endif endif # -------------------------------------------------------------- # Do some magic +ifeq ($(WASM),true) +APP_EXT = .js +endif + USE_VST2_BUNDLE = true USE_CLAP_BUNDLE = true include ../../dpf/Makefile.plugins.mk @@ -190,97 +272,77 @@ include ../../dpf/Makefile.plugins.mk # -------------------------------------------------------------- # Extra flags for VCV stuff -ifeq ($(MACOS),true) -BASE_FLAGS += -DARCH_MAC -else ifeq ($(WINDOWS),true) -BASE_FLAGS += -DARCH_WIN -else -BASE_FLAGS += -DARCH_LIN -endif - BASE_FLAGS += -DPRIVATE= -BASE_FLAGS += -I.. -BASE_FLAGS += -I../../dpf/dgl/src/nanovg -BASE_FLAGS += -I../../include -BASE_FLAGS += -I../../include/simd-compat -BASE_FLAGS += -I../Rack/include -ifeq ($(SYSDEPS),true) -BASE_FLAGS += -DCARDINAL_SYSDEPS -BASE_FLAGS += $(shell $(PKG_CONFIG) --cflags jansson libarchive samplerate speexdsp) -else -BASE_FLAGS += -DZSTDLIB_VISIBILITY= -BASE_FLAGS += -I../Rack/dep/include -endif -BASE_FLAGS += -I../Rack/dep/glfw/include -BASE_FLAGS += -I../Rack/dep/nanosvg/src -BASE_FLAGS += -I../Rack/dep/oui-blendish -ifeq ($(HEADLESS),true) -BASE_FLAGS += -DHEADLESS -endif +# -------------------------------------------------------------- +# Extra flags for MOD and Mini stuff ifeq ($(MOD_BUILD),true) -BASE_FLAGS += -DDISTRHO_PLUGIN_USES_MODGUI=1 -DDISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE=0xffff -endif - -ifneq ($(WASM),true) -ifneq ($(HAIKU),true) -BASE_FLAGS += -pthread -endif +BASE_FLAGS += -DDISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE=0xffff +BASE_FLAGS += -DDISTRHO_PLUGIN_USES_MODGUI=1 +else ifeq ($(CARDINAL_VARIANT),mini) +BASE_FLAGS += -DDISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE=0xffff endif -ifeq ($(WINDOWS),true) -BASE_FLAGS += -D_USE_MATH_DEFINES -BASE_FLAGS += -DWIN32_LEAN_AND_MEAN -BASE_FLAGS += -I../../include/mingw-compat -BASE_FLAGS += -I../../include/mingw-std-threads -endif - -ifeq ($(USE_GLES2),true) -BASE_FLAGS += -DNANOVG_GLES2_FORCED -else ifeq ($(USE_GLES3),true) -BASE_FLAGS += -DNANOVG_GLES3_FORCED -endif - -BUILD_C_FLAGS += -std=gnu11 -BUILD_C_FLAGS += -fno-finite-math-only -fno-strict-aliasing -BUILD_CXX_FLAGS += -fno-finite-math-only -fno-strict-aliasing - -ifneq ($(MACOS),true) -BUILD_CXX_FLAGS += -faligned-new -Wno-abi -endif - -# Rack code is not tested for this flag, unset it -BUILD_CXX_FLAGS += -U_GLIBCXX_ASSERTIONS -Wp,-U_GLIBCXX_ASSERTIONS - -# Ignore bad behaviour from Rack API -BUILD_CXX_FLAGS += -Wno-format-security - -# -------------------------------------------------------------- -# FIXME lots of warnings from VCV side - -BASE_FLAGS += -Wno-unused-parameter -BASE_FLAGS += -Wno-unused-variable - # -------------------------------------------------------------- # extra linker flags ifeq ($(WASM),true) -ifneq ($(STATIC_BUILD),true) -LINK_FLAGS += --use-preload-plugins -LINK_FLAGS += --preload-file=./jsfx -LINK_FLAGS += --preload-file=./lv2 -endif -LINK_FLAGS += --preload-file=../../bin/CardinalNative.lv2/resources@/resources + +LINK_FLAGS += -O3 LINK_FLAGS += -sALLOW_MEMORY_GROWTH LINK_FLAGS += -sINITIAL_MEMORY=64Mb LINK_FLAGS += -sLZ4=1 -LINK_FLAGS += --shell-file=../emscripten/shell.html -LINK_FLAGS += -O3 +LINK_FLAGS += -sSTACK_SIZE=5MB + +ifeq ($(CARDINAL_VARIANT),mini) +LINK_FLAGS += --preload-file=../../bin/CardinalMini.lv2/resources@/resources +else +LINK_FLAGS += --preload-file=../../bin/CardinalNative.lv2/resources@/resources +LINK_FLAGS += --use-preload-cache +LINK_FLAGS += --use-preload-plugins +endif + +ifneq ($(DSP_UI_SPLIT),true) +LINK_FLAGS += -lidbfs.js +JACK_LIBS += -sEXPORTED_RUNTIME_METHODS=IDBFS,FS,cwrap +endif + +# find . -type l | grep -v svg | grep -v ttf | grep -v art | grep -v json | grep -v png | grep -v otf | sort +SYMLINKED_DIRS_RESOURCES = Fundamental/presets +ifneq ($(CARDINAL_VARIANT),mini) +SYMLINKED_DIRS_RESOURCES += BaconPlugs/res/midi/chopin +SYMLINKED_DIRS_RESOURCES += BaconPlugs/res/midi/debussy +SYMLINKED_DIRS_RESOURCES += BaconPlugs/res/midi/goldberg +SYMLINKED_DIRS_RESOURCES += cf/playeroscs +SYMLINKED_DIRS_RESOURCES += DrumKit/res/samples +SYMLINKED_DIRS_RESOURCES += GrandeModular/presets +SYMLINKED_DIRS_RESOURCES += LyraeModules/presets +SYMLINKED_DIRS_RESOURCES += Meander/res +SYMLINKED_DIRS_RESOURCES += MindMeldModular/presets +SYMLINKED_DIRS_RESOURCES += MindMeldModular/res/ShapeMaster/CommunityPresets +SYMLINKED_DIRS_RESOURCES += MindMeldModular/res/ShapeMaster/CommunityShapes +SYMLINKED_DIRS_RESOURCES += MindMeldModular/res/ShapeMaster/MindMeldPresets +SYMLINKED_DIRS_RESOURCES += MindMeldModular/res/ShapeMaster/MindMeldShapes +SYMLINKED_DIRS_RESOURCES += Mog/res +SYMLINKED_DIRS_RESOURCES += nonlinearcircuits/res +SYMLINKED_DIRS_RESOURCES += Orbits/presets +SYMLINKED_DIRS_RESOURCES += stoermelder-packone/presets +SYMLINKED_DIRS_RESOURCES += surgext/build/surge-data/fx_presets +SYMLINKED_DIRS_RESOURCES += surgext/build/surge-data/wavetables +SYMLINKED_DIRS_RESOURCES += surgext/patches +SYMLINKED_DIRS_RESOURCES += surgext/presets +endif +LINK_FLAGS += $(foreach d,$(SYMLINKED_DIRS_RESOURCES),--preload-file=../../bin/CardinalNative.lv2/resources/$(d)@/resources/$(d)) + else ifeq ($(HAIKU),true) + LINK_FLAGS += -lpthread + else + LINK_FLAGS += -pthread + endif ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) @@ -289,23 +351,22 @@ LINK_FLAGS += -ldl endif endif -ifeq ($(BSD),true) -ifeq ($(DEBUG),true) +ifeq ($(BSD)$(DEBUG),truetrue) LINK_FLAGS += -lexecinfo endif -endif ifeq ($(MACOS),true) LINK_FLAGS += -framework IOKit else ifeq ($(WINDOWS),true) # needed by VCVRack -EXTRA_LIBS += -ldbghelp -lshlwapi -Wl,--stack,0x100000 +LINK_FLAGS += -Wl,--stack,0x100000 +EXTRA_DSP_LIBS += -ldbghelp -lshlwapi # needed by JW-Modules -EXTRA_LIBS += -lws2_32 -lwinmm +EXTRA_DSP_LIBS += -lws2_32 -lwinmm endif ifeq ($(SYSDEPS),true) -EXTRA_LIBS += $(shell $(PKG_CONFIG) --libs jansson libarchive samplerate speexdsp) +EXTRA_DSP_LIBS += $(shell $(PKG_CONFIG) --libs jansson libarchive samplerate speexdsp) endif ifeq ($(WITH_LTO),true) @@ -322,7 +383,7 @@ endif ifeq ($(HAVE_LIBLO),true) BASE_FLAGS += $(LIBLO_FLAGS) -LINK_FLAGS += $(LIBLO_LIBS) +EXTRA_DSP_LIBS += $(LIBLO_LIBS) endif # -------------------------------------------------------------- @@ -351,23 +412,20 @@ BUILD_CXX_FLAGS += -DCARDINAL_PLUGIN_PREFIX='"$(PREFIX)"' # Enable all possible plugin types and setup resources ifeq ($(CARDINAL_VARIANT),main) -TARGETS = lv2 vst3 -ifeq ($(HAVE_JACK),true) -TARGETS += jack -endif +TARGETS = jack lv2 vst3 clap +else ifeq ($(DSP_UI_SPLIT),true) +TARGETS = lv2_sep +else ifeq ($(CARDINAL_VARIANT),mini) +TARGETS = jack else ifeq ($(CARDINAL_VARIANT),native) TARGETS = jack else -TARGETS = lv2 vst2 vst3 static -endif - -# TESTING -ifeq ($(CARDINAL_VARIANT),fx) -TARGETS += clap +TARGETS = lv2 vst2 vst3 clap static endif all: $(TARGETS) lv2: $(LV2_RESOURCES) +lv2_sep: $(LV2_RESOURCES) vst2: $(VST2_RESOURCES) vst3: $(VST3_RESOURCES) clap: $(CLAP_RESOURCES) @@ -391,15 +449,16 @@ $(TARGET_DIR)/%.app/Contents/Resources/distrho.icns: ../../utils/distrho.icns # Extra rules for wasm resources ifeq ($(WASM),true) -$(CURDIR)/lv2: $(LV2_RESOURCES) - wget -O - https://falktx.com/data/wasm-things-2022-08-15.tar.gz | tar xz -C $(CURDIR) +$(TARGET_DIR)/$(NAME).html: ../emscripten/$(NAME).html + -@mkdir -p $(shell dirname $@) + cp $< $@ endif # -------------------------------------------------------------- # Extra rules for Windows icon ifeq ($(WINDOWS),true) -JACK_LIBS += -Wl,-subsystem,windows +WINDRES ?= $(subst gcc,windres,$(CC)) $(BUILD_DIR)/distrho.rc.o: ../../utils/distrho.rc ../../utils/distrho.ico -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @@ -417,6 +476,10 @@ else $(SILENT)ln -sf $(abspath $<) $@ endif +$(TARGET_DIR)/$(NAME).lv2/mod%: ../MOD/$(NAME).lv2/mod% + -@mkdir -p "$(shell dirname $@)" + $(SILENT)ln -sf $(abspath $<) $@ + $(TARGET_DIR)/$(NAME).lv2/resources/%: ../Rack/res/% -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ @@ -426,10 +489,6 @@ $(TARGET_DIR)/$(NAME).lv2/resources/%.svg: ../Rack/res/%.svg ../../deps/svg2stub -@mkdir -p "$(shell dirname $@)" $(SILENT)python3 ../../deps/svg2stub.py $< $@ -$(TARGET_DIR)/$(NAME).lv2/mod%: ../MOD/$(NAME).lv2/mod% - -@mkdir -p "$(shell dirname $@)" - $(SILENT)ln -sf $(abspath $<) $@ - $(TARGET_DIR)/$(NAME).lv2/%.ttl: ../MOD/$(NAME).lv2/%.ttl -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ diff --git a/src/PluginContext.hpp b/src/PluginContext.hpp index c5a22920..fa5c97db 100644 --- a/src/PluginContext.hpp +++ b/src/PluginContext.hpp @@ -25,32 +25,115 @@ # undef DEBUG #endif +#include "CardinalRemote.hpp" #include "DistrhoPlugin.hpp" -#include "extra/Mutex.hpp" + +#if CARDINAL_VARIANT_MINI || !defined(HEADLESS) +# include "WindowParameters.hpp" +#else +# define kWindowParameterCount 0 +#endif #ifndef HEADLESS # include "DistrhoUI.hpp" +#else +# include "Base.hpp" +START_NAMESPACE_DGL +class TopLevelWidget; +template class NanoBaseWidget; +typedef NanoBaseWidget NanoTopLevelWidget; +END_NAMESPACE_DGL #endif START_NAMESPACE_DISTRHO // ----------------------------------------------------------------------------------------------------------- -static constexpr const uint kModuleParameters = 24; +static constexpr const uint kModuleParameterCount = 24; enum CardinalVariant { kCardinalVariantMain, + kCardinalVariantMini, kCardinalVariantFX, kCardinalVariantNative, kCardinalVariantSynth, }; +enum CardinalParameters { + kCardinalParameterCountAtModules = kModuleParameterCount, + kCardinalParameterBypass = kCardinalParameterCountAtModules, + #if CARDINAL_VARIANT_MINI || !defined(HEADLESS) + kCardinalParameterStartWindow, + kCardinalParameterCountAtWindow = kCardinalParameterStartWindow + kWindowParameterCount, + #if CARDINAL_VARIANT_MINI + kCardinalParameterStartMini = kCardinalParameterCountAtWindow, + kCardinalParameterStartMiniBuffers = kCardinalParameterStartMini, + kCardinalParameterMiniAudioIn1 = kCardinalParameterStartMiniBuffers, + kCardinalParameterMiniAudioIn2, + kCardinalParameterMiniCVIn1, + kCardinalParameterMiniCVIn2, + kCardinalParameterMiniCVIn3, + kCardinalParameterMiniCVIn4, + kCardinalParameterMiniCVIn5, + kCardinalParameterCountAtMiniBuffers, + kCardinalParameterStartMiniTime = kCardinalParameterCountAtMiniBuffers, + kCardinalParameterMiniTimeFlags = kCardinalParameterStartMiniTime, + kCardinalParameterMiniTimeBar, + kCardinalParameterMiniTimeBeat, + kCardinalParameterMiniTimeBeatsPerBar, + kCardinalParameterMiniTimeBeatType, + kCardinalParameterMiniTimeFrame, + kCardinalParameterMiniTimeBarStartTick, + kCardinalParameterMiniTimeBeatsPerMinute, + kCardinalParameterMiniTimeTick, + kCardinalParameterMiniTimeTicksPerBeat, + kCardinalParameterCountAtMiniTime, + kCardinalParameterCountAtMini = kCardinalParameterCountAtMiniTime, + kCardinalParameterCount = kCardinalParameterCountAtMini + #else + kCardinalParameterCount = kCardinalParameterCountAtWindow + #endif + #else + kCardinalParameterCount + #endif +}; + +enum CardinalStates { + kCardinalStatePatch, + kCardinalStateScreenshot, + kCardinalStateComment, + #if CARDINAL_VARIANT_MINI || !defined(HEADLESS) + kCardinalStateWindowSize, + #endif + #if CARDINAL_VARIANT_MINI + kCardinalStateParamChange, + #endif + kCardinalStateCount +}; + +static_assert(kCardinalParameterBypass == kModuleParameterCount, "valid parameter indexes"); +#if CARDINAL_VARIANT_MINI || !defined(HEADLESS) +static_assert(kCardinalParameterStartWindow == kModuleParameterCount + 1, "valid parameter indexes"); +static_assert(kCardinalParameterStartWindow == kCardinalParameterBypass + 1, "valid parameter indexes"); +static_assert(kCardinalParameterCountAtWindow == kModuleParameterCount + kWindowParameterCount + 1, "valid parameter indexes"); +#endif +#if CARDINAL_VARIANT_MINI +static_assert(0 == kCardinalParameterStartMini - kCardinalParameterMiniAudioIn1, "valid parameter indexes"); +static_assert(kCardinalParameterStartMini == kCardinalParameterCountAtWindow, "valid parameter indexes"); +static_assert(kCardinalParameterStartMini == kCardinalParameterBypass + kWindowParameterCount + 1, "valid parameter indexes"); +static_assert(kCardinalParameterStartMini == kModuleParameterCount + kWindowParameterCount + 1, "valid parameter indexes"); +static_assert(kCardinalParameterCountAtWindow == kModuleParameterCount + kWindowParameterCount + 1, "valid parameter indexes"); +static_assert(DISTRHO_PLUGIN_NUM_INPUTS == kCardinalParameterCountAtMiniBuffers - kCardinalParameterStartMiniBuffers, "valid parameter indexes"); +#endif + +class UI; + // ----------------------------------------------------------------------------------------------------------- struct CardinalPluginContext : rack::Context { uint32_t bufferSize, processCounter; double sampleRate; - float parameters[kModuleParameters]; + float parameters[kModuleParameterCount]; CardinalVariant variant; bool bypassed, playing, reset, bbtValid; int32_t bar, beat, beatsPerBar, beatType; @@ -63,16 +146,17 @@ struct CardinalPluginContext : rack::Context { const MidiEvent* midiEvents; uint32_t midiEventCount; Plugin* const plugin; -#ifndef HEADLESS + NanoTopLevelWidget* tlw; UI* ui; -#endif CardinalPluginContext(Plugin* const p) - : bufferSize(p->getBufferSize()), + : bufferSize(p != nullptr ? p->getBufferSize() : 0), processCounter(0), - sampleRate(p->getSampleRate()), + sampleRate(p != nullptr ? p->getSampleRate() : 0.0), #if CARDINAL_VARIANT_MAIN variant(kCardinalVariantMain), + #elif CARDINAL_VARIANT_MINI + variant(kCardinalVariantMini), #elif CARDINAL_VARIANT_FX variant(kCardinalVariantFX), #elif CARDINAL_VARIANT_NATIVE @@ -103,29 +187,26 @@ struct CardinalPluginContext : rack::Context { dataOuts(nullptr), midiEvents(nullptr), midiEventCount(0), - plugin(p) -#ifndef HEADLESS - , ui(nullptr) -#endif + plugin(p), + tlw(nullptr), + ui(nullptr) { std::memset(parameters, 0, sizeof(parameters)); } void writeMidiMessage(const rack::midi::Message& message, uint8_t channel); -#ifndef HEADLESS + #ifndef HEADLESS bool addIdleCallback(IdleCallback* cb) const; void removeIdleCallback(IdleCallback* cb) const; -#endif + #endif }; -#ifndef HEADLESS -void handleHostParameterDrag(const CardinalPluginContext* pcontext, uint index, bool started); -#endif - // ----------------------------------------------------------------------------------------------------------- +#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS CardinalPluginContext* getRackContextFromPlugin(void* ptr); +#endif class CardinalBasePlugin : public Plugin { public: @@ -136,9 +217,15 @@ class CardinalBasePlugin : public Plugin { context(new CardinalPluginContext(this)) {} ~CardinalBasePlugin() override {} -#ifndef HEADLESS + #ifdef HAVE_LIBLO + virtual bool startRemoteServer(const char* port) = 0; + virtual void stopRemoteServer() = 0; + virtual void stepRemoteServer() = 0; + #endif + + #ifndef HEADLESS friend class CardinalUI; -#endif + #endif }; #ifndef HEADLESS @@ -147,6 +234,7 @@ struct WasmRemotePatchLoadingDialog; class CardinalBaseUI : public UI { public: CardinalPluginContext* const context; + remoteUtils::RemoteDetails* remoteDetails; bool saving; bool savingUncompressed; @@ -160,7 +248,12 @@ class CardinalBaseUI : public UI { CardinalBaseUI(const uint width, const uint height) : UI(width, height), + #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS context(getRackContextFromPlugin(getPluginInstancePointer())), + #else + context(new CardinalPluginContext(nullptr)), + #endif + remoteDetails(nullptr), saving(false), savingUncompressed(false), #ifdef DISTRHO_OS_WASM @@ -169,15 +262,16 @@ class CardinalBaseUI : public UI { filebrowseraction(), filebrowserhandle(nullptr) { + context->tlw = this; context->ui = this; } ~CardinalBaseUI() override { + remoteUtils::disconnectFromRemote(remoteDetails); + if (filebrowserhandle != nullptr) fileBrowserClose(filebrowserhandle); - - context->ui = nullptr; } }; #endif diff --git a/src/Rack b/src/Rack index 5551617a..f1576e2b 160000 --- a/src/Rack +++ b/src/Rack @@ -1 +1 @@ -Subproject commit 5551617afff182925940908eaf73a7d7361303cc +Subproject commit f1576e2bb870da297789300117accb9d5fe44c5e diff --git a/src/WindowParameters.hpp b/src/WindowParameters.hpp index 55c28323..d8f6780f 100644 --- a/src/WindowParameters.hpp +++ b/src/WindowParameters.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -15,10 +15,6 @@ * For a full copy of the GNU General Public License see the LICENSE file. */ -#ifdef HEADLESS -# error wrong include -#endif - #pragma once #include "DistrhoUtils.hpp" diff --git a/src/custom/RemoteNanoVG.cpp b/src/custom/RemoteNanoVG.cpp index a299cf05..59aab3dc 100644 --- a/src/custom/RemoteNanoVG.cpp +++ b/src/custom/RemoteNanoVG.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -15,23 +15,21 @@ * For a full copy of the GNU General Public License see the LICENSE file. */ -#ifndef HEADLESS -#include "OpenGL.hpp" +#include "DistrhoPluginInfo.h" + +#ifndef DISTRHO_PLUGIN_WANT_DIRECT_ACCESS +# error wrong build 1 +#endif +#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS && !defined(HEADLESS) +# error wrong build 2 #endif #include "nanovg.h" -#ifdef HEADLESS struct NVGLUframebuffer; void nvgluBindFramebuffer(NVGLUframebuffer* fb) {} NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imageFlags) { return nullptr; } void nvgluDeleteFramebuffer(NVGLUframebuffer* fb) {} -#else -# define NANOVG_GLES2_IMPLEMENTATION -# define NANOVG_FBO_VALID 1 -# include "nanovg_gl.h" -# include "nanovg_gl_utils.h" -#endif #if defined(__GNUC__) && (__GNUC__ >= 6) # pragma GCC diagnostic push @@ -61,8 +59,3 @@ GLFWAPI int glfwGetKeyScancode(int) { return 0; } GLFWAPI double glfwGetTime(void) { return 0.0; } } - -#ifndef HEADLESS -# define STB_IMAGE_WRITE_IMPLEMENTATION -# include "../src/Rack/dep/glfw/deps/stb_image_write.h" -#endif diff --git a/src/custom/RemoteWindow.cpp b/src/custom/RemoteWindow.cpp index 29a3cff4..575f322e 100644 --- a/src/custom/RemoteWindow.cpp +++ b/src/custom/RemoteWindow.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's Window.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -108,10 +108,6 @@ void Window::step() { } -void Window::activateContext() { -} - - void Window::screenshot(const std::string&) { } diff --git a/src/custom/asset.cpp b/src/custom/asset.cpp index 40ee4f27..c1a2897a 100644 --- a/src/custom/asset.cpp +++ b/src/custom/asset.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -31,10 +31,24 @@ namespace rack { namespace asset { -std::string userDir; // ignored +#ifndef HEADLESS +extern bool forceBlackScrew; +extern bool forceSilverScrew; +#endif + +std::string configDir; // points to writable config dir (might be equal to userDir) +std::string userDir; // points to common writable dir std::string systemDir; // points to plugin resources dir (or installed/local Rack dir) std::string bundlePath; // points to plugin manifests dir (or empty) +std::string config(std::string filename) { + return system::join(configDir, filename); +} + +std::string user(std::string filename) { + return system::join(userDir, filename); +} + // get rid of "res/" prefix static inline std::string& trim(std::string& s) { @@ -43,17 +57,18 @@ static inline std::string& trim(std::string& s) return s; } -// ignored, returns the same as `system` -std::string user(std::string filename) { - return system(filename); -} - // get system resource, trimming "res/" prefix if we are loaded as a plugin bundle std::string system(std::string filename) { + #ifndef HEADLESS + /**/ if (forceBlackScrew && string::endsWith(filename, "/ScrewBlack.svg")) + filename = filename.substr(0, filename.size()-15) + "/./ScrewBlack.svg"; + else if (forceSilverScrew && string::endsWith(filename, "/ScrewSilver.svg")) + filename = filename.substr(0, filename.size()-16) + "/./ScrewSilver.svg"; + #endif return system::join(systemDir, bundlePath.empty() ? filename : trim(filename)); } -// get plugin resource +// get plugin resource path std::string plugin(plugin::Plugin* plugin, std::string filename) { DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr, {}); return system::join(plugin->path, filename); diff --git a/src/custom/dep.cpp b/src/custom/dep.cpp index 278368e1..18d6df4b 100644 --- a/src/custom/dep.cpp +++ b/src/custom/dep.cpp @@ -23,9 +23,54 @@ #include namespace rack { +#ifndef HEADLESS +namespace asset { +bool forceBlackScrew = false; +bool forceSilverScrew = false; +void updateForcingBlackSilverScrewMode(std::string slug) { + forceBlackScrew = ( + // arable instruments + slug == "Joni" + // axioma + || slug == "TheBifurcator" + || slug == "Tesseract" + || slug == "Ikeda" + || slug == "Rhodonea" + // parable instruments + || slug == "Neil" + // rackwindows + || slug == "bitshiftgain" + || slug == "capacitor" + || slug == "capacitor_stereo" + || slug == "chorus" + || slug == "console" + || slug == "console_mm" + || slug == "distance" + || slug == "golem" + || slug == "holt" + || slug == "hombre" + || slug == "interstage" + || slug == "monitoring" + || slug == "mv" + || slug == "rasp" + || slug == "reseq" + || slug == "tape" + || slug == "tremolo" + || slug == "vibrato" + ); +} +} +#endif +namespace plugin { +void updateStaticPluginsDarkMode(); +} namespace settings { bool darkMode = true; int rateLimit = 0; +extern std::string uiTheme; +} +namespace ui { +void refreshTheme(); } } @@ -56,419 +101,551 @@ NVGcolor nvgRGBblank(const unsigned char r, const unsigned char g, const unsigne #undef nsvgParseFromFile #include +#ifndef HEADLESS +enum DarkMode { + kMode21kHz, + kModeAaronStatic, + kModeAlefsbits, + kModeAlgoritmarte, + kModeArableInstruments, + kModeAudibleInstruments, + kModeBidoo, + kModeCf, + kModeDrumKit, + kModeESeries, + kModeHetrickCV, + kModeJW, + kModeLilacLoop, + kModeLittleUtils, + kModeKocmoc, + kModeMyth, + kModeNonlinearcircuits, + kModeParableInstruments, + kModePathSet, + kModeVoxglitch, + kModeWhatTheRack, +}; + // Custom Cardinal filtering static const struct { + const DarkMode mode; const char* const filename; const char* shapeIdsToIgnore[5]; const int shapeNumberToIgnore; } svgFilesToInvertForDarkMode[] = { // MIT - { "/21kHz/res/Panels/D_Inf.svg", {}, -1 }, - { "/21kHz/res/Panels/PalmLoop.svg", {}, -1 }, - { "/21kHz/res/Panels/TachyonEntangler.svg", {}, -1 }, + { kMode21kHz, "/21kHz/res/Panels/D_Inf.svg", {}, -1 }, + { kMode21kHz, "/21kHz/res/Panels/PalmLoop.svg", {}, -1 }, + { kMode21kHz, "/21kHz/res/Panels/TachyonEntangler.svg", {}, -1 }, // MIT - {"/AaronStatic/res/ChordCV.svg", {}, -1 }, - {"/AaronStatic/res/DiatonicCV.svg", {}, -1 }, - {"/AaronStatic/res/RandomNoteCV.svg", {}, -1 }, - {"/AaronStatic/res/ScaleCV.svg", {}, -1 }, + { kModeAaronStatic, "/AaronStatic/res/ChordCV.svg", {}, -1 }, + { kModeAaronStatic, "/AaronStatic/res/DiatonicCV.svg", {}, -1 }, + { kModeAaronStatic, "/AaronStatic/res/RandomNoteCV.svg", {}, -1 }, + { kModeAaronStatic, "/AaronStatic/res/ScaleCV.svg", {}, -1 }, // GPL3.0-or-later - { "/Algoritmarte/res/Clockkky.svg", {}, -1 }, - { "/Algoritmarte/res/CyclicCA.svg", {}, -1 }, - { "/Algoritmarte/res/HoldMeTight.svg", {}, -1 }, - { "/Algoritmarte/res/MusiFrog.svg", {}, -1 }, - { "/Algoritmarte/res/MusiMath.svg", {}, -1 }, - { "/Algoritmarte/res/Planetz.svg", {}, -1 }, - { "/Algoritmarte/res/Zefiro.svg", {}, -1 }, - // Custom, runtime dark mode used with permission - { "/ArableInstruments/res/Joni.svg", {}, -1 }, + { kModeAlefsbits, "/alefsbits/res/blank6hp.svg", {}, -1 }, + { kModeAlefsbits, "/alefsbits/res/fibb.svg", {}, -1 }, + { kModeAlefsbits, "/alefsbits/res/logic.svg", {}, -1 }, + { kModeAlefsbits, "/alefsbits/res/math.svg", {}, -1 }, + { kModeAlefsbits, "/alefsbits/res/mlt.svg", {}, -1 }, + { kModeAlefsbits, "/alefsbits/res/noize.svg", {}, -1 }, + { kModeAlefsbits, "/alefsbits/res/octsclr.svg", {}, -1 }, + { kModeAlefsbits, "/alefsbits/res/polyrand.svg", {}, -1 }, + { kModeAlefsbits, "/alefsbits/res/shift.svg", {}, -1 }, + { kModeAlefsbits, "/alefsbits/res/simplexandhold.svg", {}, -1 }, + { kModeAlefsbits, "/alefsbits/res/simplexvco.svg", {}, -1 }, + { kModeAlefsbits, "/alefsbits/res/steps.svg", {}, -1 }, + { kModeAlefsbits, "/alefsbits/res/switch.svg", {}, -1 }, + // GPL3.0-or-later + { kModeAlgoritmarte, "/Algoritmarte/res/Clockkky.svg", {}, -1 }, + { kModeAlgoritmarte, "/Algoritmarte/res/CyclicCA.svg", {}, -1 }, + { kModeAlgoritmarte, "/Algoritmarte/res/HoldMeTight.svg", {}, -1 }, + { kModeAlgoritmarte, "/Algoritmarte/res/MusiFrog.svg", {}, -1 }, + { kModeAlgoritmarte, "/Algoritmarte/res/MusiMath.svg", {}, -1 }, + { kModeAlgoritmarte, "/Algoritmarte/res/Planetz.svg", {}, -1 }, + { kModeAlgoritmarte, "/Algoritmarte/res/Zefiro.svg", {}, -1 }, // Custom, runtime dark mode used with permission - { "/AudibleInstruments/res/Blinds.svg", {}, -1 }, - { "/AudibleInstruments/res/Braids.svg", {}, -1 }, - { "/AudibleInstruments/res/Branches.svg", {}, -1 }, - { "/AudibleInstruments/res/Clouds.svg", {}, -1 }, - { "/AudibleInstruments/res/Elements.svg", {}, -1 }, - { "/AudibleInstruments/res/Frames.svg", {}, -1 }, - { "/AudibleInstruments/res/Kinks.svg", {}, -1 }, - { "/AudibleInstruments/res/Links.svg", {}, -1 }, - { "/AudibleInstruments/res/Marbles.svg", {}, -1 }, - { "/AudibleInstruments/res/Peaks.svg", {}, -1 }, - { "/AudibleInstruments/res/Plaits.svg", {}, -1 }, - { "/AudibleInstruments/res/Rings.svg", {}, -1 }, - { "/AudibleInstruments/res/Ripples.svg", {}, -1 }, - { "/AudibleInstruments/res/Shades.svg", {}, -1 }, - { "/AudibleInstruments/res/Sheep.svg", {}, -1 }, - { "/AudibleInstruments/res/Shelves.svg", {}, -1 }, - { "/AudibleInstruments/res/Stages.svg", {}, -1 }, - { "/AudibleInstruments/res/Streams.svg", {}, -1 }, - { "/AudibleInstruments/res/Tides.svg", {}, -1 }, - { "/AudibleInstruments/res/Tides2.svg", {}, -1 }, - { "/AudibleInstruments/res/Veils.svg", {}, -1 }, - { "/AudibleInstruments/res/Warps.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Blinds.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Braids.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Branches.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Clouds.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Elements.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Frames.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Kinks.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Links.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Marbles.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Peaks.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Plaits.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Rings.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Ripples.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Shades.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Sheep.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Shelves.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Stages.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Streams.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Tides.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Tides2.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Veils.svg", {}, -1 }, + { kModeAudibleInstruments, "/AudibleInstruments/res/Warps.svg", {}, -1 }, // CC-BY-NC-ND-4.0, runtime dark mode used with permission - { "/Bidoo/res/ACNE.svg", {}, -1 }, - { "/Bidoo/res/ANTN.svg", {}, -1 }, - { "/Bidoo/res/BAFIS.svg", {}, -1 }, - { "/Bidoo/res/BANCAU.svg", {}, -1 }, - { "/Bidoo/res/BAR.svg", {"rect833"}, -1 }, - { "/Bidoo/res/BISTROT.svg", {}, -1 }, - { "/Bidoo/res/BORDL.svg", {"rect959-3-0-7-5","rect959-3-0-7","rect959-3-0","rect959-3"}, -1 }, - { "/Bidoo/res/CANARD.svg", {"rect959-3-7"}, -1 }, - { "/Bidoo/res/CHUTE.svg", {}, -1 }, - { "/Bidoo/res/DFUZE.svg", {}, -1 }, - { "/Bidoo/res/DIKTAT.svg", {"rect843","rect843-0","rect843-0-8"}, -1 }, - { "/Bidoo/res/DILEMO.svg", {}, -1 }, - { "/Bidoo/res/DTROY.svg", {"rect959-3"}, -1 }, - { "/Bidoo/res/DUKE.svg", {}, -1 }, - { "/Bidoo/res/EDSAROS.svg", {"rect959-3-7","rect959-3-7-8","rect959-3-7-8-1","rect959-3-7-8-1-4"}, -1 }, - { "/Bidoo/res/EMILE.svg", {}, -1 }, - { "/Bidoo/res/FLAME.svg", {}, -1 }, - { "/Bidoo/res/FORK.svg", {}, -1 }, - { "/Bidoo/res/FREIN.svg", {}, -1 }, - { "/Bidoo/res/HCTIP.svg", {}, -1 }, - { "/Bidoo/res/HUITRE.svg", {}, -1 }, - { "/Bidoo/res/LAMBDA.svg", {}, -1 }, - { "/Bidoo/res/LATE.svg", {}, -1 }, - { "/Bidoo/res/LIMBO.svg", {}, -1 }, - { "/Bidoo/res/LIMONADE.svg", {"rect839","rect839-6"}, -1 }, - { "/Bidoo/res/LOURDE.svg", {"rect847","rect847-7","rect847-5","rect847-3"}, -1 }, - { "/Bidoo/res/MAGMA.svg", {}, -1 }, - { "/Bidoo/res/MINIBAR.svg", {"rect833"}, -1 }, - { "/Bidoo/res/MOIRE.svg", {"rect843","rect843-7"}, -1 }, - { "/Bidoo/res/MS.svg", {}, -1 }, - { "/Bidoo/res/MU.svg", {"rect864"}, -1 }, - { "/Bidoo/res/OAI.svg", {}, -1 }, - { "/Bidoo/res/OUAIVE.svg", {"rect959-3-7"}, -1 }, - { "/Bidoo/res/PERCO.svg", {}, -1 }, - { "/Bidoo/res/PILOT.svg", {"rect843-6-4-5","rect843","rect843-4","rect843-6-4","rect843-6-7"}, -1 }, - { "/Bidoo/res/POUPRE.svg", {}, -1 }, - { "/Bidoo/res/RABBIT.svg", {}, -1 }, - { "/Bidoo/res/REI.svg", {}, -1 }, - { "/Bidoo/res/SIGMA.svg", {}, -1 }, - { "/Bidoo/res/SPORE.svg", {}, -1 }, - { "/Bidoo/res/TIARE.svg", {}, -1 }, - { "/Bidoo/res/TOCANTE.svg", {"rect843"}, -1 }, - { "/Bidoo/res/VOID.svg", {}, -1 }, - { "/Bidoo/res/ZINC.svg", {}, -1 }, - { "/Bidoo/res/ZOUMAI.svg", {}, -1 }, - { "/Bidoo/res/ZOUMAIExpander.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/ACNE.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/ANTN.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/BAFIS.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/BANCAU.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/BAR.svg", {"rect833"}, -1 }, + { kModeBidoo, "/Bidoo/res/BISTROT.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/BORDL.svg", {"rect959-3-0-7-5","rect959-3-0-7","rect959-3-0","rect959-3"}, -1 }, + { kModeBidoo, "/Bidoo/res/CANARD.svg", {"rect959-3-7"}, -1 }, + { kModeBidoo, "/Bidoo/res/CHUTE.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/DFUZE.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/DIKTAT.svg", {"rect843","rect843-0","rect843-0-8"}, -1 }, + { kModeBidoo, "/Bidoo/res/DILEMO.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/DTROY.svg", {"rect959-3"}, -1 }, + { kModeBidoo, "/Bidoo/res/DUKE.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/EDSAROS.svg", {"rect959-3-7","rect959-3-7-8","rect959-3-7-8-1","rect959-3-7-8-1-4"}, -1 }, + { kModeBidoo, "/Bidoo/res/EMILE.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/ENCORE.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/ENCOREExpander.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/FLAME.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/FORK.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/FREIN.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/HCTIP.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/HUITRE.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/LAMBDA.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/LATE.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/LIMBO.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/LIMONADE.svg", {"rect839","rect839-6"}, -1 }, + { kModeBidoo, "/Bidoo/res/LOURDE.svg", {"rect847","rect847-7","rect847-5","rect847-3"}, -1 }, + { kModeBidoo, "/Bidoo/res/MAGMA.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/MINIBAR.svg", {"rect833"}, -1 }, + { kModeBidoo, "/Bidoo/res/MOIRE.svg", {"rect843","rect843-7"}, -1 }, + { kModeBidoo, "/Bidoo/res/MS.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/MU.svg", {"rect864"}, -1 }, + { kModeBidoo, "/Bidoo/res/OAI.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/OUAIVE.svg", {"rect959-3-7"}, -1 }, + { kModeBidoo, "/Bidoo/res/PERCO.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/PILOT.svg", {"rect843-6-4-5","rect843","rect843-4","rect843-6-4","rect843-6-7"}, -1 }, + { kModeBidoo, "/Bidoo/res/POUPRE.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/RABBIT.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/REI.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/SIGMA.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/SPORE.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/TIARE.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/TOCANTE.svg", {"rect843"}, -1 }, + { kModeBidoo, "/Bidoo/res/VOID.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/ZINC.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/ZOUMAI.svg", {}, -1 }, + { kModeBidoo, "/Bidoo/res/ZOUMAIExpander.svg", {}, -1 }, // BSD-3-Clause - { "/cf/res/ALGEBRA.svg", {}, -1 }, - { "/cf/res/BUFFER.svg", {}, -1 }, - { "/cf/res/CHOKE.svg", {}, -1 }, - { "/cf/res/CUBE.svg", {}, -1 }, - { "/cf/res/CUTS.svg", {}, -1 }, - { "/cf/res/DISTO.svg", {}, -1 }, - { "/cf/res/EACH.svg", {}, -1 }, - { "/cf/res/FOUR.svg", {}, -1 }, - { "/cf/res/FUNKTION.svg", {}, -1 }, - { "/cf/res/L3DS3Q.svg", {}, 3 }, - { "/cf/res/LABEL.svg", {}, -1 }, - { "/cf/res/LEDS.svg", {}, -1 }, - { "/cf/res/LEDSEQ.svg", {}, 3 }, - { "/cf/res/MASTER.svg", {}, -1 }, - { "/cf/res/METRO.svg", {}, -1 }, - { "/cf/res/MONO.svg", {}, -1 }, - { "/cf/res/PATCH.svg", {}, -1 }, - { "/cf/res/PEAK.svg", {}, -1 }, - { "/cf/res/PLAY.svg", {}, -1 }, - { "/cf/res/PLAYER.svg", {}, -1 }, - { "/cf/res/SLIDERSEQ.svg", {}, -1 }, - { "/cf/res/STEPS.svg", {}, -1 }, - { "/cf/res/STEREO.svg", {}, -1 }, - { "/cf/res/SUB.svg", {}, -1 }, - { "/cf/res/trSEQ.svg", {}, -1 }, - { "/cf/res/VARIABLE.svg", {}, -1 }, + { kModeCf, "/cf/res/ALGEBRA.svg", {}, -1 }, + { kModeCf, "/cf/res/BUFFER.svg", {}, -1 }, + { kModeCf, "/cf/res/CHOKE.svg", {}, -1 }, + { kModeCf, "/cf/res/CUBE.svg", {}, -1 }, + { kModeCf, "/cf/res/CUTS.svg", {}, -1 }, + { kModeCf, "/cf/res/DISTO.svg", {}, -1 }, + { kModeCf, "/cf/res/EACH.svg", {}, -1 }, + { kModeCf, "/cf/res/FOUR.svg", {}, -1 }, + { kModeCf, "/cf/res/FUNKTION.svg", {}, -1 }, + { kModeCf, "/cf/res/L3DS3Q.svg", {}, 3 }, + { kModeCf, "/cf/res/LABEL.svg", {}, -1 }, + { kModeCf, "/cf/res/LEDS.svg", {}, -1 }, + { kModeCf, "/cf/res/LEDSEQ.svg", {}, 3 }, + { kModeCf, "/cf/res/MASTER.svg", {}, -1 }, + { kModeCf, "/cf/res/METRO.svg", {}, -1 }, + { kModeCf, "/cf/res/MONO.svg", {}, -1 }, + { kModeCf, "/cf/res/PATCH.svg", {}, -1 }, + { kModeCf, "/cf/res/PEAK.svg", {}, -1 }, + { kModeCf, "/cf/res/PLAY.svg", {}, -1 }, + { kModeCf, "/cf/res/PLAYER.svg", {}, -1 }, + { kModeCf, "/cf/res/SLIDERSEQ.svg", {}, -1 }, + { kModeCf, "/cf/res/STEPS.svg", {}, -1 }, + { kModeCf, "/cf/res/STEREO.svg", {}, -1 }, + { kModeCf, "/cf/res/SUB.svg", {}, -1 }, + { kModeCf, "/cf/res/trSEQ.svg", {}, -1 }, + { kModeCf, "/cf/res/VARIABLE.svg", {}, -1 }, // CC0-1.0 - { "/DrumKit/res/Baronial.svg", {}, -1 }, - { "/DrumKit/res/BD9.svg", {}, -1 }, - { "/DrumKit/res/ClosedHH.svg", {}, -1 }, - { "/DrumKit/res/CR78.svg", {}, -1 }, - { "/DrumKit/res/DMX.svg", {}, -1 }, - { "/DrumKit/res/Gnome.svg", {}, -1 }, - { "/DrumKit/res/Marionette.svg", {}, -1 }, - { "/DrumKit/res/OpenHH.svg", {}, -1 }, - { "/DrumKit/res/SBD.svg", {}, -1 }, - { "/DrumKit/res/Sequencer.svg", {}, -1 }, - { "/DrumKit/res/Snare.svg", {}, -1 }, - { "/DrumKit/res/Tomi.svg", {}, -1 }, + { kModeDrumKit, "/DrumKit/res/Baronial.svg", {}, -1 }, + { kModeDrumKit, "/DrumKit/res/BD9.svg", {}, -1 }, + { kModeDrumKit, "/DrumKit/res/ClosedHH.svg", {}, -1 }, + { kModeDrumKit, "/DrumKit/res/CR78.svg", {}, -1 }, + { kModeDrumKit, "/DrumKit/res/DMX.svg", {}, -1 }, + { kModeDrumKit, "/DrumKit/res/Gnome.svg", {}, -1 }, + { kModeDrumKit, "/DrumKit/res/Marionette.svg", {}, -1 }, + { kModeDrumKit, "/DrumKit/res/OpenHH.svg", {}, -1 }, + { kModeDrumKit, "/DrumKit/res/SBD.svg", {}, -1 }, + { kModeDrumKit, "/DrumKit/res/Sequencer.svg", {}, -1 }, + { kModeDrumKit, "/DrumKit/res/Snare.svg", {}, -1 }, + { kModeDrumKit, "/DrumKit/res/Tomi.svg", {}, -1 }, // Custom, runtime dark mode used with permission - { "/ESeries/res/E340.svg", {}, -1 }, + { kModeESeries,"/ESeries/res/E340.svg", {}, -1 }, // CC0-1.0 - { "/HetrickCV/res/1OpChaos.svg", {}, -1}, - { "/HetrickCV/res/2OpChaos.svg", {}, -1}, - { "/HetrickCV/res/2To4.svg", {}, -1}, - { "/HetrickCV/res/3OpChaos.svg", {}, -1}, - { "/HetrickCV/res/ASR.svg", {}, -1}, - { "/HetrickCV/res/AToD.svg", {}, -1}, - { "/HetrickCV/res/BinaryGate.svg", {}, -1}, - { "/HetrickCV/res/BinaryNoise.svg", {}, -1}, - { "/HetrickCV/res/Bitshift.svg", {}, -1}, - { "/HetrickCV/res/Boolean3.svg", {}, -1}, - { "/HetrickCV/res/ChaoticAttractors.svg", {}, -1}, - { "/HetrickCV/res/ClockedNoise.svg", {}, -1}, - { "/HetrickCV/res/Comparator.svg", {}, -1}, - { "/HetrickCV/res/Contrast.svg", {}, -1}, - { "/HetrickCV/res/Crackle.svg", {}, -1}, - { "/HetrickCV/res/DataCompander.svg", {}, -1}, - { "/HetrickCV/res/Delta.svg", {}, -1}, - { "/HetrickCV/res/DToA.svg", {}, -1}, - { "/HetrickCV/res/Dust.svg", {}, -1}, - { "/HetrickCV/res/Exponent.svg", {}, -1}, - { "/HetrickCV/res/FBSineChaos.svg", {}, -1}, - { "/HetrickCV/res/FlipFlop.svg", {}, -1}, - { "/HetrickCV/res/FlipPan.svg", {}, -1}, - { "/HetrickCV/res/GateJunction.svg", {}, -1}, - { "/HetrickCV/res/Gingerbread.svg", {}, -1}, - { "/HetrickCV/res/LogicCombiner.svg", {}, -1}, - { "/HetrickCV/res/LogicInverter.svg", {}, -1}, - { "/HetrickCV/res/MidSide.svg", {}, -1}, - { "/HetrickCV/res/MinMax.svg", {}, -1}, - { "/HetrickCV/res/RandomGates.svg", {}, -1}, - { "/HetrickCV/res/Rotator.svg", {}, -1}, - { "/HetrickCV/res/Rungler.svg", {}, -1}, - { "/HetrickCV/res/Scanner.svg", {}, -1}, - { "/HetrickCV/res/TrigShaper.svg", {}, -1}, - { "/HetrickCV/res/Waveshape.svg", {}, -1}, - { "/HetrickCV/res/XYToPolar.svg", {}, -1}, - { "/HetrickCV/res/Blanks/BlankPanel1.svg", {}, -1}, - { "/HetrickCV/res/Blanks/BlankPanel2.svg", {}, -1}, - { "/HetrickCV/res/Blanks/BlankPanel3.svg", {}, -1}, - { "/HetrickCV/res/Blanks/BlankPanel5.svg", {}, -1}, - { "/HetrickCV/res/Blanks/BlankPanel6.svg", {}, -1}, - { "/HetrickCV/res/Blanks/BlankPanel7.svg", {}, -1}, - { "/HetrickCV/res/Blanks/BlankPanel8.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/1OpChaos.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/2OpChaos.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/2To4.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/3OpChaos.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/ASR.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/AToD.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/BinaryGate.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/BinaryNoise.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Bitshift.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Boolean3.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/ChaoticAttractors.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/ClockedNoise.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Comparator.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Contrast.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Crackle.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/DataCompander.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Delta.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/DToA.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Dust.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Exponent.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/FBSineChaos.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/FlipFlop.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/FlipPan.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/GateJunction.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Gingerbread.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/LogicCombiner.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/LogicInverter.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/MidSide.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/MinMax.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/RandomGates.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Rotator.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Rungler.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Scanner.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/TrigShaper.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Waveshape.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/XYToPolar.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Blanks/BlankPanel1.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Blanks/BlankPanel2.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Blanks/BlankPanel3.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Blanks/BlankPanel5.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Blanks/BlankPanel6.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Blanks/BlankPanel7.svg", {}, -1}, + { kModeHetrickCV, "/HetrickCV/res/Blanks/BlankPanel8.svg", {}, -1}, // BSD-3-Clause - { "/JW-Modules/res/Add5.svg", {}, -1 }, - { "/JW-Modules/res/BlankPanel1hp.svg", {}, -1 }, - { "/JW-Modules/res/BlankPanelLarge.svg", {}, -1 }, - { "/JW-Modules/res/BlankPanelMedium.svg", {}, -1 }, - { "/JW-Modules/res/BlankPanelSmall.svg", {}, -1 }, - { "/JW-Modules/res/BouncyBalls.svg", {}, -1 }, - { "/JW-Modules/res/D1v1de.svg", {}, -1 }, - { "/JW-Modules/res/DivSeq.svg", {}, -1 }, - { "/JW-Modules/res/EightSeq.svg", {}, -1 }, - { "/JW-Modules/res/GridSeq.svg", {}, -1 }, - { "/JW-Modules/res/MinMax.svg", {"path38411"}, -1 }, - { "/JW-Modules/res/NoteSeq.svg", {}, -1 }, - { "/JW-Modules/res/NoteSeq16.svg", {}, -1 }, - { "/JW-Modules/res/NoteSeqFu.svg", {}, -1 }, - { "/JW-Modules/res/OnePattern.svg", {}, -1 }, - { "/JW-Modules/res/Patterns.svg", {}, -1 }, - { "/JW-Modules/res/Pres1t.svg", {}, -1 }, - { "/JW-Modules/res/PT.svg", {}, -1 }, - { "/JW-Modules/res/Str1ker.svg", {"rect2094","rect995","rect169"}, -1 }, - { "/JW-Modules/res/Trigs.svg", {}, -1 }, - { "/JW-Modules/res/WavHeadPanel.svg", {}, -1 }, - { "/JW-Modules/res/XYPad.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/Add5.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/BlankPanel1hp.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/BlankPanelLarge.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/BlankPanelMedium.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/BlankPanelSmall.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/BouncyBalls.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/D1v1de.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/DivSeq.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/EightSeq.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/GridSeq.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/MinMax.svg", {"path38411"}, -1 }, + { kModeJW, "/JW-Modules/res/NoteSeq.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/NoteSeq16.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/NoteSeqFu.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/OnePattern.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/Patterns.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/Pres1t.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/PT.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/Str1ker.svg", {"rect2094","rect995","rect169"}, -1 }, + { kModeJW, "/JW-Modules/res/Trigs.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/WavHeadPanel.svg", {}, -1 }, + { kModeJW, "/JW-Modules/res/XYPad.svg", {}, -1 }, // GPL3.0-or-later - { "/LilacLoop/res/Looper.svg", {}, -1 }, + { kModeLilacLoop, "/LilacLoop/res/Looper.svg", {}, -1 }, // EUPL-1.2 - { "/LittleUtils/res/Bias_Semitone.svg", {}, -1 }, - { "/LittleUtils/res/ButtonModule.svg", {}, -1 }, - { "/LittleUtils/res/MulDiv.svg", {}, -1 }, - { "/LittleUtils/res/PulseGenerator.svg", {}, -1 }, - { "/LittleUtils/res/TeleportIn.svg", {}, -1 }, - { "/LittleUtils/res/TeleportOut.svg", {}, -1 }, + { kModeLittleUtils, "/LittleUtils/res/Bias_Semitone.svg", {}, -1 }, + { kModeLittleUtils, "/LittleUtils/res/ButtonModule.svg", {}, -1 }, + { kModeLittleUtils, "/LittleUtils/res/MulDiv.svg", {}, -1 }, + { kModeLittleUtils, "/LittleUtils/res/PulseGenerator.svg", {}, -1 }, + { kModeLittleUtils, "/LittleUtils/res/TeleportIn.svg", {}, -1 }, + { kModeLittleUtils, "/LittleUtils/res/TeleportOut.svg", {}, -1 }, // GPL-3.0-or-later - { "/kocmoc/res/DDLY.svg", {}, -1 }, - { "/kocmoc/res/LADR.svg", {}, -1 }, - { "/kocmoc/res/MUL.svg", {}, -1 }, - { "/kocmoc/res/OP.svg", {}, -1 }, - { "/kocmoc/res/PHASR.svg", {}, -1 }, - { "/kocmoc/res/SKF.svg", {}, -1 }, - { "/kocmoc/res/SVF.svg", {}, -1 }, - { "/kocmoc/res/TRG.svg", {}, -1 }, + { kModeKocmoc, "/kocmoc/res/DDLY.svg", {}, -1 }, + { kModeKocmoc, "/kocmoc/res/LADR.svg", {}, -1 }, + { kModeKocmoc, "/kocmoc/res/MUL.svg", {}, -1 }, + { kModeKocmoc, "/kocmoc/res/OP.svg", {}, -1 }, + { kModeKocmoc, "/kocmoc/res/PHASR.svg", {}, -1 }, + { kModeKocmoc, "/kocmoc/res/SKF.svg", {}, -1 }, + { kModeKocmoc, "/kocmoc/res/SVF.svg", {}, -1 }, + { kModeKocmoc, "/kocmoc/res/TRG.svg", {}, -1 }, // GPL-3.0-or-later - { "/myth-modules/res/Mavka.svg", {}, -1 }, - { "/myth-modules/res/Molphar.svg", {}, -1 }, + { kModeMyth, "/myth-modules/res/Mavka.svg", {}, -1 }, + { kModeMyth, "/myth-modules/res/Molphar.svg", {}, -1 }, // CC0-1.0 - { "/nonlinearcircuits/res/BOOLs2.svg", {}, -1 }, - { "/nonlinearcircuits/res/DoubleNeuronRef.svg", {}, -1 }, - { "/nonlinearcircuits/res/LetsSplosh.svg", {}, -1 }, - { "/nonlinearcircuits/res/NLC - 4seq.svg", {}, -1 }, - { "/nonlinearcircuits/res/NLC - 8 BIT CIPHER.svg", {}, -1 }, - { "/nonlinearcircuits/res/NLC - DIVIDE & CONQUER.svg", {}, -1 }, - { "/nonlinearcircuits/res/NLC - DIVINE CMOS.svg", {}, -1 }, - { "/nonlinearcircuits/res/NLC - GENiE.svg", {}, -1 }, - { "/nonlinearcircuits/res/NLC - NEURON.svg", {}, -1 }, - { "/nonlinearcircuits/res/NLC - NUMBERWANG.svg", {}, -1 }, - { "/nonlinearcircuits/res/NLC - SEGUE.svg", {}, -1 }, - { "/nonlinearcircuits/res/NLC - STATUES.svg", {}, -1 }, - { "/nonlinearcircuits/res/squid-axon-papernoise-panel2.svg", {}, -1 }, - // Custom, runtime dark mode used with permission - { "/ParableInstruments/res/Neil.svg", {}, -1 }, + { kModeNonlinearcircuits, "/nonlinearcircuits/res/BOOLs2.svg", {}, -1 }, + { kModeNonlinearcircuits, "/nonlinearcircuits/res/DoubleNeuronRef.svg", {}, -1 }, + { kModeNonlinearcircuits, "/nonlinearcircuits/res/LetsSplosh.svg", {}, -1 }, + { kModeNonlinearcircuits, "/nonlinearcircuits/res/NLC - 4seq.svg", {}, -1 }, + { kModeNonlinearcircuits, "/nonlinearcircuits/res/NLC - 8 BIT CIPHER.svg", {}, -1 }, + { kModeNonlinearcircuits, "/nonlinearcircuits/res/NLC - DIVIDE & CONQUER.svg", {}, -1 }, + { kModeNonlinearcircuits, "/nonlinearcircuits/res/NLC - DIVINE CMOS.svg", {}, -1 }, + { kModeNonlinearcircuits, "/nonlinearcircuits/res/NLC - GENiE.svg", {}, -1 }, + { kModeNonlinearcircuits, "/nonlinearcircuits/res/NLC - NEURON.svg", {}, -1 }, + { kModeNonlinearcircuits, "/nonlinearcircuits/res/NLC - NUMBERWANG.svg", {}, -1 }, + { kModeNonlinearcircuits, "/nonlinearcircuits/res/NLC - ROUTER.svg", {}, -1 }, + { kModeNonlinearcircuits, "/nonlinearcircuits/res/NLC - SEGUE.svg", {}, -1 }, + { kModeNonlinearcircuits, "/nonlinearcircuits/res/NLC - STATUES.svg", {}, -1 }, + { kModeNonlinearcircuits, "/nonlinearcircuits/res/squid-axon-papernoise-panel2.svg", {}, -1 }, + { kModeNonlinearcircuits, "/nonlinearcircuits/res/SlothApathy.svg", {}, -1 }, + { kModeNonlinearcircuits, "/nonlinearcircuits/res/SlothInertia.svg", {}, -1 }, + { kModeNonlinearcircuits, "/nonlinearcircuits/res/SlothTorpor.svg", {}, -1 }, + { kModeNonlinearcircuits, "/nonlinearcircuits/res/TripleSloth.svg", {}, -1 }, // GPL-3.0-or-later - { "/PathSet/res/AstroVibe.svg", {}, -1 }, - { "/PathSet/res/GlassPane.svg", {}, -1 }, - { "/PathSet/res/IceTray.svg", {}, -1 }, - { "/PathSet/res/Nudge.svg", {}, -1 }, - { "/PathSet/res/ShiftyExpander.svg", {}, -1 }, - { "/PathSet/res/ShiftyMod.svg", {}, -1 }, + { kModePathSet, "/PathSet/res/AstroVibe.svg", {}, -1 }, + { kModePathSet, "/PathSet/res/GlassPane.svg", {}, -1 }, + { kModePathSet, "/PathSet/res/IceTray.svg", {}, -1 }, + { kModePathSet, "/PathSet/res/Nudge.svg", {}, -1 }, + { kModePathSet, "/PathSet/res/OneShot.svg", {}, -1 }, + { kModePathSet, "/PathSet/res/PlusPane.svg", {}, -1 }, + { kModePathSet, "/PathSet/res/ShiftyExpander.svg", {}, -1 }, + { kModePathSet, "/PathSet/res/ShiftyMod.svg", {}, -1 }, // BSD-3-Clause - { "/voxglitch/res/autobreak_front_panel.svg", {}, -1 }, - { "/voxglitch/res/bytebeat_front_panel.svg", {}, -1 }, - { "/voxglitch/res/digital_programmer_front_panel.svg", {}, -1 }, - { "/voxglitch/res/digital_sequencer_front_panel.svg", {}, -1 }, - { "/voxglitch/res/digital_sequencer_xp_front_panel.svg", {}, -1 }, - { "/voxglitch/res/ghosts_front_panel.svg", {}, -1 }, - { "/voxglitch/res/glitch_sequencer_front_panel.svg", {}, -1 }, - { "/voxglitch/res/goblins_front_panel.svg", {}, -1 }, - { "/voxglitch/res/grain_engine_mk2_expander_front_panel.svg", {}, -1 }, - { "/voxglitch/res/grain_engine_mk2_front_panel_r3.svg", {}, -1 }, - { "/voxglitch/res/grain_fx_front_panel.svg", {}, -1 }, - { "/voxglitch/res/hazumi_front_panel.svg", {}, -1 }, - { "/voxglitch/res/looper_front_panel.svg", {}, -1 }, - { "/voxglitch/res/repeater_front_panel.svg", {}, -1 }, - { "/voxglitch/res/samplerx8_front_panel.svg", {}, -1 }, - { "/voxglitch/res/satanonaut_front_panel.svg", {}, -1 }, - { "/voxglitch/res/wav_bank_front_panel.svg", {}, -1 }, - { "/voxglitch/res/wav_bank_mc_front_panel_v2.svg", {}, -1 }, - { "/voxglitch/res/xy_front_panel.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/autobreak_front_panel.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/bytebeat_front_panel.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/digital_programmer_front_panel.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/digital_sequencer_front_panel.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/digital_sequencer_xp_front_panel.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/ghosts_front_panel.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/glitch_sequencer_front_panel.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/goblins_front_panel.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/grain_engine_mk2_expander_front_panel.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/grain_engine_mk2_front_panel_r3.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/grain_fx_front_panel.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/hazumi_front_panel.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/looper_front_panel.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/repeater_front_panel.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/samplerx8_front_panel.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/satanonaut_front_panel.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/wav_bank_front_panel.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/wav_bank_mc_front_panel_v2.svg", {}, -1 }, + { kModeVoxglitch, "/voxglitch/res/xy_front_panel.svg", {}, -1 }, // WTFPL - { "/WhatTheRack/res/WhatTheJack.svg", {}, -1 }, - { "/WhatTheRack/res/WhatTheMod.svg", {}, -1 }, - { "/WhatTheRack/res/WhatTheRack.svg", {}, -1 }, + { kModeWhatTheRack, "/WhatTheRack/res/WhatTheJack.svg", {}, -1 }, + { kModeWhatTheRack, "/WhatTheRack/res/WhatTheMod.svg", {}, -1 }, + { kModeWhatTheRack, "/WhatTheRack/res/WhatTheRack.svg", {}, -1 }, +}; + +enum LightMode { + kMode8Mode, + kModeAutinn, + kModeBefaco, + kModeCardinal, + kModeExtratone, + kModeFehlerFabrik, + kModeForsitan, + kModeFundamental, + kModeGoodSheperd, + kModeH4n4, + kModeHamptonHarmonics, + kModeLomas, + kModeMockba, + kModeMog, + kModePrism, + kModeRepelzen, + kModeSonusmodular, }; static const struct { + const LightMode mode; const char* const filename; - const char* shapeIdsToIgnore[5]; - const int shapeNumberToIgnore; } svgFilesToInvertForLightMode[] = { + // BSD + { kMode8Mode, "/8Mode/res/SNsoft_Panel.svg" }, + // GPLv3+ + { kModeAutinn, "/Autinn/res/AmpModule.svg" }, + { kModeAutinn, "/Autinn/res/BassModule.svg" }, + { kModeAutinn, "/Autinn/res/CVConverterModule.svg" }, + { kModeAutinn, "/Autinn/res/ComponentLibrary" }, + { kModeAutinn, "/Autinn/res/DeadbandModule.svg" }, + { kModeAutinn, "/Autinn/res/DigiModule.svg" }, + { kModeAutinn, "/Autinn/res/DiseeModule.svg" }, + { kModeAutinn, "/Autinn/res/FilModule.svg" }, + { kModeAutinn, "/Autinn/res/FlopperModule.svg" }, + { kModeAutinn, "/Autinn/res/ImpModule.svg" }, + { kModeAutinn, "/Autinn/res/JetteModule.svg" }, + { kModeAutinn, "/Autinn/res/MelodyModule.svg" }, + { kModeAutinn, "/Autinn/res/MeraModule.svg" }, + { kModeAutinn, "/Autinn/res/Mixer6Module.svg" }, + { kModeAutinn, "/Autinn/res/NapModule.svg" }, + { kModeAutinn, "/Autinn/res/NonModule.svg" }, + { kModeAutinn, "/Autinn/res/OxcartModule.svg" }, + { kModeAutinn, "/Autinn/res/RebelModule.svg" }, + { kModeAutinn, "/Autinn/res/RetriModule.svg" }, + { kModeAutinn, "/Autinn/res/SawModule.svg" }, + { kModeAutinn, "/Autinn/res/SjipModule.svg" }, + { kModeAutinn, "/Autinn/res/SquareModule.svg" }, + { kModeAutinn, "/Autinn/res/VibratoModule.svg" }, + { kModeAutinn, "/Autinn/res/VxyModule.svg" }, + { kModeAutinn, "/Autinn/res/ZodModule.svg" }, + // Custom, runtime light mode used with permission + { kModeBefaco, "/Befaco/res/components/Knurlie.svg" }, + { kModeBefaco, "/Befaco/res/panels/ABC.svg" }, + { kModeBefaco, "/Befaco/res/panels/ADSR.svg" }, + { kModeBefaco, "/Befaco/res/panels/ChoppingKinky.svg" }, + { kModeBefaco, "/Befaco/res/panels/DualAtenuverter.svg" }, + { kModeBefaco, "/Befaco/res/panels/EvenVCO.svg" }, + { kModeBefaco, "/Befaco/res/panels/HexmixVCA.svg" }, + { kModeBefaco, "/Befaco/res/panels/Kickall.svg" }, + { kModeBefaco, "/Befaco/res/panels/Mex.svg" }, + { kModeBefaco, "/Befaco/res/panels/Mixer.svg" }, + { kModeBefaco, "/Befaco/res/panels/Morphader.svg" }, + { kModeBefaco, "/Befaco/res/panels/MotionMTR.svg" }, + { kModeBefaco, "/Befaco/res/panels/Muxlicer.svg" }, + { kModeBefaco, "/Befaco/res/panels/NoisePlethora.svg" }, + { kModeBefaco, "/Befaco/res/panels/Percall.svg" }, + { kModeBefaco, "/Befaco/res/panels/PonyVCO.svg" }, + { kModeBefaco, "/Befaco/res/panels/Rampage.svg" }, + { kModeBefaco, "/Befaco/res/panels/STMix.svg" }, + { kModeBefaco, "/Befaco/res/panels/SamplingModulator.svg" }, + { kModeBefaco, "/Befaco/res/panels/SlewLimiter.svg" }, + { kModeBefaco, "/Befaco/res/panels/SpringReverb.svg" }, + { kModeBefaco, "/Befaco/res/panels/StereoStrip.svg" }, + // GPLv3+ + { kModeCardinal, "/Cardinal/res/AudioFile.svg" }, + { kModeCardinal, "/Cardinal/res/AudioToCVPitch.svg" }, + { kModeCardinal, "/Cardinal/res/Carla.svg" }, + { kModeCardinal, "/Cardinal/res/ExpanderMIDI.svg" }, + { kModeCardinal, "/Cardinal/res/glBars.svg" }, + { kModeCardinal, "/Cardinal/res/HostAudio.svg" }, + { kModeCardinal, "/Cardinal/res/HostCV.svg" }, + { kModeCardinal, "/Cardinal/res/HostMIDI.svg" }, + { kModeCardinal, "/Cardinal/res/HostMIDICC.svg" }, + { kModeCardinal, "/Cardinal/res/HostMIDIGate.svg" }, + { kModeCardinal, "/Cardinal/res/HostMIDIMap.svg" }, + { kModeCardinal, "/Cardinal/res/HostParameters.svg" }, + { kModeCardinal, "/Cardinal/res/HostParamsMap.svg" }, + { kModeCardinal, "/Cardinal/res/HostTime.svg" }, + { kModeCardinal, "/Cardinal/res/Ildaeil.svg" }, + // GPLv3+ + { kModeExtratone, "/Extratone/res/Darwinism.svg" }, + // { kModeExtratone, "/Extratone/res/HalluciMemory.svg" }, + { kModeExtratone, "/Extratone/res/Ichneumonid.svg" }, + { kModeExtratone, "/Extratone/res/Meganeura.svg" }, + { kModeExtratone, "/Extratone/res/Mesoglea.svg" }, + { kModeExtratone, "/Extratone/res/Mesoglea2.svg" }, + { kModeExtratone, "/Extratone/res/Mesohyl.svg" }, + { kModeExtratone, "/Extratone/res/Modulo.svg" }, + { kModeExtratone, "/Extratone/res/Opabinia.svg" }, + { kModeExtratone, "/Extratone/res/Pureneura.svg" }, + { kModeExtratone, "/Extratone/res/Puzzlebox.svg" }, + { kModeExtratone, "/Extratone/res/Splitterburst.svg" }, + { kModeExtratone, "/Extratone/res/XtrtnBlank.svg" }, // GPLv3+ - /* FIXME does not work very well - { "/Autinn/res/AmpModule.svg", {}, -1 }, - { "/Autinn/res/BassModule.svg", {}, -1 }, - { "/Autinn/res/CVConverterModule.svg", {}, -1 }, - { "/Autinn/res/ComponentLibrary", {}, -1 }, - { "/Autinn/res/DeadbandModule.svg", {}, -1 }, - { "/Autinn/res/DigiModule.svg", {}, -1 }, - { "/Autinn/res/DiseeModule.svg", {}, -1 }, - { "/Autinn/res/FilModule.svg", {}, -1 }, - { "/Autinn/res/FlopperModule.svg", {}, -1 }, - { "/Autinn/res/ImpModule.svg", {}, -1 }, - { "/Autinn/res/JetteModule.svg", {}, -1 }, - { "/Autinn/res/MelodyModule.svg", {}, -1 }, - { "/Autinn/res/MeraModule.svg", {}, -1 }, - { "/Autinn/res/Mixer6Module.svg", {}, -1 }, - { "/Autinn/res/NapModule.svg", {}, -1 }, - { "/Autinn/res/NonModule.svg", {}, -1 }, - { "/Autinn/res/OxcartModule.svg", {}, -1 }, - { "/Autinn/res/RebelModule.svg", {}, -1 }, - { "/Autinn/res/RetriModule.svg", {}, -1 }, - { "/Autinn/res/SawModule.svg", {}, -1 }, - { "/Autinn/res/SjipModule.svg", {}, -1 }, - { "/Autinn/res/SquareModule.svg", {}, -1 }, - { "/Autinn/res/VibratoModule.svg", {}, -1 }, - { "/Autinn/res/VxyModule.svg", {}, -1 }, - { "/Autinn/res/ZodModule.svg", {}, -1 }, - */ - // ??? used for testing, might get turned off - { "/Befaco/res/components/Knurlie.svg", {}, -1 }, - { "/Befaco/res/panels/ABC.svg", {}, -1 }, - { "/Befaco/res/panels/ADSR.svg", {}, -1 }, - { "/Befaco/res/panels/ChoppingKinky.svg", {}, -1 }, - { "/Befaco/res/panels/DualAtenuverter.svg", {}, -1 }, - { "/Befaco/res/panels/EvenVCO.svg", {}, -1 }, - { "/Befaco/res/panels/HexmixVCA.svg", {}, -1 }, - { "/Befaco/res/panels/Kickall.svg", {}, -1 }, - { "/Befaco/res/panels/Mex.svg", {}, -1 }, - { "/Befaco/res/panels/Mixer.svg", {}, -1 }, - { "/Befaco/res/panels/Morphader.svg", {}, -1 }, - { "/Befaco/res/panels/Muxlicer.svg", {}, -1 }, - { "/Befaco/res/panels/NoisePlethora.svg", {}, -1 }, - { "/Befaco/res/panels/Percall.svg", {}, -1 }, - { "/Befaco/res/panels/Rampage.svg", {}, -1 }, - { "/Befaco/res/panels/STMix.svg", {}, -1 }, - { "/Befaco/res/panels/SamplingModulator.svg", {}, -1 }, - { "/Befaco/res/panels/SlewLimiter.svg", {}, -1 }, - { "/Befaco/res/panels/SpringReverb.svg", {}, -1 }, - { "/Befaco/res/panels/StereoStrip.svg", {}, -1 }, + { kModeFehlerFabrik, "/FehlerFabrik/res/Arpanet.svg" }, + { kModeFehlerFabrik, "/FehlerFabrik/res/Aspect.svg" }, + { kModeFehlerFabrik, "/FehlerFabrik/res/Botzinger.svg" }, + { kModeFehlerFabrik, "/FehlerFabrik/res/Chi.svg" }, + { kModeFehlerFabrik, "/FehlerFabrik/res/Components" }, + { kModeFehlerFabrik, "/FehlerFabrik/res/Fax.svg" }, + { kModeFehlerFabrik, "/FehlerFabrik/res/Lilt.svg" }, + { kModeFehlerFabrik, "/FehlerFabrik/res/Luigi.svg" }, + { kModeFehlerFabrik, "/FehlerFabrik/res/Monte.svg" }, + { kModeFehlerFabrik, "/FehlerFabrik/res/Nova.svg" }, + { kModeFehlerFabrik, "/FehlerFabrik/res/Planck.svg" }, + { kModeFehlerFabrik, "/FehlerFabrik/res/PSIOP.svg" }, + { kModeFehlerFabrik, "/FehlerFabrik/res/Rasoir.svg" }, + { kModeFehlerFabrik, "/FehlerFabrik/res/Sigma.svg" }, + { kModeFehlerFabrik, "/FehlerFabrik/res/Components/FFHexScrew.svg" }, // GPLv3+ - { "/Cardinal/res/AudioFile.svg", {}, -1 }, - { "/Cardinal/res/AudioToCVPitch.svg", {}, -1 }, - { "/Cardinal/res/Carla.svg", {}, -1 }, - { "/Cardinal/res/ExpanderMIDI.svg", {}, -1 }, - { "/Cardinal/res/glBars.svg", {}, -1 }, - { "/Cardinal/res/HostAudio.svg", {}, -1 }, - { "/Cardinal/res/HostCV.svg", {}, -1 }, - { "/Cardinal/res/HostMIDI.svg", {}, -1 }, - { "/Cardinal/res/HostMIDICC.svg", {}, -1 }, - { "/Cardinal/res/HostMIDIGate.svg", {}, -1 }, - { "/Cardinal/res/HostMIDIMap.svg", {}, -1 }, - { "/Cardinal/res/HostParameters.svg", {}, -1 }, - { "/Cardinal/res/HostParamsMap.svg", {}, -1 }, - { "/Cardinal/res/HostTime.svg", {}, -1 }, - { "/Cardinal/res/Ildaeil.svg", {}, -1 }, + { kModeForsitan, "/forsitan-modulare/res/alea.svg" }, + { kModeForsitan, "/forsitan-modulare/res/cumuli.svg" }, + { kModeForsitan, "/forsitan-modulare/res/deinde.svg" }, + { kModeForsitan, "/forsitan-modulare/res/interea.svg" }, + { kModeForsitan, "/forsitan-modulare/res/palette.svg" }, + { kModeForsitan, "/forsitan-modulare/res/pavo.svg" }, // GPLv3+ - { "/forsitan-modulare/res/alea.svg", {}, -1 }, - { "/forsitan-modulare/res/cumuli.svg", {}, -1 }, - { "/forsitan-modulare/res/deinde.svg", {}, -1 }, - { "/forsitan-modulare/res/interea.svg", {}, -1 }, - { "/forsitan-modulare/res/palette.svg", {}, -1 }, - { "/forsitan-modulare/res/pavo.svg", {}, -1 }, + { kModeFundamental, "/Fundamental/res/8vert.svg" }, + { kModeFundamental, "/Fundamental/res/ADSR.svg" }, + { kModeFundamental, "/Fundamental/res/Delay.svg" }, + { kModeFundamental, "/Fundamental/res/LFO.svg" }, + { kModeFundamental, "/Fundamental/res/Merge.svg" }, + { kModeFundamental, "/Fundamental/res/MidSide.svg" }, + { kModeFundamental, "/Fundamental/res/Mixer.svg" }, + { kModeFundamental, "/Fundamental/res/Mutes.svg" }, + { kModeFundamental, "/Fundamental/res/Noise.svg" }, + { kModeFundamental, "/Fundamental/res/Octave.svg" }, + { kModeFundamental, "/Fundamental/res/Pulses.svg" }, + { kModeFundamental, "/Fundamental/res/Quantizer.svg" }, + { kModeFundamental, "/Fundamental/res/Random.svg" }, + { kModeFundamental, "/Fundamental/res/SEQ3.svg" }, + { kModeFundamental, "/Fundamental/res/Scope.svg" }, + { kModeFundamental, "/Fundamental/res/SequentialSwitch1.svg" }, + { kModeFundamental, "/Fundamental/res/SequentialSwitch2.svg" }, + { kModeFundamental, "/Fundamental/res/Split.svg" }, + { kModeFundamental, "/Fundamental/res/Sum.svg" }, + { kModeFundamental, "/Fundamental/res/VCA-1.svg" }, + { kModeFundamental, "/Fundamental/res/VCA.svg" }, + { kModeFundamental, "/Fundamental/res/VCF.svg" }, + { kModeFundamental, "/Fundamental/res/VCMixer.svg" }, + { kModeFundamental, "/Fundamental/res/VCO.svg" }, + { kModeFundamental, "/Fundamental/res/WTLFO.svg" }, + { kModeFundamental, "/Fundamental/res/WTVCO.svg" }, + { kModeFundamental, "/Fundamental/res/components/ADSR-bg.svg" }, + { kModeFundamental, "/Fundamental/res/components/Scope-bg.svg" }, // GPLv3+ - { "/Fundamental/res/8vert.svg", {}, -1 }, - { "/Fundamental/res/ADSR.svg", {}, -1 }, - { "/Fundamental/res/Delay.svg", {}, -1 }, - { "/Fundamental/res/LFO.svg", {}, -1 }, - { "/Fundamental/res/Merge.svg", {}, -1 }, - { "/Fundamental/res/MidSide.svg", {}, -1 }, - { "/Fundamental/res/Mixer.svg", {}, -1 }, - { "/Fundamental/res/Mutes.svg", {}, -1 }, - { "/Fundamental/res/Noise.svg", {}, -1 }, - { "/Fundamental/res/Octave.svg", {}, -1 }, - { "/Fundamental/res/Pulses.svg", {}, -1 }, - { "/Fundamental/res/Quantizer.svg", {}, -1 }, - { "/Fundamental/res/Random.svg", {}, -1 }, - { "/Fundamental/res/SEQ3.svg", {}, -1 }, - { "/Fundamental/res/Scope.svg", {}, -1 }, - { "/Fundamental/res/SequentialSwitch1.svg", {}, -1 }, - { "/Fundamental/res/SequentialSwitch2.svg", {}, -1 }, - { "/Fundamental/res/Split.svg", {}, -1 }, - { "/Fundamental/res/Sum.svg", {}, -1 }, - { "/Fundamental/res/VCA-1.svg", {}, -1 }, - { "/Fundamental/res/VCA.svg", {}, -1 }, - { "/Fundamental/res/VCF.svg", {}, -1 }, - { "/Fundamental/res/VCMixer.svg", {}, -1 }, - { "/Fundamental/res/VCO.svg", {}, -1 }, - { "/Fundamental/res/WTLFO.svg", {}, -1 }, - { "/Fundamental/res/WTVCO.svg", {}, -1 }, + { kModeGoodSheperd, "/GoodSheperd/res/Holzschnabel.svg" }, + { kModeGoodSheperd, "/GoodSheperd/res/Hurdle.svg" }, + { kModeGoodSheperd, "/GoodSheperd/res/SEQ3st.svg" }, + { kModeGoodSheperd, "/GoodSheperd/res/Seqtrol.svg" }, + { kModeGoodSheperd, "/GoodSheperd/res/Stable16.svg" }, + { kModeGoodSheperd, "/GoodSheperd/res/Stall.svg" }, + { kModeGoodSheperd, "/GoodSheperd/res/Switch1.svg" }, + { kModeGoodSheperd, "/GoodSheperd/res/components/SquareSwitch_0.svg" }, + { kModeGoodSheperd, "/GoodSheperd/res/components/SquareSwitch_1.svg" }, + // GPLv3+ + { kModeH4n4, "/h4n4-modules/res/XenQnt.svg" }, // MIT - { "/HamptonHarmonics/res/Arp.svg", {}, -1 }, - { "/HamptonHarmonics/res/Progress.svg", {}, -1 }, + { kModeHamptonHarmonics, "/HamptonHarmonics/res/Arp.svg" }, + { kModeHamptonHarmonics, "/HamptonHarmonics/res/Progress.svg" }, // GPLv3+ - { "/LomasModules/res/AdvancedSampler.svg", {}, -1 }, - { "/LomasModules/res/GateSequencer.svg", {}, -1 }, + { kModeLomas, "/LomasModules/res/AdvancedSampler.svg" }, + { kModeLomas, "/LomasModules/res/GateSequencer.svg" }, + // MIT + { kModeMockba, "/MockbaModular/res/Empty_gray.svg" }, + // CC0 + { kModeMog, "/Mog/res/Network.svg" }, + { kModeMog, "/Mog/res/Nexus.svg" }, + // CC-BY-SA-4.0 + { kModePrism, "/Prism/res/prism_Droplet.svg" }, + { kModePrism, "/Prism/res/prism_Rainbow.svg" }, + { kModePrism, "/Prism/res/RainbowScaleExpander.svg" }, + // CC-BY-SA-4.0 + { kModeRepelzen, "/repelzen/res/reface/reburst_bg.svg" }, + { kModeRepelzen, "/repelzen/res/reface/refold_bg.svg" }, + { kModeRepelzen, "/repelzen/res/reface/repelzen_bg1.svg" }, + { kModeRepelzen, "/repelzen/res/reface/repelzen_bg2.svg" }, + { kModeRepelzen, "/repelzen/res/reface/repelzen_bg3.svg" }, + { kModeRepelzen, "/repelzen/res/reface/repelzen_bg4.svg" }, + { kModeRepelzen, "/repelzen/res/reface/repelzen_bg5.svg" }, + { kModeRepelzen, "/repelzen/res/reface/repelzen_bg6.svg" }, + { kModeRepelzen, "/repelzen/res/reface/repelzen_bg7.svg" }, + { kModeRepelzen, "/repelzen/res/reface/repelzen_bg8.svg" }, + { kModeRepelzen, "/repelzen/res/reface/retrig_bg.svg" }, + { kModeRepelzen, "/repelzen/res/reface/rewin_bg.svg" }, + { kModeRepelzen, "/repelzen/res/reface/rexmix_bg.svg" }, // GPLv3+ - { "/sonusmodular/res/addiction.svg", {}, -1 }, - { "/sonusmodular/res/bitter.svg", {}, -1 }, - { "/sonusmodular/res/bymidside.svg", {}, -1 }, - { "/sonusmodular/res/campione.svg", {}, -1 }, - { "/sonusmodular/res/chainsaw.svg", {}, -1 }, - { "/sonusmodular/res/ctrl.svg", {}, -1 }, - { "/sonusmodular/res/deathcrush.svg", {}, -1 }, - { "/sonusmodular/res/fraction.svg", {}, -1 }, - { "/sonusmodular/res/harmony.svg", {}, -1 }, - { "/sonusmodular/res/ladrone.svg", {}, -1 }, - { "/sonusmodular/res/luppolo.svg", {}, -1 }, - { "/sonusmodular/res/luppolo3.svg", {}, -1 }, - { "/sonusmodular/res/micromacro.svg", {}, -1 }, - { "/sonusmodular/res/mrcheb.svg", {}, -1 }, - { "/sonusmodular/res/multimulti.svg", {}, -1 }, - { "/sonusmodular/res/neurosc.svg", {}, -1 }, - { "/sonusmodular/res/oktagon.svg", {}, -1 }, - { "/sonusmodular/res/osculum.svg", {}, -1 }, - { "/sonusmodular/res/paramath.svg", {}, -1 }, - { "/sonusmodular/res/piconoise.svg", {}, -1 }, - { "/sonusmodular/res/pith.svg", {}, -1 }, - { "/sonusmodular/res/pusher.svg", {}, -1 }, - { "/sonusmodular/res/ringo.svg", {}, -1 }, - { "/sonusmodular/res/scramblase.svg", {}, -1 }, - { "/sonusmodular/res/tropicana.svg", {}, -1 }, - { "/sonusmodular/res/twoff.svg", {}, -1 }, - { "/sonusmodular/res/yabp.svg", {}, -1 }, - // TODO bacon, chowdsp, ??? + { kModeSonusmodular, "/sonusmodular/res/addiction.svg" }, + { kModeSonusmodular, "/sonusmodular/res/bitter.svg" }, + { kModeSonusmodular, "/sonusmodular/res/bymidside.svg" }, + { kModeSonusmodular, "/sonusmodular/res/campione.svg" }, + { kModeSonusmodular, "/sonusmodular/res/chainsaw.svg" }, + { kModeSonusmodular, "/sonusmodular/res/ctrl.svg" }, + { kModeSonusmodular, "/sonusmodular/res/deathcrush.svg" }, + { kModeSonusmodular, "/sonusmodular/res/fraction.svg" }, + { kModeSonusmodular, "/sonusmodular/res/harmony.svg" }, + { kModeSonusmodular, "/sonusmodular/res/ladrone.svg" }, + { kModeSonusmodular, "/sonusmodular/res/luppolo.svg" }, + { kModeSonusmodular, "/sonusmodular/res/luppolo3.svg" }, + { kModeSonusmodular, "/sonusmodular/res/micromacro.svg" }, + { kModeSonusmodular, "/sonusmodular/res/mrcheb.svg" }, + { kModeSonusmodular, "/sonusmodular/res/multimulti.svg" }, + { kModeSonusmodular, "/sonusmodular/res/neurosc.svg" }, + { kModeSonusmodular, "/sonusmodular/res/oktagon.svg" }, + { kModeSonusmodular, "/sonusmodular/res/osculum.svg" }, + { kModeSonusmodular, "/sonusmodular/res/paramath.svg" }, + { kModeSonusmodular, "/sonusmodular/res/piconoise.svg" }, + { kModeSonusmodular, "/sonusmodular/res/pith.svg" }, + { kModeSonusmodular, "/sonusmodular/res/pusher.svg" }, + { kModeSonusmodular, "/sonusmodular/res/ringo.svg" }, + { kModeSonusmodular, "/sonusmodular/res/scramblase.svg" }, + { kModeSonusmodular, "/sonusmodular/res/tropicana.svg" }, + { kModeSonusmodular, "/sonusmodular/res/twoff.svg" }, + { kModeSonusmodular, "/sonusmodular/res/yabp.svg" }, }; static inline @@ -481,24 +658,25 @@ unsigned int invertColor(const unsigned int color) noexcept } static inline -bool invertPaintForDarkMode(NSVGshape* const shape, NSVGpaint& paint, const char* const svgFileToInvert = nullptr) +bool invertPaintForDarkMode(const DarkMode mode, NSVGshape* const shape, NSVGpaint& paint, const char* const svgFileToInvert) { - if (paint.type == NSVG_PAINT_LINEAR_GRADIENT && svgFileToInvert != nullptr) + if (paint.type == NSVG_PAINT_LINEAR_GRADIENT) { - // Special case for DrumKit background gradient - if (std::strncmp(svgFileToInvert, "/DrumKit/", 9) == 0) + switch (mode) { + // Special case for DrumKit background gradient + case kModeDrumKit: std::free(paint.gradient); paint.type = NSVG_PAINT_COLOR; paint.color = 0xff191919; return true; - } // Special case for PathSet shifty gradient - if (std::strncmp(svgFileToInvert, "/PathSet/", 9) == 0) - { + case kModePathSet: paint.gradient->stops[0].color = 0xff7c4919; // 50% darker than main blue paint.gradient->stops[1].color = 0xff5b3a1a; // 33.3% darker than main blue return false; + default: + break; } } @@ -507,9 +685,10 @@ bool invertPaintForDarkMode(NSVGshape* const shape, NSVGpaint& paint, const char if (paint.type != NSVG_PAINT_COLOR) return false; - // Special case for Bidoo red color - if (svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/Bidoo/", 7) == 0) + switch (mode) { + // Special case for Bidoo red color + case kModeBidoo: if (paint.color == 0xff001fcd) { paint.color = 0xcf8b94c4; @@ -527,11 +706,9 @@ bool invertPaintForDarkMode(NSVGshape* const shape, NSVGpaint& paint, const char return false; } } - } - + break; // Special case for JW-Modules colors - if (svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/JW-Modules/", 12) == 0) - { + case kModeJW: switch (paint.color) { // do nothing @@ -565,11 +742,9 @@ bool invertPaintForDarkMode(NSVGshape* const shape, NSVGpaint& paint, const char paint.color = 0xffc0c0c0; return true; } - } - + break; // Special case for Lilac - if (svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/LilacLoop/", 11) == 0) - { + case kModeLilacLoop: switch (paint.color) { // main bg (custom) @@ -589,11 +764,9 @@ bool invertPaintForDarkMode(NSVGshape* const shape, NSVGpaint& paint, const char paint.color = 0x00000000; return true; } - } - + break; // Special case for Nonlinear Circuits - if (svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/nonlinearcircuits/", 19) == 0) - { + case kModeNonlinearcircuits: switch (paint.color) { case 0xff9a7900: @@ -612,11 +785,9 @@ bool invertPaintForDarkMode(NSVGshape* const shape, NSVGpaint& paint, const char paint.color = 0x00000000; return true; } - } - + break; // Special case for PathSet colors - if (svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/PathSet/", 9) == 0) - { + case kModePathSet: // only invert main colors for Nudge.svg if (std::strcmp(svgFileToInvert, "/PathSet/res/Nudge.svg") == 0) { @@ -639,6 +810,8 @@ bool invertPaintForDarkMode(NSVGshape* const shape, NSVGpaint& paint, const char { // main blue tone case 0xffdf7a1a: + case 0xffe78a31: + case 0xffc26a16: if (shape->opacity == 0.5f && std::strcmp(svgFileToInvert, "/PathSet/res/AstroVibe.svg") == 0) { shape->opacity = 0.2f; @@ -655,6 +828,13 @@ bool invertPaintForDarkMode(NSVGshape* const shape, NSVGpaint& paint, const char return true; } break; + /* + // OneShot beverage + case 0xff021755: + case 0xff03299a: + case 0xff032ba2: + return false; + */ // pink step 2 (pink with 50% opacity on bg) case 0xffef73ea: paint.color = 0xff812d7d; @@ -690,11 +870,9 @@ bool invertPaintForDarkMode(NSVGshape* const shape, NSVGpaint& paint, const char return true; } } - } - + break; // Special case for voxglitch colors - if (svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/voxglitch/", 11) == 0) - { + case kModeVoxglitch: switch (paint.color) { // wavbank blue @@ -708,6 +886,9 @@ bool invertPaintForDarkMode(NSVGshape* const shape, NSVGpaint& paint, const char paint.color = 0x7f3219ac; return true; } + break; + default: + break; } switch (paint.color) @@ -751,29 +932,249 @@ bool invertPaintForDarkMode(NSVGshape* const shape, NSVGpaint& paint, const char } static inline -bool invertPaintForLightMode(NSVGshape* const shape, NSVGpaint& paint) +bool invertPaintForLightMode(const LightMode mode, NSVGshape* const shape, NSVGpaint& paint) { - switch(paint.type) + if (paint.type == NSVG_PAINT_LINEAR_GRADIENT) { - case NSVG_PAINT_NONE: - return true; - case NSVG_PAINT_LINEAR_GRADIENT: - for (int i=0; instops; ++i) - paint.gradient->stops[i].color = invertColor(paint.gradient->stops[i].color); + switch (mode) + { + case kModeFundamental: + paint.gradient->stops[0].color = 0xffffffff; + paint.gradient->stops[1].color = 0xffe6d6d6; + return true; + default: + for (int i=0; instops; ++i) + paint.gradient->stops[i].color = invertColor(paint.gradient->stops[i].color); + return true; + } + } + + if (paint.type == NSVG_PAINT_RADIAL_GRADIENT && mode == kModeMog) + { + std::free(paint.gradient); + paint.type = NSVG_PAINT_COLOR; + paint.color = 0xffe5e5e5; return true; - case NSVG_PAINT_COLOR: - paint.color = invertColor(paint.color); + } + + if (paint.type == NSVG_PAINT_NONE) return true; - default: + if (paint.type != NSVG_PAINT_COLOR) return false; + + switch (mode) + { + case kMode8Mode: + switch (paint.color) + { + case 0xff000000: + if (std::strcmp(shape->id, "rect1211") == 0) + break; + return false; + case 0xff1a1a1a: + if (std::strcmp(shape->id, "rect1523") != 0) + break; + return false; + default: + return false; + } + break; + case kModeAutinn: + switch (paint.color) + { + // red stripe + case 0xff0a115e: + paint.color = 0xffa1a8f5; + return true; + // logo + case 0xff00d7ff: + paint.color = 0xff005868; + return true; + } + break; + case kModeExtratone: + switch (paint.color) + { + case 0x00000000: + case 0x00ffffff: + case 0xff000000: + case 0xffd5ffe5: + case 0xfff2f2f2: + case 0xfff2ffff: + case 0xfff9f9f9: + case 0xffffffff: + break; + default: + return false; + } + break; + case kModeFehlerFabrik: + switch (paint.color) + { + // make a few colors reverse in luminance/lightness + case 0xff3edcfc: paint.color = 0xff039fbf; return true; + case 0xff4a6fff: paint.color = 0xff0024b2; return true; + case 0xff5c49fd: paint.color = 0xff1502b6; return true; + case 0xff61a6ff: paint.color = 0xff00459e; return true; + case 0xff6e97ad: paint.color = 0xff537c93; return true; + case 0xff78ffb1: paint.color = 0xff008739; return true; + case 0xffb5cf00: paint.color = 0xff627000; return true; + case 0xffbfa463: paint.color = 0xff9c8140; return true; + case 0xffcba5e4: paint.color = 0xff411b5a; return true; + case 0xffce86ef: paint.color = 0xff58107a; return true; + case 0xffcf7685: paint.color = 0xff8a303e; return true; + case 0xffd1e471: paint.color = 0xff798c1b; return true; + // screw core + case 0xff1a1a1a: paint.color = 0xffcccccc; return true; + // keep already darkish colors + case 0xff6a8800: + case 0xff7cce00: + return false; + } + break; + case kModeFundamental: + switch (paint.color) + { + case 0xc0000000: + paint.color = 0xe6000000; + return true; + case 0xff909092: + paint.color = 0xff000000; + return true; + case 0xff000000: + if (shape->opacity == 0.5f) + { + shape->opacity = 0.9f; + return false; + } + break; + } + break; + case kModeGoodSheperd: + switch (paint.color) + { + // background + case 0xff332e21: paint.color = 0xffdfdacd; return true; + case 0xff462f17: paint.color = 0xffe8d2ba; return true; + // jack box overlays + case 0xff56534a: paint.color = 0xffb6b3aa; return true; + case 0xffbc9d8e: paint.color = 0xff705142; return true; + case 0xfeede9e2: paint.color = 0xff1c1812; return true; + // colors to keep the same + case 0xff2400fe: + case 0xffcab39b: + return false; + } + break; + case kModeH4n4: + switch (paint.color) + { + case 0xffffb380: + return false; + case 0xffffccaa: + paint.color = 0xff572300; + return true; + } + break; + case kModeMockba: + switch (paint.color) + { + case 0xff1a1a1a: + case 0xff666666: + paint.color = 0xffd7e3f4; + return true; + default: + return false; + } + break; + case kModeMog: + switch (paint.color) + { + case 0xff442499: + case 0xff587ee2: + case 0xff1ecae8: + case 0xff2dd6ac: + case 0xffcf924c: + case 0xffd8b3bb: + case 0xff29165d: + case 0xff354d89: + case 0xff127b8d: + case 0xff1b8269: + case 0xff7e592e: + case 0xff836d72: + return false; + } + break; + case kModePrism: + switch (paint.color) + { + case 0xff000000: + case 0xff505770: + case 0xff657c9b: + case 0xff7ba357: + case 0xff7f64f2: + case 0xff99e4ff: + case 0xffa7ff6c: + case 0xffc279e2: + case 0xffe079c4: + case 0xffe5ff66: + case 0xffff88d0: + case 0xffffa369: + return false; + case 0xff0f0f0f: + if (std::strcmp(shape->id, "path10") == 0 || std::strcmp(shape->id, "circle506") == 0) + { + paint.color = 0xffffffff; + return true; + } + return false; + case 0xffbababa: + paint.color = 0xff000000; + return true; + } + break; + case kModeRepelzen: + switch (paint.color) + { + case 0xff4c4ccc: + case 0xff87a610: + case 0xffb78e09: + return false; + case 0xff44bbd8: + paint.color = 0xff228ba5; + return true; + } + break; + case kModeSonusmodular: + switch (paint.color) + { + case 0xff2a2aff: + case 0xff4e4ed3: + case 0xff55ddff: + case 0xff87cdde: + case 0xffdbdbe3: + case 0xffe9afaf: + return false; + case 0xff0a1284: + paint.color = 0xff7a82f5; + return true; + } + break; + default: + break; } + + paint.color = invertColor(paint.color); + return true; } +#endif // HEADLESS extern "C" { NSVGimage* nsvgParseFromFileCardinal(const char* filename, const char* units, float dpi); void nsvgDeleteCardinal(NSVGimage*); } +#ifndef HEADLESS struct ExtendedNSVGimage { NSVGimage* const handle; NSVGimage* handleOrig; @@ -788,11 +1189,11 @@ static std::list loadedLightSVGs; static inline void nsvg__duplicatePaint(NSVGpaint& dst, NSVGpaint& src) { - if (dst.type == NSVG_PAINT_LINEAR_GRADIENT || dst.type == NSVG_PAINT_RADIAL_GRADIENT) + if (dst.type == NSVG_PAINT_LINEAR_GRADIENT || dst.type == NSVG_PAINT_RADIAL_GRADIENT) { const size_t size = sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(src.gradient->nstops-1); - dst.gradient = static_cast(malloc(size)); - std::memcpy(dst.gradient, src.gradient, size); + dst.gradient = static_cast(malloc(size)); + std::memcpy(dst.gradient, src.gradient, size); } } @@ -858,11 +1259,38 @@ void deleteExtendedNSVGimage(ExtendedNSVGimage& ext) ext.handleOrig = nullptr; } } +#endif // HEADLESS NSVGimage* nsvgParseFromFileCardinal(const char* const filename, const char* const units, const float dpi) { if (NSVGimage* const handle = nsvgParseFromFile(filename, units, dpi)) { + /* + if (NSVGshape* const shapes = handle->shapes) + { + for (NSVGshape *next, *shape = shapes;;) + { + next = shape->next; + + nsvg__deletePaint(&shape->fill); + nsvg__deletePaint(&shape->stroke); + std::free(shape); + + if (next == nullptr) + break; + + shape = next; + } + } + handle->shapes = static_cast(std::calloc(1, sizeof(NSVGshape))); + handle->shapes->stroke.color = 0xff00ff00; + handle->shapes->stroke.type = NSVG_PAINT_COLOR; + handle->shapes->fill.color = 0xff000000; + handle->shapes->fill.type = NSVG_PAINT_COLOR; + return handle; + */ + + #ifndef HEADLESS const size_t filenamelen = std::strlen(filename); bool hasDarkMode = false; @@ -872,17 +1300,14 @@ NSVGimage* nsvgParseFromFileCardinal(const char* const filename, const char* con NSVGshape* shapesOrig; NSVGshape* shapesMOD; - // Special case for light/dark screws - if (std::strncmp(filename + (filenamelen-16), "/ScrewSilver.svg", 16) == 0) + if (filenamelen < 18) { - const std::string blackfilename = std::string(filename).substr(0, filenamelen-10) + "Black.svg"; - hasDarkMode = true; shapesOrig = shapesMOD = nullptr; - handleMOD = nsvgParseFromFile(blackfilename.c_str(), units, dpi); goto postparse; } - if (std::strncmp(filename + (filenamelen-15), "/ScrewBlack.svg", 15) == 0) + // Special case for light/dark screws + if (std::strncmp(filename + (filenamelen-15), "/ScrewBlack.svg", 15) == 0 && filename[filenamelen-16] != '.') { const std::string silverfilename = std::string(filename).substr(0, filenamelen-9) + "Silver.svg"; hasLightMode = true; @@ -891,6 +1316,15 @@ NSVGimage* nsvgParseFromFileCardinal(const char* const filename, const char* con goto postparse; } + if (std::strncmp(filename + (filenamelen-16), "/ScrewSilver.svg", 16) == 0 && filename[filenamelen-17] != '.') + { + const std::string blackfilename = std::string(filename).substr(0, filenamelen-10) + "Black.svg"; + hasDarkMode = true; + shapesOrig = shapesMOD = nullptr; + handleMOD = nsvgParseFromFile(blackfilename.c_str(), units, dpi); + goto postparse; + } + #if 0 // Special case for GlueTheGiant if (std::strstr(filename, "/GlueTheGiant/res/") != nullptr) @@ -926,6 +1360,7 @@ NSVGimage* nsvgParseFromFileCardinal(const char* const filename, const char* con if (std::strncmp(filename + (filenamelen-filterlen), svgFileToInvert, filterlen) != 0) continue; + const DarkMode mode = svgFilesToInvertForDarkMode[i].mode; const char* const* const shapeIdsToIgnore = svgFilesToInvertForDarkMode[i].shapeIdsToIgnore; const int shapeNumberToIgnore = svgFilesToInvertForDarkMode[i].shapeNumberToIgnore; int shapeCounter = 0; @@ -953,8 +1388,8 @@ NSVGimage* nsvgParseFromFileCardinal(const char* const filename, const char* con if (ignore) continue; - if (invertPaintForDarkMode(shape, shape->fill, svgFileToInvert)) - invertPaintForDarkMode(shape, shape->stroke, svgFileToInvert); + if (invertPaintForDarkMode(mode, shape, shape->fill, svgFileToInvert)) + invertPaintForDarkMode(mode, shape, shape->stroke, svgFileToInvert); } goto postparse; @@ -971,6 +1406,8 @@ NSVGimage* nsvgParseFromFileCardinal(const char* const filename, const char* con if (std::strncmp(filename + (filenamelen-filterlen), svgFileToInvert, filterlen) != 0) continue; + const LightMode mode = svgFilesToInvertForLightMode[i].mode; + hasLightMode = true; handleMOD = nullptr; shapesOrig = handle->shapes; @@ -979,8 +1416,8 @@ NSVGimage* nsvgParseFromFileCardinal(const char* const filename, const char* con // shape paint inversion for (NSVGshape* shape = shapesMOD; shape != nullptr; shape = shape->next) { - if (invertPaintForLightMode(shape, shape->fill)) - invertPaintForLightMode(shape, shape->stroke); + if (invertPaintForLightMode(mode, shape, shape->fill)) + invertPaintForLightMode(mode, shape, shape->stroke); } goto postparse; @@ -1029,6 +1466,7 @@ NSVGimage* nsvgParseFromFileCardinal(const char* const filename, const char* con std::memcpy(handle, handleMOD, sizeof(NSVGimage)); } } + #endif // HEADLESS return handle; } @@ -1038,6 +1476,7 @@ NSVGimage* nsvgParseFromFileCardinal(const char* const filename, const char* con void nsvgDeleteCardinal(NSVGimage* const handle) { + #ifndef HEADLESS for (auto it = loadedDarkSVGs.begin(), end = loadedDarkSVGs.end(); it != end; ++it) { ExtendedNSVGimage& ext(*it); @@ -1061,16 +1500,23 @@ void nsvgDeleteCardinal(NSVGimage* const handle) loadedLightSVGs.erase(it); break; } + #endif nsvgDelete(handle); } +namespace rack { + void switchDarkMode(const bool darkMode) { - if (rack::settings::darkMode == darkMode) + #ifndef HEADLESS + if (settings::darkMode == darkMode) return; - rack::settings::darkMode = darkMode; + settings::darkMode = darkMode; + settings::uiTheme = darkMode ? "dark" : "light"; + ui::refreshTheme(); + plugin::updateStaticPluginsDarkMode(); for (ExtendedNSVGimage& ext : loadedDarkSVGs) { @@ -1087,12 +1533,13 @@ void switchDarkMode(const bool darkMode) else if (ext.handleMOD != nullptr) std::memcpy(ext.handle, !darkMode ? ext.handleMOD : ext.handleOrig, sizeof(NSVGimage)); } + #endif } -namespace rack { namespace asset { void destroy() { + #ifndef HEADLESS for (auto it = loadedDarkSVGs.begin(), end = loadedDarkSVGs.end(); it != end; ++it) { ExtendedNSVGimage& ext(*it); @@ -1107,6 +1554,7 @@ void destroy() { loadedDarkSVGs.clear(); loadedLightSVGs.clear(); + #endif } } diff --git a/src/custom/glfw.cpp b/src/custom/glfw.cpp index 250586e9..e3718d7a 100644 --- a/src/custom/glfw.cpp +++ b/src/custom/glfw.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -30,10 +30,10 @@ GLFWAPI const char* glfwGetClipboardString(GLFWwindow*) { CardinalPluginContext* const context = static_cast(APP); DISTRHO_SAFE_ASSERT_RETURN(context != nullptr, nullptr); - DISTRHO_SAFE_ASSERT_RETURN(context->ui != nullptr, nullptr); + DISTRHO_SAFE_ASSERT_RETURN(context->tlw != nullptr, nullptr); size_t dataSize; - return static_cast(context->ui->getClipboard(dataSize)); + return static_cast(context->tlw->getClipboard(dataSize)); } GLFWAPI void glfwSetClipboardString(GLFWwindow*, const char* const text) @@ -42,24 +42,24 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow*, const char* const text) CardinalPluginContext* const context = static_cast(APP); DISTRHO_SAFE_ASSERT_RETURN(context != nullptr,); - DISTRHO_SAFE_ASSERT_RETURN(context->ui != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(context->tlw != nullptr,); - context->ui->setClipboard(nullptr, text, std::strlen(text)+1); + context->tlw->setClipboard(nullptr, text, std::strlen(text)+1); } GLFWAPI GLFWcursor* glfwCreateStandardCursor(const int shape) { static GLFWcursor cursors[] = { - { kMouseCursorArrow }, // GLFW_ARROW_CURSOR - { kMouseCursorCaret }, // GLFW_IBEAM_CURSOR - { kMouseCursorCrosshair }, // GLFW_CROSSHAIR_CURSOR - { kMouseCursorHand }, // GLFW_POINTING_HAND_CURSOR - { kMouseCursorNotAllowed }, // GLFW_NOT_ALLOWED_CURSOR - { kMouseCursorLeftRight }, // GLFW_RESIZE_EW_CURSOR - { kMouseCursorUpDown }, // GLFW_RESIZE_NS_CURSOR - { kMouseCursorDiagonal }, // GLFW_RESIZE_NWSE_CURSOR - { kMouseCursorAntiDiagonal }, // GLFW_RESIZE_NESW_CURSOR - // NOTE GLFW_RESIZE_ALL_CURSOR is unsupported in pugl + { kMouseCursorArrow }, // GLFW_ARROW_CURSOR + { kMouseCursorCaret }, // GLFW_IBEAM_CURSOR + { kMouseCursorCrosshair }, // GLFW_CROSSHAIR_CURSOR + { kMouseCursorHand }, // GLFW_POINTING_HAND_CURSOR + { kMouseCursorNotAllowed }, // GLFW_NOT_ALLOWED_CURSOR + { kMouseCursorLeftRight }, // GLFW_RESIZE_EW_CURSOR + { kMouseCursorUpDown }, // GLFW_RESIZE_NS_CURSOR + { kMouseCursorUpLeftDownRight }, // GLFW_RESIZE_NWSE_CURSOR + { kMouseCursorUpRightDownLeft }, // GLFW_RESIZE_NESW_CURSOR + { kMouseCursorAllScroll }, // GLFW_RESIZE_ALL_CURSOR }; switch (shape) @@ -79,9 +79,11 @@ GLFWAPI GLFWcursor* glfwCreateStandardCursor(const int shape) case GLFW_RESIZE_NS_CURSOR: return &cursors[kMouseCursorUpDown]; case GLFW_RESIZE_NWSE_CURSOR: - return &cursors[kMouseCursorDiagonal]; + return &cursors[kMouseCursorUpLeftDownRight]; case GLFW_RESIZE_NESW_CURSOR: - return &cursors[kMouseCursorAntiDiagonal]; + return &cursors[kMouseCursorUpRightDownLeft]; + case GLFW_RESIZE_ALL_CURSOR: + return &cursors[kMouseCursorAllScroll]; default: return nullptr; } @@ -91,18 +93,18 @@ GLFWAPI void glfwSetCursor(GLFWwindow*, GLFWcursor* const cursor) { CardinalPluginContext* const context = static_cast(APP); DISTRHO_SAFE_ASSERT_RETURN(context != nullptr,); - DISTRHO_SAFE_ASSERT_RETURN(context->ui != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(context->tlw != nullptr,); - context->ui->setCursor(cursor != nullptr ? cursor->cursorId : kMouseCursorArrow); + context->tlw->setCursor(cursor != nullptr ? cursor->cursorId : kMouseCursorArrow); } GLFWAPI double glfwGetTime(void) { CardinalPluginContext* const context = static_cast(APP); DISTRHO_SAFE_ASSERT_RETURN(context != nullptr, 0.0); - DISTRHO_SAFE_ASSERT_RETURN(context->ui != nullptr, 0.0); + DISTRHO_SAFE_ASSERT_RETURN(context->tlw != nullptr, 0.0); - return context->ui->getApp().getTime(); + return context->tlw->getApp().getTime(); } GLFWAPI const char* glfwGetKeyName(const int key, int) diff --git a/src/emscripten/CardinalMini.html b/src/emscripten/CardinalMini.html new file mode 100644 index 00000000..c1f68efd --- /dev/null +++ b/src/emscripten/CardinalMini.html @@ -0,0 +1,207 @@ + + + + + + + + + Cardinal Mini + + + +
+
+
Cardinal Mini
+
+
+
Downloading...
+
+ +
+
+ + +
+ + + + diff --git a/src/emscripten/shell.html b/src/emscripten/CardinalNative.html similarity index 90% rename from src/emscripten/shell.html rename to src/emscripten/CardinalNative.html index 8a372f87..98cb1911 100644 --- a/src/emscripten/shell.html +++ b/src/emscripten/CardinalNative.html @@ -115,18 +115,9 @@ if (typeof(WebAssembly) === "undefined") { wasmErrors.push('WebAssembly unsupported'); } else { - if (!WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,2,1,0,5,3,1,0,1,10,14,1,12,0,65,0,65,0,65,0,252,10,0,0,11]))) { - wasmErrors.push('Bulk Memory Operations unsupported'); - } - if (!WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,2,1,0,10,8,1,6,0,6,64,25,11,11]))) { - wasmErrors.push('Exception handling unsupported'); - } if (!WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,2,8,1,1,97,1,98,3,127,1,6,6,1,127,1,65,0,11,7,5,1,1,97,3,1]))) { wasmErrors.push('Importable/Exportable mutable globals unsupported'); } - if (!WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,123,3,2,1,0,10,10,1,8,0,65,0,253,15,253,98,11]))) { - wasmErrors.push('Fixed-Width SIMD unsupported'); - } } if (wasmErrors.length !== 0) { @@ -137,6 +128,7 @@ spinnerElement.style.display = 'none'; } else { var canvasWrapper = document.getElementById('canvas_wrapper'); + var simdSupported = WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,123,3,2,1,0,10,10,1,8,0,65,0,253,15,253,98,11])); var Module = { preRun: [], @@ -147,6 +139,9 @@ canvasWrapper.style.display = 'block'; window.dispatchEvent(new Event('resize')); }, + locateFile: function(p,_) { + return simdSupported ? p : p.replace("CardinalNative", "CardinalNative-nosimd"); + }, canvas: (function() { var canvas = document.getElementById('canvas'); @@ -194,8 +189,19 @@ if (text) console.error('[post-exception status] ' + text); }; }; + + var jsModuleName; + if (simdSupported) { + jsModuleName = "CardinalNative.js"; + } else { + jsModuleName = "CardinalNative-nosimd.js"; + } + var jsModuleScript = document.createElement('script'); + jsModuleScript.setAttribute('async', true); + jsModuleScript.setAttribute('src', jsModuleName); + jsModuleScript.setAttribute('type','text/javascript'); + document.head.appendChild(jsModuleScript); } - {{{ SCRIPT }}} diff --git a/src/emscripten/htaccess b/src/emscripten/htaccess index b47b6ab4..408eeffa 100644 --- a/src/emscripten/htaccess +++ b/src/emscripten/htaccess @@ -1,13 +1,16 @@ +AddType application/octet-stream .data +AddType application/wasm .wasm + RewriteEngine on -RewriteCond %{HTTP:Accept-Encoding} gzip +RewriteCond %{HTTP:Accept-Encoding} br RewriteCond %{REQUEST_URI} .*\.(data|js|wasm) #RewriteCond %{REQUEST_FILENAME}.gz -s -RewriteRule ^(.+) $1.gz -RewriteRule "\.data\.gz$" "-" [T=application/octet-stream,E=no-brotli,E=no-gzip] -RewriteRule "\.js\.gz$" "-" [T=application/javascript,E=no-brotli,E=no-gzip] -RewriteRule "\.wasm\.gz$" "-" [T=application/wasm,E=no-brotli,E=no-gzip] +RewriteRule ^(.+) $1.br +RewriteRule "\.data\.br$" "-" [T=application/octet-stream,E=no-brotli,E=no-gzip] +RewriteRule "\.js\.br$" "-" [T=application/javascript,E=no-brotli,E=no-gzip] +RewriteRule "\.wasm\.br$" "-" [T=application/wasm,E=no-brotli,E=no-gzip] - - Header set Content-Encoding gzip + + Header set Content-Encoding br Header append Vary Accept-Encoding diff --git a/src/extra/ScopedLock.hpp b/src/extra/ScopedLock.hpp deleted file mode 100644 index 419e60a9..00000000 --- a/src/extra/ScopedLock.hpp +++ /dev/null @@ -1,238 +0,0 @@ -/* - ============================================================================== - - This file is part of the Water library. - Copyright (c) 2016 ROLI Ltd. - Copyright (C) 2017 Filipe Coelho - - Permission is granted to use this software under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license/ - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD - TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, - OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - OF THIS SOFTWARE. - - ============================================================================== -*/ - -#ifndef WATER_SCOPEDLOCK_HPP_INCLUDED -#define WATER_SCOPEDLOCK_HPP_INCLUDED - -#include "DistrhoUtils.hpp" - -START_NAMESPACE_DISTRHO - -//============================================================================== -/** - Automatically locks and unlocks a mutex object. - - Use one of these as a local variable to provide RAII-based locking of a mutex. - - The templated class could be a CriticalSection, SpinLock, or anything else that - provides enter() and exit() methods. - - e.g. @code - CriticalSection myCriticalSection; - - for (;;) - { - const GenericScopedLock myScopedLock (myCriticalSection); - // myCriticalSection is now locked - - ...do some stuff... - - // myCriticalSection gets unlocked here. - } - @endcode - - @see GenericScopedUnlock, CriticalSection, SpinLock, ScopedLock, ScopedUnlock -*/ -template -class GenericScopedLock -{ -public: - //============================================================================== - /** Creates a GenericScopedLock. - - As soon as it is created, this will acquire the lock, and when the GenericScopedLock - object is deleted, the lock will be released. - - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! Best just to use it - as a local stack object, rather than creating one with the new() operator. - */ - inline explicit GenericScopedLock (const LockType& lock) noexcept : lock_ (lock) { lock.enter(); } - - /** Destructor. - The lock will be released when the destructor is called. - Make sure this object is created and deleted by the same thread, otherwise there are - no guarantees what will happen! - */ - inline ~GenericScopedLock() noexcept { lock_.exit(); } - -private: - //============================================================================== - const LockType& lock_; - - DISTRHO_DECLARE_NON_COPYABLE (GenericScopedLock) -}; - - -//============================================================================== -/** - Automatically unlocks and re-locks a mutex object. - - This is the reverse of a GenericScopedLock object - instead of locking the mutex - for the lifetime of this object, it unlocks it. - - Make sure you don't try to unlock mutexes that aren't actually locked! - - e.g. @code - - CriticalSection myCriticalSection; - - for (;;) - { - const GenericScopedLock myScopedLock (myCriticalSection); - // myCriticalSection is now locked - - ... do some stuff with it locked .. - - while (xyz) - { - ... do some stuff with it locked .. - - const GenericScopedUnlock unlocker (myCriticalSection); - - // myCriticalSection is now unlocked for the remainder of this block, - // and re-locked at the end. - - ...do some stuff with it unlocked ... - } - - // myCriticalSection gets unlocked here. - } - @endcode - - @see GenericScopedLock, CriticalSection, ScopedLock, ScopedUnlock -*/ -template -class GenericScopedUnlock -{ -public: - //============================================================================== - /** Creates a GenericScopedUnlock. - - As soon as it is created, this will unlock the CriticalSection, and - when the ScopedLock object is deleted, the CriticalSection will - be re-locked. - - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! Best just to use it - as a local stack object, rather than creating one with the new() operator. - */ - inline explicit GenericScopedUnlock (const LockType& lock) noexcept : lock_ (lock) { lock.exit(); } - - /** Destructor. - - The CriticalSection will be unlocked when the destructor is called. - - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! - */ - inline ~GenericScopedUnlock() noexcept { lock_.enter(); } - - -private: - //============================================================================== - const LockType& lock_; - - DISTRHO_DECLARE_NON_COPYABLE (GenericScopedUnlock) -}; - - -//============================================================================== -/** - Automatically locks and unlocks a mutex object. - - Use one of these as a local variable to provide RAII-based locking of a mutex. - - The templated class could be a CriticalSection, SpinLock, or anything else that - provides enter() and exit() methods. - - e.g. @code - - CriticalSection myCriticalSection; - - for (;;) - { - const GenericScopedTryLock myScopedTryLock (myCriticalSection); - - // Unlike using a ScopedLock, this may fail to actually get the lock, so you - // should test this with the isLocked() method before doing your thread-unsafe - // action.. - if (myScopedTryLock.isLocked()) - { - ...do some stuff... - } - else - { - ..our attempt at locking failed because another thread had already locked it.. - } - - // myCriticalSection gets unlocked here (if it was locked) - } - @endcode - - @see CriticalSection::tryEnter, GenericScopedLock, GenericScopedUnlock -*/ -template -class GenericScopedTryLock -{ -public: - //============================================================================== - /** Creates a GenericScopedTryLock. - - As soon as it is created, this will attempt to acquire the lock, and when the - GenericScopedTryLock is deleted, the lock will be released (if the lock was - successfully acquired). - - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! Best just to use it - as a local stack object, rather than creating one with the new() operator. - */ - inline explicit GenericScopedTryLock (const LockType& lock) noexcept - : lock_ (lock), lockWasSuccessful (lock.tryEnter()) {} - - /** Destructor. - - The mutex will be unlocked (if it had been successfully locked) when the - destructor is called. - - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! - */ - inline ~GenericScopedTryLock() noexcept { if (lockWasSuccessful) lock_.exit(); } - - /** Returns true if the mutex was successfully locked. */ - bool isLocked() const noexcept { return lockWasSuccessful; } - -private: - //============================================================================== - const LockType& lock_; - const bool lockWasSuccessful; - - DISTRHO_DECLARE_NON_COPYABLE (GenericScopedTryLock) -}; - -END_NAMESPACE_DISTRHO - -#endif // WATER_SCOPEDLOCK_HPP_INCLUDED diff --git a/src/extra/SharedResourcePointer.hpp b/src/extra/SharedResourcePointer.hpp index 005c42e9..fdfc4ca2 100644 --- a/src/extra/SharedResourcePointer.hpp +++ b/src/extra/SharedResourcePointer.hpp @@ -3,7 +3,7 @@ This file is part of the Water library. Copyright (c) 2016 ROLI Ltd. - Copyright (C) 2017-2019 Filipe Coelho + Copyright (C) 2017-2022 Filipe Coelho Permission is granted to use this software under the terms of the ISC license http://www.isc.org/downloads/software-support-policy/isc-license/ @@ -27,7 +27,7 @@ #define WATER_SHAREDRESOURCEPOINTER_HPP_INCLUDED #include "ReferenceCountedObject.hpp" -#include "SpinLock.hpp" +#include "extra/Mutex.hpp" #include "extra/ScopedPointer.hpp" START_NAMESPACE_DISTRHO @@ -107,6 +107,13 @@ class SharedResourcePointer initialise_variant(variant); } + template + SharedResourcePointer(const T1* const v1, const T2* const v2) + : sharedObject(nullptr) + { + initialise_variant2(v1, v2); + } + SharedResourcePointer (const SharedResourcePointer&) : sharedObject(nullptr) { @@ -120,7 +127,7 @@ class SharedResourcePointer ~SharedResourcePointer() { SharedObjectHolder& holder = getSharedObjectHolder(); - const SpinLock::ScopedLockType sl (holder.lock); + const MutexLocker cml (holder.lock); if (--(holder.refCount) == 0) holder.sharedInstance = nullptr; @@ -143,7 +150,7 @@ class SharedResourcePointer private: struct SharedObjectHolder : public ReferenceCountedObject { - SpinLock lock; + Mutex lock; ScopedPointer sharedInstance; int refCount; }; @@ -159,7 +166,7 @@ class SharedResourcePointer void initialise() { SharedObjectHolder& holder = getSharedObjectHolder(); - const SpinLock::ScopedLockType sl (holder.lock); + const MutexLocker cml (holder.lock); if (++(holder.refCount) == 1) holder.sharedInstance = new SharedObjectType(); @@ -171,7 +178,7 @@ class SharedResourcePointer void initialise_variant(const T* const variant) { SharedObjectHolder& holder = getSharedObjectHolder(); - const SpinLock::ScopedLockType sl (holder.lock); + const MutexLocker cml (holder.lock); if (++(holder.refCount) == 1) holder.sharedInstance = new SharedObjectType(variant); @@ -179,6 +186,18 @@ class SharedResourcePointer sharedObject = holder.sharedInstance; } + template + void initialise_variant2(const T1* const v1, const T2* const v2) + { + SharedObjectHolder& holder = getSharedObjectHolder(); + const MutexLocker cml (holder.lock); + + if (++(holder.refCount) == 1) + holder.sharedInstance = new SharedObjectType(v1, v2); + + sharedObject = holder.sharedInstance; + } + // There's no need to assign to a SharedResourcePointer because every // instance of the class is exactly the same! SharedResourcePointer& operator= (const SharedResourcePointer&) = delete; diff --git a/src/extra/SpinLock.hpp b/src/extra/SpinLock.hpp deleted file mode 100644 index 210f1dd1..00000000 --- a/src/extra/SpinLock.hpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - ============================================================================== - - This file is part of the Water library. - Copyright (c) 2016 ROLI Ltd. - Copyright (C) 2017 Filipe Coelho - - Permission is granted to use this software under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license/ - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD - TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, - OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - OF THIS SOFTWARE. - - ============================================================================== -*/ - -#ifndef WATER_SPINLOCK_HPP_INCLUDED -#define WATER_SPINLOCK_HPP_INCLUDED - -#include "Atomic.hpp" -#include "ScopedLock.hpp" - -START_NAMESPACE_DISTRHO - -//============================================================================== -/** - A simple spin-lock class that can be used as a simple, low-overhead mutex for - uncontended situations. - - Note that unlike a CriticalSection, this type of lock is not re-entrant, and may - be less efficient when used it a highly contended situation, but it's very small and - requires almost no initialisation. - It's most appropriate for simple situations where you're only going to hold the - lock for a very brief time. - - @see CriticalSection -*/ -class SpinLock -{ -public: - inline SpinLock() noexcept : lock() {} - inline ~SpinLock() noexcept {} - - /** Acquires the lock. - This will block until the lock has been successfully acquired by this thread. - Note that a SpinLock is NOT re-entrant, and is not smart enough to know whether the - caller thread already has the lock - so if a thread tries to acquire a lock that it - already holds, this method will never return! - - It's strongly recommended that you never call this method directly - instead use the - ScopedLockType class to manage the locking using an RAII pattern instead. - */ - void enter() const noexcept - { - if (! tryEnter()) - { - for (int i = 20; --i >= 0;) - if (tryEnter()) - return; - - while (! tryEnter()) - { -#ifdef DISTRHO_OS_WINDOWS - Sleep (0); -#else - sched_yield(); -#endif - } - } - } - - /** Attempts to acquire the lock, returning true if this was successful. */ - inline bool tryEnter() const noexcept - { - return lock.compareAndSetBool (1, 0); - } - - /** Releases the lock. */ - inline void exit() const noexcept - { - DISTRHO_SAFE_ASSERT_RETURN (lock.get() == 1,); - lock = 0; - } - - //============================================================================== - /** Provides the type of scoped lock to use for locking a SpinLock. */ - typedef GenericScopedLock ScopedLockType; - - /** Provides the type of scoped unlocker to use with a SpinLock. */ - typedef GenericScopedUnlock ScopedUnlockType; - -private: - //============================================================================== - mutable Atomic lock; - - DISTRHO_DECLARE_NON_COPYABLE (SpinLock) -}; - -END_NAMESPACE_DISTRHO - -#endif // WATER_SPINLOCK_HPP_INCLUDED diff --git a/src/override/.generate-diffs.sh b/src/override/.generate-diffs.sh index 887e2933..a8e7be88 100755 --- a/src/override/.generate-diffs.sh +++ b/src/override/.generate-diffs.sh @@ -2,13 +2,21 @@ cd $(dirname ${0}) +diff -U3 ../Rack/include/midi.hpp ../../include/midi.hpp > diffs/midi.hpp.diff +diff -U3 ../Rack/include/dsp/fir.hpp ../../include/dsp/fir.hpp > diffs/dsp-fir.hpp.diff +diff -U3 ../Rack/include/engine/Port.hpp ../../include/engine/Port.hpp > diffs/engine-Port.hpp.diff +diff -U3 ../Rack/include/simd/Vector.hpp ../../include/simd/Vector.hpp > diffs/simd-Vector.hpp.diff + diff -U3 ../Rack/dep/oui-blendish/blendish.c blendish.c > diffs/blendish.c.diff + diff -U3 ../Rack/src/common.cpp common.cpp > diffs/common.cpp.diff diff -U3 ../Rack/src/context.cpp context.cpp > diffs/context.cpp.diff diff -U3 ../Rack/src/plugin.cpp plugin.cpp > diffs/plugin.cpp.diff diff -U3 ../Rack/src/app/MenuBar.cpp MenuBar.cpp > diffs/MenuBar.cpp.diff +diff -U3 ../Rack/src/app/ModuleWidget.cpp ModuleWidget.cpp > diffs/ModuleWidget.cpp.diff diff -U3 ../Rack/src/app/Scene.cpp Scene.cpp > diffs/Scene.cpp.diff diff -U3 ../Rack/src/engine/Engine.cpp Engine.cpp > diffs/Engine.cpp.diff +diff -U3 ../Rack/src/dsp/minblep.cpp minblep.cpp > diffs/minblep.cpp.diff diff -U3 ../Rack/src/plugin/Model.cpp Model.cpp > diffs/Model.cpp.diff diff -U3 ../Rack/src/widget/OpenGlWidget.cpp OpenGlWidget.cpp > diffs/OpenGlWidget.cpp.diff diff -U3 ../Rack/src/window/Window.cpp Window.cpp > diffs/Window.cpp.diff diff --git a/src/override/Engine.cpp b/src/override/Engine.cpp index 2a31fe87..de598426 100644 --- a/src/override/Engine.cpp +++ b/src/override/Engine.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's engine/Engine.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,7 @@ # undef DEBUG #endif +#include "../CardinalRemote.hpp" #include "DistrhoUtils.hpp" @@ -59,6 +61,13 @@ namespace rack { namespace engine { +static constexpr const int PORT_DIVIDER = 7; +// Arbitrary prime number so it doesn't over- or under-estimate time of buffered processors. +static constexpr const int METER_DIVIDER = 37; +static constexpr const int METER_BUFFER_LEN = 32; +static constexpr const float METER_TIME = 1.f; + + struct Engine::Internal { std::vector modules; std::vector terminalModules; @@ -74,8 +83,8 @@ struct Engine::Internal { float sampleRate = 0.f; float sampleTime = 0.f; - int64_t block = 0; int64_t frame = 0; + int64_t block = 0; int64_t blockFrame = 0; double blockTime = 0.0; int blockFrames = 0; @@ -96,6 +105,9 @@ struct Engine::Internal { int smoothParamId = 0; float smoothValue = 0.f; + // Remote control + remoteUtils::RemoteDetails* remoteDetails = nullptr; + /** Mutex that guards the Engine state, such as settings, Modules, and Cables. Writers lock when mutating the engine's state or stepping the block. Readers lock when using the engine's state. @@ -104,6 +116,17 @@ struct Engine::Internal { }; +struct Module::Internal { + bool bypassed = false; + + int meterSamples = 0; + float meterDurationTotal = 0.f; + + float meterBuffer[METER_BUFFER_LEN] = {}; + int meterIndex = 0; +}; + + static void Engine_updateExpander_NoLock(Engine* that, Module* module, bool side) { Module::Expander& expander = side ? module->rightExpander : module->leftExpander; Module* oldExpanderModule = expander.module; @@ -135,11 +158,9 @@ static void Cable_step(Cable* that) { const int channels = output->channels; // Copy all voltages from output to input for (int c = 0; c < channels; c++) { - float v = output->voltages[c]; - // Set 0V if infinite or NaN - if (!std::isfinite(v)) - v = 0.f; - input->voltages[c] = v; + if (!std::isfinite(output->voltages[c])) + __builtin_unreachable(); + input->voltages[c] = output->voltages[c]; } // Set higher channel voltages to 0 for (int c = channels; c < input->channels; c++) { @@ -149,6 +170,7 @@ static void Cable_step(Cable* that) { } +#ifndef HEADLESS static void Port_step(Port* that, float deltaTime) { // Set plug lights if (that->channels == 0) { @@ -169,9 +191,10 @@ static void Port_step(Port* that, float deltaTime) { that->plugLights[2].setSmoothBrightness(v, deltaTime); } } +#endif -static void TerminalModule__doProcess(TerminalModule* terminalModule, const Module::ProcessArgs& args, bool input) { +static void TerminalModule__doProcess(TerminalModule* const terminalModule, const Module::ProcessArgs& args, bool input) { // Step module if (input) { terminalModule->processTerminalInput(args); @@ -183,9 +206,10 @@ static void TerminalModule__doProcess(TerminalModule* terminalModule, const Modu terminalModule->processTerminalOutput(args); } +#ifndef HEADLESS // Iterate ports to step plug lights - if (args.frame % 7 /* PORT_DIVIDER */ == 0) { - float portTime = args.sampleTime * 7 /* PORT_DIVIDER */; + if (args.frame % PORT_DIVIDER == 0) { + float portTime = args.sampleTime * PORT_DIVIDER; for (Input& input : terminalModule->inputs) { Port_step(&input, portTime); } @@ -193,6 +217,68 @@ static void TerminalModule__doProcess(TerminalModule* terminalModule, const Modu Port_step(&output, portTime); } } +#endif +} + + +static void Module__doProcess(Module* const module, const Module::ProcessArgs& args) { + Module::Internal* const internal = module->internal; + +#ifndef HEADLESS + // This global setting can change while the function is running, so use a local variable. + bool meterEnabled = settings::cpuMeter && (args.frame % METER_DIVIDER == 0); + + // Start CPU timer + double startTime; + if (meterEnabled) { + startTime = system::getTime(); + } +#endif + + // Step module + if (!internal->bypassed) + module->process(args); + else + module->processBypass(args); + +#ifndef HEADLESS + // Stop CPU timer + if (meterEnabled) { + double endTime = system::getTime(); + // Subtract call time of getTime() itself, since we only want to measure process() time. + double endTime2 = system::getTime(); + float duration = (endTime - startTime) - (endTime2 - endTime); + + internal->meterSamples++; + internal->meterDurationTotal += duration; + + // Seconds we've been measuring + float meterTime = internal->meterSamples * METER_DIVIDER * args.sampleTime; + + if (meterTime >= METER_TIME) { + // Push time to buffer + if (internal->meterSamples > 0) { + internal->meterIndex++; + internal->meterIndex %= METER_BUFFER_LEN; + internal->meterBuffer[internal->meterIndex] = internal->meterDurationTotal / internal->meterSamples; + } + // Reset total + internal->meterSamples = 0; + internal->meterDurationTotal = 0.f; + } + } + + // Iterate ports to step plug lights + if (args.frame % PORT_DIVIDER == 0) { + float portTime = args.sampleTime * PORT_DIVIDER; + for (Input& input : module->inputs) { + Port_step(&input, portTime); + } + for (Output& output : module->outputs) { + Port_step(&output, portTime); + } + } +#endif } @@ -208,10 +294,16 @@ static void Engine_stepFrame(Engine* that) { float smoothValue = internal->smoothValue; Param* smoothParam = &smoothModule->params[smoothParamId]; float value = smoothParam->value; - // Use decay rate of roughly 1 graphics frame - const float smoothLambda = 60.f; - float newValue = value + (smoothValue - value) * smoothLambda * internal->sampleTime; - if (value == newValue) { + float newValue; + if (internal->remoteDetails != nullptr) { + newValue = value; + sendParamChangeToRemote(internal->remoteDetails, smoothModule->id, smoothParamId, value); + } else { + // Use decay rate of roughly 1 graphics frame + const float smoothLambda = 60.f; + newValue = value + (smoothValue - value) * smoothLambda * internal->sampleTime; + } + if (d_isEqual(value, newValue)) { // Snap to actual smooth value if the value doesn't change enough (due to the granularity of floats) smoothParam->setValue(smoothValue); internal->smoothModule = NULL; @@ -247,7 +339,7 @@ static void Engine_stepFrame(Engine* that) { // Step each module and cables for (Module* module : internal->modules) { - module->doProcess(processArgs); + Module__doProcess(module, processArgs); for (Output& output : module->outputs) { for (Cable* cable : output.cables) Cable_step(cable); @@ -278,6 +370,75 @@ static void Port_setConnected(Port* that) { } +template +using IdentityDictionary = std::unordered_map; + +template +inline bool dictContains(IdentityDictionary& dict, T key) { + return dict.find(key) != dict.end(); +} + +template +inline void dictAdd(IdentityDictionary& dict, T key) { + dict[key] = key; +} + +static void Engine_storeTerminalModulesIDs(std::vector terminalModules, IdentityDictionary& terminalModulesIDs) { + for (TerminalModule* terminalModule : terminalModules) + dictAdd(terminalModulesIDs, terminalModule->id); +} + +static void Engine_orderModule(Module* module, IdentityDictionary& touchedModules, std::vector& orderedModules, IdentityDictionary& terminalModulesIDs) { + if (!dictContains(touchedModules, module) && !dictContains(terminalModulesIDs, module->id)) { // Ignore feedback loops and terminal modules + dictAdd(touchedModules, module); + for (Output& output : module->outputs) { + for (Cable* cable : output.cables) { + Module* receiver = cable->inputModule; // The input to the cable is the receiving module + Engine_orderModule(receiver, touchedModules, orderedModules, terminalModulesIDs); + } + } + orderedModules.push_back(module); + } +} + +static void Engine_assignOrderedModules(std::vector& modules, std::vector& orderedModules) { + std::reverse(orderedModules.begin(), orderedModules.end()); // These are stored bottom up + if (orderedModules.size() == modules.size()) { + for (unsigned int i = 0; i < orderedModules.size(); i++) + modules[i] = orderedModules[i]; + } +} + +#if DEBUG_ORDERED_MODULES +static void Engine_debugOrderedModules(std::vector& modules) { + printf("\n--- Ordered modules ---\n"); + for (unsigned int i = 0; i < modules.size(); i++) + printf("%d) %s - %ld\n", i, modules[i]->model->getFullName().c_str(), modules[i]->id); +} +#endif + +/** Order the modules so that they always read the most recent sample from their inputs +*/ +static void Engine_orderModules(Engine* that) { + Engine::Internal* internal = that->internal; + + IdentityDictionary terminalModulesIDs; + Engine_storeTerminalModulesIDs(internal->terminalModules, terminalModulesIDs); + + IdentityDictionary touchedModules; + std::vector orderedModules; + orderedModules.reserve(internal->modules.size()); + for (Module* module : internal->modules) + Engine_orderModule(module, touchedModules, orderedModules, terminalModulesIDs); + + Engine_assignOrderedModules(internal->modules, orderedModules); + +#if DEBUG_ORDERED_MODULES + Engine_debugOrderedModules(internal->modules); +#endif +} + + static void Engine_updateConnected(Engine* that) { // Find disconnected ports std::set disconnectedInputs; @@ -320,6 +481,8 @@ static void Engine_updateConnected(Engine* that) { Port_setDisconnected(output); DISTRHO_SAFE_ASSERT(output->cables.empty()); } + // Order the modules according to their connections + Engine_orderModules(that); } @@ -490,18 +653,13 @@ void Engine::yieldWorkers() { } -int64_t Engine::getBlock() { - return internal->block; -} - - int64_t Engine::getFrame() { return internal->frame; } -void Engine::setFrame(int64_t frame) { - internal->frame = frame; +int64_t Engine::getBlock() { + return internal->block; } @@ -619,6 +777,9 @@ void Engine::addModule(Module* module) { if (paramHandle->moduleId == module->id) paramHandle->module = module; } +#if DEBUG_ORDERED_MODULES + printf("New module: %s - %ld\n", module->model->getFullName().c_str(), module->id); +#endif } @@ -933,19 +1094,22 @@ void Engine::setParamValue(Module* module, int paramId, float value) { internal->smoothModule = NULL; internal->smoothParamId = 0; } - module->params[paramId].value = value; + if (internal->remoteDetails != nullptr) { + sendParamChangeToRemote(internal->remoteDetails, module->id, paramId, value); + } + module->params[paramId].setValue(value); } float Engine::getParamValue(Module* module, int paramId) { - return module->params[paramId].value; + return module->params[paramId].getValue(); } void Engine::setParamSmoothValue(Module* module, int paramId, float value) { // If another param is being smoothed, jump value if (internal->smoothModule && !(internal->smoothModule == module && internal->smoothParamId == paramId)) { - internal->smoothModule->params[internal->smoothParamId].value = internal->smoothValue; + internal->smoothModule->params[internal->smoothParamId].setValue(internal->smoothValue); } internal->smoothParamId = paramId; internal->smoothValue = value; @@ -957,7 +1121,7 @@ void Engine::setParamSmoothValue(Module* module, int paramId, float value) { float Engine::getParamSmoothValue(Module* module, int paramId) { if (internal->smoothModule == module && internal->smoothParamId == paramId) return internal->smoothValue; - return module->params[paramId].value; + return module->params[paramId].getValue(); } @@ -1183,5 +1347,10 @@ void Engine_setAboutToClose(Engine* const engine) { } +void Engine_setRemoteDetails(Engine* const engine, remoteUtils::RemoteDetails* const remoteDetails) { + engine->internal->remoteDetails = remoteDetails; +} + + } // namespace engine } // namespace rack diff --git a/src/override/MenuBar.cpp b/src/override/MenuBar.cpp index 1b2326ea..c4464be8 100644 --- a/src/override/MenuBar.cpp +++ b/src/override/MenuBar.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's app/MenuBar.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -52,21 +52,26 @@ #include #include "../CardinalCommon.hpp" +#include "../CardinalRemote.hpp" +#include "../PluginContext.hpp" +#include "DistrhoPlugin.hpp" #include "DistrhoStandaloneUtils.hpp" +#ifdef DISTRHO_OS_WASM +# include +# undef HAVE_LIBLO +#endif + #ifdef HAVE_LIBLO # include #endif -void switchDarkMode(bool darkMode); - namespace rack { namespace asset { std::string patchesPath(); } - -namespace plugin { -void updateStaticPluginsDarkMode(); +namespace engine { +void Engine_setRemoteDetails(Engine*, remoteUtils::RemoteDetails*); } namespace app { @@ -97,15 +102,42 @@ struct MenuButton : ui::Button { struct FileButton : MenuButton { const bool isStandalone; -#if !(defined(DISTRHO_OS_WASM) && defined(STATIC_BUILD)) std::vector demoPatches; + +#ifdef DISTRHO_OS_WASM + static void WebBrowserDataSaved(const int err) + { + err ? async_dialog_message("Error, could not save web browser data!") + : async_dialog_message("Web browser data saved!"); + } + + static void wasmSaveAs() + { + async_dialog_text_input("Filename", nullptr, [](char* const filename) { + if (filename == nullptr) + return; + + APP->patch->path = asset::user("patches"); + system::createDirectories(APP->patch->path); + + APP->patch->path += filename; + if (rack::system::getExtension(filename) != ".vcv") + APP->patch->path += ".vcv"; + + patchUtils::saveDialog(APP->patch->path); + std::free(filename); + }); + } #endif FileButton(const bool standalone) : MenuButton(), isStandalone(standalone) { -#if !(defined(DISTRHO_OS_WASM) && defined(STATIC_BUILD)) +#if CARDINAL_VARIANT_MINI + const std::string patchesDir = asset::patchesPath() + DISTRHO_OS_SEP_STR "mini"; +#else const std::string patchesDir = asset::patchesPath() + DISTRHO_OS_SEP_STR "examples"; +#endif if (system::isDirectory(patchesDir)) { @@ -114,7 +146,6 @@ struct FileButton : MenuButton { return string::lowercase(a) < string::lowercase(b); }); } -#endif } void onAction(const ActionEvent& e) override { @@ -123,107 +154,167 @@ struct FileButton : MenuButton { menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); #ifndef DISTRHO_OS_WASM - const char* const NewShortcut = RACK_MOD_CTRL_NAME "+N"; + constexpr const char* const NewShortcut = RACK_MOD_CTRL_NAME "+N"; #else - const char* const NewShortcut = ""; + constexpr const char* const NewShortcut = ""; #endif menu->addChild(createMenuItem("New", NewShortcut, []() { - patchUtils::loadTemplateDialog(); + patchUtils::loadTemplateDialog(false); + })); + +#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + menu->addChild(createMenuItem("New (factory template)", "", []() { + patchUtils::loadTemplateDialog(true); })); #ifndef DISTRHO_OS_WASM - menu->addChild(createMenuItem("Open / Import...", RACK_MOD_CTRL_NAME "+O", []() { + constexpr const char* const OpenName = "Open..."; +#else + constexpr const char* const OpenName = "Import patch..."; +#endif + menu->addChild(createMenuItem(OpenName, RACK_MOD_CTRL_NAME "+O", []() { patchUtils::loadDialog(); })); + const std::string patchesDir = asset::user("patches"); + const std::vector patches = system::isDirectory(patchesDir) ? system::getEntries(patchesDir) : std::vector(); + menu->addChild(createSubmenuItem("Open local patch", "", [patches](ui::Menu* menu) { + for (const std::string& path : patches) { + std::string name = system::getStem(path); + menu->addChild(createMenuItem(name, "", [=]() { + patchUtils::loadPathDialog(path, false); + })); + } + }, patches.empty())); + + menu->addChild(createSubmenuItem("Open recent", "", [](ui::Menu* menu) { + for (const std::string& path : settings::recentPatchPaths) { + std::string name = system::getStem(path); + menu->addChild(createMenuItem(name, "", [=]() { + patchUtils::loadPathDialog(path, false); + })); + } + }, settings::recentPatchPaths.empty())); +#endif + + if (!demoPatches.empty()) + { + menu->addChild(createSubmenuItem("Open demo / example project", "", [=](ui::Menu* const menu) { + for (std::string path : demoPatches) { + std::string label = system::getStem(path); + + for (size_t i=0, len=label.size(); iaddChild(createMenuItem(label, "", [path]() { + patchUtils::loadPathDialog(path, true); + })); + } + + menu->addChild(new ui::MenuSeparator); + + menu->addChild(createMenuItem("Open patchstorage.com for more patches", "", []() { + patchUtils::openBrowser("https://patchstorage.com/platform/cardinal/"); + })); + })); + } + +#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + menu->addChild(createMenuItem("Import selection...", "", [=]() { + patchUtils::loadSelectionDialog(); + }, false, true)); + + menu->addChild(new ui::MenuSeparator); + +#ifndef DISTRHO_OS_WASM menu->addChild(createMenuItem("Save", RACK_MOD_CTRL_NAME "+S", []() { - // NOTE: will do nothing if path is empty, intentionally + // NOTE: for plugin versions it will do nothing if path is empty, intentionally patchUtils::saveDialog(APP->patch->path); - }, APP->patch->path.empty())); + }, APP->patch->path.empty() && !isStandalone)); menu->addChild(createMenuItem("Save as / Export...", RACK_MOD_CTRL_NAME "+Shift+S", []() { patchUtils::saveAsDialog(); })); #else - menu->addChild(createMenuItem("Import patch...", RACK_MOD_CTRL_NAME "+O", []() { - patchUtils::loadDialog(); + menu->addChild(createMenuItem("Save", "", []() { + if (APP->patch->path.empty()) + wasmSaveAs(); + else + patchUtils::saveDialog(APP->patch->path); })); - menu->addChild(createMenuItem("Import selection...", "", [=]() { - patchUtils::loadSelectionDialog(); - }, false, true)); + menu->addChild(createMenuItem("Save as...", "", []() { + wasmSaveAs(); + })); - menu->addChild(createMenuItem("Save and download compressed", RACK_MOD_CTRL_NAME "+Shift+S", []() { + menu->addChild(createMenuItem("Save and download compressed", "", []() { patchUtils::saveAsDialog(); })); menu->addChild(createMenuItem("Save and download uncompressed", "", []() { patchUtils::saveAsDialogUncompressed(); })); +#endif #endif menu->addChild(createMenuItem("Revert", RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME "+O", []() { patchUtils::revertDialog(); }, APP->patch->path.empty())); -#ifdef HAVE_LIBLO - menu->addChild(new ui::MenuSeparator); - - if (patchUtils::isRemoteConnected()) { - menu->addChild(createMenuItem("Deploy to MOD", "F7", []() { - patchUtils::deployToRemote(); - })); - - const bool autoDeploy = patchUtils::isRemoteAutoDeployed(); - menu->addChild(createCheckMenuItem("Auto deploy to MOD", "", - [=]() {return autoDeploy;}, - [=]() {patchUtils::setRemoteAutoDeploy(!autoDeploy);} - )); - } else { - menu->addChild(createMenuItem("Connect to MOD", "", []() { - patchUtils::connectToRemote(); - })); - } -#endif +#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + menu->addChild(createMenuItem("Overwrite template", "", []() { + patchUtils::saveTemplateDialog(); + })); -#ifndef DISTRHO_OS_WASM +#ifdef DISTRHO_OS_WASM menu->addChild(new ui::MenuSeparator); - // Load selection - menu->addChild(createMenuItem("Import selection...", "", [=]() { - patchUtils::loadSelectionDialog(); - }, false, true)); - - menu->addChild(createMenuItem("Export uncompressed json...", "", []() { - patchUtils::saveAsDialogUncompressed(); + menu->addChild(createMenuItem("Save persistent browser data", "", []() { + settings::save(); + EM_ASM({ + Module.FS.syncfs(false, function(err){ dynCall('vi', $0, [!!err]) }); + }, WebBrowserDataSaved); })); #endif +#endif -#if !(defined(DISTRHO_OS_WASM) && defined(STATIC_BUILD)) - if (!demoPatches.empty()) - { - menu->addChild(new ui::MenuSeparator); +#if defined(HAVE_LIBLO) || ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS +#ifdef __MOD_DEVICES__ +#define REMOTE_NAME "MOD" +#else +#define REMOTE_NAME "Remote" +#endif + menu->addChild(new ui::MenuSeparator); - menu->addChild(createSubmenuItem("Open Demo / Example project", "", [=](ui::Menu* const menu) { - for (std::string path : demoPatches) { - std::string label = system::getStem(path); + remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote(); - for (size_t i=0, len=label.size(); iconnected) { + menu->addChild(createMenuItem("Deploy to " REMOTE_NAME, "F7", [remoteDetails]() { + remoteUtils::sendFullPatchToRemote(remoteDetails); + })); - menu->addChild(createMenuItem(label, "", [path]() { - patchUtils::loadPathDialog(path, true); - })); + menu->addChild(createCheckMenuItem("Auto deploy to " REMOTE_NAME, "", + [remoteDetails]() {return remoteDetails->autoDeploy;}, + [remoteDetails]() { + remoteDetails->autoDeploy = !remoteDetails->autoDeploy; + Engine_setRemoteDetails(APP->engine, remoteDetails->autoDeploy ? remoteDetails : nullptr); } - - menu->addChild(new ui::MenuSeparator); - - menu->addChild(createMenuItem("Open PatchStorage.com for more patches", "", []() { - patchUtils::openBrowser("https://patchstorage.com/platform/cardinal/"); - })); + )); +#ifndef __MOD_DEVICES__ + } else { + menu->addChild(createMenuItem("Connect to " REMOTE_NAME "...", "", [remoteDetails]() { + const std::string url = remoteDetails != nullptr ? remoteDetails->url : CARDINAL_DEFAULT_REMOTE_URL; + async_dialog_text_input("Remote:", url.c_str(), [](char* const url) { + if (url == nullptr) + return; + + DISTRHO_SAFE_ASSERT(remoteUtils::connectToRemote(url)); + std::free(url); + }); })); +#endif } #endif @@ -508,6 +599,7 @@ struct KnobScrollSensitivitySlider : ui::Slider { }; +#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS static void setAllFramebufferWidgetsDirty(widget::Widget* const widget) { for (widget::Widget* child : widget->children) @@ -520,6 +612,7 @@ static void setAllFramebufferWidgetsDirty(widget::Widget* const widget) setAllFramebufferWidgetsDirty(child); } } +#endif struct ViewButton : MenuButton { @@ -530,14 +623,15 @@ struct ViewButton : MenuButton { menu->addChild(createMenuLabel("Appearance")); +#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS std::string darkModeText; if (settings::darkMode) darkModeText = CHECKMARK_STRING; menu->addChild(createMenuItem("Dark Mode", darkModeText, []() { switchDarkMode(!settings::darkMode); - plugin::updateStaticPluginsDarkMode(); setAllFramebufferWidgetsDirty(APP->scene); })); +#endif menu->addChild(createBoolPtrMenuItem("Show tooltips", "", &settings::tooltips)); @@ -636,6 +730,10 @@ struct ViewButton : MenuButton { struct EngineButton : MenuButton { +#ifdef HAVE_LIBLO + bool remoteServerStarted = false; +#endif + void onAction(const ActionEvent& e) override { ui::Menu* menu = createMenu(); menu->cornerFlags = BND_CORNER_TOP; @@ -648,6 +746,34 @@ struct EngineButton : MenuButton { settings::cpuMeter ^= true; })); +#ifdef HAVE_LIBLO + if (isStandalone()) { + CardinalPluginContext* const context = static_cast(APP); + CardinalBasePlugin* const plugin = static_cast(context->plugin); + + // const bool remoteServerStarted = this->remoteServerStarted; + const std::string remoteControlText = remoteServerStarted ? " " CHECKMARK_STRING : ""; + + menu->addChild(createMenuItem("Enable OSC remote control", remoteControlText, [=]() { + if (remoteServerStarted) { + remoteServerStarted = false; + plugin->stopRemoteServer(); + return; + } + + async_dialog_text_input("OSC network port", CARDINAL_DEFAULT_REMOTE_PORT, [=](char* const port) { + if (port == nullptr) + return; + + if (plugin->startRemoteServer(port)) + remoteServerStarted = true; + + std::free(port); + }); + })); + } +#endif + if (isUsingNativeAudio()) { if (supportsAudioInput()) { const bool enabled = isAudioInputEnabled(); @@ -670,7 +796,13 @@ struct EngineButton : MenuButton { } if (supportsBufferSizeChanges()) { - static const std::vector bufferSizes = {256, 512, 1024, 2048, 4096, 8192, 16384}; + static const std::vector bufferSizes = { + #ifdef DISTRHO_OS_WASM + 256, 512, 1024, 2048, 4096, 8192, 16384 + #else + 128, 256, 512, 1024, 2048, 4096, 8192 + #endif + }; const uint32_t currentBufferSize = getBufferSize(); menu->addChild(createSubmenuItem("Buffer Size", std::to_string(currentBufferSize), [=](ui::Menu* menu) { for (uint32_t bufferSize : bufferSizes) { @@ -683,6 +815,18 @@ struct EngineButton : MenuButton { } } } + +#ifdef HAVE_LIBLO + void step() override { + MenuButton::step(); + + if (remoteServerStarted) { + CardinalPluginContext* const context = static_cast(APP); + CardinalBasePlugin* const plugin = static_cast(context->plugin); + plugin->stepRemoteServer(); + } + } +#endif }; @@ -701,13 +845,20 @@ struct HelpButton : MenuButton { patchUtils::openBrowser("https://vcvrack.com/manual"); })); - menu->addChild(createMenuItem("Cardinal Project page", "", [=]() { + menu->addChild(createMenuItem("Cardinal project page", "", [=]() { patchUtils::openBrowser("https://github.com/DISTRHO/Cardinal/"); })); menu->addChild(new ui::MenuSeparator); - menu->addChild(createMenuLabel("Cardinal " + APP_EDITION + " " + CARDINAL_VERSION)); +#ifndef DISTRHO_OS_WASM + menu->addChild(createMenuItem("Open user folder", "", [=]() { + system::openDirectory(asset::user("")); + })); + + menu->addChild(new ui::MenuSeparator); +#endif + menu->addChild(createMenuLabel("Rack " + APP_VERSION + " Compatible")); } }; @@ -718,23 +869,25 @@ struct HelpButton : MenuButton { //////////////////// -struct MeterLabel : ui::Label { - int frameIndex = 0; +struct InfoLabel : ui::Label { + int frameCount = 0; double frameDurationTotal = 0.0; - double frameDurationAvg = 0.0; - double uiLastTime = 0.0; - double uiLastThreadTime = 0.0; - double uiFrac = 0.0; + double frameDurationAvg = NAN; + // double uiLastTime = 0.0; + // double uiLastThreadTime = 0.0; + // double uiFrac = 0.0; void step() override { // Compute frame rate double frameDuration = APP->window->getLastFrameDuration(); - frameDurationTotal += frameDuration; - frameIndex++; + if (std::isfinite(frameDuration)) { + frameDurationTotal += frameDuration; + frameCount++; + } if (frameDurationTotal >= 1.0) { - frameDurationAvg = frameDurationTotal / frameIndex; + frameDurationAvg = frameDurationTotal / frameCount; frameDurationTotal = 0.0; - frameIndex = 0; + frameCount = 0; } // Compute UI thread CPU @@ -747,16 +900,29 @@ struct MeterLabel : ui::Label { // uiLastTime = time; // } - double meterAverage = APP->engine->getMeterAverage(); - double meterMax = APP->engine->getMeterMax(); - text = string::f("%.1f fps %.1f%% avg %.1f%% max", 1.0 / frameDurationAvg, meterAverage * 100, meterMax * 100); + text = ""; + + if (box.size.x >= 400) { + double fps = std::isfinite(frameDurationAvg) ? 1.0 / frameDurationAvg : 0.0; +#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + double meterAverage = APP->engine->getMeterAverage(); + double meterMax = APP->engine->getMeterMax(); + text = string::f("%.1f fps %.1f%% avg %.1f%% max", fps, meterAverage * 100, meterMax * 100); +#else + text = string::f("%.1f fps", fps); +#endif + text += " "; + } + + text += "Cardinal " + APP_EDITION + " " + CARDINAL_VERSION; + Label::step(); } }; struct MenuBar : widget::OpaqueWidget { - MeterLabel* meterLabel; + InfoLabel* infoLabel; MenuBar(const bool isStandalone) : widget::OpaqueWidget() @@ -781,24 +947,20 @@ struct MenuBar : widget::OpaqueWidget { viewButton->text = "View"; layout->addChild(viewButton); +#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS EngineButton* engineButton = new EngineButton; engineButton->text = "Engine"; layout->addChild(engineButton); +#endif HelpButton* helpButton = new HelpButton; helpButton->text = "Help"; layout->addChild(helpButton); - // ui::Label* titleLabel = new ui::Label; - // titleLabel->color.a = 0.5; - // layout->addChild(titleLabel); - - meterLabel = new MeterLabel; - meterLabel->box.pos.y = margin; - meterLabel->box.size.x = 300; - meterLabel->alignment = ui::Label::RIGHT_ALIGNMENT; - meterLabel->color.a = 0.5; - addChild(meterLabel); + infoLabel = new InfoLabel; + infoLabel->box.size.x = 600; + infoLabel->alignment = ui::Label::RIGHT_ALIGNMENT; + layout->addChild(infoLabel); } void draw(const DrawArgs& args) override { @@ -809,8 +971,10 @@ struct MenuBar : widget::OpaqueWidget { } void step() override { - meterLabel->box.pos.x = box.size.x - meterLabel->box.size.x - 5; Widget::step(); + infoLabel->box.size.x = box.size.x - infoLabel->box.pos.x - 5; + // Setting 50% alpha prevents Label from using the default UI theme color, so set the color manually here. + infoLabel->color = color::alpha(bndGetTheme()->regularTheme.textColor, 0.5); } }; @@ -819,11 +983,7 @@ struct MenuBar : widget::OpaqueWidget { widget::Widget* createMenuBar() { - return new widget::Widget; -} - -widget::Widget* createMenuBar(const bool isStandalone) { - menuBar::MenuBar* menuBar = new menuBar::MenuBar(isStandalone); + menuBar::MenuBar* menuBar = new menuBar::MenuBar(isStandalone()); return menuBar; } diff --git a/src/override/Model.cpp b/src/override/Model.cpp index a2541be1..454292bb 100644 --- a/src/override/Model.cpp +++ b/src/override/Model.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's plugin/Model.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -85,9 +85,12 @@ void Model::fromJson(json_t* rootJ) { // hidden json_t* hiddenJ = json_object_get(rootJ, "hidden"); - // Use `disabled` as an alias which was deprecated in Rack 2.0 + // "disabled" was a deprecated alias in Rack <2 if (!hiddenJ) hiddenJ = json_object_get(rootJ, "disabled"); + // "deprecated" was a deprecated alias in Rack <2.2.4 + if (!hiddenJ) + hiddenJ = json_object_get(rootJ, "deprecated"); if (hiddenJ) { // Don't un-hide Model if already hidden by C++ if (json_boolean_value(hiddenJ)) @@ -185,6 +188,13 @@ void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) { })); } + // author email + if (plugin->authorEmail != "") { + menu->addChild(createMenuItem("Author email", "Copy to clipboard", [=]() { + glfwSetClipboardString(APP->window->win, plugin->authorEmail.c_str()); + })); + } + // Favorite std::string favoriteRightText = inBrowser ? (RACK_MOD_CTRL_NAME "+click") : ""; if (isFavorite()) diff --git a/src/override/ModuleWidget.cpp b/src/override/ModuleWidget.cpp new file mode 100644 index 00000000..36423e3f --- /dev/null +++ b/src/override/ModuleWidget.cpp @@ -0,0 +1,1168 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the LICENSE file. + */ + +/** + * This file is an edited version of VCVRack's ModuleWidget.cpp + * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + */ + +#include "../../CardinalCommon.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace rack { +namespace app { + + +static const char PRESET_FILTERS[] = "VCV Rack module preset (.vcvm):vcvm"; + + +struct ModuleWidget::Internal { + /** The module position clicked on to start dragging in the rack. + */ + math::Vec dragOffset; + + /** Global rack position the user clicked on. + */ + math::Vec dragRackPos; + bool dragEnabled = true; + + widget::Widget* panel = NULL; +}; + + +ModuleWidget::ModuleWidget() { + internal = new Internal; + box.size = math::Vec(0, RACK_GRID_HEIGHT); +} + +ModuleWidget::~ModuleWidget() { + clearChildren(); + setModule(NULL); + delete internal; +} + +plugin::Model* ModuleWidget::getModel() { + return model; +} + +void ModuleWidget::setModel(plugin::Model* model) { + assert(!this->model); + this->model = model; +} + +engine::Module* ModuleWidget::getModule() { + return module; +} + +void ModuleWidget::setModule(engine::Module* module) { + if (this->module) { + APP->engine->removeModule(this->module); + delete this->module; + this->module = NULL; + } + this->module = module; +} + +widget::Widget* ModuleWidget::getPanel() { + return internal->panel; +} + +void ModuleWidget::setPanel(widget::Widget* panel) { + // Remove existing panel + if (internal->panel) { + removeChild(internal->panel); + delete internal->panel; + internal->panel = NULL; + } + + if (panel) { + addChildBottom(panel); + internal->panel = panel; + box.size.x = std::round(panel->box.size.x / RACK_GRID_WIDTH) * RACK_GRID_WIDTH; + // If width is zero, set it to 12HP for sanity + if (box.size.x == 0.0) + box.size.x = 12 * RACK_GRID_WIDTH; + } +} + +void ModuleWidget::setPanel(std::shared_ptr svg) { + // Create SvgPanel + SvgPanel* panel = new SvgPanel; + panel->setBackground(svg); + setPanel(panel); +} + +void ModuleWidget::addParam(ParamWidget* param) { + addChild(param); +} + +void ModuleWidget::addInput(PortWidget* input) { + // Check that the port is an input + assert(input->type == engine::Port::INPUT); + // Check that the port doesn't have a duplicate ID + PortWidget* input2 = getInput(input->portId); + assert(!input2); + // Add port + addChild(input); +} + +void ModuleWidget::addOutput(PortWidget* output) { + // Check that the port is an output + assert(output->type == engine::Port::OUTPUT); + // Check that the port doesn't have a duplicate ID + PortWidget* output2 = getOutput(output->portId); + assert(!output2); + // Add port + addChild(output); +} + +template +T* getFirstDescendantOfTypeWithCondition(widget::Widget* w, F f) { + T* t = dynamic_cast(w); + if (t && f(t)) + return t; + + for (widget::Widget* child : w->children) { + T* foundT = getFirstDescendantOfTypeWithCondition(child, f); + if (foundT) + return foundT; + } + return NULL; +} + +ParamWidget* ModuleWidget::getParam(int paramId) { + return getFirstDescendantOfTypeWithCondition(this, [&](ParamWidget* pw) -> bool { + return pw->paramId == paramId; + }); +} + +PortWidget* ModuleWidget::getInput(int portId) { + return getFirstDescendantOfTypeWithCondition(this, [&](PortWidget* pw) -> bool { + return pw->type == engine::Port::INPUT && pw->portId == portId; + }); +} + +PortWidget* ModuleWidget::getOutput(int portId) { + return getFirstDescendantOfTypeWithCondition(this, [&](PortWidget* pw) -> bool { + return pw->type == engine::Port::OUTPUT && pw->portId == portId; + }); +} + +template +void doIfTypeRecursive(widget::Widget* w, F f) { + T* t = dynamic_cast(w); + if (t) + f(t); + + for (widget::Widget* child : w->children) { + doIfTypeRecursive(child, f); + } +} + +std::vector ModuleWidget::getParams() { + std::vector pws; + doIfTypeRecursive(this, [&](ParamWidget* pw) { + pws.push_back(pw); + }); + return pws; +} + +std::vector ModuleWidget::getPorts() { + std::vector pws; + doIfTypeRecursive(this, [&](PortWidget* pw) { + pws.push_back(pw); + }); + return pws; +} + +std::vector ModuleWidget::getInputs() { + std::vector pws; + doIfTypeRecursive(this, [&](PortWidget* pw) { + if (pw->type == engine::Port::INPUT) + pws.push_back(pw); + }); + return pws; +} + +std::vector ModuleWidget::getOutputs() { + std::vector pws; + doIfTypeRecursive(this, [&](PortWidget* pw) { + if (pw->type == engine::Port::OUTPUT) + pws.push_back(pw); + }); + return pws; +} + +void ModuleWidget::draw(const DrawArgs& args) { + nvgScissor(args.vg, RECT_ARGS(args.clipBox)); + + if (module && module->isBypassed()) { + nvgAlpha(args.vg, 0.33); + } + + Widget::draw(args); + + // Meter + if (module && settings::cpuMeter) { + float sampleRate = APP->engine->getSampleRate(); + const float* meterBuffer = module->meterBuffer(); + int meterLength = module->meterLength(); + int meterIndex = module->meterIndex(); + + // // Text background + // nvgBeginPath(args.vg); + // nvgRect(args.vg, 0.0, box.size.y - infoHeight, box.size.x, infoHeight); + // nvgFillColor(args.vg, nvgRGBAf(0, 0, 0, 0.75)); + // nvgFill(args.vg); + + // Draw time plot + const float plotHeight = box.size.y - BND_WIDGET_HEIGHT; + nvgBeginPath(args.vg); + nvgMoveTo(args.vg, 0.0, plotHeight); + math::Vec p1; + for (int i = 0; i < meterLength; i++) { + int index = math::eucMod(meterIndex + i + 1, meterLength); + float meter = math::clamp(meterBuffer[index] * sampleRate, 0.f, 1.f); + meter = std::max(0.f, meter); + math::Vec p; + p.x = (float) i / (meterLength - 1) * box.size.x; + p.y = (1.f - meter) * plotHeight; + if (i == 0) { + nvgLineTo(args.vg, VEC_ARGS(p)); + } + else { + math::Vec p2 = p; + p2.x -= 0.5f / (meterLength - 1) * box.size.x; + nvgBezierTo(args.vg, VEC_ARGS(p1), VEC_ARGS(p2), VEC_ARGS(p)); + } + p1 = p; + p1.x += 0.5f / (meterLength - 1) * box.size.x; + } + nvgLineTo(args.vg, box.size.x, plotHeight); + nvgClosePath(args.vg); + NVGcolor color = componentlibrary::SCHEME_ORANGE; + nvgFillColor(args.vg, color::alpha(color, 0.75)); + nvgFill(args.vg); + nvgStrokeWidth(args.vg, 2.0); + nvgStrokeColor(args.vg, color); + nvgStroke(args.vg); + + // Text background + bndMenuBackground(args.vg, 0.0, plotHeight, box.size.x, BND_WIDGET_HEIGHT, BND_CORNER_ALL); + + // Text + float percent = meterBuffer[meterIndex] * sampleRate * 100.f; + // float microseconds = meterBuffer[meterIndex] * 1e6f; + std::string meterText = string::f("%.1f", percent); + // Only append "%" if wider than 2 HP + if (box.getWidth() > RACK_GRID_WIDTH * 2) + meterText += "%"; + math::Vec pt; + pt.x = box.size.x - bndLabelWidth(args.vg, -1, meterText.c_str()) + 3; + pt.y = plotHeight + 0.5; + bndMenuLabel(args.vg, VEC_ARGS(pt), INFINITY, BND_WIDGET_HEIGHT, -1, meterText.c_str()); + } + + // Selection + if (APP->scene->rack->isSelected(this)) { + nvgBeginPath(args.vg); + nvgRect(args.vg, 0.0, 0.0, VEC_ARGS(box.size)); + nvgFillColor(args.vg, nvgRGBAf(1, 0, 0, 0.25)); + nvgFill(args.vg); + nvgStrokeWidth(args.vg, 2.0); + nvgStrokeColor(args.vg, nvgRGBAf(1, 0, 0, 0.5)); + nvgStroke(args.vg); + } + + nvgResetScissor(args.vg); +} + +void ModuleWidget::drawLayer(const DrawArgs& args, int layer) { + if (layer == -1) { + nvgBeginPath(args.vg); + float r = 20; // Blur radius + float c = 20; // Corner radius + math::Rect shadowBox = box.zeroPos().grow(math::Vec(10, -30)); + math::Rect shadowOutsideBox = shadowBox.grow(math::Vec(r, r)); + nvgRect(args.vg, RECT_ARGS(shadowOutsideBox)); + NVGcolor shadowColor = nvgRGBAf(0, 0, 0, 0.2); + NVGcolor transparentColor = nvgRGBAf(0, 0, 0, 0); + nvgFillPaint(args.vg, nvgBoxGradient(args.vg, RECT_ARGS(shadowBox), c, r, shadowColor, transparentColor)); + nvgFill(args.vg); + } + else { + Widget::drawLayer(args, layer); + } +} + +void ModuleWidget::onHover(const HoverEvent& e) { + if (APP->scene->rack->isSelected(this)) { + e.consume(this); + } + + OpaqueWidget::onHover(e); +} + +void ModuleWidget::onHoverKey(const HoverKeyEvent& e) { + if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { + if (e.keyName == "c" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { + copyClipboard(); + e.consume(this); + } + if (e.keyName == "v" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { + if (pasteClipboardAction()) { + e.consume(this); + } + } + if (e.keyName == "d" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { + cloneAction(false); + e.consume(this); + } + if (e.keyName == "d" && (e.mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) { + cloneAction(true); + e.consume(this); + } + if (e.keyName == "i" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { + resetAction(); + e.consume(this); + } + if (e.keyName == "r" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { + randomizeAction(); + e.consume(this); + } + if (e.keyName == "u" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { + disconnectAction(); + e.consume(this); + } + if (e.keyName == "e" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { + bypassAction(!module->isBypassed()); + e.consume(this); + } + if ((e.key == GLFW_KEY_DELETE || e.key == GLFW_KEY_BACKSPACE) && (e.mods & RACK_MOD_MASK) == 0) { + // Deletes `this` + removeAction(); + e.consume(NULL); + return; + } + if (e.key == GLFW_KEY_F1 && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { + std::string manualUrl = model->getManualUrl(); + if (!manualUrl.empty()) + system::openBrowser(manualUrl); + e.consume(this); + } + } + + if (e.isConsumed()) + return; + OpaqueWidget::onHoverKey(e); +} + +void ModuleWidget::onButton(const ButtonEvent& e) { + bool selected = APP->scene->rack->isSelected(this); + + if (selected) { + if (e.button == GLFW_MOUSE_BUTTON_RIGHT) { + if (e.action == GLFW_PRESS) { + // Open selection context menu on right-click + ui::Menu* menu = createMenu(); + patchUtils::appendSelectionContextMenu(menu); + } + e.consume(this); + } + + if (e.button == GLFW_MOUSE_BUTTON_LEFT) { + if (e.action == GLFW_PRESS) { + // Toggle selection on Shift-click + if ((e.mods & RACK_MOD_MASK) == GLFW_MOD_SHIFT) { + APP->scene->rack->select(this, false); + e.consume(NULL); + return; + } + + // If module positions are locked, don't consume left-click + if (settings::lockModules) { + e.consume(NULL); + return; + } + + internal->dragOffset = e.pos; + } + + e.consume(this); + } + + return; + } + + // Dispatch event to children + Widget::onButton(e); + e.stopPropagating(); + if (e.isConsumed()) + return; + + if (e.button == GLFW_MOUSE_BUTTON_LEFT) { + if (e.action == GLFW_PRESS) { + // Toggle selection on Shift-click + if ((e.mods & RACK_MOD_MASK) == GLFW_MOD_SHIFT) { + APP->scene->rack->select(this, true); + e.consume(NULL); + return; + } + + // If module positions are locked, don't consume left-click + if (settings::lockModules) { + e.consume(NULL); + return; + } + + internal->dragOffset = e.pos; + } + e.consume(this); + } + + // Open context menu on right-click + if (e.button == GLFW_MOUSE_BUTTON_RIGHT && e.action == GLFW_PRESS) { + createContextMenu(); + e.consume(this); + } +} + +void ModuleWidget::onDragStart(const DragStartEvent& e) { + if (e.button == GLFW_MOUSE_BUTTON_LEFT) { + // HACK Disable FramebufferWidget redrawing subpixels while dragging + APP->window->fbDirtyOnSubpixelChange() = false; + + // Clear dragRack so dragging in not enabled until mouse is moved a bit. + internal->dragRackPos = math::Vec(NAN, NAN); + + // Prepare initial position of modules for history. + APP->scene->rack->updateModuleOldPositions(); + } +} + +void ModuleWidget::onDragEnd(const DragEndEvent& e) { + if (e.button == GLFW_MOUSE_BUTTON_LEFT) { + APP->window->fbDirtyOnSubpixelChange() = true; + + // The next time the module is dragged, it should always move immediately + internal->dragEnabled = true; + + history::ComplexAction* h = APP->scene->rack->getModuleDragAction(); + if (!h->isEmpty()) + APP->history->push(h); + else + delete h; + } +} + +void ModuleWidget::onDragMove(const DragMoveEvent& e) { + if (e.button == GLFW_MOUSE_BUTTON_LEFT) { + math::Vec mousePos = APP->scene->rack->getMousePos(); + + if (!internal->dragEnabled) { + // Set dragRackPos on the first time after dragging + if (!internal->dragRackPos.isFinite()) + internal->dragRackPos = mousePos; + // Check if the mouse has moved enough to start dragging the module. + const float minDist = RACK_GRID_WIDTH; + if (internal->dragRackPos.minus(mousePos).square() >= std::pow(minDist, 2)) + internal->dragEnabled = true; + } + + // Move module + if (internal->dragEnabled) { + // Round y coordinate to nearest rack height + math::Vec pos = mousePos; + pos.x -= internal->dragOffset.x; + pos.y -= RACK_GRID_HEIGHT / 2; + + if (APP->scene->rack->isSelected(this)) { + pos = (pos / RACK_GRID_SIZE).round() * RACK_GRID_SIZE; + math::Vec delta = pos.minus(box.pos); + APP->scene->rack->setSelectionPosNearest(delta); + } + else { + if (settings::squeezeModules) { + APP->scene->rack->setModulePosSqueeze(this, pos); + } + else { + if ((APP->window->getMods() & RACK_MOD_MASK) == RACK_MOD_CTRL) + APP->scene->rack->setModulePosForce(this, pos); + else + APP->scene->rack->setModulePosNearest(this, pos); + } + } + } + } +} + +void ModuleWidget::onDragHover(const DragHoverEvent& e) { + if (APP->scene->rack->isSelected(this)) { + e.consume(this); + } + + OpaqueWidget::onDragHover(e); +} + +json_t* ModuleWidget::toJson() { + json_t* moduleJ = APP->engine->moduleToJson(module); + return moduleJ; +} + +void ModuleWidget::fromJson(json_t* moduleJ) { + APP->engine->moduleFromJson(module, moduleJ); +} + +bool ModuleWidget::pasteJsonAction(json_t* moduleJ) { + engine::Module::jsonStripIds(moduleJ); + + json_t* oldModuleJ = toJson(); + DEFER({json_decref(oldModuleJ);}); + + try { + fromJson(moduleJ); + } + catch (Exception& e) { + WARN("%s", e.what()); + return false; + } + + // history::ModuleChange + history::ModuleChange* h = new history::ModuleChange; + h->name = "paste module preset"; + h->moduleId = module->id; + json_incref(oldModuleJ); + h->oldModuleJ = oldModuleJ; + json_incref(moduleJ); + h->newModuleJ = moduleJ; + APP->history->push(h); + return true; +} + +void ModuleWidget::copyClipboard() { + json_t* moduleJ = toJson(); + engine::Module::jsonStripIds(moduleJ); + + DEFER({json_decref(moduleJ);}); + char* json = json_dumps(moduleJ, JSON_INDENT(2)); + DEFER({std::free(json);}); + glfwSetClipboardString(APP->window->win, json); +} + +bool ModuleWidget::pasteClipboardAction() { + const char* json = glfwGetClipboardString(APP->window->win); + if (!json) { + WARN("Could not get text from clipboard."); + return false; + } + + json_error_t error; + json_t* moduleJ = json_loads(json, 0, &error); + if (!moduleJ) { + WARN("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); + return false; + } + DEFER({json_decref(moduleJ);}); + + return pasteJsonAction(moduleJ); +} + +void ModuleWidget::load(std::string filename) { + FILE* file = std::fopen(filename.c_str(), "r"); + if (!file) + throw Exception("Could not load patch file %s", filename.c_str()); + DEFER({std::fclose(file);}); + + INFO("Loading preset %s", filename.c_str()); + + json_error_t error; + json_t* moduleJ = json_loadf(file, 0, &error); + if (!moduleJ) + throw Exception("File is not a valid patch file. JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); + DEFER({json_decref(moduleJ);}); + + engine::Module::jsonStripIds(moduleJ); + fromJson(moduleJ); +} + +void ModuleWidget::loadAction(std::string filename) { + // history::ModuleChange + history::ModuleChange* h = new history::ModuleChange; + h->name = "load module preset"; + h->moduleId = module->id; + h->oldModuleJ = toJson(); + + try { + load(filename); + } + catch (Exception& e) { + delete h; + throw; + } + + // TODO We can use `moduleJ` here instead to save a toJson() call. + h->newModuleJ = toJson(); + APP->history->push(h); +} + +void ModuleWidget::loadTemplate() { + std::string templatePath = system::join(model->getUserPresetDirectory(), "template.vcvm"); + try { + load(templatePath); + } + catch (Exception& e) { + // Do nothing + } +} + +void ModuleWidget::loadDialog() { + std::string presetDir = model->getUserPresetDirectory(); + system::createDirectories(presetDir); + + WeakPtr weakThis = this; + async_dialog_filebrowser(false, nullptr, presetDir.c_str(), "Load preset", [=](char* pathC) { + + // Delete directories if empty + DEFER({ + try { + system::remove(presetDir); + system::remove(system::getDirectory(presetDir)); + } + catch (Exception& e) { + // Ignore exceptions if directory cannot be removed. + } + }); + + if (!weakThis) + return; + if (!pathC) { + // No path selected + return; + } + DEFER({std::free(pathC);}); + + try { + weakThis->loadAction(pathC); + } + catch (Exception& e) { + async_dialog_message(e.what()); + } + + }); +} + +void ModuleWidget::save(std::string filename) { + INFO("Saving preset %s", filename.c_str()); + + json_t* moduleJ = toJson(); + assert(moduleJ); + DEFER({json_decref(moduleJ);}); + + engine::Module::jsonStripIds(moduleJ); + + FILE* file = std::fopen(filename.c_str(), "w"); + if (!file) { + std::string message = string::f("Could not save preset to file %s", filename.c_str()); + async_dialog_message(message.c_str()); + return; + } + DEFER({std::fclose(file);}); + + json_dumpf(moduleJ, file, JSON_INDENT(2)); +} + +void ModuleWidget::saveTemplate() { + std::string presetDir = model->getUserPresetDirectory(); + system::createDirectories(presetDir); + std::string templatePath = system::join(presetDir, "template.vcvm"); + save(templatePath); +} + +void ModuleWidget::saveTemplateDialog() { + if (hasTemplate()) { + std::string message = string::f("Overwrite default preset for %s?", model->getFullName().c_str()); + WeakPtr weakThis = this; + async_dialog_message(message.c_str(), [=]{ + if (weakThis) + weakThis->saveTemplate(); + }); + } +} + +bool ModuleWidget::hasTemplate() { + std::string presetDir = model->getUserPresetDirectory(); + std::string templatePath = system::join(presetDir, "template.vcvm"); + return system::exists(templatePath);; +} + +void ModuleWidget::clearTemplate() { + std::string presetDir = model->getUserPresetDirectory(); + std::string templatePath = system::join(presetDir, "template.vcvm"); + system::remove(templatePath); +} + +void ModuleWidget::clearTemplateDialog() { + std::string message = string::f("Delete default preset for %s?", model->getFullName().c_str()); + WeakPtr weakThis = this; + async_dialog_message(message.c_str(), [=]{ + if (weakThis) + weakThis->clearTemplate(); + }); +} + +void ModuleWidget::saveDialog() { + std::string presetDir = model->getUserPresetDirectory(); + system::createDirectories(presetDir); + + WeakPtr weakThis = this; + async_dialog_filebrowser(true, "preset.vcvm", presetDir.c_str(), "Save preset", [=](char* pathC) { + + // Delete directories if empty + DEFER({ + try { + system::remove(presetDir); + system::remove(system::getDirectory(presetDir)); + } + catch (Exception& e) { + // Ignore exceptions if directory cannot be removed. + } + }); + + if (!weakThis) + return; + if (!pathC) { + // No path selected + return; + } + DEFER({std::free(pathC);}); + + std::string path = pathC; + // Automatically append .vcvm extension + if (system::getExtension(path) != ".vcvm") + path += ".vcvm"; + + weakThis->save(path); + }); +} + +void ModuleWidget::disconnect() { + for (PortWidget* pw : getPorts()) { + APP->scene->rack->clearCablesOnPort(pw); + } +} + +void ModuleWidget::resetAction() { + assert(module); + + // history::ModuleChange + history::ModuleChange* h = new history::ModuleChange; + h->name = "reset module"; + h->moduleId = module->id; + h->oldModuleJ = toJson(); + + APP->engine->resetModule(module); + + h->newModuleJ = toJson(); + APP->history->push(h); +} + +void ModuleWidget::randomizeAction() { + assert(module); + + // history::ModuleChange + history::ModuleChange* h = new history::ModuleChange; + h->name = "randomize module"; + h->moduleId = module->id; + h->oldModuleJ = toJson(); + + APP->engine->randomizeModule(module); + + h->newModuleJ = toJson(); + APP->history->push(h); +} + +void ModuleWidget::appendDisconnectActions(history::ComplexAction* complexAction) { + for (PortWidget* pw : getPorts()) { + for (CableWidget* cw : APP->scene->rack->getCompleteCablesOnPort(pw)) { + // history::CableRemove + history::CableRemove* h = new history::CableRemove; + h->setCable(cw); + complexAction->push(h); + // Delete cable + APP->scene->rack->removeCable(cw); + delete cw; + } + }; +} + +void ModuleWidget::disconnectAction() { + history::ComplexAction* complexAction = new history::ComplexAction; + complexAction->name = "disconnect cables"; + appendDisconnectActions(complexAction); + + if (!complexAction->isEmpty()) + APP->history->push(complexAction); + else + delete complexAction; +} + +void ModuleWidget::cloneAction(bool cloneCables) { + // history::ComplexAction + history::ComplexAction* h = new history::ComplexAction; + h->name = "duplicate module"; + + // Save patch store in this module so we can copy it below + APP->engine->prepareSaveModule(module); + + // JSON serialization is the obvious way to do this + json_t* moduleJ = toJson(); + DEFER({ + json_decref(moduleJ); + }); + engine::Module::jsonStripIds(moduleJ); + + // Clone Module + INFO("Creating module %s", model->getFullName().c_str()); + engine::Module* clonedModule = model->createModule(); + + // Set ID here so we can copy module storage dir + clonedModule->id = random::u64() % (1ull << 53); + system::copy(module->getPatchStorageDirectory(), clonedModule->getPatchStorageDirectory()); + + // This doesn't need a lock (via Engine::moduleFromJson()) because the Module is not added to the Engine yet. + try { + clonedModule->fromJson(moduleJ); + } + catch (Exception& e) { + WARN("%s", e.what()); + } + APP->engine->addModule(clonedModule); + + // Clone ModuleWidget + INFO("Creating module widget %s", model->getFullName().c_str()); + ModuleWidget* clonedModuleWidget = model->createModuleWidget(clonedModule); + APP->scene->rack->updateModuleOldPositions(); + APP->scene->rack->addModule(clonedModuleWidget); + // Place module to the right of `this` module, by forcing it to 1 HP to the right. + math::Vec clonedPos = box.pos; + clonedPos.x += clonedModuleWidget->box.getWidth(); + if (settings::squeezeModules) + APP->scene->rack->squeezeModulePos(clonedModuleWidget, clonedPos); + else + APP->scene->rack->setModulePosNearest(clonedModuleWidget, clonedPos); + h->push(APP->scene->rack->getModuleDragAction()); + APP->scene->rack->updateExpanders(); + + // history::ModuleAdd + history::ModuleAdd* hma = new history::ModuleAdd; + hma->setModule(clonedModuleWidget); + h->push(hma); + + if (cloneCables) { + // Clone cables attached to input ports + for (PortWidget* pw : getInputs()) { + for (CableWidget* cw : APP->scene->rack->getCompleteCablesOnPort(pw)) { + // Create cable attached to cloned ModuleWidget's input + engine::Cable* clonedCable = new engine::Cable; + clonedCable->inputModule = clonedModule; + clonedCable->inputId = cw->cable->inputId; + // If cable is self-patched, attach to cloned module instead + if (cw->cable->outputModule == module) + clonedCable->outputModule = clonedModule; + else + clonedCable->outputModule = cw->cable->outputModule; + clonedCable->outputId = cw->cable->outputId; + APP->engine->addCable(clonedCable); + + app::CableWidget* clonedCw = new app::CableWidget; + clonedCw->setCable(clonedCable); + clonedCw->color = cw->color; + APP->scene->rack->addCable(clonedCw); + + // history::CableAdd + history::CableAdd* hca = new history::CableAdd; + hca->setCable(clonedCw); + h->push(hca); + } + } + } + + APP->history->push(h); +} + +void ModuleWidget::bypassAction(bool bypassed) { + assert(module); + + // history::ModuleBypass + history::ModuleBypass* h = new history::ModuleBypass; + h->moduleId = module->id; + h->bypassed = bypassed; + if (!bypassed) + h->name = "un-bypass module"; + APP->history->push(h); + + APP->engine->bypassModule(module, bypassed); +} + +void ModuleWidget::removeAction() { + history::ComplexAction* h = new history::ComplexAction; + h->name = "delete module"; + + // Disconnect cables + appendDisconnectActions(h); + + // Unset module position from rack. + APP->scene->rack->updateModuleOldPositions(); + if (settings::squeezeModules) + APP->scene->rack->unsqueezeModulePos(this); + h->push(APP->scene->rack->getModuleDragAction()); + + // history::ModuleRemove + history::ModuleRemove* moduleRemove = new history::ModuleRemove; + moduleRemove->setModule(this); + h->push(moduleRemove); + + APP->history->push(h); + + // This removes the module and transfers ownership to caller + APP->scene->rack->removeModule(this); + delete this; + + APP->scene->rack->updateExpanders(); +} + + +// Create ModulePresetPathItems for each patch in a directory. +static void appendPresetItems(ui::Menu* menu, WeakPtr moduleWidget, std::string presetDir) { + bool hasPresets = false; + if (system::isDirectory(presetDir)) { + // Note: This is not cached, so opening this menu each time might have a bit of latency. + std::vector entries = system::getEntries(presetDir); + std::sort(entries.begin(), entries.end()); + for (std::string path : entries) { + std::string name = system::getStem(path); + // Remove "1_", "42_", "001_", etc at the beginning of preset filenames + std::regex r("^\\d+_"); + name = std::regex_replace(name, r, ""); + + if (system::isDirectory(path)) { + hasPresets = true; + + menu->addChild(createSubmenuItem(name, "", [=](ui::Menu* menu) { + if (!moduleWidget) + return; + appendPresetItems(menu, moduleWidget, path); + })); + } + else if (system::getExtension(path) == ".vcvm" && name != "template") { + hasPresets = true; + + menu->addChild(createMenuItem(name, "", [=]() { + if (!moduleWidget) + return; + try { + moduleWidget->loadAction(path); + } + catch (Exception& e) { + async_dialog_message(e.what()); + } + })); + } + } + } + if (!hasPresets) { + menu->addChild(createMenuLabel("(None)")); + } +}; + + +void ModuleWidget::createContextMenu() { + ui::Menu* menu = createMenu(); + assert(model); + + WeakPtr weakThis = this; + + // Brand and module name + menu->addChild(createMenuLabel(model->name)); + menu->addChild(createMenuLabel(model->plugin->brand)); + + // Info + menu->addChild(createSubmenuItem("Info", "", [=](ui::Menu* menu) { + model->appendContextMenu(menu); + })); + + // Preset + menu->addChild(createSubmenuItem("Preset", "", [=](ui::Menu* menu) { + menu->addChild(createMenuItem("Copy", RACK_MOD_CTRL_NAME "+C", [=]() { + if (!weakThis) + return; + weakThis->copyClipboard(); + })); + + menu->addChild(createMenuItem("Paste", RACK_MOD_CTRL_NAME "+V", [=]() { + if (!weakThis) + return; + weakThis->pasteClipboardAction(); + })); + + menu->addChild(createMenuItem("Open", "", [=]() { + if (!weakThis) + return; + weakThis->loadDialog(); + })); + + menu->addChild(createMenuItem("Save as", "", [=]() { + if (!weakThis) + return; + weakThis->saveDialog(); + })); + + menu->addChild(createMenuItem("Save default", "", [=]() { + if (!weakThis) + return; + weakThis->saveTemplateDialog(); + })); + + menu->addChild(createMenuItem("Clear default", "", [=]() { + if (!weakThis) + return; + weakThis->clearTemplateDialog(); + }, !weakThis->hasTemplate())); + + // Scan `/presets//` for presets. + menu->addChild(new ui::MenuSeparator); + menu->addChild(createMenuLabel("User presets")); + appendPresetItems(menu, weakThis, weakThis->model->getUserPresetDirectory()); + + // Scan `/presets/` for presets. + menu->addChild(new ui::MenuSeparator); + menu->addChild(createMenuLabel("Factory presets")); + appendPresetItems(menu, weakThis, weakThis->model->getFactoryPresetDirectory()); + })); + + // Initialize + menu->addChild(createMenuItem("Initialize", RACK_MOD_CTRL_NAME "+I", [=]() { + if (!weakThis) + return; + weakThis->resetAction(); + })); + + // Randomize + menu->addChild(createMenuItem("Randomize", RACK_MOD_CTRL_NAME "+R", [=]() { + if (!weakThis) + return; + weakThis->randomizeAction(); + })); + + // Disconnect cables + menu->addChild(createMenuItem("Disconnect cables", RACK_MOD_CTRL_NAME "+U", [=]() { + if (!weakThis) + return; + weakThis->disconnectAction(); + })); + + // Bypass + std::string bypassText = RACK_MOD_CTRL_NAME "+E"; + bool bypassed = module && module->isBypassed(); + if (bypassed) + bypassText += " " CHECKMARK_STRING; + menu->addChild(createMenuItem("Bypass", bypassText, [=]() { + if (!weakThis) + return; + weakThis->bypassAction(!bypassed); + })); + + // Duplicate + menu->addChild(createMenuItem("Duplicate", RACK_MOD_CTRL_NAME "+D", [=]() { + if (!weakThis) + return; + weakThis->cloneAction(false); + })); + + // Duplicate with cables + menu->addChild(createMenuItem("└ with cables", RACK_MOD_SHIFT_NAME "+" RACK_MOD_CTRL_NAME "+D", [=]() { + if (!weakThis) + return; + weakThis->cloneAction(true); + })); + + // Delete + menu->addChild(createMenuItem("Delete", "Backspace/Delete", [=]() { + if (!weakThis) + return; + weakThis->removeAction(); + }, false, true)); + + appendContextMenu(menu); +} + +math::Vec ModuleWidget::getGridPosition() { + return ((getPosition() - RACK_OFFSET) / RACK_GRID_SIZE).round(); +} + +void ModuleWidget::setGridPosition(math::Vec pos) { + setPosition(pos * RACK_GRID_SIZE + RACK_OFFSET); +} + +math::Vec ModuleWidget::getGridSize() { + return (getSize() / RACK_GRID_SIZE).round(); +} + +math::Rect ModuleWidget::getGridBox() { + return math::Rect(getGridPosition(), getGridSize()); +} + +math::Vec& ModuleWidget::dragOffset() { + return internal->dragOffset; +} + +bool& ModuleWidget::dragEnabled() { + return internal->dragEnabled; +} + +engine::Module* ModuleWidget::releaseModule() { + engine::Module* module = this->module; + this->module = NULL; + return module; +} + + +} // namespace app +} // namespace rack diff --git a/src/override/OpenGlWidget.cpp b/src/override/OpenGlWidget.cpp index a8aad193..da448d0f 100644 --- a/src/override/OpenGlWidget.cpp +++ b/src/override/OpenGlWidget.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's OpenGlWidget.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/override/Scene.cpp b/src/override/Scene.cpp index 8f4a9e8c..07976df8 100644 --- a/src/override/Scene.cpp +++ b/src/override/Scene.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's app/Scene.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -25,10 +25,6 @@ * the License, or (at your option) any later version. */ -#include - -#include - #include #include #include @@ -46,18 +42,10 @@ # undef DEBUG #endif -#ifdef STATIC_BUILD -# undef HAVE_LIBLO -#endif - -#ifdef HAVE_LIBLO -# include -#endif - #include "../CardinalCommon.hpp" -#include "extra/Base64.hpp" -#include "DistrhoUtils.hpp" +#include "../CardinalRemote.hpp" +#include namespace rack { namespace app { @@ -131,30 +119,8 @@ struct Scene::Internal { bool heldArrowKeys[4] = {}; -#ifdef HAVE_LIBLO double lastSceneChangeTime = 0.0; int historyActionIndex = -1; - - bool oscAutoDeploy = false; - bool oscConnected = false; - lo_server oscServer = nullptr; - - static int osc_handler(const char* const path, const char* const types, lo_arg** argv, const int argc, lo_message, void* const self) - { - d_stdout("osc_handler(\"%s\", \"%s\", %p, %i)", path, types, argv, argc); - - if (std::strcmp(path, "/resp") == 0 && argc == 2 && types[0] == 's' && types[1] == 's') { - d_stdout("osc_handler(\"%s\", ...) - got resp | '%s' '%s'", path, &argv[0]->s, &argv[1]->s); - if (std::strcmp(&argv[0]->s, "hello") == 0 && std::strcmp(&argv[1]->s, "ok") == 0) - static_cast(self)->oscConnected = true; - } - return 0; - } - - ~Internal() { - lo_server_free(oscServer); - } -#endif }; @@ -173,7 +139,7 @@ Scene::Scene() { browser->hide(); addChild(browser); - if (isStandalone()) + if (isStandalone() || isMini()) return; internal->resizeHandle = new ResizeHandle; @@ -238,22 +204,33 @@ void Scene::step() { rackScroll->offset += arrowDelta * arrowSpeed; } -#ifdef HAVE_LIBLO - if (internal->oscServer != nullptr) { - while (lo_server_recv_noblock(internal->oscServer, 0) != 0) {} + if (remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote()) { + idleRemote(remoteDetails); - if (internal->oscAutoDeploy) { + if (remoteDetails->autoDeploy) { const int actionIndex = APP->history->actionIndex; const double time = system::getTime(); - if (internal->historyActionIndex != actionIndex && time - internal->lastSceneChangeTime >= 5.0) { + + if (internal->historyActionIndex == -1) { + internal->historyActionIndex = actionIndex; + internal->lastSceneChangeTime = time; + } else if (internal->historyActionIndex != actionIndex && actionIndex > 0 && time - internal->lastSceneChangeTime >= 1.0) { + const std::string& name(APP->history->actions[actionIndex - 1]->name); + static const std::vector ignoredNames = { + "move knob", + "move modules", + "move switch", + }; + if (std::find(ignoredNames.cbegin(), ignoredNames.cend(), name) == ignoredNames.cend()) { + printf("action '%s'\n", APP->history->actions[actionIndex - 1]->name.c_str()); + remoteUtils::sendFullPatchToRemote(remoteDetails); + window::generateScreenshot(); + } internal->historyActionIndex = actionIndex; internal->lastSceneChangeTime = time; - patchUtils::deployToRemote(); - window::generateScreenshot(); } } } -#endif Widget::step(); } @@ -284,7 +261,7 @@ void Scene::onHoverKey(const HoverKeyEvent& e) { if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { // DEBUG("key '%d '%c' scancode %d '%c' keyName '%s'", e.key, e.key, e.scancode, e.scancode, e.keyName.c_str()); if (e.keyName == "n" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { - patchUtils::loadTemplateDialog(); + patchUtils::loadTemplateDialog(false); e.consume(this); } if (e.keyName == "q" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { @@ -299,13 +276,16 @@ void Scene::onHoverKey(const HoverKeyEvent& e) { patchUtils::revertDialog(); e.consume(this); } -#ifndef DISTRHO_OS_WASM if (e.keyName == "s" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { - // NOTE: will do nothing if path is empty, intentionally - patchUtils::saveDialog(APP->patch->path); + // NOTE: for plugin versions it will do nothing if path is empty, intentionally + if (APP->patch->path.empty()) { + if (isStandalone()) + patchUtils::saveAsDialog(); + } else { + patchUtils::saveDialog(APP->patch->path); + } e.consume(this); } -#endif if (e.keyName == "s" && (e.mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) { patchUtils::saveAsDialog(); e.consume(this); @@ -352,8 +332,11 @@ void Scene::onHoverKey(const HoverKeyEvent& e) { e.consume(this); } if (e.key == GLFW_KEY_F7 && (e.mods & RACK_MOD_MASK) == 0) { - patchUtils::deployToRemote(); - window::generateScreenshot(); + if (remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote()) + { + remoteUtils::sendFullPatchToRemote(remoteDetails); + window::generateScreenshot(); + } e.consume(this); } if (e.key == GLFW_KEY_F9 && (e.mods & RACK_MOD_MASK) == 0) { @@ -363,6 +346,8 @@ void Scene::onHoverKey(const HoverKeyEvent& e) { #ifdef DISTRHO_OS_WASM if (e.key == GLFW_KEY_F11 && (e.mods & RACK_MOD_MASK) == 0) { APP->window->setFullScreen(!APP->window->isFullScreen()); + // The MenuBar will be hidden when the mouse moves over the RackScrollWidget. + // menuBar->hide(); e.consume(this); } #endif @@ -489,94 +474,3 @@ void Scene::onPathDrop(const PathDropEvent& e) { } // namespace app } // namespace rack - - -namespace patchUtils { - - -bool connectToRemote() { -#ifdef HAVE_LIBLO - rack::app::Scene::Internal* const internal = APP->scene->internal; - - if (internal->oscServer == nullptr) { - const lo_server oscServer = lo_server_new_with_proto(nullptr, LO_UDP, nullptr); - DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr, false); - lo_server_add_method(oscServer, "/resp", nullptr, rack::app::Scene::Internal::osc_handler, internal); - internal->oscServer = oscServer; - } - - const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); - DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr, false); - lo_send(addr, "/hello", ""); - lo_address_free(addr); - - return true; -#else - return false; -#endif -} - - -bool isRemoteConnected() { -#ifdef HAVE_LIBLO - return APP->scene->internal->oscConnected; -#else - return false; -#endif -} - - -bool isRemoteAutoDeployed() { -#ifdef HAVE_LIBLO - return APP->scene->internal->oscAutoDeploy; -#else - return false; -#endif -} - - -void setRemoteAutoDeploy(bool autoDeploy) { -#ifdef HAVE_LIBLO - APP->scene->internal->oscAutoDeploy = autoDeploy; -#endif -} - - -void deployToRemote() { -#ifdef HAVE_LIBLO - const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); - DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,); - - APP->engine->prepareSave(); - APP->patch->saveAutosave(); - APP->patch->cleanAutosave(); - std::vector data(rack::system::archiveDirectory(APP->patch->autosavePath, 1)); - - if (const lo_blob blob = lo_blob_new(data.size(), data.data())) { - lo_send(addr, "/load", "b", blob); - lo_blob_free(blob); - } - - lo_address_free(addr); -#endif -} - - -void sendScreenshotToRemote(const char* const screenshot) { -#ifdef HAVE_LIBLO - const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); - DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,); - - std::vector data(d_getChunkFromBase64String(screenshot)); - - if (const lo_blob blob = lo_blob_new(data.size(), data.data())) { - lo_send(addr, "/screenshot", "b", blob); - lo_blob_free(blob); - } - - lo_address_free(addr); -#endif -} - - -} // namespace patchUtils diff --git a/src/override/Window.cpp b/src/override/Window.cpp index 7c9d481b..20056520 100644 --- a/src/override/Window.cpp +++ b/src/override/Window.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's window/Window.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -42,6 +42,21 @@ # undef DEBUG #endif +#include "DistrhoUI.hpp" +#include "Application.hpp" +#include "extra/String.hpp" +#include "../CardinalCommon.hpp" +#include "../PluginContext.hpp" +#include "../WindowParameters.hpp" + +#ifndef DGL_NO_SHARED_RESOURCES +# include "src/Resources.hpp" +#endif + +#if !(defined(DGL_USE_GLES) || CARDINAL_VARIANT_MINI) + +#define CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS + // comment out if wanting to generate a local screenshot.png #define STBI_WRITE_NO_STDIO @@ -52,14 +67,6 @@ #define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h" -#include "DistrhoUI.hpp" -#include "Application.hpp" -#include "extra/String.hpp" -#include "../CardinalCommon.hpp" -#include "../WindowParameters.hpp" - -#ifndef DGL_NO_SHARED_RESOURCES -# include "src/Resources.hpp" #endif #ifdef DISTRHO_OS_WASM @@ -132,6 +139,7 @@ std::shared_ptr Image::load(const std::string& filename) { } +#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS enum ScreenshotStep { kScreenshotStepNone, kScreenshotStepStarted, @@ -139,20 +147,24 @@ enum ScreenshotStep { kScreenshotStepSecondPass, kScreenshotStepSaving }; +#endif struct Window::Internal { std::string lastWindowTitle; - DISTRHO_NAMESPACE::UI* ui = nullptr; + CardinalBaseUI* ui = nullptr; + DGL_NAMESPACE::NanoTopLevelWidget* tlw = nullptr; DISTRHO_NAMESPACE::WindowParameters params; DISTRHO_NAMESPACE::WindowParametersCallback* callback = nullptr; +#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS DGL_NAMESPACE::Application hiddenApp; DGL_NAMESPACE::Window hiddenWindow; NVGcontext* r_vg = nullptr; NVGcontext* r_fbVg = nullptr; NVGcontext* o_vg = nullptr; NVGcontext* o_fbVg = nullptr; +#endif math::Vec size = WINDOW_SIZE_MIN; @@ -160,13 +172,12 @@ struct Window::Internal { int currentRateLimit = 0; int frame = 0; - int frameSwapInterval = 1; -#ifndef DGL_USE_GLES +#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS int generateScreenshotStep = kScreenshotStepNone; #endif double monitorRefreshRate = 60.0; - double frameTime = 0.0; - double lastFrameDuration = 0.0; + double frameTime = NAN; + double lastFrameDuration = NAN; std::map> fontCache; std::map> imageCache; @@ -175,12 +186,16 @@ struct Window::Internal { int fbCount = 0; Internal() +#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS : hiddenApp(false), - hiddenWindow(hiddenApp) + hiddenWindow(hiddenApp, 0, DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT, 0.0, true) { hiddenWindow.setIgnoringKeyRepeat(true); hiddenApp.idle(); } +#else + {} +#endif }; @@ -202,12 +217,17 @@ static int loadFallbackFont(NVGcontext* const vg) Window::Window() { internal = new Internal; - DGL_NAMESPACE::Window::ScopedGraphicsContext sgc(internal->hiddenWindow); - // Set up NanoVG const int nvgFlags = NVG_ANTIALIAS; + +#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + const DGL_NAMESPACE::Window::ScopedGraphicsContext sgc(internal->hiddenWindow); vg = nvgCreateGL(nvgFlags); +#else + vg = static_cast(APP)->tlw->getContext(); +#endif DISTRHO_SAFE_ASSERT_RETURN(vg != nullptr,); + #ifdef NANOVG_GLES2 fbVg = nvgCreateSharedGLES2(vg, nvgFlags); #else @@ -238,7 +258,119 @@ Window::Window() { #endif } -void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) +void WindowSetPluginRemote(Window* const window, NanoTopLevelWidget* const tlw) +{ + // if nanovg context failed, init only bare minimum + if (window->vg == nullptr) + { + if (tlw != nullptr) + { + window->internal->tlw = tlw; + window->internal->size = rack::math::Vec(tlw->getWidth(), tlw->getHeight()); + } + else + { + window->internal->tlw = nullptr; + window->internal->callback = nullptr; + } + return; + } + + if (tlw != nullptr) + { + const GLubyte* vendor = glGetString(GL_VENDOR); + const GLubyte* renderer = glGetString(GL_RENDERER); + const GLubyte* version = glGetString(GL_VERSION); + INFO("Renderer: %s %s", vendor, renderer); + INFO("OpenGL: %s", version); + + window->internal->tlw = tlw; + window->internal->size = rack::math::Vec(tlw->getWidth(), tlw->getHeight()); + +#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + // Set up NanoVG + window->internal->r_vg = tlw->getContext(); +#ifdef NANOVG_GLES2 + window->internal->r_fbVg = nvgCreateSharedGLES2(window->internal->r_vg, NVG_ANTIALIAS); +#else + window->internal->r_fbVg = nvgCreateSharedGL2(window->internal->r_vg, NVG_ANTIALIAS); +#endif + + // swap contexts + window->internal->o_vg = window->vg; + window->internal->o_fbVg = window->fbVg; + window->vg = window->internal->r_vg; + window->fbVg = window->internal->r_fbVg; + + // also for fonts and images + window->uiFont->vg = window->vg; + window->uiFont->handle = loadFallbackFont(window->vg); + for (auto& font : window->internal->fontCache) + { + font.second->vg = window->vg; + font.second->ohandle = font.second->handle; + font.second->handle = nvgCreateFont(window->vg, + font.second->ofilename.c_str(), font.second->ofilename.c_str()); + } + for (auto& image : window->internal->imageCache) + { + image.second->vg = window->vg; + image.second->ohandle = image.second->handle; + image.second->handle = nvgCreateImage(window->vg, image.second->ofilename.c_str(), + NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); + } +#endif + + // Init settings + WindowParametersRestore(window); + + widget::Widget::ContextCreateEvent e = {}; + e.vg = window->vg; + APP->scene->onContextCreate(e); + } + else + { + widget::Widget::ContextDestroyEvent e = {}; + e.vg = window->vg; + APP->scene->onContextDestroy(e); + +#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + // swap contexts + window->uiFont->vg = window->internal->o_vg; + window->vg = window->internal->o_vg; + window->fbVg = window->internal->o_fbVg; + window->internal->o_vg = nullptr; + window->internal->o_fbVg = nullptr; + + // also for fonts and images + window->uiFont->vg = window->vg; + window->uiFont->handle = loadFallbackFont(window->vg); + for (auto& font : window->internal->fontCache) + { + font.second->vg = window->vg; + font.second->handle = font.second->ohandle; + font.second->ohandle = -1; + } + for (auto& image : window->internal->imageCache) + { + image.second->vg = window->vg; + image.second->handle = image.second->ohandle; + image.second->ohandle = -1; + } + +#if defined NANOVG_GLES2 + nvgDeleteGLES2(window->internal->r_fbVg); +#else + nvgDeleteGL2(window->internal->r_fbVg); +#endif +#endif + + window->internal->tlw = nullptr; + window->internal->callback = nullptr; + } +} + +void WindowSetPluginUI(Window* const window, CardinalBaseUI* const ui) { // if nanovg context failed, init only bare minimum if (window->vg == nullptr) @@ -264,9 +396,11 @@ void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) INFO("Renderer: %s %s", vendor, renderer); INFO("OpenGL: %s", version); + window->internal->tlw = ui; window->internal->ui = ui; window->internal->size = rack::math::Vec(ui->getWidth(), ui->getHeight()); +#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS // Set up NanoVG window->internal->r_vg = ui->getContext(); #ifdef NANOVG_GLES2 @@ -298,18 +432,22 @@ void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) image.second->handle = nvgCreateImage(window->vg, image.second->ofilename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); } +#endif // Init settings WindowParametersRestore(window); - widget::Widget::ContextCreateEvent e; + widget::Widget::ContextCreateEvent e = {}; + e.vg = window->vg; APP->scene->onContextCreate(e); } else { - widget::Widget::ContextDestroyEvent e; + widget::Widget::ContextDestroyEvent e = {}; + e.vg = window->vg; APP->scene->onContextDestroy(e); +#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS // swap contexts window->uiFont->vg = window->internal->o_vg; window->vg = window->internal->o_vg; @@ -337,8 +475,10 @@ void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) nvgDeleteGLES2(window->internal->r_fbVg); #else nvgDeleteGL2(window->internal->r_fbVg); +#endif #endif + window->internal->tlw = nullptr; window->internal->ui = nullptr; window->internal->callback = nullptr; } @@ -351,9 +491,11 @@ void WindowSetMods(Window* const window, const int mods) Window::~Window() { { +#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS DGL_NAMESPACE::Window::ScopedGraphicsContext sgc(internal->hiddenWindow); internal->hiddenWindow.close(); internal->hiddenApp.idle(); +#endif // Fonts and Images in the cache must be deleted before the NanoVG context is deleted internal->fontCache.clear(); @@ -361,12 +503,20 @@ Window::~Window() { if (vg != nullptr) { +#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS #if defined NANOVG_GLES2 nvgDeleteGLES2(internal->o_fbVg != nullptr ? internal->o_fbVg : fbVg); nvgDeleteGLES2(internal->o_vg != nullptr ? internal->o_vg : vg); #else nvgDeleteGL2(internal->o_fbVg != nullptr ? internal->o_fbVg : fbVg); nvgDeleteGL2(internal->o_vg != nullptr ? internal->o_vg : vg); +#endif +#else +#if defined NANOVG_GLES2 + nvgDeleteGLES2(fbVg); +#else + nvgDeleteGL2(fbVg); +#endif #endif } } @@ -384,8 +534,8 @@ void Window::setSize(math::Vec size) { size = size.max(WINDOW_SIZE_MIN); internal->size = size; - if (DISTRHO_NAMESPACE::UI* const ui = internal->ui) - ui->setSize(internal->size.x, internal->size.y); + if (DGL_NAMESPACE::NanoTopLevelWidget* const tlw = internal->ui) + tlw->setSize(internal->size.x, internal->size.y); } void WindowSetInternalSize(rack::window::Window* const window, math::Vec size) { @@ -399,7 +549,7 @@ void Window::run() { } -#ifndef DGL_USE_GLES +#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS static void Window__flipBitmap(uint8_t* pixels, const int width, const int height, const int depth) { for (int y = 0; y < height / 2; y++) { const int flipY = height - y - 1; @@ -445,25 +595,29 @@ static void Window__downscaleBitmap(uint8_t* pixels, int& width, int& height) { static void Window__writeImagePNG(void* context, void* data, int size) { USE_NAMESPACE_DISTRHO - UI* const ui = static_cast(context); - ui->setState("screenshot", String::asBase64(data, size).buffer()); + CardinalBaseUI* const ui = static_cast(context); + if (char* const screenshot = String::asBase64(data, size).getAndReleaseBuffer()) { + ui->setState("screenshot", screenshot); + if (ui->remoteDetails != nullptr) + remoteUtils::sendScreenshotToRemote(ui->remoteDetails, screenshot); + std::free(screenshot); + } } #endif #endif void Window::step() { - DISTRHO_SAFE_ASSERT_RETURN(internal->ui != nullptr,); - - if (vg == nullptr) + if (internal->tlw == nullptr || vg == nullptr) return; double frameTime = system::getTime(); - double lastFrameTime = internal->frameTime; + if (std::isfinite(internal->frameTime)) { + internal->lastFrameDuration = frameTime - internal->frameTime; + } internal->frameTime = frameTime; - internal->lastFrameDuration = frameTime - lastFrameTime; internal->fbCount = 0; - // DEBUG("%.2lf Hz", 1.0 / internal->lastFrameDuration); + // double t1 = 0.0, t2 = 0.0, t3 = 0.0, t4 = 0.0, t5 = 0.0; // Make event handlers and step() have a clean NanoVG context nvgReset(vg); @@ -472,26 +626,32 @@ void Window::step() { bndSetFont(uiFont->handle); // Set window title - std::string windowTitle = "Cardinal"; - if (APP->patch->path != "") { - windowTitle += " - "; - if (!APP->history->isSaved()) - windowTitle += "*"; - windowTitle += system::getFilename(APP->patch->path); - } - if (windowTitle != internal->lastWindowTitle) { - internal->ui->getWindow().setTitle(windowTitle.c_str()); - internal->lastWindowTitle = windowTitle; + if (isStandalone()) { +#if CARDINAL_VARIANT_MINI + std::string windowTitle = "Cardinal Mini"; +#else + std::string windowTitle = "Cardinal"; +#endif + if (APP->patch->path != "") { + windowTitle += " - "; + if (!APP->history->isSaved()) + windowTitle += "*"; + windowTitle += system::getFilename(APP->patch->path); + } + if (windowTitle != internal->lastWindowTitle) { + internal->tlw->getWindow().setTitle(windowTitle.c_str()); + internal->lastWindowTitle = windowTitle; + } } // Get desired pixel ratio - float newPixelRatio = internal->ui->getScaleFactor(); + float newPixelRatio = internal->tlw->getScaleFactor(); if (newPixelRatio != pixelRatio) { pixelRatio = newPixelRatio; APP->event->handleDirty(); } -#ifndef DGL_USE_GLES +#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS // Hide menu and background if generating screenshot if (internal->generateScreenshotStep == kScreenshotStepStarted) { #ifdef CARDINAL_TRANSPARENT_SCREENSHOTS @@ -504,30 +664,33 @@ void Window::step() { #endif // Get framebuffer/window ratio - int winWidth = internal->ui->getWidth(); - int winHeight = internal->ui->getHeight(); - int fbWidth = winWidth;// * newPixelRatio; - int fbHeight = winHeight;// * newPixelRatio; + int winWidth = internal->tlw->getWidth(); + int winHeight = internal->tlw->getHeight(); + int fbWidth = winWidth; + int fbHeight = winHeight; windowRatio = (float)fbWidth / winWidth; + // t1 = system::getTime(); if (APP->scene) { // DEBUG("%f %f %d %d", pixelRatio, windowRatio, fbWidth, winWidth); // Resize scene - APP->scene->box.size = math::Vec(fbWidth, fbHeight).div(newPixelRatio); + APP->scene->box.size = math::Vec(fbWidth, fbHeight).div(pixelRatio); // Step scene APP->scene->step(); + // t2 = system::getTime(); // Render scene { // Update and render - nvgScale(vg, newPixelRatio, newPixelRatio); + nvgScale(vg, pixelRatio, pixelRatio); // Draw scene widget::Widget::DrawArgs args; args.vg = vg; args.clipBox = APP->scene->box.zeroPos(); APP->scene->draw(args); + // t3 = system::getTime(); glViewport(0, 0, fbWidth, fbHeight); #ifdef CARDINAL_TRANSPARENT_SCREENSHOTS @@ -537,11 +700,21 @@ void Window::step() { #endif glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } + // t4 = system::getTime(); } + // t5 = system::getTime(); + // DEBUG("pre-step %6.1f step %6.1f draw %6.1f nvgEndFrame %6.1f glfwSwapBuffers %6.1f total %6.1f", + // (t1 - frameTime) * 1e3f, + // (t2 - t1) * 1e3f, + // (t3 - t2) * 1e3f, + // (t4 - t3) * 1e3f, + // (t5 - t4) * 1e3f, + // (t5 - frameTime) * 1e3f + // ); ++internal->frame; -#ifndef DGL_USE_GLES +#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS if (internal->generateScreenshotStep != kScreenshotStepNone) { ++internal->generateScreenshotStep; @@ -563,10 +736,10 @@ void Window::step() { if (internal->generateScreenshotStep == kScreenshotStepSaving) { // Write pixels to PNG - const int stride = winWidth * depth; - uint8_t* const pixelsWithOffset = pixels + (stride * y); Window__flipBitmap(pixels, winWidth, winHeight, depth); winHeight -= y; + const int stride = winWidth * depth; + uint8_t* const pixelsWithOffset = pixels + (stride * y); #ifdef STBI_WRITE_NO_STDIO Window__downscaleBitmap(pixelsWithOffset, winWidth, winHeight); stbi_write_png_to_func(Window__writeImagePNG, internal->ui, @@ -576,8 +749,10 @@ void Window::step() { #endif internal->generateScreenshotStep = kScreenshotStepNone; +#ifdef CARDINAL_TRANSPARENT_SCREENSHOTS APP->scene->menuBar->show(); APP->scene->rack->children.front()->show(); +#endif } delete[] pixels; @@ -586,22 +761,18 @@ void Window::step() { } -void Window::activateContext() { +void Window::screenshot(const std::string& screenshotPath) { } -void Window::screenshot(const std::string&) { -} - - -void Window::screenshotModules(const std::string&, float) { +void Window::screenshotModules(const std::string& screenshotsDir, float zoom) { } void Window::close() { - DISTRHO_SAFE_ASSERT_RETURN(internal->ui != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(internal->tlw != nullptr,); - internal->ui->getWindow().close(); + internal->tlw->getWindow().close(); } @@ -610,7 +781,7 @@ void Window::cursorLock() { if (!settings::allowCursorLock) return; - emscripten_request_pointerlock(internal->ui->getWindow().getApp().getClassName(), false); + emscripten_request_pointerlock(internal->tlw->getWindow().getApp().getClassName(), false); #endif } @@ -640,12 +811,18 @@ int Window::getMods() { } -void Window::setFullScreen(const bool fullscreen) { +void Window::setFullScreen(bool fullScreen) { #ifdef DISTRHO_OS_WASM - if (fullscreen) - emscripten_request_fullscreen(internal->ui->getWindow().getApp().getClassName(), false); + if (fullScreen) + { + try { + emscripten_request_fullscreen(internal->tlw->getWindow().getApp().getClassName(), false); + } DISTRHO_SAFE_EXCEPTION("fullscreen"); + } else + { emscripten_exit_fullscreen(); + } #endif } @@ -656,13 +833,14 @@ bool Window::isFullScreen() { if (emscripten_get_fullscreen_status(&status) == EMSCRIPTEN_RESULT_SUCCESS) return status.isFullscreen; return false; -#elif defined(CARDINAL_TRANSPARENT_SCREENSHOTS) && !defined(DGL_USE_GLES) +#elif defined(CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS) && defined(CARDINAL_TRANSPARENT_SCREENSHOTS) return internal->generateScreenshotStep != kScreenshotStepNone; #else return false; #endif } + double Window::getMonitorRefreshRate() { return internal->monitorRefreshRate; } @@ -679,8 +857,8 @@ double Window::getLastFrameDuration() { double Window::getFrameDurationRemaining() { - double frameDurationDesired = internal->frameSwapInterval / internal->monitorRefreshRate; - return frameDurationDesired - (system::getTime() - internal->frameTime); + double frameDuration = 1.f / internal->monitorRefreshRate; + return frameDuration - (system::getTime() - internal->frameTime); } @@ -737,7 +915,7 @@ int& Window::fbCount() { void generateScreenshot() { -#ifndef DGL_USE_GLES +#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS APP->window->internal->generateScreenshotStep = kScreenshotStepStarted; #endif } diff --git a/src/override/common.cpp b/src/override/common.cpp index 191914e3..336034b8 100644 --- a/src/override/common.cpp +++ b/src/override/common.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's common.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -38,9 +38,11 @@ #include FILE* fopen_u8(const char* filename, const char* mode) { + if (FILE* const f = _wfopen(rack::string::UTF8toUTF16(filename).c_str(), rack::string::UTF8toUTF16(mode).c_str())) + return f; if (std::strncmp(filename, "\\\\?\\", 4) == 0 && std::getenv("CARDINAL_UNDER_WINE") != nullptr) - filename = "Z:\\dev\\null"; - return _wfopen(rack::string::UTF8toUTF16(filename).c_str(), rack::string::UTF8toUTF16(mode).c_str()); + return _wfopen(L"Z:\\dev\\null", rack::string::UTF8toUTF16(mode).c_str()); + return nullptr; } #elif defined(DISTRHO_OS_WASM) @@ -61,7 +63,7 @@ const std::string APP_NAME = "Cardinal"; const std::string APP_EDITION = getPluginFormatName(); const std::string APP_EDITION_NAME = "Audio Plugin"; const std::string APP_VERSION_MAJOR = "2"; -const std::string APP_VERSION = "2.1.2"; +const std::string APP_VERSION = "2.3.0"; #if defined ARCH_WIN const std::string APP_OS = "win"; #elif defined ARCH_MAC diff --git a/src/override/context.cpp b/src/override/context.cpp index 3f08e741..f1ce13b6 100644 --- a/src/override/context.cpp +++ b/src/override/context.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's context.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -31,7 +31,6 @@ #include #include #include -#include #ifdef NDEBUG # undef DEBUG diff --git a/src/override/diffs/Engine.cpp.diff b/src/override/diffs/Engine.cpp.diff index 7a58e95b..df125357 100644 --- a/src/override/diffs/Engine.cpp.diff +++ b/src/override/diffs/Engine.cpp.diff @@ -1,9 +1,9 @@ ---- ../Rack/src/engine/Engine.cpp 2022-04-11 20:05:02.011283836 +0100 -+++ Engine.cpp 2022-06-29 01:30:02.024102120 +0100 +--- ../Rack/src/engine/Engine.cpp 2023-09-10 12:59:02.631898592 +0200 ++++ Engine.cpp 2023-05-22 04:26:39.902464764 +0200 @@ -1,3 +1,30 @@ +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ + +/** + * This file is an edited version of VCVRack's engine/Engine.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -31,8 +31,15 @@ #include #include #include -@@ -8,181 +35,35 @@ - #include +@@ -5,192 +32,47 @@ + #include + #include + #include +-#if defined ARCH_X64 +- #include +-#endif ++#include ++#include #include +#include @@ -45,14 +52,12 @@ #include +#include -+#ifdef NDEBUG -+# undef DEBUG -+#endif - +- -namespace rack { -namespace engine { - - +-#if defined ARCH_X64 -static void initMXCSR() { - // Set CPU to flush-to-zero (FTZ) and denormals-are-zero (DAZ) mode - // https://software.intel.com/en-us/node/682949 @@ -61,8 +66,13 @@ - // Reset other flags - _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST); -} -- -- ++#ifdef NDEBUG ++# undef DEBUG + #endif + ++#include "../CardinalRemote.hpp" ++#include "DistrhoUtils.hpp" + -/** Barrier based on mutexes. -Not finished or tested, do not use. -*/ @@ -109,8 +119,7 @@ - void setThreads(int threads) { - this->threads = threads; - } -+#include "DistrhoUtils.hpp" - +- - void wait() { - uint8_t s = step; - if (count.fetch_add(1, std::memory_order_acquire) + 1 >= threads) { @@ -125,7 +134,9 @@ - while (true) { - if (step.load(std::memory_order_relaxed) != s) - return; +-#if defined ARCH_X64 - __builtin_ia32_pause(); +-#endif - } - } -}; @@ -174,7 +185,9 @@ - while (!yielded.load(std::memory_order_relaxed)) { - if (step.load(std::memory_order_relaxed) != s) - return; +-#if defined ARCH_X64 - __builtin_ia32_pause(); +-#endif - } - - // Wait on mutex CV @@ -191,7 +204,9 @@ - int id; - std::thread thread; - bool running = false; -- ++namespace rack { ++namespace engine { + - void start() { - assert(!running); - running = true; @@ -199,7 +214,7 @@ - run(); - }); - } -- + - void requestStop() { - running = false; - } @@ -211,8 +226,11 @@ - - void run(); -}; -+namespace rack { -+namespace engine { ++static constexpr const int PORT_DIVIDER = 7; ++// Arbitrary prime number so it doesn't over- or under-estimate time of buffered processors. ++static constexpr const int METER_DIVIDER = 37; ++static constexpr const int METER_BUFFER_LEN = 32; ++static constexpr const float METER_TIME = 1.f; struct Engine::Internal { @@ -224,7 +242,7 @@ // moduleId std::map modulesCache; -@@ -198,7 +79,9 @@ +@@ -206,7 +88,9 @@ int64_t blockFrame = 0; double blockTime = 0.0; int blockFrames = 0; @@ -234,7 +252,7 @@ // Meter int meterCount = 0; double meterTotal = 0.0; -@@ -206,6 +89,7 @@ +@@ -214,33 +98,32 @@ double meterLastTime = -INFINITY; double meterLastAverage = 0.0; double meterLastMax = 0.0; @@ -242,14 +260,23 @@ // Parameter smoothing Module* smoothModule = NULL; -@@ -217,22 +101,6 @@ + int smoothParamId = 0; + float smoothValue = 0.f; + ++ // Remote control ++ remoteUtils::RemoteDetails* remoteDetails = nullptr; ++ + /** Mutex that guards the Engine state, such as settings, Modules, and Cables. + Writers lock when mutating the engine's state or stepping the block. Readers lock when using the engine's state. */ SharedMutex mutex; - /** Mutex that guards stepBlock() so it's not called simultaneously. - */ - std::mutex blockMutex; -- ++}; ++ + - int threadCount = 0; - std::vector workers; - HybridBarrier engineBarrier; @@ -262,10 +289,18 @@ - std::thread fallbackThread; - std::mutex fallbackMutex; - std::condition_variable fallbackCv; ++struct Module::Internal { ++ bool bypassed = false; ++ ++ int meterSamples = 0; ++ float meterDurationTotal = 0.f; ++ ++ float meterBuffer[METER_BUFFER_LEN] = {}; ++ int meterIndex = 0; }; -@@ -260,76 +128,11 @@ +@@ -268,89 +151,134 @@ } @@ -273,28 +308,66 @@ - Engine::Internal* internal = that->internal; - if (threadCount == internal->threadCount) - return; -- ++static void Cable_step(Cable* that) { ++ Output* output = &that->outputModule->outputs[that->outputId]; ++ Input* input = &that->inputModule->inputs[that->inputId]; ++ // Match number of polyphonic channels to output port ++ const int channels = output->channels; ++ // Copy all voltages from output to input ++ for (int c = 0; c < channels; c++) { ++ if (!std::isfinite(output->voltages[c])) ++ __builtin_unreachable(); ++ input->voltages[c] = output->voltages[c]; ++ } ++ // Set higher channel voltages to 0 ++ for (int c = channels; c < input->channels; c++) { ++ input->voltages[c] = 0.f; ++ } ++ input->channels = channels; ++} + - if (internal->threadCount > 0) { - // Stop engine workers - for (EngineWorker& worker : internal->workers) { - worker.requestStop(); - } - internal->engineBarrier.wait(); -- + - // Join and destroy engine workers - for (EngineWorker& worker : internal->workers) { - worker.join(); - } - internal->workers.resize(0); -- } -- ++#ifndef HEADLESS ++static void Port_step(Port* that, float deltaTime) { ++ // Set plug lights ++ if (that->channels == 0) { ++ that->plugLights[0].setBrightness(0.f); ++ that->plugLights[1].setBrightness(0.f); ++ that->plugLights[2].setBrightness(0.f); ++ } ++ else if (that->channels == 1) { ++ float v = that->getVoltage() / 10.f; ++ that->plugLights[0].setSmoothBrightness(-v, deltaTime); ++ that->plugLights[1].setSmoothBrightness(v, deltaTime); ++ that->plugLights[2].setBrightness(0.f); + } ++ else { ++ float v = that->getVoltageRMS() / 10.f; ++ that->plugLights[0].setBrightness(0.f); ++ that->plugLights[1].setBrightness(0.f); ++ that->plugLights[2].setSmoothBrightness(v, deltaTime); ++ } ++} ++#endif + - // Configure engine - internal->threadCount = threadCount; - - // Set barrier counts - internal->engineBarrier.setThreads(threadCount); - internal->workerBarrier.setThreads(threadCount); -- + - if (threadCount > 0) { - // Create and start engine workers - internal->workers.resize(threadCount - 1); @@ -303,17 +376,41 @@ - worker.id = id; - worker.engine = that; - worker.start(); -- } -- } --} -- -- ++static void TerminalModule__doProcess(TerminalModule* const terminalModule, const Module::ProcessArgs& args, bool input) { ++ // Step module ++ if (input) { ++ terminalModule->processTerminalInput(args); ++ for (Output& output : terminalModule->outputs) { ++ for (Cable* cable : output.cables) ++ Cable_step(cable); ++ } ++ } else { ++ terminalModule->processTerminalOutput(args); ++ } ++ ++#ifndef HEADLESS ++ // Iterate ports to step plug lights ++ if (args.frame % PORT_DIVIDER == 0) { ++ float portTime = args.sampleTime * PORT_DIVIDER; ++ for (Input& input : terminalModule->inputs) { ++ Port_step(&input, portTime); ++ } ++ for (Output& output : terminalModule->outputs) { ++ Port_step(&output, portTime); + } + } ++#endif + } + + -static void Engine_stepWorker(Engine* that, int threadId) { - Engine::Internal* internal = that->internal; - - // int threadCount = internal->threadCount; - int modulesLen = internal->modules.size(); -- ++static void Module__doProcess(Module* const module, const Module::ProcessArgs& args) { ++ Module::Internal* const internal = module->internal; + - // Build ProcessArgs - Module::ProcessArgs processArgs; - processArgs.sampleRate = internal->sampleRate; @@ -330,74 +427,104 @@ - - Module* module = internal->modules[i]; - module->doProcess(processArgs); -- } ++#ifndef HEADLESS ++ // This global setting can change while the function is running, so use a local variable. ++ bool meterEnabled = settings::cpuMeter && (args.frame % METER_DIVIDER == 0); ++ ++ // Start CPU timer ++ double startTime; ++ if (meterEnabled) { ++ startTime = system::getTime(); + } -} - -- - static void Cable_step(Cable* that) { - Output* output = &that->outputModule->outputs[that->outputId]; - Input* input = &that->inputModule->inputs[that->inputId]; - // Match number of polyphonic channels to output port -- int channels = output->channels; -+ const int channels = output->channels; - // Copy all voltages from output to input - for (int c = 0; c < channels; c++) { - float v = output->voltages[c]; -@@ -346,6 +149,53 @@ - } - ++#endif -+static void Port_step(Port* that, float deltaTime) { -+ // Set plug lights -+ if (that->channels == 0) { -+ that->plugLights[0].setBrightness(0.f); -+ that->plugLights[1].setBrightness(0.f); -+ that->plugLights[2].setBrightness(0.f); -+ } -+ else if (that->channels == 1) { -+ float v = that->getVoltage() / 10.f; -+ that->plugLights[0].setSmoothBrightness(-v, deltaTime); -+ that->plugLights[1].setSmoothBrightness(v, deltaTime); -+ that->plugLights[2].setBrightness(0.f); -+ } -+ else { -+ float v = that->getVoltageRMS() / 10.f; -+ that->plugLights[0].setBrightness(0.f); -+ that->plugLights[1].setBrightness(0.f); -+ that->plugLights[2].setSmoothBrightness(v, deltaTime); -+ } -+} +-static void Cable_step(Cable* that) { +- Output* output = &that->outputModule->outputs[that->outputId]; +- Input* input = &that->inputModule->inputs[that->inputId]; +- // Match number of polyphonic channels to output port +- int channels = output->channels; +- // Copy all voltages from output to input +- for (int c = 0; c < channels; c++) { +- float v = output->voltages[c]; +- // Set 0V if infinite or NaN +- if (!std::isfinite(v)) +- v = 0.f; +- input->voltages[c] = v; ++ // Step module ++ if (!internal->bypassed) ++ module->process(args); ++ else ++ module->processBypass(args); ++ ++#ifndef HEADLESS ++ // Stop CPU timer ++ if (meterEnabled) { ++ double endTime = system::getTime(); ++ // Subtract call time of getTime() itself, since we only want to measure process() time. ++ double endTime2 = system::getTime(); ++ float duration = (endTime - startTime) - (endTime2 - endTime); + ++ internal->meterSamples++; ++ internal->meterDurationTotal += duration; + -+static void TerminalModule__doProcess(TerminalModule* terminalModule, const Module::ProcessArgs& args, bool input) { -+ // Step module -+ if (input) { -+ terminalModule->processTerminalInput(args); -+ for (Output& output : terminalModule->outputs) { -+ for (Cable* cable : output.cables) -+ Cable_step(cable); ++ // Seconds we've been measuring ++ float meterTime = internal->meterSamples * METER_DIVIDER * args.sampleTime; ++ ++ if (meterTime >= METER_TIME) { ++ // Push time to buffer ++ if (internal->meterSamples > 0) { ++ internal->meterIndex++; ++ internal->meterIndex %= METER_BUFFER_LEN; ++ internal->meterBuffer[internal->meterIndex] = internal->meterDurationTotal / internal->meterSamples; ++ } ++ // Reset total ++ internal->meterSamples = 0; ++ internal->meterDurationTotal = 0.f; + } -+ } else { -+ terminalModule->processTerminalOutput(args); -+ } + } +- // Set higher channel voltages to 0 +- for (int c = channels; c < input->channels; c++) { +- input->voltages[c] = 0.f; + + // Iterate ports to step plug lights -+ if (args.frame % 7 /* PORT_DIVIDER */ == 0) { -+ float portTime = args.sampleTime * 7 /* PORT_DIVIDER */; -+ for (Input& input : terminalModule->inputs) { ++ if (args.frame % PORT_DIVIDER == 0) { ++ float portTime = args.sampleTime * PORT_DIVIDER; ++ for (Input& input : module->inputs) { + Port_step(&input, portTime); + } -+ for (Output& output : terminalModule->outputs) { ++ for (Output& output : module->outputs) { + Port_step(&output, portTime); + } -+ } -+} -+ -+ - /** Steps a single frame - */ - static void Engine_stepFrame(Engine* that) { -@@ -372,13 +222,8 @@ + } +- input->channels = channels; ++#endif + } + + +@@ -366,10 +294,16 @@ + float smoothValue = internal->smoothValue; + Param* smoothParam = &smoothModule->params[smoothParamId]; + float value = smoothParam->value; +- // Use decay rate of roughly 1 graphics frame +- const float smoothLambda = 60.f; +- float newValue = value + (smoothValue - value) * smoothLambda * internal->sampleTime; +- if (value == newValue) { ++ float newValue; ++ if (internal->remoteDetails != nullptr) { ++ newValue = value; ++ sendParamChangeToRemote(internal->remoteDetails, smoothModule->id, smoothParamId, value); ++ } else { ++ // Use decay rate of roughly 1 graphics frame ++ const float smoothLambda = 60.f; ++ newValue = value + (smoothValue - value) * smoothLambda * internal->sampleTime; ++ } ++ if (d_isEqual(value, newValue)) { + // Snap to actual smooth value if the value doesn't change enough (due to the granularity of floats) + smoothParam->setValue(smoothValue); + internal->smoothModule = NULL; +@@ -380,13 +314,8 @@ } } @@ -412,7 +539,7 @@ if (module->leftExpander.messageFlipRequested) { std::swap(module->leftExpander.producerMessage, module->leftExpander.consumerMessage); module->leftExpander.messageFlipRequested = false; -@@ -389,13 +234,32 @@ +@@ -397,13 +326,32 @@ } } @@ -431,17 +558,17 @@ + for (TerminalModule* terminalModule : internal->terminalModules) { + TerminalModule__doProcess(terminalModule, processArgs, true); + } -+ + +- internal->frame++; + // Step each module and cables + for (Module* module : internal->modules) { -+ module->doProcess(processArgs); ++ Module__doProcess(module, processArgs); + for (Output& output : module->outputs) { + for (Cable* cable : output.cables) + Cable_step(cable); + } + } - -- internal->frame++; ++ + // Process terminal outputs last + for (TerminalModule* terminalModule : internal->terminalModules) { + TerminalModule__doProcess(terminalModule, processArgs, false); @@ -451,8 +578,79 @@ } -@@ -416,32 +280,45 @@ +@@ -422,35 +370,119 @@ + } + ++template ++using IdentityDictionary = std::unordered_map; ++ ++template ++inline bool dictContains(IdentityDictionary& dict, T key) { ++ return dict.find(key) != dict.end(); ++} ++ ++template ++inline void dictAdd(IdentityDictionary& dict, T key) { ++ dict[key] = key; ++} ++ ++static void Engine_storeTerminalModulesIDs(std::vector terminalModules, IdentityDictionary& terminalModulesIDs) { ++ for (TerminalModule* terminalModule : terminalModules) ++ dictAdd(terminalModulesIDs, terminalModule->id); ++} ++ ++static void Engine_orderModule(Module* module, IdentityDictionary& touchedModules, std::vector& orderedModules, IdentityDictionary& terminalModulesIDs) { ++ if (!dictContains(touchedModules, module) && !dictContains(terminalModulesIDs, module->id)) { // Ignore feedback loops and terminal modules ++ dictAdd(touchedModules, module); ++ for (Output& output : module->outputs) { ++ for (Cable* cable : output.cables) { ++ Module* receiver = cable->inputModule; // The input to the cable is the receiving module ++ Engine_orderModule(receiver, touchedModules, orderedModules, terminalModulesIDs); ++ } ++ } ++ orderedModules.push_back(module); ++ } ++} ++ ++static void Engine_assignOrderedModules(std::vector& modules, std::vector& orderedModules) { ++ std::reverse(orderedModules.begin(), orderedModules.end()); // These are stored bottom up ++ if (orderedModules.size() == modules.size()) { ++ for (unsigned int i = 0; i < orderedModules.size(); i++) ++ modules[i] = orderedModules[i]; ++ } ++} ++ ++#if DEBUG_ORDERED_MODULES ++static void Engine_debugOrderedModules(std::vector& modules) { ++ printf("\n--- Ordered modules ---\n"); ++ for (unsigned int i = 0; i < modules.size(); i++) ++ printf("%d) %s - %ld\n", i, modules[i]->model->getFullName().c_str(), modules[i]->id); ++} ++#endif ++ ++/** Order the modules so that they always read the most recent sample from their inputs ++*/ ++static void Engine_orderModules(Engine* that) { ++ Engine::Internal* internal = that->internal; ++ ++ IdentityDictionary terminalModulesIDs; ++ Engine_storeTerminalModulesIDs(internal->terminalModules, terminalModulesIDs); ++ ++ IdentityDictionary touchedModules; ++ std::vector orderedModules; ++ orderedModules.reserve(internal->modules.size()); ++ for (Module* module : internal->modules) ++ Engine_orderModule(module, touchedModules, orderedModules, terminalModulesIDs); ++ ++ Engine_assignOrderedModules(internal->modules, orderedModules); ++ ++#if DEBUG_ORDERED_MODULES ++ Engine_debugOrderedModules(internal->modules); ++#endif ++} ++ ++ static void Engine_updateConnected(Engine* that) { // Find disconnected ports - std::set disconnectedPorts; @@ -501,14 +699,17 @@ - Port_setDisconnected(port); + for (Input* input : disconnectedInputs) { + Port_setDisconnected(input); -+ } + } + for (Output* output : disconnectedOutputs) { + Port_setDisconnected(output); + DISTRHO_SAFE_ASSERT(output->cables.empty()); - } ++ } ++ // Order the modules according to their connections ++ Engine_orderModules(that); } -@@ -460,37 +337,23 @@ + +@@ -468,37 +500,23 @@ Engine::Engine() { internal = new Internal; @@ -554,7 +755,7 @@ delete internal; } -@@ -519,18 +382,22 @@ +@@ -527,20 +545,22 @@ removeModule_NoLock(module); delete module; } @@ -575,12 +776,14 @@ - std::lock_guard stepLock(internal->blockMutex); SharedLock lock(internal->mutex); // Configure thread +-#if defined ARCH_X64 - uint32_t csr = _mm_getcsr(); - initMXCSR(); +-#endif random::init(); internal->blockFrame = internal->frame; -@@ -543,18 +410,14 @@ +@@ -553,18 +573,14 @@ Engine_updateExpander_NoLock(this, module, true); } @@ -600,14 +803,15 @@ // Stop timer double endTime = system::getTime(); double meter = (endTime - startTime) / (frames * internal->sampleTime); -@@ -572,47 +435,20 @@ +@@ -582,49 +598,20 @@ internal->meterTotal = 0.0; internal->meterMax = 0.0; } - +-#if defined ARCH_X64 - // Reset MXCSR back to original value - _mm_setcsr(csr); -+#endif + #endif } @@ -650,7 +854,7 @@ } -@@ -635,20 +471,13 @@ +@@ -647,20 +634,13 @@ for (Module* module : internal->modules) { module->onSampleRateChange(e); } @@ -674,7 +878,7 @@ } -@@ -658,7 +487,6 @@ +@@ -670,7 +650,6 @@ void Engine::yieldWorkers() { @@ -682,7 +886,7 @@ } -@@ -698,17 +526,25 @@ +@@ -705,17 +684,25 @@ double Engine::getMeterAverage() { @@ -709,7 +913,7 @@ } -@@ -718,8 +554,12 @@ +@@ -725,8 +712,12 @@ for (Module* m : internal->modules) { if (i >= len) break; @@ -724,7 +928,7 @@ } return i; } -@@ -728,27 +568,43 @@ +@@ -735,27 +726,43 @@ std::vector Engine::getModuleIds() { SharedLock lock(internal->mutex); std::vector moduleIds; @@ -772,7 +976,17 @@ internal->modulesCache[module->id] = module; // Dispatch AddEvent Module::AddEvent eAdd; -@@ -772,11 +628,11 @@ +@@ -770,6 +777,9 @@ + if (paramHandle->moduleId == module->id) + paramHandle->module = module; + } ++#if DEBUG_ORDERED_MODULES ++ printf("New module: %s - %ld\n", module->model->getFullName().c_str(), module->id); ++#endif + } + + +@@ -779,11 +789,11 @@ } @@ -789,7 +1003,7 @@ // Dispatch RemoveEvent Module::RemoveEvent eRemove; module->onRemove(eRemove); -@@ -785,18 +641,14 @@ +@@ -792,18 +802,14 @@ if (paramHandle->moduleId == module->id) paramHandle->module = NULL; } @@ -810,7 +1024,7 @@ } // Update expanders of other modules for (Module* m : internal->modules) { -@@ -809,14 +661,31 @@ +@@ -816,14 +822,31 @@ m->rightExpander.module = NULL; } } @@ -845,7 +1059,7 @@ } -@@ -824,7 +693,8 @@ +@@ -831,7 +854,8 @@ SharedLock lock(internal->mutex); // TODO Performance could be improved by searching modulesCache, but more testing would be needed to make sure it's always valid. auto it = std::find(internal->modules.begin(), internal->modules.end(), module); @@ -855,7 +1069,7 @@ } -@@ -844,7 +714,7 @@ +@@ -851,7 +875,7 @@ void Engine::resetModule(Module* module) { std::lock_guard lock(internal->mutex); @@ -864,7 +1078,7 @@ Module::ResetEvent eReset; module->onReset(eReset); -@@ -853,7 +723,7 @@ +@@ -860,7 +884,7 @@ void Engine::randomizeModule(Module* module) { std::lock_guard lock(internal->mutex); @@ -873,7 +1087,7 @@ Module::RandomizeEvent eRandomize; module->onRandomize(eRandomize); -@@ -861,7 +731,7 @@ +@@ -868,7 +892,7 @@ void Engine::bypassModule(Module* module, bool bypassed) { @@ -882,7 +1096,7 @@ if (module->isBypassed() == bypassed) return; -@@ -907,11 +777,17 @@ +@@ -914,11 +938,17 @@ void Engine::prepareSave() { @@ -900,7 +1114,7 @@ } -@@ -946,16 +822,16 @@ +@@ -953,16 +983,16 @@ void Engine::addCable(Cable* cable) { std::lock_guard lock(internal->mutex); @@ -922,7 +1136,7 @@ // Get connected status of output, to decide whether we need to call a PortChangeEvent. // It's best to not trust `cable->outputModule->outputs[cable->outputId]->isConnected()` if (cable2->outputModule == cable->outputModule && cable2->outputId == cable->outputId) -@@ -969,6 +845,8 @@ +@@ -976,6 +1006,8 @@ // Add the cable internal->cables.push_back(cable); internal->cablesCache[cable->id] = cable; @@ -931,7 +1145,7 @@ Engine_updateConnected(this); // Dispatch input port event { -@@ -996,10 +874,12 @@ +@@ -1003,10 +1035,12 @@ void Engine::removeCable_NoLock(Cable* cable) { @@ -946,7 +1160,17 @@ // Remove the cable internal->cablesCache.erase(cable->id); internal->cables.erase(it); -@@ -1085,11 +965,11 @@ +@@ -1060,6 +1094,9 @@ + internal->smoothModule = NULL; + internal->smoothParamId = 0; + } ++ if (internal->remoteDetails != nullptr) { ++ sendParamChangeToRemote(internal->remoteDetails, module->id, paramId, value); ++ } + module->params[paramId].setValue(value); + } + +@@ -1092,11 +1129,11 @@ std::lock_guard lock(internal->mutex); // New ParamHandles must be blank. // This means we don't have to refresh the cache. @@ -960,7 +1184,7 @@ // Add it internal->paramHandles.insert(paramHandle); -@@ -1106,7 +986,7 @@ +@@ -1113,7 +1150,7 @@ void Engine::removeParamHandle_NoLock(ParamHandle* paramHandle) { // Check that the ParamHandle is already added auto it = internal->paramHandles.find(paramHandle); @@ -969,7 +1193,7 @@ // Remove it paramHandle->module = NULL; -@@ -1143,7 +1023,7 @@ +@@ -1150,7 +1187,7 @@ void Engine::updateParamHandle_NoLock(ParamHandle* paramHandle, int64_t moduleId, int paramId, bool overwrite) { // Check that it exists auto it = internal->paramHandles.find(paramHandle); @@ -978,7 +1202,7 @@ // Set IDs paramHandle->moduleId = moduleId; -@@ -1187,6 +1067,10 @@ +@@ -1194,6 +1231,10 @@ json_t* moduleJ = module->toJson(); json_array_append_new(modulesJ, moduleJ); } @@ -989,7 +1213,7 @@ json_object_set_new(rootJ, "modules", modulesJ); // cables -@@ -1197,11 +1081,6 @@ +@@ -1204,11 +1245,6 @@ } json_object_set_new(rootJ, "cables", cablesJ); @@ -1001,7 +1225,7 @@ return rootJ; } -@@ -1225,14 +1104,20 @@ +@@ -1232,14 +1268,20 @@ } catch (Exception& e) { WARN("Cannot load model: %s", e.what()); @@ -1026,7 +1250,7 @@ try { // This doesn't need a lock because the Module is not added to the Engine yet. -@@ -1248,7 +1133,8 @@ +@@ -1255,7 +1297,8 @@ } catch (Exception& e) { WARN("Cannot load module: %s", e.what()); @@ -1036,7 +1260,7 @@ delete module; continue; } -@@ -1285,67 +1171,15 @@ +@@ -1292,69 +1335,20 @@ continue; } } @@ -1054,7 +1278,9 @@ - // Configure thread - contextSet(engine->internal->context); - system::setThreadName(string::f("Worker %d", id)); +-#if defined ARCH_X64 - initMXCSR(); +-#endif - random::init(); - - while (true) { @@ -1064,9 +1290,10 @@ - Engine_stepWorker(engine, id); - engine->internal->workerBarrier.wait(); - } --} -- -- ++void Engine::startFallbackThread() { + } + + -static void Engine_fallbackRun(Engine* that) { - system::setThreadName("Engine fallback"); - contextSet(that->internal->context); @@ -1092,7 +1319,8 @@ - }); - } - } -+void Engine::startFallbackThread() { ++void Engine_setAboutToClose(Engine* const engine) { ++ engine->internal->aboutToClose = true; } @@ -1102,8 +1330,8 @@ - - internal->fallbackRunning = true; - internal->fallbackThread = std::thread(Engine_fallbackRun, this); -+void Engine_setAboutToClose(Engine* const engine) { -+ engine->internal->aboutToClose = true; ++void Engine_setRemoteDetails(Engine* const engine, remoteUtils::RemoteDetails* const remoteDetails) { ++ engine->internal->remoteDetails = remoteDetails; } diff --git a/src/override/diffs/MenuBar.cpp.diff b/src/override/diffs/MenuBar.cpp.diff index 5a32860c..21099eb8 100644 --- a/src/override/diffs/MenuBar.cpp.diff +++ b/src/override/diffs/MenuBar.cpp.diff @@ -1,9 +1,9 @@ ---- ../Rack/src/app/MenuBar.cpp 2022-07-12 09:46:20.716165650 +0100 -+++ MenuBar.cpp 2022-07-12 09:45:31.518663160 +0100 +--- ../Rack/src/app/MenuBar.cpp 2023-09-10 12:59:02.630898560 +0200 ++++ MenuBar.cpp 2023-08-15 17:56:23.782915145 +0200 @@ -1,8 +1,33 @@ +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ + +/** + * This file is an edited version of VCVRack's app/MenuBar.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -36,29 +36,45 @@ #include #include #include -@@ -25,8 +50,21 @@ +@@ -15,6 +40,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -25,8 +51,29 @@ #include #include +#include "../CardinalCommon.hpp" ++#include "../CardinalRemote.hpp" ++#include "../PluginContext.hpp" ++#include "DistrhoPlugin.hpp" ++#include "DistrhoStandaloneUtils.hpp" + -+#ifdef HAVE_LIBLO -+# include ++#ifdef DISTRHO_OS_WASM ++# include ++# undef HAVE_LIBLO +#endif + -+#ifdef DISTRHO_OS_WASM -+# include "DistrhoStandaloneUtils.hpp" ++#ifdef HAVE_LIBLO ++# include +#endif namespace rack { +namespace asset { +std::string patchesPath(); +} ++namespace engine { ++void Engine_setRemoteDetails(Engine*, remoteUtils::RemoteDetails*); ++} + namespace app { namespace menuBar { -@@ -48,79 +86,140 @@ +@@ -48,79 +95,238 @@ }; @@ -84,10 +100,40 @@ + const bool isStandalone; + std::vector demoPatches; + ++#ifdef DISTRHO_OS_WASM ++ static void WebBrowserDataSaved(const int err) ++ { ++ err ? async_dialog_message("Error, could not save web browser data!") ++ : async_dialog_message("Web browser data saved!"); ++ } ++ ++ static void wasmSaveAs() ++ { ++ async_dialog_text_input("Filename", nullptr, [](char* const filename) { ++ if (filename == nullptr) ++ return; ++ ++ APP->patch->path = asset::user("patches"); ++ system::createDirectories(APP->patch->path); ++ ++ APP->patch->path += filename; ++ if (rack::system::getExtension(filename) != ".vcv") ++ APP->patch->path += ".vcv"; ++ ++ patchUtils::saveDialog(APP->patch->path); ++ std::free(filename); ++ }); ++ } ++#endif ++ + FileButton(const bool standalone) + : MenuButton(), isStandalone(standalone) + { -+ const std::string patchesDir = asset::patchesPath(); ++#if CARDINAL_VARIANT_MINI ++ const std::string patchesDir = asset::patchesPath() + DISTRHO_OS_SEP_STR "mini"; ++#else ++ const std::string patchesDir = asset::patchesPath() + DISTRHO_OS_SEP_STR "examples"; ++#endif + + if (system::isDirectory(patchesDir)) + { @@ -105,129 +151,192 @@ - menu->addChild(createMenuItem("New", RACK_MOD_CTRL_NAME "+N", []() { - APP->patch->loadTemplateDialog(); +- })); +- +- menu->addChild(createMenuItem("Open", RACK_MOD_CTRL_NAME "+O", []() { +- APP->patch->loadDialog(); +- })); +#ifndef DISTRHO_OS_WASM -+ const char* const NewShortcut = RACK_MOD_CTRL_NAME "+N"; ++ constexpr const char* const NewShortcut = RACK_MOD_CTRL_NAME "+N"; +#else -+ const char* const NewShortcut = ""; ++ constexpr const char* const NewShortcut = ""; +#endif + menu->addChild(createMenuItem("New", NewShortcut, []() { -+ patchUtils::loadTemplateDialog(); - })); - -- menu->addChild(createMenuItem("Open", RACK_MOD_CTRL_NAME "+O", []() { -- APP->patch->loadDialog(); ++ patchUtils::loadTemplateDialog(false); ++ })); ++ ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS ++ menu->addChild(createMenuItem("New (factory template)", "", []() { ++ patchUtils::loadTemplateDialog(true); ++ })); ++ +#ifndef DISTRHO_OS_WASM -+ menu->addChild(createMenuItem("Open / Import...", RACK_MOD_CTRL_NAME "+O", []() { ++ constexpr const char* const OpenName = "Open..."; ++#else ++ constexpr const char* const OpenName = "Import patch..."; ++#endif ++ menu->addChild(createMenuItem(OpenName, RACK_MOD_CTRL_NAME "+O", []() { + patchUtils::loadDialog(); - })); ++ })); ++ ++ const std::string patchesDir = asset::user("patches"); ++ const std::vector patches = system::isDirectory(patchesDir) ? system::getEntries(patchesDir) : std::vector(); ++ menu->addChild(createSubmenuItem("Open local patch", "", [patches](ui::Menu* menu) { ++ for (const std::string& path : patches) { ++ std::string name = system::getStem(path); ++ menu->addChild(createMenuItem(name, "", [=]() { ++ patchUtils::loadPathDialog(path, false); ++ })); ++ } ++ }, patches.empty())); -- menu->addChild(createSubmenuItem("Open recent", "", [](ui::Menu* menu) { -- for (const std::string& path : settings::recentPatchPaths) { -- std::string name = system::getStem(path); -- menu->addChild(createMenuItem(name, "", [=]() { + menu->addChild(createSubmenuItem("Open recent", "", [](ui::Menu* menu) { + for (const std::string& path : settings::recentPatchPaths) { + std::string name = system::getStem(path); + menu->addChild(createMenuItem(name, "", [=]() { - APP->patch->loadPathDialog(path); -- })); -- } -- }, settings::recentPatchPaths.empty())); -- ++ patchUtils::loadPathDialog(path, false); + })); + } + }, settings::recentPatchPaths.empty())); ++#endif ++ ++ if (!demoPatches.empty()) ++ { ++ menu->addChild(createSubmenuItem("Open demo / example project", "", [=](ui::Menu* const menu) { ++ for (std::string path : demoPatches) { ++ std::string label = system::getStem(path); ++ ++ for (size_t i=0, len=label.size(); iaddChild(createMenuItem(label, "", [path]() { ++ patchUtils::loadPathDialog(path, true); ++ })); ++ } ++ ++ menu->addChild(new ui::MenuSeparator); + ++ menu->addChild(createMenuItem("Open patchstorage.com for more patches", "", []() { ++ patchUtils::openBrowser("https://patchstorage.com/platform/cardinal/"); ++ })); ++ })); ++ } ++ ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS ++ menu->addChild(createMenuItem("Import selection...", "", [=]() { ++ patchUtils::loadSelectionDialog(); ++ }, false, true)); ++ ++ menu->addChild(new ui::MenuSeparator); ++ ++#ifndef DISTRHO_OS_WASM menu->addChild(createMenuItem("Save", RACK_MOD_CTRL_NAME "+S", []() { - APP->patch->saveDialog(); -+ // NOTE: will do nothing if path is empty, intentionally ++ // NOTE: for plugin versions it will do nothing if path is empty, intentionally + patchUtils::saveDialog(APP->patch->path); -+ }, APP->patch->path.empty())); ++ }, APP->patch->path.empty() && !isStandalone)); + + menu->addChild(createMenuItem("Save as / Export...", RACK_MOD_CTRL_NAME "+Shift+S", []() { + patchUtils::saveAsDialog(); + })); +#else -+ menu->addChild(createMenuItem("Import patch...", RACK_MOD_CTRL_NAME "+O", []() { -+ patchUtils::loadDialog(); ++ menu->addChild(createMenuItem("Save", "", []() { ++ if (APP->patch->path.empty()) ++ wasmSaveAs(); ++ else ++ patchUtils::saveDialog(APP->patch->path); })); - menu->addChild(createMenuItem("Save as", RACK_MOD_CTRL_NAME "+Shift+S", []() { - APP->patch->saveAsDialog(); -+ menu->addChild(createMenuItem("Import selection...", "", [=]() { -+ patchUtils::loadSelectionDialog(); -+ }, false, true)); -+ -+ menu->addChild(createMenuItem("Save and download compressed", RACK_MOD_CTRL_NAME "+Shift+S", []() { -+ patchUtils::saveAsDialog(); ++ menu->addChild(createMenuItem("Save as...", "", []() { ++ wasmSaveAs(); })); - menu->addChild(createMenuItem("Save a copy", "", []() { - APP->patch->saveAsDialog(false); ++ menu->addChild(createMenuItem("Save and download compressed", "", []() { ++ patchUtils::saveAsDialog(); + })); + + menu->addChild(createMenuItem("Save and download uncompressed", "", []() { + patchUtils::saveAsDialogUncompressed(); - })); ++ })); +#endif - ++#endif ++ menu->addChild(createMenuItem("Revert", RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME "+O", []() { - APP->patch->revertDialog(); - }, APP->patch->path == "")); + patchUtils::revertDialog(); + }, APP->patch->path.empty())); -- menu->addChild(createMenuItem("Overwrite template", "", []() { ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + menu->addChild(createMenuItem("Overwrite template", "", []() { - APP->patch->saveTemplateDialog(); -- })); -+#ifdef HAVE_LIBLO -+ menu->addChild(new ui::MenuSeparator); -+ -+ if (patchUtils::isRemoteConnected()) { -+ menu->addChild(createMenuItem("Deploy to MOD", "F7", []() { -+ patchUtils::deployToRemote(); -+ })); -+ -+ const bool autoDeploy = patchUtils::isRemoteAutoDeployed(); -+ menu->addChild(createCheckMenuItem("Auto deploy to MOD", "", -+ [=]() {return autoDeploy;}, -+ [=]() {patchUtils::setRemoteAutoDeploy(!autoDeploy);} -+ )); -+ } else { -+ menu->addChild(createMenuItem("Connect to MOD", "", []() { -+ patchUtils::connectToRemote(); -+ })); -+ } -+#endif ++ patchUtils::saveTemplateDialog(); + })); -+#ifndef DISTRHO_OS_WASM ++#ifdef DISTRHO_OS_WASM menu->addChild(new ui::MenuSeparator); - // Load selection +- // Load selection - menu->addChild(createMenuItem("Import selection", "", [=]() { - APP->scene->rack->loadSelectionDialog(); -+ menu->addChild(createMenuItem("Import selection...", "", [=]() { -+ patchUtils::loadSelectionDialog(); - }, false, true)); - -- menu->addChild(new ui::MenuSeparator); +- }, false, true)); - -- menu->addChild(createMenuItem("Quit", RACK_MOD_CTRL_NAME "+Q", []() { -- APP->window->close(); -+ menu->addChild(createMenuItem("Export uncompressed json...", "", []() { -+ patchUtils::saveAsDialogUncompressed(); - })); ++ menu->addChild(createMenuItem("Save persistent browser data", "", []() { ++ settings::save(); ++ EM_ASM({ ++ Module.FS.syncfs(false, function(err){ dynCall('vi', $0, [!!err]) }); ++ }, WebBrowserDataSaved); ++ })); ++#endif +#endif + -+ if (!demoPatches.empty()) -+ { -+ menu->addChild(new ui::MenuSeparator); -+ -+ menu->addChild(createSubmenuItem("Open Demo / Example project", "", [=](ui::Menu* const menu) { -+ for (std::string path : demoPatches) { -+ std::string label = system::getStem(path); ++#if defined(HAVE_LIBLO) || ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS ++#ifdef __MOD_DEVICES__ ++#define REMOTE_NAME "MOD" ++#else ++#define REMOTE_NAME "Remote" ++#endif + menu->addChild(new ui::MenuSeparator); + +- menu->addChild(createMenuItem("Quit", RACK_MOD_CTRL_NAME "+Q", []() { +- APP->window->close(); +- })); ++ remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote(); + -+ for (size_t i=0, len=label.size(); iconnected) { ++ menu->addChild(createMenuItem("Deploy to " REMOTE_NAME, "F7", [remoteDetails]() { ++ remoteUtils::sendFullPatchToRemote(remoteDetails); ++ })); + -+ menu->addChild(createMenuItem(label, "", [path]() { -+ patchUtils::loadPathDialog(path, true); -+ })); ++ menu->addChild(createCheckMenuItem("Auto deploy to " REMOTE_NAME, "", ++ [remoteDetails]() {return remoteDetails->autoDeploy;}, ++ [remoteDetails]() { ++ remoteDetails->autoDeploy = !remoteDetails->autoDeploy; ++ Engine_setRemoteDetails(APP->engine, remoteDetails->autoDeploy ? remoteDetails : nullptr); + } ++ )); ++#ifndef __MOD_DEVICES__ ++ } else { ++ menu->addChild(createMenuItem("Connect to " REMOTE_NAME "...", "", [remoteDetails]() { ++ const std::string url = remoteDetails != nullptr ? remoteDetails->url : CARDINAL_DEFAULT_REMOTE_URL; ++ async_dialog_text_input("Remote:", url.c_str(), [](char* const url) { ++ if (url == nullptr) ++ return; ++ ++ DISTRHO_SAFE_ASSERT(remoteUtils::connectToRemote(url)); ++ std::free(url); ++ }); + })); ++#endif + } ++#endif + +#ifndef DISTRHO_OS_WASM + if (isStandalone) { @@ -241,7 +350,7 @@ } }; -@@ -166,7 +265,7 @@ +@@ -166,7 +372,7 @@ menu->addChild(new ui::MenuSeparator); @@ -250,7 +359,7 @@ } }; -@@ -256,7 +355,7 @@ +@@ -256,7 +462,7 @@ return settings::cableTension; } float getDefaultValue() override { @@ -259,7 +368,29 @@ } float getDisplayValue() override { return getValue() * 100; -@@ -399,28 +498,6 @@ +@@ -393,49 +599,39 @@ + }; + + ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS ++static void setAllFramebufferWidgetsDirty(widget::Widget* const widget) ++{ ++ for (widget::Widget* child : widget->children) ++ { ++ if (widget::FramebufferWidget* const fbw = dynamic_cast(child)) ++ { ++ fbw->setDirty(); ++ break; ++ } ++ setAllFramebufferWidgetsDirty(child); ++ } ++} ++#endif ++ ++ + struct ViewButton : MenuButton { + void onAction(const ActionEvent& e) override { + ui::Menu* menu = createMenu(); menu->cornerFlags = BND_CORNER_TOP; menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); @@ -273,13 +404,12 @@ - APP->window->setFullScreen(!fullscreen); - })); - -- double frameRate = APP->window->getMonitorRefreshRate() / settings::frameSwapInterval; -- menu->addChild(createSubmenuItem("Frame rate", string::f("%.0f Hz", frameRate), [=](ui::Menu* menu) { +- menu->addChild(createSubmenuItem("Frame rate", string::f("%.0f Hz", settings::frameRateLimit), [=](ui::Menu* menu) { - for (int i = 1; i <= 6; i++) { - double frameRate = APP->window->getMonitorRefreshRate() / i; - menu->addChild(createCheckMenuItem(string::f("%.0f Hz", frameRate), "", -- [=]() {return settings::frameSwapInterval == i;}, -- [=]() {settings::frameSwapInterval = i;} +- [=]() {return settings::frameRateLimit == frameRate;}, +- [=]() {settings::frameRateLimit = frameRate;} - )); - } - })); @@ -287,8 +417,33 @@ - menu->addChild(new ui::MenuSeparator); menu->addChild(createMenuLabel("Appearance")); +- static const std::vector uiThemes = {"dark", "light", "hcdark"}; +- static const std::vector uiThemeLabels = {"Dark", "Light", "High contrast dark"}; +- menu->addChild(createIndexSubmenuItem("Theme", uiThemeLabels, +- [=]() -> size_t { +- auto it = std::find(uiThemes.begin(), uiThemes.end(), settings::uiTheme); +- if (it == uiThemes.end()) +- return -1; +- return it - uiThemes.begin(); +- }, +- [=](size_t i) { +- settings::uiTheme = uiThemes[i]; +- ui::refreshTheme(); +- } +- )); ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS ++ std::string darkModeText; ++ if (settings::darkMode) ++ darkModeText = CHECKMARK_STRING; ++ menu->addChild(createMenuItem("Dark Mode", darkModeText, []() { ++ switchDarkMode(!settings::darkMode); ++ setAllFramebufferWidgetsDirty(APP->scene); ++ })); ++#endif + menu->addChild(createBoolPtrMenuItem("Show tooltips", "", &settings::tooltips)); -@@ -446,9 +523,18 @@ + +@@ -460,9 +656,18 @@ menu->addChild(haloBrightnessSlider); menu->addChild(new ui::MenuSeparator); @@ -307,20 +462,20 @@ static const std::vector knobModeLabels = { "Linear", -@@ -473,11 +559,34 @@ +@@ -487,11 +692,34 @@ menu->addChild(knobScrollSensitivitySlider); menu->addChild(new ui::MenuSeparator); -- menu->addChild(createMenuLabel("Module dragging")); +- menu->addChild(createMenuLabel("Module")); + menu->addChild(createMenuLabel("Window")); - menu->addChild(createBoolPtrMenuItem("Lock positions", "", &settings::lockModules)); +#ifdef DISTRHO_OS_WASM + const bool fullscreen = APP->window->isFullScreen(); -+ std::string fullscreenText = "F11"; ++ std::string rightText = "F11"; + if (fullscreen) -+ fullscreenText += " " CHECKMARK_STRING; -+ menu->addChild(createMenuItem("Fullscreen", fullscreenText, [=]() { ++ rightText += " " CHECKMARK_STRING; ++ menu->addChild(createMenuItem("Fullscreen", rightText, [=]() { + APP->window->setFullScreen(!fullscreen); + })); +#endif @@ -345,7 +500,7 @@ } }; -@@ -487,47 +596,6 @@ +@@ -501,48 +729,11 @@ //////////////////// @@ -391,9 +546,14 @@ - - struct EngineButton : MenuButton { ++#ifdef HAVE_LIBLO ++ bool remoteServerStarted = false; ++#endif ++ void onAction(const ActionEvent& e) override { ui::Menu* menu = createMenu(); -@@ -541,268 +609,42 @@ + menu->cornerFlags = BND_CORNER_TOP; +@@ -555,269 +746,87 @@ settings::cpuMeter ^= true; })); @@ -536,11 +696,24 @@ - plugin::Plugin* p = plugin::getPlugin(slug); - if (p) { - rightText += p->version + " → "; -- } ++#ifdef HAVE_LIBLO ++ if (isStandalone()) { ++ CardinalPluginContext* const context = static_cast(APP); ++ CardinalBasePlugin* const plugin = static_cast(context->plugin); ++ ++ // const bool remoteServerStarted = this->remoteServerStarted; ++ const std::string remoteControlText = remoteServerStarted ? " " CHECKMARK_STRING : ""; ++ ++ menu->addChild(createMenuItem("Enable OSC remote control", remoteControlText, [=]() { ++ if (remoteServerStarted) { ++ remoteServerStarted = false; ++ plugin->stopRemoteServer(); ++ return; + } - rightText += update.version; - } - } -- + - MenuItem::step(); - } - @@ -552,8 +725,13 @@ - e.unconsume(); - } -}; -- -- ++ async_dialog_text_input("OSC network port", CARDINAL_DEFAULT_REMOTE_PORT, [=](char* const port) { ++ if (port == nullptr) ++ return; + ++ if (plugin->startRemoteServer(port)) ++ remoteServerStarted = true; + -struct LibraryMenu : ui::Menu { - LibraryMenu() { - refresh(); @@ -578,17 +756,12 @@ - else if (!library::isLoggedIn()) { - addChild(createMenuItem("Register VCV account", "", [=]() { - system::openBrowser("https://vcvrack.com/login"); -+#ifdef DISTRHO_OS_WASM -+ if (supportsAudioInput()) { -+ const bool enabled = isAudioInputEnabled(); -+ std::string text = "Enable Audio Input"; -+ if (enabled) -+ text += " " CHECKMARK_STRING; -+ menu->addChild(createMenuItem(text, "", [enabled]() { -+ if (!enabled) -+ requestAudioInput(); ++ std::free(port); ++ }); })); -- ++ } ++#endif + - ui::TextField* emailField = new ui::TextField; - emailField->placeholder = "Email"; - emailField->box.size.x = 240.0; @@ -606,24 +779,35 @@ - logInItem->passwordField = passwordField; - passwordField->logInItem = logInItem; - addChild(logInItem); - } +- } - else { - addChild(createMenuItem("Log out", "", [=]() { - library::logOut(); - })); ++ if (isUsingNativeAudio()) { ++ if (supportsAudioInput()) { ++ const bool enabled = isAudioInputEnabled(); ++ std::string rightText; ++ if (enabled) ++ rightText = CHECKMARK_STRING; ++ menu->addChild(createMenuItem("Enable Audio Input", rightText, [enabled]() { ++ if (!enabled) ++ requestAudioInput(); ++ })); ++ } - addChild(createMenuItem("Browse VCV Library", "", [=]() { - system::openBrowser("https://library.vcvrack.com/"); -+ if (supportsMIDI()) { -+ const bool enabled = isMIDIEnabled(); -+ std::string text = "Enable MIDI"; -+ if (enabled) -+ text += " " CHECKMARK_STRING; -+ menu->addChild(createMenuItem(text, "", [enabled]() { -+ if (!enabled) +- })); ++ if (supportsMIDI()) { ++ std::string rightText; ++ if (isMIDIEnabled()) ++ rightText = CHECKMARK_STRING; ++ menu->addChild(createMenuItem("Enable/Reconnect MIDI", rightText, []() { + requestMIDI(); - })); -- ++ })); ++ } + - SyncUpdatesItem* syncItem = new SyncUpdatesItem; - syncItem->text = "Update all"; - addChild(syncItem); @@ -637,12 +821,29 @@ - updateItem->setUpdate(pair.first); - addChild(updateItem); - } -- } ++ if (supportsBufferSizeChanges()) { ++ static const std::vector bufferSizes = { ++ #ifdef DISTRHO_OS_WASM ++ 256, 512, 1024, 2048, 4096, 8192, 16384 ++ #else ++ 128, 256, 512, 1024, 2048, 4096, 8192 ++ #endif ++ }; ++ const uint32_t currentBufferSize = getBufferSize(); ++ menu->addChild(createSubmenuItem("Buffer Size", std::to_string(currentBufferSize), [=](ui::Menu* menu) { ++ for (uint32_t bufferSize : bufferSizes) { ++ menu->addChild(createCheckMenuItem(std::to_string(bufferSize), "", ++ [=]() {return currentBufferSize == bufferSize;}, ++ [=]() {requestBufferSizeChange(bufferSize);} ++ )); ++ } ++ })); + } } -- } + } -}; - - +- -struct LibraryButton : MenuButton { - NotificationIcon* notification; - @@ -662,36 +863,32 @@ - }); - t.detach(); - } -- -- void step() override { + ++#ifdef HAVE_LIBLO + void step() override { - notification->box.pos = math::Vec(0, 0); - notification->visible = library::hasUpdates(); -- ++ MenuButton::step(); + - // Popup when updates finish downloading - if (library::restartRequested) { - library::restartRequested = false; - if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, "All plugins have been downloaded. Close and re-launch Rack to load new updates.")) { - APP->window->close(); - } -+ if (supportsBufferSizeChanges()) { -+ static const std::vector bufferSizes = {256, 512, 1024, 2048, 4096, 8192, 16384}; -+ const uint32_t currentBufferSize = getBufferSize(); -+ menu->addChild(createSubmenuItem("Buffer Size", std::to_string(currentBufferSize), [=](ui::Menu* menu) { -+ for (uint32_t bufferSize : bufferSizes) { -+ menu->addChild(createCheckMenuItem(std::to_string(bufferSize), "", -+ [=]() {return currentBufferSize == bufferSize;}, -+ [=]() {requestBufferSizeChange(bufferSize);} -+ )); -+ } -+ })); ++ if (remoteServerStarted) { ++ CardinalPluginContext* const context = static_cast(APP); ++ CardinalBasePlugin* const plugin = static_cast(context->plugin); ++ plugin->stepRemoteServer(); } - - MenuButton::step(); -+#endif } ++#endif }; -@@ -813,65 +655,23 @@ + +@@ -827,63 +836,30 @@ struct HelpButton : MenuButton { @@ -709,32 +906,31 @@ - menu->addChild(createMenuItem("Tips", "", [=]() { - APP->scene->addChild(tipWindowCreate()); +- })); +- +- menu->addChild(createMenuItem("User manual", "F1", [=]() { +- system::openBrowser("https://vcvrack.com/manual"); + menu->addChild(createMenuItem("Rack User manual", "F1", [=]() { + patchUtils::openBrowser("https://vcvrack.com/manual"); })); -- menu->addChild(createMenuItem("User manual", "F1", [=]() { -- system::openBrowser("https://vcvrack.com/manual"); -- })); -- - menu->addChild(createMenuItem("Support", "", [=]() { - system::openBrowser("https://vcvrack.com/support"); - })); - - menu->addChild(createMenuItem("VCVRack.com", "", [=]() { - system::openBrowser("https://vcvrack.com/"); -+ menu->addChild(createMenuItem("Cardinal Project page", "", [=]() { ++ menu->addChild(createMenuItem("Cardinal project page", "", [=]() { + patchUtils::openBrowser("https://github.com/DISTRHO/Cardinal/"); })); menu->addChild(new ui::MenuSeparator); -- menu->addChild(createMenuLabel(APP_NAME + " " + APP_EDITION_NAME + " " + APP_VERSION)); -- -- menu->addChild(createMenuItem("Open user folder", "", [=]() { -- system::openDirectory(asset::user("")); -- })); -- ++#ifndef DISTRHO_OS_WASM + menu->addChild(createMenuItem("Open user folder", "", [=]() { + system::openDirectory(asset::user("")); + })); + - menu->addChild(createMenuItem("Changelog", "", [=]() { - system::openBrowser("https://github.com/VCVRack/Rack/blob/v2/CHANGELOG.md"); - })); @@ -753,19 +949,43 @@ - }, false, true)); - } - } -- ++ menu->addChild(new ui::MenuSeparator); ++#endif + - void step() override { - notification->box.pos = math::Vec(0, 0); - notification->visible = library::isAppUpdateAvailable(); - MenuButton::step(); -+ menu->addChild(createMenuLabel("Cardinal " + APP_EDITION + " " + CARDINAL_VERSION)); + menu->addChild(createMenuLabel("Rack " + APP_VERSION + " Compatible")); } }; -@@ -921,7 +721,9 @@ +@@ -926,15 +902,19 @@ + + text = ""; + +- if (box.size.x >= 460) { ++ if (box.size.x >= 400) { + double fps = std::isfinite(frameDurationAvg) ? 1.0 / frameDurationAvg : 0.0; ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + double meterAverage = APP->engine->getMeterAverage(); + double meterMax = APP->engine->getMeterMax(); +- text += string::f("%.1f fps %.1f%% avg %.1f%% max", fps, meterAverage * 100, meterMax * 100); ++ text = string::f("%.1f fps %.1f%% avg %.1f%% max", fps, meterAverage * 100, meterMax * 100); ++#else ++ text = string::f("%.1f fps", fps); ++#endif + text += " "; + } + +- text += APP_NAME + " " + APP_EDITION_NAME + " " + APP_VERSION + " " + APP_OS_NAME + " " + APP_CPU_NAME; ++ text += "Cardinal " + APP_EDITION + " " + CARDINAL_VERSION; + + Label::step(); + } +@@ -944,7 +924,9 @@ struct MenuBar : widget::OpaqueWidget { - MeterLabel* meterLabel; + InfoLabel* infoLabel; - MenuBar() { + MenuBar(const bool isStandalone) @@ -774,7 +994,7 @@ const float margin = 5; box.size.y = BND_WIDGET_HEIGHT + 2 * margin; -@@ -930,7 +732,7 @@ +@@ -953,7 +935,7 @@ layout->spacing = math::Vec(0, 0); addChild(layout); @@ -783,27 +1003,28 @@ fileButton->text = "File"; layout->addChild(fileButton); -@@ -946,10 +748,6 @@ +@@ -965,13 +947,11 @@ + viewButton->text = "View"; + layout->addChild(viewButton); + ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + EngineButton* engineButton = new EngineButton; engineButton->text = "Engine"; layout->addChild(engineButton); - +- - LibraryButton* libraryButton = new LibraryButton; - libraryButton->text = "Library"; - layout->addChild(libraryButton); -- ++#endif + HelpButton* helpButton = new HelpButton; helpButton->text = "Help"; - layout->addChild(helpButton); -@@ -984,7 +782,11 @@ +@@ -1003,7 +983,7 @@ widget::Widget* createMenuBar() { - menuBar::MenuBar* menuBar = new menuBar::MenuBar; -+ return new widget::Widget; -+} -+ -+widget::Widget* createMenuBar(const bool isStandalone) { -+ menuBar::MenuBar* menuBar = new menuBar::MenuBar(isStandalone); ++ menuBar::MenuBar* menuBar = new menuBar::MenuBar(isStandalone()); return menuBar; } diff --git a/src/override/diffs/Model.cpp.diff b/src/override/diffs/Model.cpp.diff index b1f5617c..1807058a 100644 --- a/src/override/diffs/Model.cpp.diff +++ b/src/override/diffs/Model.cpp.diff @@ -1,9 +1,9 @@ ---- ../Rack/src/plugin/Model.cpp 2022-07-12 09:46:20.716165650 +0100 -+++ Model.cpp 2022-07-06 16:19:37.977002863 +0100 +--- ../Rack/src/plugin/Model.cpp 2023-05-20 17:03:33.007081806 +0200 ++++ Model.cpp 2023-05-20 18:29:51.484669742 +0200 @@ -1,3 +1,30 @@ +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ + +/** + * This file is an edited version of VCVRack's plugin/Model.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -61,8 +61,8 @@ - // hidden json_t* hiddenJ = json_object_get(rootJ, "hidden"); - // Use `disabled` as an alias which was deprecated in Rack 2.0 -@@ -74,7 +97,7 @@ + // "disabled" was a deprecated alias in Rack <2 +@@ -77,7 +100,7 @@ std::string Model::getFullName() { @@ -71,7 +71,7 @@ return plugin->getBrand() + " " + name; } -@@ -99,7 +122,7 @@ +@@ -102,7 +125,7 @@ void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) { // plugin menu->addChild(createMenuItem("Plugin: " + plugin->name, "", [=]() { @@ -80,7 +80,7 @@ }, plugin->pluginUrl == "")); // version -@@ -108,7 +131,7 @@ +@@ -111,7 +134,7 @@ // author if (plugin->author != "") { menu->addChild(createMenuItem("Author: " + plugin->author, "", [=]() { @@ -89,7 +89,7 @@ }, plugin->authorUrl.empty())); } -@@ -116,7 +139,7 @@ +@@ -119,7 +142,7 @@ std::string license = plugin->license; if (string::startsWith(license, "https://") || string::startsWith(license, "http://")) { menu->addChild(createMenuItem("License: Open in browser", "", [=]() { @@ -98,7 +98,7 @@ })); } else if (license != "") { -@@ -133,58 +156,32 @@ +@@ -136,44 +159,32 @@ menu->addChild(new ui::MenuSeparator); @@ -143,21 +143,21 @@ if (plugin->changelogUrl != "") { menu->addChild(createMenuItem("Changelog", "", [=]() { - system::openBrowser(plugin->changelogUrl); -- })); -- } -- -- // author email -- if (plugin->authorEmail != "") { -- menu->addChild(createMenuItem("Author email", "Copy to clipboard", [=]() { -- glfwSetClipboardString(APP->window->win, plugin->authorEmail.c_str()); -- })); -- } -- -- // plugin folder -- if (plugin->path != "") { -- menu->addChild(createMenuItem("Open plugin folder", "", [=]() { -- system::openDirectory(plugin->path); + patchUtils::openBrowser(plugin->changelogUrl); })); } +@@ -184,13 +195,6 @@ + })); + } + +- // plugin folder +- if (plugin->path != "") { +- menu->addChild(createMenuItem("Open plugin folder", "", [=]() { +- system::openDirectory(plugin->path); +- })); +- } +- + // Favorite + std::string favoriteRightText = inBrowser ? (RACK_MOD_CTRL_NAME "+click") : ""; + if (isFavorite()) diff --git a/src/override/diffs/ModuleWidget.cpp.diff b/src/override/diffs/ModuleWidget.cpp.diff new file mode 100644 index 00000000..3217e3b6 --- /dev/null +++ b/src/override/diffs/ModuleWidget.cpp.diff @@ -0,0 +1,176 @@ +--- ../Rack/src/app/ModuleWidget.cpp 2023-09-10 12:59:02.630898560 +0200 ++++ ModuleWidget.cpp 2023-05-20 18:40:08.948302802 +0200 +@@ -1,8 +1,35 @@ ++/* ++ * DISTRHO Cardinal Plugin ++ * Copyright (C) 2021-2023 Filipe Coelho ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 3 of ++ * the License, or any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * For a full copy of the GNU General Public License see the LICENSE file. ++ */ ++ ++/** ++ * This file is an edited version of VCVRack's ModuleWidget.cpp ++ * Copyright (C) 2016-2023 VCV. ++ * ++ * This program is free software: you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 3 of ++ * the License, or (at your option) any later version. ++ */ ++ ++#include "../../CardinalCommon.hpp" ++ + #include + #include + +-#include +- + #include + #include + #include +@@ -375,7 +402,7 @@ + if (e.action == GLFW_PRESS) { + // Open selection context menu on right-click + ui::Menu* menu = createMenu(); +- APP->scene->rack->appendSelectionContextMenu(menu); ++ patchUtils::appendSelectionContextMenu(menu); + } + e.consume(this); + } +@@ -629,6 +656,9 @@ + std::string presetDir = model->getUserPresetDirectory(); + system::createDirectories(presetDir); + ++ WeakPtr weakThis = this; ++ async_dialog_filebrowser(false, nullptr, presetDir.c_str(), "Load preset", [=](char* pathC) { ++ + // Delete directories if empty + DEFER({ + try { +@@ -640,10 +670,8 @@ + } + }); + +- osdialog_filters* filters = osdialog_filters_parse(PRESET_FILTERS); +- DEFER({osdialog_filters_free(filters);}); +- +- char* pathC = osdialog_file(OSDIALOG_OPEN, presetDir.c_str(), NULL, filters); ++ if (!weakThis) ++ return; + if (!pathC) { + // No path selected + return; +@@ -651,11 +679,13 @@ + DEFER({std::free(pathC);}); + + try { +- loadAction(pathC); ++ weakThis->loadAction(pathC); + } + catch (Exception& e) { +- osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, e.what()); ++ async_dialog_message(e.what()); + } ++ ++ }); + } + + void ModuleWidget::save(std::string filename) { +@@ -670,7 +700,7 @@ + FILE* file = std::fopen(filename.c_str(), "w"); + if (!file) { + std::string message = string::f("Could not save preset to file %s", filename.c_str()); +- osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str()); ++ async_dialog_message(message.c_str()); + return; + } + DEFER({std::fclose(file);}); +@@ -688,10 +718,12 @@ + void ModuleWidget::saveTemplateDialog() { + if (hasTemplate()) { + std::string message = string::f("Overwrite default preset for %s?", model->getFullName().c_str()); +- if (!osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, message.c_str())) +- return; ++ WeakPtr weakThis = this; ++ async_dialog_message(message.c_str(), [=]{ ++ if (weakThis) ++ weakThis->saveTemplate(); ++ }); + } +- saveTemplate(); + } + + bool ModuleWidget::hasTemplate() { +@@ -708,15 +740,20 @@ + + void ModuleWidget::clearTemplateDialog() { + std::string message = string::f("Delete default preset for %s?", model->getFullName().c_str()); +- if (!osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, message.c_str())) +- return; +- clearTemplate(); ++ WeakPtr weakThis = this; ++ async_dialog_message(message.c_str(), [=]{ ++ if (weakThis) ++ weakThis->clearTemplate(); ++ }); + } + + void ModuleWidget::saveDialog() { + std::string presetDir = model->getUserPresetDirectory(); + system::createDirectories(presetDir); + ++ WeakPtr weakThis = this; ++ async_dialog_filebrowser(true, "preset.vcvm", presetDir.c_str(), "Save preset", [=](char* pathC) { ++ + // Delete directories if empty + DEFER({ + try { +@@ -728,10 +765,8 @@ + } + }); + +- osdialog_filters* filters = osdialog_filters_parse(PRESET_FILTERS); +- DEFER({osdialog_filters_free(filters);}); +- +- char* pathC = osdialog_file(OSDIALOG_SAVE, presetDir.c_str(), "Untitled.vcvm", filters); ++ if (!weakThis) ++ return; + if (!pathC) { + // No path selected + return; +@@ -743,7 +778,8 @@ + if (system::getExtension(path) != ".vcvm") + path += ".vcvm"; + +- save(path); ++ weakThis->save(path); ++ }); + } + + void ModuleWidget::disconnect() { +@@ -965,7 +1001,7 @@ + moduleWidget->loadAction(path); + } + catch (Exception& e) { +- osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, e.what()); ++ async_dialog_message(e.what()); + } + })); + } +@@ -1129,4 +1165,4 @@ + + + } // namespace app +-} // namespace rack +\ No newline at end of file ++} // namespace rack diff --git a/src/override/diffs/OpenGlWidget.cpp.diff b/src/override/diffs/OpenGlWidget.cpp.diff index 1ada3cd0..202f8640 100644 --- a/src/override/diffs/OpenGlWidget.cpp.diff +++ b/src/override/diffs/OpenGlWidget.cpp.diff @@ -1,9 +1,9 @@ ---- ../Rack/src/widget/OpenGlWidget.cpp 2022-04-11 20:05:02.023283713 +0100 -+++ OpenGlWidget.cpp 2022-07-14 01:14:57.028367786 +0100 +--- ../Rack/src/widget/OpenGlWidget.cpp 2022-09-21 20:49:12.201540766 +0200 ++++ OpenGlWidget.cpp 2023-05-20 18:41:22.249200486 +0200 @@ -1,3 +1,30 @@ +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ + +/** + * This file is an edited version of VCVRack's OpenGlWidget.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as diff --git a/src/override/diffs/Scene.cpp.diff b/src/override/diffs/Scene.cpp.diff index 3d338e9f..6d9371e7 100644 --- a/src/override/diffs/Scene.cpp.diff +++ b/src/override/diffs/Scene.cpp.diff @@ -1,9 +1,12 @@ ---- ../Rack/src/app/Scene.cpp 2022-04-11 20:05:02.007283878 +0100 -+++ Scene.cpp 2022-07-12 09:45:31.518663160 +0100 -@@ -1,3 +1,30 @@ +--- ../Rack/src/app/Scene.cpp 2022-09-21 20:49:12.199540706 +0200 ++++ Scene.cpp 2023-07-03 09:30:14.548718644 +0200 +@@ -1,12 +1,36 @@ +-#include +- +-#include +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -20,18 +23,16 @@ + +/** + * This file is an edited version of VCVRack's app/Scene.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + */ -+ - #include - #include -@@ -7,6 +34,7 @@ + #include + #include #include #include #include @@ -39,7 +40,7 @@ #include #include #include -@@ -14,6 +42,22 @@ +@@ -14,6 +38,14 @@ #include #include @@ -47,22 +48,14 @@ +# undef DEBUG +#endif + -+#ifdef STATIC_BUILD -+# undef HAVE_LIBLO -+#endif -+ -+#ifdef HAVE_LIBLO -+# include -+#endif -+ +#include "../CardinalCommon.hpp" -+#include "extra/Base64.hpp" -+#include "DistrhoUtils.hpp" ++#include "../CardinalRemote.hpp" + ++#include namespace rack { namespace app { -@@ -23,32 +67,94 @@ +@@ -23,32 +55,72 @@ math::Vec size; void draw(const DrawArgs& args) override { @@ -109,17 +102,17 @@ + + void onHover(const HoverEvent& e) override { + e.consume(this); -+ } -+ + } + +- void onDragStart(const DragStartEvent& e) override { + void onEnter(const EnterEvent& e) override { + glfwSetCursor(APP->window->win, glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR)); + } + + void onLeave(const LeaveEvent& e) override { + glfwSetCursor(APP->window->win, nullptr); - } - -- void onDragStart(const DragStartEvent& e) override { ++ } ++ + void onDragStart(const DragStartEvent&) override { size = APP->window->getSize(); } @@ -140,41 +133,19 @@ bool heldArrowKeys[4] = {}; + -+#ifdef HAVE_LIBLO + double lastSceneChangeTime = 0.0; + int historyActionIndex = -1; -+ -+ bool oscAutoDeploy = false; -+ bool oscConnected = false; -+ lo_server oscServer = nullptr; -+ -+ static int osc_handler(const char* const path, const char* const types, lo_arg** argv, const int argc, lo_message, void* const self) -+ { -+ d_stdout("osc_handler(\"%s\", \"%s\", %p, %i)", path, types, argv, argc); -+ -+ if (std::strcmp(path, "/resp") == 0 && argc == 2 && types[0] == 's' && types[1] == 's') { -+ d_stdout("osc_handler(\"%s\", ...) - got resp | '%s' '%s'", path, &argv[0]->s, &argv[1]->s); -+ if (std::strcmp(&argv[0]->s, "hello") == 0 && std::strcmp(&argv[1]->s, "ok") == 0) -+ static_cast(self)->oscConnected = true; -+ } -+ return 0; -+ } -+ -+ ~Internal() { -+ lo_server_free(oscServer); -+ } -+#endif }; -@@ -67,13 +173,11 @@ +@@ -67,13 +139,11 @@ browser->hide(); addChild(browser); - if (settings::showTipsOnLaunch) { - addChild(tipWindowCreate()); - } -+ if (isStandalone()) ++ if (isStandalone() || isMini()) + return; internal->resizeHandle = new ResizeHandle; @@ -184,7 +155,7 @@ addChild(internal->resizeHandle); } -@@ -99,22 +203,13 @@ +@@ -99,22 +169,13 @@ rackScroll->box.pos.y = menuBar->box.size.y; } @@ -209,40 +180,51 @@ // Scroll RackScrollWidget with arrow keys math::Vec arrowDelta; if (internal->heldArrowKeys[0]) { -@@ -143,6 +238,23 @@ +@@ -143,6 +204,34 @@ rackScroll->offset += arrowDelta * arrowSpeed; } -+#ifdef HAVE_LIBLO -+ if (internal->oscServer != nullptr) { -+ while (lo_server_recv_noblock(internal->oscServer, 0) != 0) {} ++ if (remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote()) { ++ idleRemote(remoteDetails); + -+ if (internal->oscAutoDeploy) { ++ if (remoteDetails->autoDeploy) { + const int actionIndex = APP->history->actionIndex; + const double time = system::getTime(); -+ if (internal->historyActionIndex != actionIndex && time - internal->lastSceneChangeTime >= 5.0) { ++ ++ if (internal->historyActionIndex == -1) { ++ internal->historyActionIndex = actionIndex; ++ internal->lastSceneChangeTime = time; ++ } else if (internal->historyActionIndex != actionIndex && actionIndex > 0 && time - internal->lastSceneChangeTime >= 1.0) { ++ const std::string& name(APP->history->actions[actionIndex - 1]->name); ++ static const std::vector ignoredNames = { ++ "move knob", ++ "move modules", ++ "move switch", ++ }; ++ if (std::find(ignoredNames.cbegin(), ignoredNames.cend(), name) == ignoredNames.cend()) { ++ printf("action '%s'\n", APP->history->actions[actionIndex - 1]->name.c_str()); ++ remoteUtils::sendFullPatchToRemote(remoteDetails); ++ window::generateScreenshot(); ++ } + internal->historyActionIndex = actionIndex; + internal->lastSceneChangeTime = time; -+ patchUtils::deployToRemote(); -+ window::generateScreenshot(); + } + } + } -+#endif + Widget::step(); } -@@ -172,7 +284,7 @@ +@@ -172,7 +261,7 @@ if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { // DEBUG("key '%d '%c' scancode %d '%c' keyName '%s'", e.key, e.key, e.scancode, e.scancode, e.keyName.c_str()); if (e.keyName == "n" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { - APP->patch->loadTemplateDialog(); -+ patchUtils::loadTemplateDialog(); ++ patchUtils::loadTemplateDialog(false); e.consume(this); } if (e.keyName == "q" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { -@@ -180,19 +292,22 @@ +@@ -180,19 +269,25 @@ e.consume(this); } if (e.keyName == "o" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { @@ -255,21 +237,24 @@ + patchUtils::revertDialog(); e.consume(this); } -+#ifndef DISTRHO_OS_WASM if (e.keyName == "s" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { - APP->patch->saveDialog(); -+ // NOTE: will do nothing if path is empty, intentionally -+ patchUtils::saveDialog(APP->patch->path); ++ // NOTE: for plugin versions it will do nothing if path is empty, intentionally ++ if (APP->patch->path.empty()) { ++ if (isStandalone()) ++ patchUtils::saveAsDialog(); ++ } else { ++ patchUtils::saveDialog(APP->patch->path); ++ } e.consume(this); } -+#endif if (e.keyName == "s" && (e.mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) { - APP->patch->saveAsDialog(); + patchUtils::saveAsDialog(); e.consume(this); } if (e.keyName == "z" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { -@@ -220,24 +335,37 @@ +@@ -220,24 +315,42 @@ APP->scene->rackScroll->setZoom(std::pow(2.f, zoom)); e.consume(this); } @@ -292,8 +277,11 @@ e.consume(this); } + if (e.key == GLFW_KEY_F7 && (e.mods & RACK_MOD_MASK) == 0) { -+ patchUtils::deployToRemote(); -+ window::generateScreenshot(); ++ if (remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote()) ++ { ++ remoteUtils::sendFullPatchToRemote(remoteDetails); ++ window::generateScreenshot(); ++ } + e.consume(this); + } + if (e.key == GLFW_KEY_F9 && (e.mods & RACK_MOD_MASK) == 0) { @@ -303,15 +291,15 @@ +#ifdef DISTRHO_OS_WASM if (e.key == GLFW_KEY_F11 && (e.mods & RACK_MOD_MASK) == 0) { APP->window->setFullScreen(!APP->window->isFullScreen()); -- // The MenuBar will be hidden when the mouse moves over the RackScrollWidget. -- // menuBar->hide(); + // The MenuBar will be hidden when the mouse moves over the RackScrollWidget. + // menuBar->hide(); e.consume(this); } +#endif // Module selections if (e.keyName == "a" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { -@@ -326,13 +454,6 @@ +@@ -326,13 +439,6 @@ // Key commands that can be overridden by children if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { @@ -325,7 +313,7 @@ if (e.keyName == "v" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { rack->pasteClipboardAction(); e.consume(this); -@@ -351,7 +472,7 @@ +@@ -351,7 +457,7 @@ std::string extension = system::getExtension(path); if (extension == ".vcv") { @@ -334,98 +322,3 @@ e.consume(this); return; } -@@ -368,3 +489,94 @@ - - } // namespace app - } // namespace rack -+ -+ -+namespace patchUtils { -+ -+ -+bool connectToRemote() { -+#ifdef HAVE_LIBLO -+ rack::app::Scene::Internal* const internal = APP->scene->internal; -+ -+ if (internal->oscServer == nullptr) { -+ const lo_server oscServer = lo_server_new_with_proto(nullptr, LO_UDP, nullptr); -+ DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr, false); -+ lo_server_add_method(oscServer, "/resp", nullptr, rack::app::Scene::Internal::osc_handler, internal); -+ internal->oscServer = oscServer; -+ } -+ -+ const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); -+ DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr, false); -+ lo_send(addr, "/hello", ""); -+ lo_address_free(addr); -+ -+ return true; -+#else -+ return false; -+#endif -+} -+ -+ -+bool isRemoteConnected() { -+#ifdef HAVE_LIBLO -+ return APP->scene->internal->oscConnected; -+#else -+ return false; -+#endif -+} -+ -+ -+bool isRemoteAutoDeployed() { -+#ifdef HAVE_LIBLO -+ return APP->scene->internal->oscAutoDeploy; -+#else -+ return false; -+#endif -+} -+ -+ -+void setRemoteAutoDeploy(bool autoDeploy) { -+#ifdef HAVE_LIBLO -+ APP->scene->internal->oscAutoDeploy = autoDeploy; -+#endif -+} -+ -+ -+void deployToRemote() { -+#ifdef HAVE_LIBLO -+ const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); -+ DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,); -+ -+ APP->engine->prepareSave(); -+ APP->patch->saveAutosave(); -+ APP->patch->cleanAutosave(); -+ std::vector data(rack::system::archiveDirectory(APP->patch->autosavePath, 1)); -+ -+ if (const lo_blob blob = lo_blob_new(data.size(), data.data())) { -+ lo_send(addr, "/load", "b", blob); -+ lo_blob_free(blob); -+ } -+ -+ lo_address_free(addr); -+#endif -+} -+ -+ -+void sendScreenshotToRemote(const char* const screenshot) { -+#ifdef HAVE_LIBLO -+ const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); -+ DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,); -+ -+ std::vector data(d_getChunkFromBase64String(screenshot)); -+ -+ if (const lo_blob blob = lo_blob_new(data.size(), data.data())) { -+ lo_send(addr, "/screenshot", "b", blob); -+ lo_blob_free(blob); -+ } -+ -+ lo_address_free(addr); -+#endif -+} -+ -+ -+} // namespace patchUtils diff --git a/src/override/diffs/Window.cpp.diff b/src/override/diffs/Window.cpp.diff index 2082672a..fbd18940 100644 --- a/src/override/diffs/Window.cpp.diff +++ b/src/override/diffs/Window.cpp.diff @@ -1,9 +1,9 @@ ---- ../Rack/src/window/Window.cpp 2022-04-11 20:05:02.023283713 +0100 -+++ Window.cpp 2022-07-12 09:45:31.518663160 +0100 -@@ -1,33 +1,87 @@ +--- ../Rack/src/window/Window.cpp 2023-09-10 12:59:02.631898592 +0200 ++++ Window.cpp 2023-08-28 09:55:57.292032175 +0200 +@@ -1,33 +1,94 @@ +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ + +/** + * This file is an edited version of VCVRack's window/Window.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -57,9 +57,24 @@ +# undef DEBUG +#endif + ++#include "DistrhoUI.hpp" ++#include "Application.hpp" ++#include "extra/String.hpp" ++#include "../CardinalCommon.hpp" ++#include "../PluginContext.hpp" ++#include "../WindowParameters.hpp" ++ ++#ifndef DGL_NO_SHARED_RESOURCES ++# include "src/Resources.hpp" ++#endif + ++#if !(defined(DGL_USE_GLES) || CARDINAL_VARIANT_MINI) ++ ++#define CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS ++ +// comment out if wanting to generate a local screenshot.png +#define STBI_WRITE_NO_STDIO - ++ +// uncomment to generate screenshots without the rack rail background (ie, transparent) +// #define CARDINAL_TRANSPARENT_SCREENSHOTS + @@ -67,14 +82,6 @@ +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "stb_image_write.h" + -+#include "DistrhoUI.hpp" -+#include "Application.hpp" -+#include "extra/String.hpp" -+#include "../CardinalCommon.hpp" -+#include "../WindowParameters.hpp" -+ -+#ifndef DGL_NO_SHARED_RESOURCES -+# include "src/Resources.hpp" +#endif + +#ifdef DISTRHO_OS_WASM @@ -85,7 +92,7 @@ namespace window { --static const math::Vec WINDOW_SIZE_MIN = math::Vec(480, 320); +-static const math::Vec WINDOW_SIZE_MIN = math::Vec(640, 480); +static const math::Vec WINDOW_SIZE_MIN = math::Vec(648, 538); + + @@ -101,7 +108,7 @@ Font::~Font() { -@@ -42,9 +96,8 @@ +@@ -42,9 +103,8 @@ // Transfer ownership of font data to font object uint8_t* data = system::readFile(filename, &size); // Don't use nvgCreateFont because it doesn't properly handle UTF-8 filenames on Windows. @@ -112,10 +119,11 @@ throw Exception("Failed to load font %s", filename.c_str()); } INFO("Loaded font %s", filename.c_str()); -@@ -79,375 +132,325 @@ +@@ -79,338 +139,478 @@ } ++#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS +enum ScreenshotStep { + kScreenshotStepNone, + kScreenshotStepStarted, @@ -123,6 +131,7 @@ + kScreenshotStepSecondPass, + kScreenshotStepSaving +}; ++#endif + + struct Window::Internal { @@ -132,15 +141,18 @@ - int lastWindowY = 0; - int lastWindowWidth = 0; - int lastWindowHeight = 0; -+ DISTRHO_NAMESPACE::UI* ui = nullptr; ++ CardinalBaseUI* ui = nullptr; ++ DGL_NAMESPACE::NanoTopLevelWidget* tlw = nullptr; + DISTRHO_NAMESPACE::WindowParameters params; + DISTRHO_NAMESPACE::WindowParametersCallback* callback = nullptr; ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + DGL_NAMESPACE::Application hiddenApp; + DGL_NAMESPACE::Window hiddenWindow; + NVGcontext* r_vg = nullptr; + NVGcontext* r_fbVg = nullptr; + NVGcontext* o_vg = nullptr; + NVGcontext* o_fbVg = nullptr; ++#endif + + math::Vec size = WINDOW_SIZE_MIN; + @@ -149,15 +161,13 @@ int frame = 0; - bool ignoreNextMouseDelta = false; -- int frameSwapInterval = -1; - double monitorRefreshRate = 0.0; -+ int frameSwapInterval = 1; -+#ifndef DGL_USE_GLES ++#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS + int generateScreenshotStep = kScreenshotStepNone; +#endif + double monitorRefreshRate = 60.0; - double frameTime = 0.0; - double lastFrameDuration = 0.0; + double frameTime = NAN; + double lastFrameDuration = NAN; - math::Vec lastMousePos; - @@ -168,26 +178,42 @@ bool fbDirtyOnSubpixelChange = true; int fbCount = 0; -+ +-}; + +- +-static void windowPosCallback(GLFWwindow* win, int x, int y) { +- if (glfwGetWindowAttrib(win, GLFW_MAXIMIZED)) +- return; +- if (glfwGetWindowAttrib(win, GLFW_ICONIFIED)) +- return; +- if (glfwGetWindowMonitor(win)) +- return; +- settings::windowPos = math::Vec(x, y); +- // DEBUG("windowPosCallback %d %d", x, y); +-} + Internal() ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + : hiddenApp(false), + hiddenWindow(hiddenApp) + { + hiddenWindow.setIgnoringKeyRepeat(true); + hiddenApp.idle(); + } - }; ++#else ++ {} ++#endif ++}; --static void windowPosCallback(GLFWwindow* win, int x, int y) { +-static void windowSizeCallback(GLFWwindow* win, int width, int height) { - if (glfwGetWindowAttrib(win, GLFW_MAXIMIZED)) - return; - if (glfwGetWindowAttrib(win, GLFW_ICONIFIED)) - return; - if (glfwGetWindowMonitor(win)) - return; -- settings::windowPos = math::Vec(x, y); -- // DEBUG("windowPosCallback %d %d", x, y); +- settings::windowSize = math::Vec(width, height); +- // DEBUG("windowSizeCallback %d %d", width, height); -} +#ifndef DGL_NO_SHARED_RESOURCES +static int loadFallbackFont(NVGcontext* const vg) @@ -198,30 +224,14 @@ + using namespace dpf_resources; --static void windowSizeCallback(GLFWwindow* win, int width, int height) { -- if (glfwGetWindowAttrib(win, GLFW_MAXIMIZED)) -- return; -- if (glfwGetWindowAttrib(win, GLFW_ICONIFIED)) -- return; -- if (glfwGetWindowMonitor(win)) -- return; -- settings::windowSize = math::Vec(width, height); -- // DEBUG("windowSizeCallback %d %d", width, height); -+ return nvgCreateFontMem(vg, NANOVG_DEJAVU_SANS_TTF, -+ (uchar*)dejavusans_ttf, dejavusans_ttf_size, 0); - } -+#endif - - -static void windowMaximizeCallback(GLFWwindow* win, int maximized) { - settings::windowMaximized = maximized; - // DEBUG("windowMaximizeCallback %d", maximized); --} -+Window::Window() { -+ internal = new Internal; - -+ DGL_NAMESPACE::Window::ScopedGraphicsContext sgc(internal->hiddenWindow); - ++ return nvgCreateFontMem(vg, NANOVG_DEJAVU_SANS_TTF, ++ (uchar*)dejavusans_ttf, dejavusans_ttf_size, 0); + } +- +- -static void mouseButtonCallback(GLFWwindow* win, int button, int action, int mods) { - contextSet((Context*) glfwGetWindowUserPointer(win)); -#if defined ARCH_MAC @@ -235,30 +245,55 @@ - button = GLFW_MOUSE_BUTTON_MIDDLE; - mods &= ~(GLFW_MOD_CONTROL | GLFW_MOD_SHIFT); - } -+ // Set up NanoVG -+ const int nvgFlags = NVG_ANTIALIAS; -+ vg = nvgCreateGL(nvgFlags); -+ DISTRHO_SAFE_ASSERT_RETURN(vg != nullptr,); -+#ifdef NANOVG_GLES2 -+ fbVg = nvgCreateSharedGLES2(vg, nvgFlags); -+#else -+ fbVg = nvgCreateSharedGL2(vg, nvgFlags); #endif - APP->event->handleButton(APP->window->internal->lastMousePos, button, action, mods); -} - -- + -static void cursorPosCallback(GLFWwindow* win, double xpos, double ypos) { - contextSet((Context*) glfwGetWindowUserPointer(win)); - math::Vec mousePos = math::Vec(xpos, ypos).div(APP->window->pixelRatio / APP->window->windowRatio).round(); - math::Vec mouseDelta = mousePos.minus(APP->window->internal->lastMousePos); -- ++Window::Window() { ++ internal = new Internal; + - // Workaround for GLFW warping mouse to a different position when the cursor is locked or unlocked. - if (APP->window->internal->ignoreNextMouseDelta) { - APP->window->internal->ignoreNextMouseDelta = false; - mouseDelta = math::Vec(); - } ++ // Set up NanoVG ++ const int nvgFlags = NVG_ANTIALIAS; + +- int cursorMode = glfwGetInputMode(win, GLFW_CURSOR); +- (void) cursorMode; ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS ++ DGL_NAMESPACE::Window::ScopedGraphicsContext sgc(internal->hiddenWindow); ++ vg = nvgCreateGL(nvgFlags); ++#else ++ vg = static_cast(APP)->tlw->getContext(); ++#endif ++ DISTRHO_SAFE_ASSERT_RETURN(vg != nullptr,); + +-#if defined ARCH_MAC +- // Workaround for Mac. We can't use GLFW_CURSOR_DISABLED because it's buggy, so implement it on our own. +- // This is not an ideal implementation. For example, if the user drags off the screen, the new mouse position will be clamped. +- if (cursorMode == GLFW_CURSOR_HIDDEN) { +- // CGSetLocalEventsSuppressionInterval(0.0); +- glfwSetCursorPos(win, APP->window->internal->lastMousePos.x, APP->window->internal->lastMousePos.y); +- CGAssociateMouseAndMouseCursorPosition(true); +- mousePos = APP->window->internal->lastMousePos; +- } +- // Because sometimes the cursor turns into an arrow when its position is on the boundary of the window +- glfwSetCursor(win, NULL); ++#ifdef NANOVG_GLES2 ++ fbVg = nvgCreateSharedGLES2(vg, nvgFlags); ++#else ++ fbVg = nvgCreateSharedGL2(vg, nvgFlags); + #endif + +- APP->window->internal->lastMousePos = mousePos; + // Load default Blendish font +#ifndef DGL_NO_SHARED_RESOURCES + uiFont = std::make_shared(); @@ -275,33 +310,51 @@ + uiFont = loadFont(asset::system("res/fonts/DejaVuSans.ttf")); +#endif -- int cursorMode = glfwGetInputMode(win, GLFW_CURSOR); -- (void) cursorMode; +- APP->event->handleHover(mousePos, mouseDelta); + if (uiFont != nullptr) + bndSetFont(uiFont->handle); --#if defined ARCH_MAC -- // Workaround for Mac. We can't use GLFW_CURSOR_DISABLED because it's buggy, so implement it on our own. -- // This is not an ideal implementation. For example, if the user drags off the screen, the new mouse position will be clamped. -- if (cursorMode == GLFW_CURSOR_HIDDEN) { -- // CGSetLocalEventsSuppressionInterval(0.0); -- glfwSetCursorPos(win, APP->window->internal->lastMousePos.x, APP->window->internal->lastMousePos.y); -- CGAssociateMouseAndMouseCursorPosition(true); -- mousePos = APP->window->internal->lastMousePos; -- } -- // Because sometimes the cursor turns into an arrow when its position is on the boundary of the window -- glfwSetCursor(win, NULL); +- // Keyboard/mouse MIDI driver +- int width, height; +- glfwGetWindowSize(win, &width, &height); +- math::Vec scaledPos(xpos / width, ypos / height); +- keyboard::mouseMove(scaledPos); +#ifdef DISTRHO_OS_WASM + emscripten_lock_orientation(EMSCRIPTEN_ORIENTATION_LANDSCAPE_PRIMARY); - #endif -+} ++#endif + } -- APP->window->internal->lastMousePos = mousePos; - -- APP->event->handleHover(mousePos, mouseDelta); -+void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) +-static void cursorEnterCallback(GLFWwindow* win, int entered) { +- contextSet((Context*) glfwGetWindowUserPointer(win)); +- if (!entered) { +- APP->event->handleLeave(); ++void WindowSetPluginRemote(Window* const window, NanoTopLevelWidget* const tlw) +{ -+ if (ui != nullptr) ++ // if nanovg context failed, init only bare minimum ++ if (window->vg == nullptr) ++ { ++ if (tlw != nullptr) ++ { ++ window->internal->tlw = tlw; ++ window->internal->size = rack::math::Vec(tlw->getWidth(), tlw->getHeight()); ++ } ++ else ++ { ++ window->internal->tlw = nullptr; ++ window->internal->callback = nullptr; ++ } ++ return; + } +-} + +- +-static void scrollCallback(GLFWwindow* win, double x, double y) { +- contextSet((Context*) glfwGetWindowUserPointer(win)); +- math::Vec scrollDelta = math::Vec(x, y); +-#if defined ARCH_MAC +- scrollDelta = scrollDelta.mult(10.0); ++ if (tlw != nullptr) + { + const GLubyte* vendor = glGetString(GL_VENDOR); + const GLubyte* renderer = glGetString(GL_RENDERER); @@ -309,22 +362,20 @@ + INFO("Renderer: %s %s", vendor, renderer); + INFO("OpenGL: %s", version); + -+ window->internal->ui = ui; -+ window->internal->size = rack::math::Vec(ui->getWidth(), ui->getHeight()); ++ window->internal->tlw = tlw; ++ window->internal->size = rack::math::Vec(tlw->getWidth(), tlw->getHeight()); + ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + // Set up NanoVG -+ window->internal->r_vg = ui->getContext(); ++ window->internal->r_vg = tlw->getContext(); +#ifdef NANOVG_GLES2 + window->internal->r_fbVg = nvgCreateSharedGLES2(window->internal->r_vg, NVG_ANTIALIAS); -+#else + #else +- scrollDelta = scrollDelta.mult(50.0); + window->internal->r_fbVg = nvgCreateSharedGL2(window->internal->r_vg, NVG_ANTIALIAS); -+#endif + #endif -- // Keyboard/mouse MIDI driver -- int width, height; -- glfwGetWindowSize(win, &width, &height); -- math::Vec scaledPos(xpos / width, ypos / height); -- keyboard::mouseMove(scaledPos); +- APP->event->handleScroll(APP->window->internal->lastMousePos, scrollDelta); -} + // swap contexts + window->internal->o_vg = window->vg; @@ -349,23 +400,27 @@ + image.second->handle = nvgCreateImage(window->vg, image.second->ofilename.c_str(), + NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); + } ++#endif + // Init settings + WindowParametersRestore(window); --static void cursorEnterCallback(GLFWwindow* win, int entered) { +-static void charCallback(GLFWwindow* win, unsigned int codepoint) { - contextSet((Context*) glfwGetWindowUserPointer(win)); -- if (!entered) { -- APP->event->handleLeave(); -+ widget::Widget::ContextCreateEvent e; -+ APP->scene->onContextCreate(e); - } +- if (APP->event->handleText(APP->window->internal->lastMousePos, codepoint)) +- return; -} ++ widget::Widget::ContextCreateEvent e = {}; ++ e.vg = window->vg; ++ APP->scene->onContextCreate(e); ++ } + else + { -+ widget::Widget::ContextDestroyEvent e; ++ widget::Widget::ContextDestroyEvent e = {}; ++ e.vg = window->vg; + APP->scene->onContextDestroy(e); ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + // swap contexts + window->uiFont->vg = window->internal->o_vg; + window->vg = window->internal->o_vg; @@ -389,92 +444,84 @@ + image.second->ohandle = -1; + } --static void scrollCallback(GLFWwindow* win, double x, double y) { +-static void keyCallback(GLFWwindow* win, int key, int scancode, int action, int mods) { - contextSet((Context*) glfwGetWindowUserPointer(win)); -- math::Vec scrollDelta = math::Vec(x, y); --#if defined ARCH_MAC -- scrollDelta = scrollDelta.mult(10.0); +- if (APP->event->handleKey(APP->window->internal->lastMousePos, key, scancode, action, mods)) +- return; +#if defined NANOVG_GLES2 + nvgDeleteGLES2(window->internal->r_fbVg); - #else -- scrollDelta = scrollDelta.mult(50.0); ++#else + nvgDeleteGL2(window->internal->r_fbVg); - #endif - -- APP->event->handleScroll(APP->window->internal->lastMousePos, scrollDelta); -+ window->internal->ui = nullptr; -+ window->internal->callback = nullptr; -+ } - } - -- --static void charCallback(GLFWwindow* win, unsigned int codepoint) { -- contextSet((Context*) glfwGetWindowUserPointer(win)); -- if (APP->event->handleText(APP->window->internal->lastMousePos, codepoint)) -- return; -+void WindowSetMods(Window* const window, const int mods) -+{ -+ window->internal->mods = mods; - } ++#endif ++#endif -- --static void keyCallback(GLFWwindow* win, int key, int scancode, int action, int mods) { -- contextSet((Context*) glfwGetWindowUserPointer(win)); -- if (APP->event->handleKey(APP->window->internal->lastMousePos, key, scancode, action, mods)) -- return; -- - // Keyboard/mouse MIDI driver - if (action == GLFW_PRESS && (mods & RACK_MOD_MASK) == 0) { - keyboard::press(key); - } - if (action == GLFW_RELEASE) { - keyboard::release(key); -+Window::~Window() { -+ { -+ DGL_NAMESPACE::Window::ScopedGraphicsContext sgc(internal->hiddenWindow); -+ internal->hiddenWindow.close(); -+ internal->hiddenApp.idle(); -+ -+ // Fonts and Images in the cache must be deleted before the NanoVG context is deleted -+ internal->fontCache.clear(); -+ internal->imageCache.clear(); -+ -+#if defined NANOVG_GLES2 -+ nvgDeleteGLES2(internal->o_fbVg != nullptr ? internal->o_fbVg : fbVg); -+ nvgDeleteGLES2(internal->o_vg != nullptr ? internal->o_vg : vg); -+#else -+ nvgDeleteGL2(internal->o_fbVg != nullptr ? internal->o_fbVg : fbVg); -+ nvgDeleteGL2(internal->o_vg != nullptr ? internal->o_vg : vg); -+#endif ++ window->internal->tlw = nullptr; ++ window->internal->callback = nullptr; } --} -- + } +- -static void dropCallback(GLFWwindow* win, int count, const char** paths) { - contextSet((Context*) glfwGetWindowUserPointer(win)); - std::vector pathsVec; - for (int i = 0; i < count; i++) { - pathsVec.push_back(paths[i]); -- } ++void WindowSetPluginUI(Window* const window, CardinalBaseUI* const ui) ++{ ++ // if nanovg context failed, init only bare minimum ++ if (window->vg == nullptr) ++ { ++ if (ui != nullptr) ++ { ++ window->internal->ui = ui; ++ window->internal->size = rack::math::Vec(ui->getWidth(), ui->getHeight()); ++ } ++ else ++ { ++ window->internal->ui = nullptr; ++ window->internal->callback = nullptr; ++ } ++ return; + } - APP->event->handleDrop(APP->window->internal->lastMousePos, pathsVec); -+ delete internal; - } - - +-} +- +- -static void errorCallback(int error, const char* description) { - WARN("GLFW error %d: %s", error, description); -+math::Vec Window::getSize() { -+ return internal->size; - } +-} ++ if (ui != nullptr) ++ { ++ const GLubyte* vendor = glGetString(GL_VENDOR); ++ const GLubyte* renderer = glGetString(GL_RENDERER); ++ const GLubyte* version = glGetString(GL_VERSION); ++ INFO("Renderer: %s %s", vendor, renderer); ++ INFO("OpenGL: %s", version); ++ ++ window->internal->tlw = ui; ++ window->internal->ui = ui; ++ window->internal->size = rack::math::Vec(ui->getWidth(), ui->getHeight()); ++ ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS ++ // Set up NanoVG ++ window->internal->r_vg = ui->getContext(); ++#ifdef NANOVG_GLES2 ++ window->internal->r_fbVg = nvgCreateSharedGLES2(window->internal->r_vg, NVG_ANTIALIAS); ++#else ++ window->internal->r_fbVg = nvgCreateSharedGL2(window->internal->r_vg, NVG_ANTIALIAS); ++#endif -Window::Window() { - internal = new Internal; - int err; -+void Window::setSize(math::Vec size) { -+ size = size.max(WINDOW_SIZE_MIN); -+ internal->size = size; - +- - // Set window hints -#if defined NANOVG_GL2 - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); @@ -519,7 +566,7 @@ - glfwSetInputMode(win, GLFW_LOCK_KEY_MODS, 1); - - glfwMakeContextCurrent(win); -- glfwSwapInterval(1); +- glfwSwapInterval(0); - const GLFWvidmode* monitorMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); - if (monitorMode->refreshRate > 0) { - internal->monitorRefreshRate = monitorMode->refreshRate; @@ -555,16 +602,35 @@ - const GLubyte* version = glGetString(GL_VERSION); - INFO("Renderer: %s %s", vendor, renderer); - INFO("OpenGL: %s", version); -+ if (DISTRHO_NAMESPACE::UI* const ui = internal->ui) -+ ui->setSize(internal->size.x, internal->size.y); -+} ++ // swap contexts ++ window->internal->o_vg = window->vg; ++ window->internal->o_fbVg = window->fbVg; ++ window->vg = window->internal->r_vg; ++ window->fbVg = window->internal->r_fbVg; ++ ++ // also for fonts and images ++ window->uiFont->vg = window->vg; ++ window->uiFont->handle = loadFallbackFont(window->vg); ++ for (auto& font : window->internal->fontCache) ++ { ++ font.second->vg = window->vg; ++ font.second->ohandle = font.second->handle; ++ font.second->handle = nvgCreateFont(window->vg, ++ font.second->ofilename.c_str(), font.second->ofilename.c_str()); ++ } ++ for (auto& image : window->internal->imageCache) ++ { ++ image.second->vg = window->vg; ++ image.second->ohandle = image.second->handle; ++ image.second->handle = nvgCreateImage(window->vg, image.second->ofilename.c_str(), ++ NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); ++ } ++#endif - // GLEW generates GL error because it calls glGetString(GL_EXTENSIONS), we'll consume it here. - glGetError(); -+void WindowSetInternalSize(rack::window::Window* const window, math::Vec size) { -+ size = size.max(WINDOW_SIZE_MIN); -+ window->internal->size = size; -+} ++ // Init settings ++ WindowParametersRestore(window); - // Set up NanoVG - int nvgFlags = NVG_ANTIALIAS; @@ -579,35 +645,76 @@ - if (!vg) { - osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "Could not initialize NanoVG. Does your graphics card support OpenGL 2.0 or greater? If so, make sure you have the latest graphics drivers installed."); - throw Exception("Could not initialize NanoVG"); -- } ++ widget::Widget::ContextCreateEvent e = {}; ++ e.vg = window->vg; ++ APP->scene->onContextCreate(e); + } ++ else ++ { ++ widget::Widget::ContextDestroyEvent e = {}; ++ e.vg = window->vg; ++ APP->scene->onContextDestroy(e); - // Load default Blendish font - uiFont = loadFont(asset::system("res/fonts/DejaVuSans.ttf")); - bndSetFont(uiFont->handle); -- ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS ++ // swap contexts ++ window->uiFont->vg = window->internal->o_vg; ++ window->vg = window->internal->o_vg; ++ window->fbVg = window->internal->o_fbVg; ++ window->internal->o_vg = nullptr; ++ window->internal->o_fbVg = nullptr; ++ ++ // also for fonts and images ++ window->uiFont->vg = window->vg; ++ window->uiFont->handle = loadFallbackFont(window->vg); ++ for (auto& font : window->internal->fontCache) ++ { ++ font.second->vg = window->vg; ++ font.second->handle = font.second->ohandle; ++ font.second->ohandle = -1; ++ } ++ for (auto& image : window->internal->imageCache) ++ { ++ image.second->vg = window->vg; ++ image.second->handle = image.second->ohandle; ++ image.second->ohandle = -1; ++ } + - if (APP->scene) { - widget::Widget::ContextCreateEvent e; - APP->scene->onContextCreate(e); -- } -+void Window::run() { -+ internal->frame = 0; ++#if defined NANOVG_GLES2 ++ nvgDeleteGLES2(window->internal->r_fbVg); ++#else ++ nvgDeleteGL2(window->internal->r_fbVg); ++#endif ++#endif ++ ++ window->internal->tlw = nullptr; ++ window->internal->ui = nullptr; ++ window->internal->callback = nullptr; + } } ++void WindowSetMods(Window* const window, const int mods) ++{ ++ window->internal->mods = mods; ++} --Window::~Window() { + Window::~Window() { - if (APP->scene) { - widget::Widget::ContextDestroyEvent e; - APP->scene->onContextDestroy(e); -+#ifndef DGL_USE_GLES -+static void Window__flipBitmap(uint8_t* pixels, const int width, const int height, const int depth) { -+ for (int y = 0; y < height / 2; y++) { -+ const int flipY = height - y - 1; -+ uint8_t tmp[width * depth]; -+ std::memcpy(tmp, &pixels[y * width * depth], width * depth); -+ std::memmove(&pixels[y * width * depth], &pixels[flipY * width * depth], width * depth); -+ std::memcpy(&pixels[flipY * width * depth], tmp, width * depth); - } -- +- } ++ { ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS ++ DGL_NAMESPACE::Window::ScopedGraphicsContext sgc(internal->hiddenWindow); ++ internal->hiddenWindow.close(); ++ internal->hiddenApp.idle(); ++#endif + - // Fonts and Images in the cache must be deleted before the NanoVG context is deleted - internal->fontCache.clear(); - internal->imageCache.clear(); @@ -621,19 +728,77 @@ - nvgDeleteGL3(vg); -#elif defined NANOVG_GLES2 - nvgDeleteGLES2(vg); --#endif -- ++ // Fonts and Images in the cache must be deleted before the NanoVG context is deleted ++ internal->fontCache.clear(); ++ internal->imageCache.clear(); ++ ++ if (vg != nullptr) ++ { ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS ++#if defined NANOVG_GLES2 ++ nvgDeleteGLES2(internal->o_fbVg != nullptr ? internal->o_fbVg : fbVg); ++ nvgDeleteGLES2(internal->o_vg != nullptr ? internal->o_vg : vg); ++#else ++ nvgDeleteGL2(internal->o_fbVg != nullptr ? internal->o_fbVg : fbVg); ++ nvgDeleteGL2(internal->o_vg != nullptr ? internal->o_vg : vg); + #endif ++#else ++#if defined NANOVG_GLES2 ++ nvgDeleteGLES2(fbVg); ++#else ++ nvgDeleteGL2(fbVg); ++#endif ++#endif ++ } ++ } + - glfwDestroyWindow(win); -- delete internal; + delete internal; } --math::Vec Window::getSize() { + math::Vec Window::getSize() { - int width, height; - glfwGetWindowSize(win, &width, &height); - return math::Vec(width, height); --} -- ++ return internal->size; + } + + + void Window::setSize(math::Vec size) { + size = size.max(WINDOW_SIZE_MIN); +- glfwSetWindowSize(win, size.x, size.y); ++ internal->size = size; ++ ++ if (DGL_NAMESPACE::NanoTopLevelWidget* const tlw = internal->ui) ++ tlw->setSize(internal->size.x, internal->size.y); ++} ++ ++void WindowSetInternalSize(rack::window::Window* const window, math::Vec size) { ++ size = size.max(WINDOW_SIZE_MIN); ++ window->internal->size = size; + } + + + void Window::run() { + internal->frame = 0; +- while (!glfwWindowShouldClose(win)) { +- step(); ++} ++ ++ ++#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS ++static void Window__flipBitmap(uint8_t* pixels, const int width, const int height, const int depth) { ++ for (int y = 0; y < height / 2; y++) { ++ const int flipY = height - y - 1; ++ uint8_t tmp[width * depth]; ++ std::memcpy(tmp, &pixels[y * width * depth], width * depth); ++ std::memmove(&pixels[y * width * depth], &pixels[flipY * width * depth], width * depth); ++ std::memcpy(&pixels[flipY * width * depth], tmp, width * depth); ++ } ++} ++ ++ +#ifdef STBI_WRITE_NO_STDIO +static void Window__downscaleBitmap(uint8_t* pixels, int& width, int& height) { + int targetWidth = width; @@ -661,40 +826,33 @@ + std::memmove(pixels + (width * y + x) * 3, pixels + (width * ys + xs) * 3, 3); + } + } - --void Window::setSize(math::Vec size) { -- size = size.max(WINDOW_SIZE_MIN); -- glfwSetWindowSize(win, size.x, size.y); ++ + width = targetWidth; + height = targetHeight; - } - -- --void Window::run() { -- internal->frame = 0; -- while (!glfwWindowShouldClose(win)) { -- step(); -- } ++} ++ +static void Window__writeImagePNG(void* context, void* data, int size) { + USE_NAMESPACE_DISTRHO -+ UI* const ui = static_cast(context); -+ ui->setState("screenshot", String::asBase64(data, size).buffer()); ++ CardinalBaseUI* const ui = static_cast(context); ++ if (char* const screenshot = String::asBase64(data, size).getAndReleaseBuffer()) { ++ ui->setState("screenshot", screenshot); ++ if (ui->remoteDetails != nullptr) ++ remoteUtils::sendScreenshotToRemote(ui->remoteDetails, screenshot); ++ std::free(screenshot); + } } +#endif +#endif void Window::step() { -+ DISTRHO_SAFE_ASSERT_RETURN(internal->ui != nullptr,); ++ if (internal->tlw == nullptr || vg == nullptr) ++ return; + double frameTime = system::getTime(); - double lastFrameTime = internal->frameTime; - internal->frameTime = frameTime; - internal->lastFrameDuration = frameTime - lastFrameTime; - internal->fbCount = 0; - // DEBUG("%.2lf Hz", 1.0 / internal->lastFrameDuration); -- // double t1 = 0.0, t2 = 0.0, t3 = 0.0, t4 = 0.0, t5 = 0.0; - + if (std::isfinite(internal->frameTime)) { + internal->lastFrameDuration = frameTime - internal->frameTime; +@@ -422,57 +622,52 @@ // Make event handlers and step() have a clean NanoVG context nvgReset(vg); @@ -708,10 +866,6 @@ - - // In case glfwPollEvents() sets another OpenGL context - glfwMakeContextCurrent(win); -- if (settings::frameSwapInterval != internal->frameSwapInterval) { -- glfwSwapInterval(settings::frameSwapInterval); -- internal->frameSwapInterval = settings::frameSwapInterval; -- } - - // Call cursorPosCallback every frame, not just when the mouse moves - { @@ -725,17 +879,31 @@ // Set window title - std::string windowTitle = APP_NAME + " " + APP_EDITION_NAME + " " + APP_VERSION; -+ std::string windowTitle = "Cardinal"; - if (APP->patch->path != "") { - windowTitle += " - "; - if (!APP->history->isSaved()) -@@ -455,246 +458,189 @@ - windowTitle += system::getFilename(APP->patch->path); - } - if (windowTitle != internal->lastWindowTitle) { +- if (APP->patch->path != "") { +- windowTitle += " - "; +- if (!APP->history->isSaved()) +- windowTitle += "*"; +- windowTitle += system::getFilename(APP->patch->path); +- } +- if (windowTitle != internal->lastWindowTitle) { - glfwSetWindowTitle(win, windowTitle.c_str()); -+ internal->ui->getWindow().setTitle(windowTitle.c_str()); - internal->lastWindowTitle = windowTitle; +- internal->lastWindowTitle = windowTitle; ++ if (isStandalone()) { ++#if CARDINAL_VARIANT_MINI ++ std::string windowTitle = "Cardinal Mini"; ++#else ++ std::string windowTitle = "Cardinal"; ++#endif ++ if (APP->patch->path != "") { ++ windowTitle += " - "; ++ if (!APP->history->isSaved()) ++ windowTitle += "*"; ++ windowTitle += system::getFilename(APP->patch->path); ++ } ++ if (windowTitle != internal->lastWindowTitle) { ++ internal->tlw->getWindow().setTitle(windowTitle.c_str()); ++ internal->lastWindowTitle = windowTitle; ++ } } // Get desired pixel ratio @@ -747,13 +915,13 @@ - glfwGetWindowContentScale(win, &newPixelRatio, NULL); - newPixelRatio = std::floor(newPixelRatio + 0.5); - } -+ float newPixelRatio = internal->ui->getScaleFactor(); ++ float newPixelRatio = internal->tlw->getScaleFactor(); if (newPixelRatio != pixelRatio) { pixelRatio = newPixelRatio; APP->event->handleDirty(); } -+#ifndef DGL_USE_GLES ++#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS + // Hide menu and background if generating screenshot + if (internal->generateScreenshotStep == kScreenshotStepStarted) { +#ifdef CARDINAL_TRANSPARENT_SCREENSHOTS @@ -770,22 +938,15 @@ - glfwGetFramebufferSize(win, &fbWidth, &fbHeight); - int winWidth, winHeight; - glfwGetWindowSize(win, &winWidth, &winHeight); -+ int winWidth = internal->ui->getWidth(); -+ int winHeight = internal->ui->getHeight(); -+ int fbWidth = winWidth;// * newPixelRatio; -+ int fbHeight = winHeight;// * newPixelRatio; ++ int winWidth = internal->tlw->getWidth(); ++ int winHeight = internal->tlw->getHeight(); ++ int fbWidth = winWidth; ++ int fbHeight = winHeight; windowRatio = (float)fbWidth / winWidth; -- // t1 = system::getTime(); - - if (APP->scene) { - // DEBUG("%f %f %d %d", pixelRatio, windowRatio, fbWidth, winWidth); - // Resize scene -- APP->scene->box.size = math::Vec(fbWidth, fbHeight).div(pixelRatio); -+ APP->scene->box.size = math::Vec(fbWidth, fbHeight).div(newPixelRatio); + // t1 = system::getTime(); - // Step scene - APP->scene->step(); -- // t2 = system::getTime(); +@@ -486,10 +681,8 @@ + // t2 = system::getTime(); // Render scene - bool visible = glfwGetWindowAttrib(win, GLFW_VISIBLE) && !glfwGetWindowAttrib(win, GLFW_ICONIFIED); @@ -793,15 +954,11 @@ + { // Update and render - nvgBeginFrame(vg, fbWidth, fbHeight, pixelRatio); -- nvgScale(vg, pixelRatio, pixelRatio); -+ nvgScale(vg, newPixelRatio, newPixelRatio); + nvgScale(vg, pixelRatio, pixelRatio); // Draw scene - widget::Widget::DrawArgs args; - args.vg = vg; - args.clipBox = APP->scene->box.zeroPos(); - APP->scene->draw(args); -- // t3 = system::getTime(); +@@ -500,23 +693,16 @@ + // t3 = system::getTime(); glViewport(0, 0, fbWidth, fbHeight); +#ifdef CARDINAL_TRANSPARENT_SCREENSHOTS @@ -811,32 +968,32 @@ +#endif glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - nvgEndFrame(vg); -- // t4 = system::getTime(); } + // t4 = system::getTime(); } - glfwSwapBuffers(win); -+ ++internal->frame; - -- // On some platforms, glfwSwapBuffers() doesn't wait on monitor refresh, so we have to sleep as a fallback. -- double frameDurationRemaining = getFrameDurationRemaining(); -- if (frameDurationRemaining > 0.0) { -- std::this_thread::sleep_for(std::chrono::duration(frameDurationRemaining)); -- } - -- // t5 = system::getTime(); +- // Limit frame rate +- if (settings::frameRateLimit > 0) { +- double remaining = getFrameDurationRemaining(); +- if (remaining > 0.0) { +- system::sleep(remaining); +- } +- } - -- // DEBUG("pre-step %6.1f step %6.1f draw %6.1f nvgEndFrame %6.1f glfwSwapBuffers %6.1f total %6.1f", -- // (t1 - frameTime) * 1e3f, -- // (t2 - t1) * 1e3f, -- // (t3 - t2) * 1e3f, -- // (t4 - t2) * 1e3f, -- // (t5 - t4) * 1e3f, -- // (t5 - frameTime) * 1e3f -- // ); + // t5 = system::getTime(); + // DEBUG("pre-step %6.1f step %6.1f draw %6.1f nvgEndFrame %6.1f glfwSwapBuffers %6.1f total %6.1f", + // (t1 - frameTime) * 1e3f, +@@ -526,163 +712,132 @@ + // (t5 - t4) * 1e3f, + // (t5 - frameTime) * 1e3f + // ); - internal->frame++; -} -+#ifndef DGL_USE_GLES ++ ++internal->frame; ++ ++#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS + if (internal->generateScreenshotStep != kScreenshotStepNone) { + ++internal->generateScreenshotStep; + @@ -851,20 +1008,24 @@ + // Allocate pixel color buffer + uint8_t* const pixels = new uint8_t[winHeight * winWidth * 4]; --void Window::activateContext() { -- glfwMakeContextCurrent(win); --} +-static void flipBitmap(uint8_t* pixels, int width, int height, int depth) { +- for (int y = 0; y < height / 2; y++) { +- int flipY = height - y - 1; +- uint8_t tmp[width * depth]; +- std::memcpy(tmp, &pixels[y * width * depth], width * depth); +- std::memcpy(&pixels[y * width * depth], &pixels[flipY * width * depth], width * depth); +- std::memcpy(&pixels[flipY * width * depth], tmp, width * depth); + // glReadPixels defaults to GL_BACK, but the back-buffer is unstable, so use the front buffer (what the user sees) + glReadBuffer(GL_FRONT); + glReadPixels(0, 0, winWidth, winHeight, depth == 3 ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, pixels); - ++ + if (internal->generateScreenshotStep == kScreenshotStepSaving) + { + // Write pixels to PNG -+ const int stride = winWidth * depth; -+ uint8_t* const pixelsWithOffset = pixels + (stride * y); + Window__flipBitmap(pixels, winWidth, winHeight, depth); + winHeight -= y; ++ const int stride = winWidth * depth; ++ uint8_t* const pixelsWithOffset = pixels + (stride * y); +#ifdef STBI_WRITE_NO_STDIO + Window__downscaleBitmap(pixelsWithOffset, winWidth, winHeight); + stbi_write_png_to_func(Window__writeImagePNG, internal->ui, @@ -872,17 +1033,12 @@ +#else + stbi_write_png("screenshot.png", winWidth, winHeight, depth, pixelsWithOffset, stride); +#endif - --static void flipBitmap(uint8_t* pixels, int width, int height, int depth) { -- for (int y = 0; y < height / 2; y++) { -- int flipY = height - y - 1; -- uint8_t tmp[width * depth]; -- std::memcpy(tmp, &pixels[y * width * depth], width * depth); -- std::memcpy(&pixels[y * width * depth], &pixels[flipY * width * depth], width * depth); -- std::memcpy(&pixels[flipY * width * depth], tmp, width * depth); ++ + internal->generateScreenshotStep = kScreenshotStepNone; ++#ifdef CARDINAL_TRANSPARENT_SCREENSHOTS + APP->scene->menuBar->show(); + APP->scene->rack->children.front()->show(); ++#endif + } + + delete[] pixels; @@ -891,7 +1047,7 @@ } --void Window::screenshot(const std::string& screenshotPath) { + void Window::screenshot(const std::string& screenshotPath) { - // Get window framebuffer size - int width, height; - glfwGetFramebufferSize(APP->window->win, &width, &height); @@ -908,10 +1064,10 @@ - stbi_write_png(screenshotPath.c_str(), width, height, 4, pixels, width * 4); - - delete[] pixels; --} -- -- --void Window::screenshotModules(const std::string& screenshotsDir, float zoom) { + } + + + void Window::screenshotModules(const std::string& screenshotsDir, float zoom) { - // Iterate plugins and create directories - system::createDirectories(screenshotsDir); - for (plugin::Plugin* p : plugin::plugins) { @@ -956,32 +1112,25 @@ - nvgImageSize(vg, fbw->getImageHandle(), &width, &height); - uint8_t* pixels = new uint8_t[height * width * 4]; - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); -+void Window::activateContext() { -+} - +- - // Write pixels to PNG - flipBitmap(pixels, width, height, 4); - stbi_write_png(filename.c_str(), width, height, 4, pixels, width * 4); - +- - // Cleanup - delete[] pixels; - nvgluBindFramebuffer(NULL); - delete fbw; - } - } -+void Window::screenshot(const std::string&) { -+} -+ -+ -+void Window::screenshotModules(const std::string&, float) { } void Window::close() { - glfwSetWindowShouldClose(win, GLFW_TRUE); -+ DISTRHO_SAFE_ASSERT_RETURN(internal->ui != nullptr,); ++ DISTRHO_SAFE_ASSERT_RETURN(internal->tlw != nullptr,); + -+ internal->ui->getWindow().close(); ++ internal->tlw->getWindow().close(); } @@ -994,7 +1143,7 @@ - glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); -#else - glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_DISABLED); -+ emscripten_request_pointerlock(internal->ui->getWindow().getApp().getClassName(), false); ++ emscripten_request_pointerlock(internal->tlw->getWindow().getApp().getClassName(), false); #endif - internal->ignoreNextMouseDelta = true; } @@ -1038,23 +1187,26 @@ } --void Window::setFullScreen(bool fullScreen) { + void Window::setFullScreen(bool fullScreen) { - if (!fullScreen) { - glfwSetWindowMonitor(win, NULL, internal->lastWindowX, internal->lastWindowY, internal->lastWindowWidth, internal->lastWindowHeight, GLFW_DONT_CARE); -- } ++#ifdef DISTRHO_OS_WASM ++ if (fullScreen) ++ { ++ try { ++ emscripten_request_fullscreen(internal->tlw->getWindow().getApp().getClassName(), false); ++ } DISTRHO_SAFE_EXCEPTION("fullscreen"); + } - else { - glfwGetWindowPos(win, &internal->lastWindowX, &internal->lastWindowY); - glfwGetWindowSize(win, &internal->lastWindowWidth, &internal->lastWindowHeight); - GLFWmonitor* monitor = glfwGetPrimaryMonitor(); - const GLFWvidmode* mode = glfwGetVideoMode(monitor); - glfwSetWindowMonitor(win, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); -- } -+void Window::setFullScreen(const bool fullscreen) { -+#ifdef DISTRHO_OS_WASM -+ if (fullscreen) -+ emscripten_request_fullscreen(internal->ui->getWindow().getApp().getClassName(), false); + else ++ { + emscripten_exit_fullscreen(); + } +#endif } @@ -1067,18 +1219,24 @@ + if (emscripten_get_fullscreen_status(&status) == EMSCRIPTEN_RESULT_SUCCESS) + return status.isFullscreen; + return false; -+#elif defined(CARDINAL_TRANSPARENT_SCREENSHOTS) && !defined(DGL_USE_GLES) ++#elif defined(CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS) && defined(CARDINAL_TRANSPARENT_SCREENSHOTS) + return internal->generateScreenshotStep != kScreenshotStepNone; +#else + return false; +#endif } -- - double Window::getMonitorRefreshRate() { - return internal->monitorRefreshRate; + +@@ -702,7 +857,7 @@ + + + double Window::getFrameDurationRemaining() { +- double frameDuration = 1.f / settings::frameRateLimit; ++ double frameDuration = 1.f / internal->monitorRefreshRate; + return frameDuration - (system::getTime() - internal->frameTime); } -@@ -722,14 +668,15 @@ + +@@ -713,14 +868,15 @@ return pair->second; // Load font @@ -1097,7 +1255,7 @@ } internal->fontCache[filename] = font; return font; -@@ -742,14 +689,15 @@ +@@ -733,14 +889,15 @@ return pair->second; // Load image @@ -1116,7 +1274,7 @@ } internal->imageCache[filename] = image; return image; -@@ -766,28 +714,156 @@ +@@ -757,28 +914,156 @@ } @@ -1128,7 +1286,7 @@ - glfwInitHint(GLFW_COCOA_CHDIR_RESOURCES, GLFW_TRUE); - glfwInitHint(GLFW_COCOA_MENUBAR, GLFW_FALSE); +void generateScreenshot() { -+#ifndef DGL_USE_GLES ++#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS + APP->window->internal->generateScreenshotStep = kScreenshotStepStarted; #endif +} diff --git a/src/override/diffs/blendish.c.diff b/src/override/diffs/blendish.c.diff index 69f860af..ee4b10ed 100644 --- a/src/override/diffs/blendish.c.diff +++ b/src/override/diffs/blendish.c.diff @@ -1,5 +1,5 @@ ---- ../Rack/dep/oui-blendish/blendish.c 2022-04-11 20:05:39.202902589 +0100 -+++ blendish.c 2022-04-11 19:51:05.409742542 +0100 +--- ../Rack/dep/oui-blendish/blendish.c 2022-09-21 20:49:29.973066921 +0200 ++++ blendish.c 2022-09-21 20:41:45.883648777 +0200 @@ -61,7 +61,7 @@ } diff --git a/src/override/diffs/common.cpp.diff b/src/override/diffs/common.cpp.diff index 78d1a3d6..fce74343 100644 --- a/src/override/diffs/common.cpp.diff +++ b/src/override/diffs/common.cpp.diff @@ -1,9 +1,9 @@ ---- ../Rack/src/common.cpp 2022-04-11 20:05:02.007283878 +0100 -+++ common.cpp 2022-07-12 09:45:31.518663160 +0100 -@@ -1,33 +1,77 @@ +--- ../Rack/src/common.cpp 2023-05-20 17:03:33.006081772 +0200 ++++ common.cpp 2023-05-20 19:44:40.371645493 +0200 +@@ -1,12 +1,57 @@ +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ + +/** + * This file is an edited version of VCVRack's common.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -42,11 +42,14 @@ #include FILE* fopen_u8(const char* filename, const char* mode) { +- return _wfopen(rack::string::UTF8toUTF16(filename).c_str(), rack::string::UTF8toUTF16(mode).c_str()); ++ if (FILE* const f = _wfopen(rack::string::UTF8toUTF16(filename).c_str(), rack::string::UTF8toUTF16(mode).c_str())) ++ return f; + if (std::strncmp(filename, "\\\\?\\", 4) == 0 && std::getenv("CARDINAL_UNDER_WINE") != nullptr) -+ filename = "Z:\\dev\\null"; - return _wfopen(rack::string::UTF8toUTF16(filename).c_str(), rack::string::UTF8toUTF16(mode).c_str()); - } - ++ return _wfopen(L"Z:\\dev\\null", rack::string::UTF8toUTF16(mode).c_str()); ++ return nullptr; ++} ++ +#elif defined(DISTRHO_OS_WASM) +#include +#undef fopen @@ -54,10 +57,10 @@ +FILE* fopen_wasm(const char* filename, const char* mode) { + chmod(filename, 0777); + return std::fopen(filename, mode); -+} -+ - #endif + } + #endif +@@ -14,30 +59,21 @@ namespace rack { @@ -70,14 +73,23 @@ +const std::string APP_EDITION_NAME = "Audio Plugin"; const std::string APP_VERSION_MAJOR = "2"; -const std::string APP_VERSION = TOSTRING(_APP_VERSION); -+const std::string APP_VERSION = "2.1.2"; ++const std::string APP_VERSION = "2.3.0"; #if defined ARCH_WIN const std::string APP_OS = "win"; --#elif ARCH_MAC -+#elif defined ARCH_MAC +- const std::string APP_OS_NAME = "Windows"; + #elif defined ARCH_MAC const std::string APP_OS = "mac"; +- const std::string APP_OS_NAME = "macOS"; #elif defined ARCH_LIN const std::string APP_OS = "lin"; +- const std::string APP_OS_NAME = "Linux"; +-#endif +-#if defined ARCH_X64 +- const std::string APP_CPU = "x64"; +- const std::string APP_CPU_NAME = "x64"; +-#elif defined ARCH_ARM64 +- const std::string APP_CPU = "arm64"; +- const std::string APP_CPU_NAME = "ARM64"; +#else + #error ARCH_LIN undefined #endif diff --git a/src/override/diffs/context.cpp.diff b/src/override/diffs/context.cpp.diff index 875e354b..0987ca00 100644 --- a/src/override/diffs/context.cpp.diff +++ b/src/override/diffs/context.cpp.diff @@ -1,9 +1,9 @@ ---- ../Rack/src/context.cpp 2022-04-11 20:05:02.007283878 +0100 -+++ context.cpp 2022-04-11 19:51:05.409742542 +0100 -@@ -1,3 +1,30 @@ +--- ../Rack/src/context.cpp 2023-09-10 12:59:02.630898560 +0200 ++++ context.cpp 2023-05-20 18:08:56.497736615 +0200 +@@ -1,14 +1,44 @@ +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ + +/** + * This file is an edited version of VCVRack's context.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -31,9 +31,10 @@ #include #include #include -@@ -6,9 +33,13 @@ + #include + #include #include - #include +-#include +#ifdef NDEBUG +# undef DEBUG @@ -46,7 +47,17 @@ Context::~Context() { // Deleting NULL is safe in C++. -@@ -44,7 +75,7 @@ +@@ -38,17 +68,13 @@ + INFO("Deleting engine"); + delete engine; + engine = NULL; +- +- INFO("Deleting MIDI loopback"); +- delete midiLoopbackContext; +- midiLoopbackContext = NULL; + } + + static thread_local Context* threadContext = NULL; Context* contextGet() { diff --git a/src/override/diffs/dsp-fir.hpp.diff b/src/override/diffs/dsp-fir.hpp.diff new file mode 100644 index 00000000..8e261296 --- /dev/null +++ b/src/override/diffs/dsp-fir.hpp.diff @@ -0,0 +1,56 @@ +--- ../Rack/include/dsp/fir.hpp 2022-09-21 20:49:12.181540170 +0200 ++++ ../../include/dsp/fir.hpp 2022-09-21 20:41:45.860647778 +0200 +@@ -1,4 +1,32 @@ ++/* ++ * DISTRHO Cardinal Plugin ++ * Copyright (C) 2021-2022 Filipe Coelho ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 3 of ++ * the License, or any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * For a full copy of the GNU General Public License see the LICENSE file. ++ */ ++ ++/** ++ * This file is an edited version of VCVRack's dsp/fir.hpp ++ * Copyright (C) 2016-2021 VCV. ++ * ++ * This program is free software: you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 3 of ++ * the License, or (at your option) any later version. ++ */ ++ + #pragma once ++ + #include + + #include +@@ -42,16 +70,16 @@ + RealTimeConvolver(size_t blockSize) { + this->blockSize = blockSize; + pffft = pffft_new_setup(blockSize * 2, PFFFT_REAL); +- outputTail = new float[blockSize]; ++ outputTail = (float*) pffft_aligned_malloc(sizeof(float) * blockSize); + std::memset(outputTail, 0, blockSize * sizeof(float)); +- tmpBlock = new float[blockSize * 2]; ++ tmpBlock = (float*) pffft_aligned_malloc(sizeof(float) * blockSize * 2); + std::memset(tmpBlock, 0, blockSize * 2 * sizeof(float)); + } + + ~RealTimeConvolver() { + setKernel(NULL, 0); +- delete[] outputTail; +- delete[] tmpBlock; ++ pffft_aligned_free(outputTail); ++ pffft_aligned_free(tmpBlock); + pffft_destroy_setup(pffft); + } + diff --git a/src/override/diffs/engine-Port.hpp.diff b/src/override/diffs/engine-Port.hpp.diff new file mode 100644 index 00000000..7fad783b --- /dev/null +++ b/src/override/diffs/engine-Port.hpp.diff @@ -0,0 +1,226 @@ +--- ../Rack/include/engine/Port.hpp 2023-09-10 12:59:02.629898529 +0200 ++++ ../../include/engine/Port.hpp 2023-07-07 18:20:12.030329564 +0200 +@@ -1,19 +1,57 @@ ++/* ++ * DISTRHO Cardinal Plugin ++ * Copyright (C) 2021-2022 Filipe Coelho ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 3 of ++ * the License, or any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * For a full copy of the GNU General Public License see the LICENSE file. ++ */ ++ ++/** ++ * This file is an edited version of VCVRack's engine/Port.hpp ++ * Copyright (C) 2016-2021 VCV. ++ * ++ * This program is free software: you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 3 of ++ * the License, or (at your option) any later version. ++ */ ++ + #pragma once ++ + #include + #include + ++#include ++ ++/** NOTE alignas is required in some systems in order to allow SSE usage. */ ++#define SIMD_ALIGN alignas(16) ++ + + namespace rack { + namespace engine { + + + /** This is inspired by the number of MIDI channels. */ +-static const int PORT_MAX_CHANNELS = 16; ++static constexpr const int PORT_MAX_CHANNELS = 16; ++ ++ ++struct Cable; + + + struct Port { + /** Voltage of the port. */ +- union { ++ /** NOTE alignas is required in order to allow SSE usage. ++ Consecutive data (like in a vector) would otherwise pack Ports in a way that breaks SSE. */ ++ union SIMD_ALIGN { + /** Unstable API. Use getVoltage() and setVoltage() instead. */ + float voltages[PORT_MAX_CHANNELS] = {}; + /** DEPRECATED. Unstable API. Use getVoltage() and setVoltage() instead. */ +@@ -40,40 +78,40 @@ + }; + + /** Sets the voltage of the given channel. */ +- void setVoltage(float voltage, int channel = 0) { ++ void setVoltage(float voltage, int channel = 0) noexcept { + voltages[channel] = voltage; + } + + /** Returns the voltage of the given channel. + Because of proper bookkeeping, all channels higher than the input port's number of channels should be 0V. + */ +- float getVoltage(int channel = 0) { ++ float getVoltage(int channel = 0) const noexcept { + return voltages[channel]; + } + + /** Returns the given channel's voltage if the port is polyphonic, otherwise returns the first voltage (channel 0). */ +- float getPolyVoltage(int channel) { ++ float getPolyVoltage(int channel) const noexcept { + return isMonophonic() ? getVoltage(0) : getVoltage(channel); + } + + /** Returns the voltage if a cable is connected, otherwise returns the given normal voltage. */ +- float getNormalVoltage(float normalVoltage, int channel = 0) { ++ float getNormalVoltage(float normalVoltage, int channel = 0) const noexcept { + return isConnected() ? getVoltage(channel) : normalVoltage; + } + +- float getNormalPolyVoltage(float normalVoltage, int channel) { ++ float getNormalPolyVoltage(float normalVoltage, int channel) const noexcept { + return isConnected() ? getPolyVoltage(channel) : normalVoltage; + } + + /** Returns a pointer to the array of voltages beginning with firstChannel. + The pointer can be used for reading and writing. + */ +- float* getVoltages(int firstChannel = 0) { ++ float* getVoltages(int firstChannel = 0) noexcept { + return &voltages[firstChannel]; + } + + /** Copies the port's voltages to an array of size at least `channels`. */ +- void readVoltages(float* v) { ++ void readVoltages(float* v) const noexcept { + for (int c = 0; c < channels; c++) { + v[c] = voltages[c]; + } +@@ -89,14 +127,14 @@ + } + + /** Sets all voltages to 0. */ +- void clearVoltages() { ++ void clearVoltages() noexcept { + for (int c = 0; c < channels; c++) { + voltages[c] = 0.f; + } + } + + /** Returns the sum of all voltages. */ +- float getVoltageSum() { ++ float getVoltageSum() const noexcept { + float sum = 0.f; + for (int c = 0; c < channels; c++) { + sum += voltages[c]; +@@ -107,7 +145,7 @@ + /** Returns the root-mean-square of all voltages. + Uses sqrt() which is slow, so use a custom approximation if calling frequently. + */ +- float getVoltageRMS() { ++ float getVoltageRMS() const { + if (channels == 0) { + return 0.f; + } +@@ -124,22 +162,22 @@ + } + + template +- T getVoltageSimd(int firstChannel) { ++ T getVoltageSimd(int firstChannel) const noexcept { + return T::load(&voltages[firstChannel]); + } + + template +- T getPolyVoltageSimd(int firstChannel) { ++ T getPolyVoltageSimd(int firstChannel) const noexcept { + return isMonophonic() ? getVoltage(0) : getVoltageSimd(firstChannel); + } + + template +- T getNormalVoltageSimd(T normalVoltage, int firstChannel) { ++ T getNormalVoltageSimd(T normalVoltage, int firstChannel) const noexcept { + return isConnected() ? getVoltageSimd(firstChannel) : normalVoltage; + } + + template +- T getNormalPolyVoltageSimd(T normalVoltage, int firstChannel) { ++ T getNormalPolyVoltageSimd(T normalVoltage, int firstChannel) const noexcept { + return isConnected() ? getPolyVoltageSimd(firstChannel) : normalVoltage; + } + +@@ -153,13 +191,15 @@ + If disconnected, this does nothing (`channels` remains 0). + If 0 is given, `channels` is set to 1 but all voltages are cleared. + */ +- void setChannels(int channels) { ++ void setChannels(int channels) noexcept { + // If disconnected, keep the number of channels at 0. + if (this->channels == 0) { + return; + } + // Set higher channel voltages to 0 + for (int c = channels; c < this->channels; c++) { ++ if (c >= PORT_MAX_CHANNELS) ++ __builtin_unreachable(); + voltages[c] = 0.f; + } + // Don't allow caller to set port as disconnected +@@ -172,35 +212,39 @@ + /** Returns the number of channels. + If the port is disconnected, it has 0 channels. + */ +- int getChannels() { ++ int getChannels() const noexcept { + return channels; + } + + /** Returns whether a cable is connected to the Port. + You can use this for skipping code that generates output voltages. + */ +- bool isConnected() { ++ bool isConnected() const noexcept { + return channels > 0; + } + + /** Returns whether the cable exists and has 1 channel. */ +- bool isMonophonic() { ++ bool isMonophonic() const noexcept { + return channels == 1; + } + + /** Returns whether the cable exists and has more than 1 channel. */ +- bool isPolyphonic() { ++ bool isPolyphonic() const noexcept { + return channels > 1; + } + + /** Use getNormalVoltage() instead. */ +- DEPRECATED float normalize(float normalVoltage) { ++ DEPRECATED float normalize(float normalVoltage) const noexcept { + return getNormalVoltage(normalVoltage); + } + }; + + +-struct Output : Port {}; ++struct Output : Port { ++ /** List of cables connected to this port. */ ++ std::list cables; ++}; ++ + + struct Input : Port {}; + diff --git a/src/override/diffs/midi.hpp.diff b/src/override/diffs/midi.hpp.diff new file mode 100644 index 00000000..ce891d4a --- /dev/null +++ b/src/override/diffs/midi.hpp.diff @@ -0,0 +1,280 @@ +--- ../Rack/include/midi.hpp 2022-09-21 20:49:12.182540200 +0200 ++++ ../../include/midi.hpp 2022-09-21 20:41:45.861647821 +0200 +@@ -1,12 +1,33 @@ +-#pragma once +-#include +-#include +- +-#include ++/* ++ * DISTRHO Cardinal Plugin ++ * Copyright (C) 2021-2022 Filipe Coelho ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 3 of ++ * the License, or any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * For a full copy of the GNU General Public License see the LICENSE file. ++ */ ++ ++/** ++ * This file is an edited version of VCVRack's midi.hpp ++ * Copyright (C) 2016-2021 VCV. ++ * ++ * This program is free software: you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 3 of ++ * the License, or (at your option) any later version. ++ */ + +-#include +-#include ++#pragma once + ++#include "choc/choc_SmallVector.h" + + namespace rack { + /** Abstraction for all MIDI drivers in Rack */ +@@ -15,7 +36,7 @@ + + struct Message { + /** Initialized to 3 empty bytes. */ +- std::vector bytes; ++ choc::SmallVector bytes; + /** The Engine frame timestamp of the Message. + For output messages, the frame when the message was generated. + For input messages, the frame when it is intended to be processed. +@@ -23,7 +44,9 @@ + */ + int64_t frame = -1; + +- Message() : bytes(3) {} ++ Message() { ++ bytes.resize(3); ++ } + + int getSize() const { + return bytes.size(); +@@ -87,213 +110,10 @@ + } + }; + +-//////////////////// +-// Driver +-//////////////////// +- +-struct InputDevice; +-struct Input; +-struct OutputDevice; +-struct Output; +- +-/** Wraps a MIDI driver API containing any number of MIDI devices. +-*/ +-struct Driver { +- virtual ~Driver() {} +- /** Returns the name of the driver. E.g. "ALSA". */ +- virtual std::string getName() { +- return ""; +- } +- /** Returns a list of all input device IDs that can be subscribed to. */ +- virtual std::vector getInputDeviceIds() { +- return {}; +- } +- /** Returns the default device to use when the driver is selected, or -1 for none. */ +- virtual int getDefaultInputDeviceId() { +- return -1; +- } +- /** Returns the name of an input device without obtaining it. */ +- virtual std::string getInputDeviceName(int deviceId) { +- return ""; +- } +- /** Adds the given port as a reference holder of a device and returns the it. +- Creates the Device if no ports are subscribed before calling. +- */ +- virtual InputDevice* subscribeInput(int deviceId, Input* input) { +- return NULL; +- } +- /** Removes the give port as a reference holder of a device. +- Deletes the Device if no ports are subscribed after calling. +- */ +- virtual void unsubscribeInput(int deviceId, Input* input) {} +- +- // The following behave identically as the above methods except for outputs. +- +- virtual std::vector getOutputDeviceIds() { +- return {}; +- } +- virtual int getDefaultOutputDeviceId() { +- return -1; +- } +- virtual std::string getOutputDeviceName(int deviceId) { +- return ""; +- } +- virtual OutputDevice* subscribeOutput(int deviceId, Output* output) { +- return NULL; +- } +- virtual void unsubscribeOutput(int deviceId, Output* output) {} +-}; +- +-//////////////////// +-// Device +-//////////////////// +- +-/** A single MIDI device of a driver API. +- +-Modules and the UI should not interact with this API directly. Use Port instead. +- +-Methods throw `rack::Exception` if the driver API has an exception. +-*/ +-struct Device { +- virtual ~Device() {} +- virtual std::string getName() { +- return ""; +- } +-}; +- +-struct InputDevice : Device { +- std::set subscribed; +- /** Not public. Use Driver::subscribeInput(). */ +- void subscribe(Input* input); +- /** Not public. Use Driver::unsubscribeInput(). */ +- void unsubscribe(Input* input); +- /** Called when a MIDI message is received from the device. */ +- void onMessage(const Message& message); +-}; +- +-struct OutputDevice : Device { +- std::set subscribed; +- /** Not public. Use Driver::subscribeOutput(). */ +- void subscribe(Output* output); +- /** Not public. Use Driver::unsubscribeOutput(). */ +- void unsubscribe(Output* output); +- /** Sends a MIDI message to the device. */ +- virtual void sendMessage(const Message& message) {} +-}; +- +-//////////////////// +-// Port +-//////////////////// +- +-/** A handle to a Device, typically owned by modules to have shared access to a single Device. +- +-All Port methods safely wrap Drivers methods. +-That is, if the active Device throws a `rack::Exception`, it is caught and logged inside all Port methods, so they do not throw exceptions. +- +-Use Input or Output subclasses in your module, not Port directly. +-*/ +-struct Port { +- /** For MIDI output, the channel to automatically set outbound messages. +- If -1, the channel is not overwritten and must be set by MIDI generator. +- +- For MIDI input, messages will be filtered by the channel. +- If -1, all MIDI channels pass through. +- */ +- int channel = -1; +- +- // private +- int driverId = -1; +- int deviceId = -1; +- /** Not owned */ +- Driver* driver = NULL; +- Device* device = NULL; +- Context* context; +- +- Port(); +- virtual ~Port(); +- +- Driver* getDriver(); +- int getDriverId(); +- void setDriverId(int driverId); +- +- Device* getDevice(); +- virtual std::vector getDeviceIds() = 0; +- virtual int getDefaultDeviceId() = 0; +- int getDeviceId(); +- virtual void setDeviceId(int deviceId) = 0; +- virtual std::string getDeviceName(int deviceId) = 0; +- +- virtual std::vector getChannels() = 0; +- int getChannel(); +- void setChannel(int channel); +- std::string getChannelName(int channel); +- +- json_t* toJson(); +- void fromJson(json_t* rootJ); +-}; +- +- +-struct Input : Port { +- /** Not owned */ +- InputDevice* inputDevice = NULL; +- +- Input(); +- ~Input(); +- void reset(); +- +- std::vector getDeviceIds() override; +- int getDefaultDeviceId() override; +- void setDeviceId(int deviceId) override; +- std::string getDeviceName(int deviceId) override; +- +- std::vector getChannels() override; +- +- virtual void onMessage(const Message& message) {} +-}; +- +- +-/** An Input port that stores incoming MIDI messages and releases them when ready according to their frame timestamp. +-*/ +-struct InputQueue : Input { +- struct Internal; +- Internal* internal; +- +- InputQueue(); +- ~InputQueue(); +- void onMessage(const Message& message) override; +- /** Pops and returns the next message (by setting `messageOut`) if its frame timestamp is `maxFrame` or earlier. +- Returns whether a message was returned. +- */ +- bool tryPop(Message* messageOut, int64_t maxFrame); +- size_t size(); +-}; +- +- +-struct Output : Port { +- /** Not owned */ +- OutputDevice* outputDevice = NULL; +- +- Output(); +- ~Output(); +- void reset(); +- +- std::vector getDeviceIds() override; +- int getDefaultDeviceId() override; +- void setDeviceId(int deviceId) override; +- std::string getDeviceName(int deviceId) override; +- +- std::vector getChannels() override; +- +- void sendMessage(const Message& message); +-}; +- + +-PRIVATE void init(); +-PRIVATE void destroy(); +-/** Registers a new MIDI driver. Takes pointer ownership. */ +-void addDriver(int driverId, Driver* driver); +-std::vector getDriverIds(); +-Driver* getDriver(int driverId); ++/* NOTE all the other MIDI stuff (drivers, ports etc) is purposefully missing here, unwanted in Cardinal ++ */ ++struct Port; + + + } // namespace midi diff --git a/src/override/diffs/minblep.cpp.diff b/src/override/diffs/minblep.cpp.diff new file mode 100644 index 00000000..def49969 --- /dev/null +++ b/src/override/diffs/minblep.cpp.diff @@ -0,0 +1,62 @@ +--- ../Rack/src/dsp/minblep.cpp 2022-09-21 20:49:12.200540736 +0200 ++++ minblep.cpp 2023-05-20 18:21:44.019059009 +0200 +@@ -1,3 +1,30 @@ ++/* ++ * DISTRHO Cardinal Plugin ++ * Copyright (C) 2021-2023 Filipe Coelho ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 3 of ++ * the License, or any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * For a full copy of the GNU General Public License see the LICENSE file. ++ */ ++ ++/** ++ * This file is an edited version of VCVRack's dsp/minblep.cpp ++ * Copyright (C) 2016-2023 VCV. ++ * ++ * This program is free software: you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 3 of ++ * the License, or (at your option) any later version. ++ */ ++ + #include + #include + #include +@@ -10,7 +37,7 @@ + void minBlepImpulse(int z, int o, float* output) { + // Symmetric sinc array with `z` zero-crossings on each side + int n = 2 * z * o; +- float* x = new float[n]; ++ float* x = (float*) pffft_aligned_malloc(sizeof(float) * n); + for (int i = 0; i < n; i++) { + float p = math::rescale((float) i, 0.f, (float)(n - 1), (float) - z, (float) z); + x[i] = sinc(p); +@@ -20,7 +47,7 @@ + blackmanHarrisWindow(x, n); + + // Real cepstrum +- float* fx = new float[2 * n]; ++ float* fx = (float*) pffft_aligned_malloc(sizeof(float) * 2 * n); + // Valgrind complains that the array is uninitialized for some reason, unless we clear it. + std::memset(fx, 0, sizeof(float) * 2 * n); + RealFFT rfft(n); +@@ -75,8 +102,8 @@ + std::memcpy(output, x, n * sizeof(float)); + + // Cleanup +- delete[] x; +- delete[] fx; ++ pffft_aligned_free(x); ++ pffft_aligned_free(fx); + } + + diff --git a/src/override/diffs/plugin.cpp.diff b/src/override/diffs/plugin.cpp.diff index 6e8392e6..d4fe4bf4 100644 --- a/src/override/diffs/plugin.cpp.diff +++ b/src/override/diffs/plugin.cpp.diff @@ -1,6 +1,6 @@ ---- ../Rack/src/plugin.cpp 2022-07-12 09:46:20.716165650 +0100 -+++ plugin.cpp 2022-05-27 23:15:35.681273727 +0100 -@@ -1,342 +1,41 @@ +--- ../Rack/src/plugin.cpp 2023-09-10 12:59:02.631898592 +0200 ++++ plugin.cpp 2023-05-20 18:43:27.496323540 +0200 +@@ -1,356 +1,46 @@ -#include -#include -#include @@ -20,7 +20,7 @@ -#include +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -37,7 +37,7 @@ + +/** + * This file is an edited version of VCVRack's plugin.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -133,7 +133,16 @@ -#elif ARCH_MAC - libraryExt = "dylib"; -#endif -- std::string libraryPath = system::join(plugin->path, "plugin." + libraryExt); +- +-#if defined ARCH_X64 +- // Use `plugin.EXT` on x64 for backward compatibility. +- // Change to `plugin-OS-CPU.EXT` in Rack 3. +- std::string libraryFilename = "plugin." + libraryExt; +-#else +- // Use `plugin-CPU.EXT` on other CPUs like ARM64 +- std::string libraryFilename = "plugin-" + APP_CPU + "." + libraryExt; +-#endif +- std::string libraryPath = system::join(plugin->path, libraryFilename); - - // Check file existence - if (!system::isFile(libraryPath)) @@ -227,7 +236,7 @@ - return NULL; - } - -- INFO("Loaded %s v%s", plugin->slug.c_str(), plugin->version.c_str()); +- INFO("Loaded %s %s", plugin->slug.c_str(), plugin->version.c_str()); - plugins.push_back(plugin); - return plugin; -} @@ -372,7 +381,13 @@ /** Given slug => fallback slug. -@@ -389,8 +88,19 @@ + Supports bidirectional fallbacks. +-To request fallback slugs to be added to this list, contact VCV support. ++To request fallback slugs to be added to this list, open a GitHub issue. + */ + static const std::map pluginSlugFallbacks = { + {"VultModulesFree", "VultModules"}, +@@ -399,8 +89,19 @@ */ using PluginModuleSlug = std::tuple; static const std::map moduleSlugFallbacks = { @@ -393,7 +408,7 @@ // {{"", ""}, {"", ""}}, }; -@@ -478,7 +188,6 @@ +@@ -488,7 +189,6 @@ } diff --git a/src/override/diffs/simd-Vector.hpp.diff b/src/override/diffs/simd-Vector.hpp.diff new file mode 100644 index 00000000..8b58b488 --- /dev/null +++ b/src/override/diffs/simd-Vector.hpp.diff @@ -0,0 +1,59 @@ +--- ../Rack/include/simd/Vector.hpp 2023-05-20 17:03:33.004081703 +0200 ++++ ../../include/simd/Vector.hpp 2022-12-02 20:11:45.779215949 +0100 +@@ -1,6 +1,37 @@ ++/* ++ * DISTRHO Cardinal Plugin ++ * Copyright (C) 2021-2022 Filipe Coelho ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 3 of ++ * the License, or any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * For a full copy of the GNU General Public License see the LICENSE file. ++ */ ++ ++/** ++ * This file is an edited version of VCVRack's simd/Vector.hpp ++ * Copyright (C) 2016-2021 VCV. ++ * ++ * This program is free software: you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 3 of ++ * the License, or (at your option) any later version. ++ */ ++ + #pragma once ++ + #include +-#include "common.hpp" ++#include ++ ++/** NOTE alignas is required in some systems in order to allow SSE usage. */ ++#define SIMD_ALIGN alignas(16) + + + namespace rack { +@@ -34,7 +65,7 @@ + using type = float; + constexpr static int size = 4; + +- union { ++ union SIMD_ALIGN { + __m128 v; + /** Accessing this array of scalars is slow and defeats the purpose of vectorizing. + */ +@@ -108,7 +139,7 @@ + using type = int32_t; + constexpr static int size = 4; + +- union { ++ union SIMD_ALIGN { + __m128i v; + int32_t s[4]; + }; diff --git a/src/override/minblep.cpp b/src/override/minblep.cpp index 6242b0df..fa5bbfe1 100644 --- a/src/override/minblep.cpp +++ b/src/override/minblep.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's dsp/minblep.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/override/plugin.cpp b/src/override/plugin.cpp index a23b26cb..957fe9db 100644 --- a/src/override/plugin.cpp +++ b/src/override/plugin.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's plugin.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -39,7 +39,7 @@ void settingsMergeJson(json_t*) {} /** Given slug => fallback slug. -Correctly handles bidirectional fallbacks. +Supports bidirectional fallbacks. To request fallback slugs to be added to this list, open a GitHub issue. */ static const std::map pluginSlugFallbacks = { @@ -47,6 +47,7 @@ static const std::map pluginSlugFallbacks = { {"VultModules", "VultModulesFree"}, {"AudibleInstrumentsPreview", "AudibleInstruments"}, {"SequelSequencers", "DanielDavies"}, + {"DelexanderVol1", "DelexandraVol1"}, // {"", ""}, }; diff --git a/utils/create-macos-installer.sh b/utils/create-macos-installer.sh index a465d2dc..c88d2d13 100755 --- a/utils/create-macos-installer.sh +++ b/utils/create-macos-installer.sh @@ -9,8 +9,8 @@ else exit fi -rm -rf res jack native au lv2 vst2 vst3 -mkdir jack native au lv2 vst2 vst3 +rm -rf res jack native au lv2 vst2 vst3 clap +mkdir jack native au lv2 vst2 vst3 clap mv Cardinal.app jack/CardinalJACK.app mv CardinalNative.app native/CardinalNative.app @@ -19,10 +19,12 @@ mv *.component au/ mv *.lv2 lv2/ mv *.vst vst2/ mv *.vst3 vst3/ +mv *.clap clap/ cp -RL lv2/Cardinal.lv2/resources res rm -rf lv2/*.lv2/resources rm -rf vst2/*.vst/Contents/Resources rm -rf vst3/*.vst3/Contents/Resources +rm -rf clap/*.clap/Contents/Resources pkgbuild \ --identifier "studio.kx.distrho.cardinal.resources" \ @@ -32,12 +34,14 @@ pkgbuild \ pkgbuild \ --identifier "studio.kx.distrho.plugins.cardinal.jack" \ + --component-plist "../utils/macOS/Build_JACK.plist" \ --install-location "/Applications/" \ --root "${PWD}/jack/" \ ../dpf-cardinal-jack.pkg pkgbuild \ --identifier "studio.kx.distrho.plugins.cardinal.native" \ + --component-plist "../utils/macOS/Build_Native.plist" \ --install-location "/Applications/" \ --root "${PWD}/native/" \ ../dpf-cardinal-native.pkg @@ -66,10 +70,15 @@ pkgbuild \ --root "${PWD}/vst3/" \ ../dpf-cardinal-vst3bundles.pkg +pkgbuild \ + --identifier "studio.kx.distrho.plugins.cardinal.clapbundles" \ + --install-location "/Library/Audio/Plug-Ins/CLAP/" \ + --root "${PWD}/clap/" \ + ../dpf-cardinal-clapbundles.pkg + cd .. sed -e "s|@builddir@|${PWD}/build|" \ - -e "s|@buildarchs@|${MACOS_ARCHS}|" \ utils/macOS/package.xml.in > build/package.xml productbuild \ diff --git a/utils/create-windows-installer.sh b/utils/create-windows-installer.sh index a6f2a213..638d5ad0 100755 --- a/utils/create-windows-installer.sh +++ b/utils/create-windows-installer.sh @@ -7,9 +7,19 @@ if [ ! -d bin ]; then exit fi -# args -bit=${1} -bit=${bit:=64} +if [ -z "${1}" ]; then + echo "usage: ${0} win32|win64" + exit +fi + +if [ "${1}" = "win32" ]; then + bit=32 +elif [ "${1}" = "win64" ]; then + bit=64 +else + echo "usage: ${0} win32|win64" + exit +fi # setup innosetup dlfile="${PWD}/bin/innosetup-6.0.5.exe" diff --git a/utils/distrho.rc b/utils/distrho.rc index e75698d7..91e98472 100644 --- a/utils/distrho.rc +++ b/utils/distrho.rc @@ -1 +1,2 @@ +id ICON "distrho.ico" 401 ICON "distrho.ico" diff --git a/utils/inno/win32.iss b/utils/inno/win32.iss index cff7ed9a..0aba6d39 100644 --- a/utils/inno/win32.iss +++ b/utils/inno/win32.iss @@ -27,6 +27,7 @@ Name: native; Description: "Standalone (Native)"; Types: custom; Name: lv2; Description: "LV2 plugin"; Types: normal; Name: vst2; Description: "VST2 plugin"; Types: normal; Name: vst3; Description: "VST3 plugin"; Types: normal; +Name: clap; Description: "CLAP plugin"; Types: normal; [Files] #include "resources.iss" @@ -35,6 +36,7 @@ Source: "..\..\utils\distrho.ico"; DestDir: "{app}"; Components: resources; Flag ; carla Source: "..\..\carla\bin\carla-bridge-*.*"; DestDir: "{commoncf32}\Cardinal\Carla"; Components: carla; Flags: ignoreversion; Source: "..\..\carla\bin\carla-discovery-*.exe"; DestDir: "{commoncf32}\Cardinal\Carla"; Components: carla; Flags: ignoreversion; +Source: "..\..\carla\bin\libcarla_frontend.dll"; DestDir: "{commoncf32}\Cardinal\Carla"; Components: carla; Flags: ignoreversion; Source: "..\..\carla\bin\libcarla_utils.dll"; DestDir: "{commoncf32}\Cardinal\Carla"; Components: carla; Flags: ignoreversion; Source: "..\..\carla\build\Carla\libpython3.8.dll"; DestDir: "{commoncf32}\Cardinal\Carla\resources"; Components: carla; Flags: ignoreversion; Source: "..\..\carla\build\Carla\Qt5*.dll"; DestDir: "{commoncf32}\Cardinal\Carla\resources"; Components: carla; Flags: ignoreversion; @@ -54,12 +56,72 @@ Source: "..\..\bin\Cardinal.lv2\*.*"; DestDir: "{commoncf32}\LV2\Cardinal.lv2"; Source: "..\..\bin\CardinalFX.lv2\*.*"; DestDir: "{commoncf32}\LV2\CardinalFX.lv2"; Components: lv2; Flags: ignoreversion; Source: "..\..\bin\CardinalSynth.lv2\*.*"; DestDir: "{commoncf32}\LV2\CardinalSynth.lv2"; Components: lv2; Flags: ignoreversion; ; vst2 -Source: "..\..\bin\Cardinal.vst\*.*"; DestDir: "{commoncf32}\VST2\Cardinal.vst"; Components: vst2; Flags: ignoreversion; +Source: "..\..\bin\Cardinal.vst\*.*"; DestDir: "{code:GetVST2Dir}\Cardinal.vst"; Components: vst2; Flags: ignoreversion; ; vst3 Source: "..\..\bin\Cardinal.vst3\Contents\x86-win\Cardinal.vst3"; DestDir: "{commoncf32}\VST3\Cardinal.vst3\Contents\x86-win"; Components: vst3; Flags: ignoreversion; Source: "..\..\bin\CardinalFX.vst3\Contents\x86-win\CardinalFX.vst3"; DestDir: "{commoncf32}\VST3\CardinalFX.vst3\Contents\x86-win"; Components: vst3; Flags: ignoreversion; Source: "..\..\bin\CardinalSynth.vst3\Contents\x86-win\CardinalSynth.vst3"; DestDir: "{commoncf32}\VST3\CardinalSynth.vst3\Contents\x86-win"; Components: vst3; Flags: ignoreversion; +; clap +Source: "..\..\bin\Cardinal.clap\*.*"; DestDir: "{commoncf32}\CLAP\Cardinal.clap"; Components: clap; Flags: ignoreversion; [Icons] Name: "{commonprograms}\Cardinal (JACK)"; Filename: "{app}\Cardinal.exe"; IconFilename: "{app}\distrho.ico"; WorkingDir: "{app}"; Comment: "Virtual modular synthesizer plugin (JACK variant)"; Components: jack; Name: "{commonprograms}\Cardinal (Native)"; Filename: "{app}\CardinalNative.exe"; IconFilename: "{app}\distrho.ico"; WorkingDir: "{app}"; Comment: "Virtual modular synthesizer plugin (Native variant)"; Components: native; + +; based on https://www.kvraudio.com/forum/viewtopic.php?t=501615 +[Code] +var + VST2DirPage: TInputDirWizardPage; + TypesComboOnChangePrev: TNotifyEvent; +procedure ComponentsListCheckChanges; +begin + WizardForm.NextButton.Enabled := (WizardSelectedComponents(False) <> ''); +end; +procedure ComponentsListClickCheck(Sender: TObject); +begin + ComponentsListCheckChanges; +end; +procedure TypesComboOnChange(Sender: TObject); +begin + TypesComboOnChangePrev(Sender); + ComponentsListCheckChanges; +end; +procedure InitializeWizard; +begin + WizardForm.ComponentsList.OnClickCheck := @ComponentsListClickCheck; + TypesComboOnChangePrev := WizardForm.TypesCombo.OnChange; + WizardForm.TypesCombo.OnChange := @TypesComboOnChange; + VST2DirPage := CreateInputDirPage(wpSelectComponents, + 'Confirm VST2 Plugin Directory', '', + 'Select the folder in which setup should install the VST2 Plugin, then click Next.', + False, ''); + VST2DirPage.Add('VST2 Plugin Directory'); + VST2DirPage.Values[0] := ExpandConstant('{reg:HKLM\SOFTWARE\VST,VSTPluginsPath|{commonpf32}\VSTPlugins}'); +end; +procedure CurPageChanged(CurPageID: Integer); +begin + if CurPageID = VST2DirPage.ID then + begin + VST2DirPage.Buttons[0].Enabled := WizardIsComponentSelected('vst2'); + VST2DirPage.PromptLabels[0].Enabled := VST2DirPage.Buttons[0].Enabled; + VST2DirPage.Edits[0].Enabled := VST2DirPage.Buttons[0].Enabled; + end; + if CurPageID = wpSelectComponents then + begin + ComponentsListCheckChanges; + end; +end; +function ShouldSkipPage(PageID: Integer): Boolean; +begin + if PageID = VST2DirPage.ID then + begin + If (not WizardIsComponentSelected('vst2'))then + begin + Result := True + end; + end; +end; +function GetVST2Dir(Param: string): string; +begin + Result := VST2DirPage.Values[0]; +end; diff --git a/utils/inno/win64.iss b/utils/inno/win64.iss index 90cfa810..b840f7ba 100644 --- a/utils/inno/win64.iss +++ b/utils/inno/win64.iss @@ -28,6 +28,7 @@ Name: native; Description: "Standalone (Native)"; Types: custom; Name: lv2; Description: "LV2 plugin"; Types: normal; Name: vst2; Description: "VST2 plugin"; Types: normal; Name: vst3; Description: "VST3 plugin"; Types: normal; +Name: clap; Description: "CLAP plugin"; Types: normal; [Files] #include "resources.iss" @@ -37,6 +38,7 @@ Source: "..\..\utils\distrho.ico"; DestDir: "{app}"; Components: resources; Flag Source: "..\..\carla\bin\carla-bridge-*.*"; DestDir: "{commoncf64}\Cardinal\Carla"; Components: carla; Flags: ignoreversion; Source: "..\..\carla\bin\carla-discovery-*.exe"; DestDir: "{commoncf64}\Cardinal\Carla"; Components: carla; Flags: ignoreversion; Source: "..\..\carla\bin\libcarla_utils.dll"; DestDir: "{commoncf64}\Cardinal\Carla"; Components: carla; Flags: ignoreversion; +Source: "..\..\carla\bin\libcarla_frontend.dll"; DestDir: "{commoncf64}\Cardinal\Carla"; Components: carla; Flags: ignoreversion; Source: "..\..\carla\build\Carla\libpython3.8.dll"; DestDir: "{commoncf64}\Cardinal\Carla\resources"; Components: carla; Flags: ignoreversion; Source: "..\..\carla\build\Carla\Qt5*.dll"; DestDir: "{commoncf64}\Cardinal\Carla\resources"; Components: carla; Flags: ignoreversion; Source: "..\..\carla\build\Carla\resources\*.*"; DestDir: "{commoncf64}\Cardinal\Carla\resources"; Components: carla; Flags: ignoreversion; @@ -55,12 +57,72 @@ Source: "..\..\bin\Cardinal.lv2\*.*"; DestDir: "{commoncf64}\LV2\Cardinal.lv2"; Source: "..\..\bin\CardinalFX.lv2\*.*"; DestDir: "{commoncf64}\LV2\CardinalFX.lv2"; Components: lv2; Flags: ignoreversion; Source: "..\..\bin\CardinalSynth.lv2\*.*"; DestDir: "{commoncf64}\LV2\CardinalSynth.lv2"; Components: lv2; Flags: ignoreversion; ; vst2 -Source: "..\..\bin\Cardinal.vst\*.*"; DestDir: "{commoncf64}\VST2\Cardinal.vst"; Components: vst2; Flags: ignoreversion; +Source: "..\..\bin\Cardinal.vst\*.*"; DestDir: "{code:GetVST2Dir}\Cardinal.vst"; Components: vst2; Flags: ignoreversion; ; vst3 Source: "..\..\bin\Cardinal.vst3\Contents\x86_64-win\Cardinal.vst3"; DestDir: "{commoncf64}\VST3\Cardinal.vst3\Contents\x86_64-win"; Components: vst3; Flags: ignoreversion; Source: "..\..\bin\CardinalFX.vst3\Contents\x86_64-win\CardinalFX.vst3"; DestDir: "{commoncf64}\VST3\CardinalFX.vst3\Contents\x86_64-win"; Components: vst3; Flags: ignoreversion; Source: "..\..\bin\CardinalSynth.vst3\Contents\x86_64-win\CardinalSynth.vst3"; DestDir: "{commoncf64}\VST3\CardinalSynth.vst3\Contents\x86_64-win"; Components: vst3; Flags: ignoreversion; +; clap +Source: "..\..\bin\Cardinal.clap\*.*"; DestDir: "{commoncf64}\CLAP\Cardinal.clap"; Components: clap; Flags: ignoreversion; [Icons] Name: "{commonprograms}\Cardinal (JACK)"; Filename: "{app}\Cardinal.exe"; IconFilename: "{app}\distrho.ico"; WorkingDir: "{app}"; Comment: "Virtual modular synthesizer plugin (JACK variant)"; Components: jack; Name: "{commonprograms}\Cardinal (Native)"; Filename: "{app}\CardinalNative.exe"; IconFilename: "{app}\distrho.ico"; WorkingDir: "{app}"; Comment: "Virtual modular synthesizer plugin (Native variant)"; Components: native; + +; based on https://www.kvraudio.com/forum/viewtopic.php?t=501615 +[Code] +var + VST2DirPage: TInputDirWizardPage; + TypesComboOnChangePrev: TNotifyEvent; +procedure ComponentsListCheckChanges; +begin + WizardForm.NextButton.Enabled := (WizardSelectedComponents(False) <> ''); +end; +procedure ComponentsListClickCheck(Sender: TObject); +begin + ComponentsListCheckChanges; +end; +procedure TypesComboOnChange(Sender: TObject); +begin + TypesComboOnChangePrev(Sender); + ComponentsListCheckChanges; +end; +procedure InitializeWizard; +begin + WizardForm.ComponentsList.OnClickCheck := @ComponentsListClickCheck; + TypesComboOnChangePrev := WizardForm.TypesCombo.OnChange; + WizardForm.TypesCombo.OnChange := @TypesComboOnChange; + VST2DirPage := CreateInputDirPage(wpSelectComponents, + 'Confirm VST2 Plugin Directory', '', + 'Select the folder in which setup should install the VST2 Plugin, then click Next.', + False, ''); + VST2DirPage.Add('VST2 Plugin Directory'); + VST2DirPage.Values[0] := ExpandConstant('{reg:HKLM\SOFTWARE\VST,VSTPluginsPath|{commonpf64}\VSTPlugins}'); +end; +procedure CurPageChanged(CurPageID: Integer); +begin + if CurPageID = VST2DirPage.ID then + begin + VST2DirPage.Buttons[0].Enabled := WizardIsComponentSelected('vst2'); + VST2DirPage.PromptLabels[0].Enabled := VST2DirPage.Buttons[0].Enabled; + VST2DirPage.Edits[0].Enabled := VST2DirPage.Buttons[0].Enabled; + end; + if CurPageID = wpSelectComponents then + begin + ComponentsListCheckChanges; + end; +end; +function ShouldSkipPage(PageID: Integer): Boolean; +begin + if PageID = VST2DirPage.ID then + begin + If (not WizardIsComponentSelected('vst2'))then + begin + Result := True + end; + end; +end; +function GetVST2Dir(Param: string): string; +begin + Result := VST2DirPage.Values[0]; +end; diff --git a/utils/macOS/Build_JACK.plist b/utils/macOS/Build_JACK.plist new file mode 100644 index 00000000..6495e197 --- /dev/null +++ b/utils/macOS/Build_JACK.plist @@ -0,0 +1,18 @@ + + + + + + BundleHasStrictIdentifier + + BundleIsRelocatable + + BundleIsVersionChecked + + BundleOverwriteAction + upgrade + RootRelativeBundlePath + CardinalJACK.app + + + diff --git a/utils/macOS/Build_Native.plist b/utils/macOS/Build_Native.plist new file mode 100644 index 00000000..a206413b --- /dev/null +++ b/utils/macOS/Build_Native.plist @@ -0,0 +1,18 @@ + + + + + + BundleHasStrictIdentifier + + BundleIsRelocatable + + BundleIsVersionChecked + + BundleOverwriteAction + upgrade + RootRelativeBundlePath + CardinalNative.app + + + diff --git a/utils/macOS/Info_JACK.plist b/utils/macOS/Info_JACK.plist index 40d6d665..4b6644c7 100644 --- a/utils/macOS/Info_JACK.plist +++ b/utils/macOS/Info_JACK.plist @@ -9,7 +9,14 @@ CFBundleIconFile distrho.icns CFBundleIdentifier - Cardinal + studio.kx.distrho.cardinal.jack + CFBundleShortVersionString + 23.10 + LSMinimumSystemVersion + 10.15 + NSHumanReadableCopyright + (C) 2011-2023 Filipe Coelho. +This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or any later version. NSHighResolutionCapable NSRequiresAquaSystemAppearance diff --git a/utils/macOS/Info_Native.plist b/utils/macOS/Info_Native.plist index bfc67c13..e1e6d35f 100644 --- a/utils/macOS/Info_Native.plist +++ b/utils/macOS/Info_Native.plist @@ -9,7 +9,14 @@ CFBundleIconFile distrho.icns CFBundleIdentifier - CardinalNative + studio.kx.distrho.cardinal.native + CFBundleShortVersionString + 23.10 + LSMinimumSystemVersion + 10.15 + NSHumanReadableCopyright + (C) 2011-2023 Filipe Coelho. +This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or any later version. NSHighResolutionCapable NSRequiresAquaSystemAppearance diff --git a/utils/macOS/package.xml.in b/utils/macOS/package.xml.in index 381a28bb..eae843ac 100644 --- a/utils/macOS/package.xml.in +++ b/utils/macOS/package.xml.in @@ -3,30 +3,33 @@ Cardinal - + - + dpf-cardinal-resources.pkg - + dpf-cardinal-jack.pkg - + dpf-cardinal-native.pkg - + dpf-cardinal-components.pkg - + dpf-cardinal-lv2bundles.pkg - + dpf-cardinal-vst2bundles.pkg - + dpf-cardinal-vst3bundles.pkg + + dpf-cardinal-clapbundles.pkg + @@ -35,5 +38,6 @@ + diff --git a/utils/macOS/welcome.txt b/utils/macOS/welcome.txt index 48a4ca01..44cf7bb1 100644 --- a/utils/macOS/welcome.txt +++ b/utils/macOS/welcome.txt @@ -6,7 +6,7 @@ They are all equivalent in performance and behaviour. FX and Synth variants both have 2 audio outputs, while "main" has 8. All variants have MIDI input and output support. -This package provides the AU, LV2, VST2 and VST3 audio plugins, plus standalones for both JACK and native audio/MIDI. +This package provides the AU, LV2, VST2, VST3 and CLAP audio plugins, plus standalones for both JACK and native audio/MIDI. Notes: - Due to AU and VST2 not supporting CV ports, the main variant is not available for these formats