diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fdc73725..a05f5aee 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,7 @@ on: push: env: - CACHE_VERSION: 6 + CACHE_VERSION: 19 DEBIAN_FRONTEND: noninteractive HOMEBREW_NO_AUTO_UPDATE: 1 LIBGL_ALWAYS_SOFTWARE: 'true' @@ -17,10 +17,31 @@ jobs: with: submodules: recursive - name: Set up cache + id: cache uses: actions/cache@v2 with: path: | ~/PawPawBuilds + */*.a + bin/*.*/*.so + bin/*.vst3/Contents/*/*.so + bin/Cardinal + build/Cardinal + build/CardinalFX + build/CardinalSynth + build/plugins + build/rack + carla/build + dpf/build + 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-arm64-v${{ env.CACHE_VERSION }} - name: Fix GitHub's mess run: | @@ -40,12 +61,12 @@ jobs: env: PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig run: | - ./deps/PawPaw/bootstrap-cardinal.sh linux-aarch64 + ./deps/PawPaw/bootstrap-cardinal.sh linux-aarch64 && ./deps/PawPaw/.cleanup.sh linux-aarch64 - name: Build linux arm64 cross-compiled run: | pushd deps/PawPaw; source local.env linux-aarch64; popd make features - make NOOPT=true WITH_LTO=true -j $(nproc) + make CIBUILD=true NOOPT=true WITH_LTO=true -j $(nproc) make unzipfx - name: Set sha8 (non-release) if: startsWith(github.ref, 'refs/tags/') != true @@ -83,10 +104,31 @@ jobs: with: submodules: recursive - name: Set up cache + id: cache uses: actions/cache@v2 with: path: | ~/PawPawBuilds + */*.a + bin/*.*/*.so + bin/*.vst3/Contents/*/*.so + bin/Cardinal + build/Cardinal + build/CardinalFX + build/CardinalSynth + build/plugins + build/rack + carla/build + dpf/build + 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 }} - name: Fix GitHub's mess run: | @@ -106,12 +148,12 @@ jobs: env: PKG_CONFIG_PATH: /usr/lib/arm-linux-gnueabihf/pkgconfig run: | - ./deps/PawPaw/bootstrap-cardinal.sh linux-armhf + ./deps/PawPaw/bootstrap-cardinal.sh linux-armhf && ./deps/PawPaw/.cleanup.sh linux-armhf - name: Build linux armhf cross-compiled run: | pushd deps/PawPaw; source local.env linux-armhf; popd make features - make NOOPT=true WITH_LTO=true -j $(nproc) + make CIBUILD=true NOOPT=true WITH_LTO=true -j $(nproc) make unzipfx - name: Set sha8 (non-release) if: startsWith(github.ref, 'refs/tags/') != true @@ -149,10 +191,31 @@ jobs: with: submodules: recursive - name: Set up cache + id: cache uses: actions/cache@v2 with: path: | ~/PawPawBuilds + */*.a + bin/*.*/*.so + bin/*.vst3/Contents/*/*.so + bin/Cardinal + build/Cardinal + build/CardinalFX + build/CardinalSynth + build/plugins + build/rack + carla/build + dpf/build + 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 }} - name: Fix GitHub's mess run: | @@ -168,12 +231,12 @@ jobs: env: PKG_CONFIG_PATH: /usr/lib/i386-linux-gnu/pkgconfig run: | - ./deps/PawPaw/bootstrap-cardinal.sh linux-i686 + ./deps/PawPaw/bootstrap-cardinal.sh linux-i686 && ./deps/PawPaw/.cleanup.sh linux-i686 - name: Build linux i686 run: | pushd deps/PawPaw; source local.env linux-i686; popd make features - make NOOPT=true WITH_LTO=true -j $(nproc) + make CIBUILD=true NOOPT=true WITH_LTO=true -j $(nproc) make unzipfx - name: Set sha8 (non-release) if: startsWith(github.ref, 'refs/tags/') != true @@ -211,10 +274,31 @@ jobs: with: submodules: recursive - name: Set up cache + id: cache uses: actions/cache@v2 with: path: | ~/PawPawBuilds + */*.a + bin/*.*/*.so + bin/*.vst3/Contents/*/*.so + bin/Cardinal + build/Cardinal + build/CardinalFX + build/CardinalSynth + build/plugins + build/rack + carla/build + dpf/build + 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 }} - name: Set up dependencies run: | @@ -222,12 +306,12 @@ jobs: sudo apt-get install -yqq libdbus-1-dev libgl1-mesa-dev libglib2.0-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev - name: Build extra dependencies run: | - ./deps/PawPaw/bootstrap-cardinal.sh linux + ./deps/PawPaw/bootstrap-cardinal.sh linux && ./deps/PawPaw/.cleanup.sh linux - name: Build linux x86_64 run: | pushd deps/PawPaw; source local.env linux; popd make features - make NOOPT=true WITH_LTO=true -j $(nproc) + make CIBUILD=true NOOPT=true WITH_LTO=true -j $(nproc) make unzipfx - name: Set sha8 (non-release) if: startsWith(github.ref, 'refs/tags/') != true @@ -317,6 +401,89 @@ jobs: make features make SYSDEPS=true -j $(nproc) + macos-intel: + runs-on: macos-10.15 + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Set up cache + id: cache + uses: actions/cache@v2 + with: + path: | + ~/PawPawBuilds + */*.a + bin/*.*/*.dylib + bin/*.*/Contents/MacOS/* + bin/Cardinal + build/Cardinal + build/CardinalFX + build/CardinalSynth + build/plugins + build/rack + carla/build + dpf/build + jucewrapper/build + 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-intel-v${{ env.CACHE_VERSION }} + - name: Build extra dependencies + run: | + ./deps/PawPaw/bootstrap-cardinal.sh macos && ./deps/PawPaw/.cleanup.sh macos + - name: Build macOS intel (base) + run: | + pushd deps/PawPaw; source local.env macos; popd + make features + make CIBUILD=true NOOPT=true WITH_LTO=true -j $(sysctl -n hw.logicalcpu) + - name: Build macOS intel (AU using juce) + run: | + pushd deps/PawPaw; source local.env macos; popd + git clone --depth=1 -b master 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_OSX_ARCHITECTURES=x86_64 -DCMAKE_OSX_DEPLOYMENT_TARGET=10.8 -DCMAKE_BUILD_TYPE=Release .. && make -j $(sysctl -n hw.logicalcpu); popd + mv jucewrapper/build/*_artefacts/Release/AU/*.component bin/ + - name: Build macOS intel (packaging) + 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-10.15 steps: @@ -324,10 +491,32 @@ jobs: with: submodules: recursive - name: Set up cache + id: cache uses: actions/cache@v2 with: path: | ~/PawPawBuilds + */*.a + bin/*.*/*.dylib + bin/*.*/Contents/MacOS/* + bin/Cardinal + build/Cardinal + build/CardinalFX + build/CardinalSynth + build/plugins + build/rack + carla/build + dpf/build + jucewrapper/build + 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 }} - name: Fix up Xcode run: | @@ -335,13 +524,23 @@ jobs: sudo xcode-select -s "/Applications/Xcode_12.3.app" - name: Build extra dependencies run: | - ./deps/PawPaw/bootstrap-cardinal.sh macos-universal - - name: Build macOS universal + ./deps/PawPaw/bootstrap-cardinal.sh macos-universal && ./deps/PawPaw/.cleanup.sh macos-universal + - name: Build macOS universal (base) run: | pushd deps/PawPaw; source local.env macos-universal; popd make features - make NOOPT=true WITH_LTO=true -j $(sysctl -n hw.logicalcpu) - ./dpf/utils/package-osx-bundles.sh + make CIBUILD=true NOOPT=true WITH_LTO=true -j $(sysctl -n hw.logicalcpu) + - name: Build macOS universal (AU using juce) + run: | + pushd deps/PawPaw; source local.env macos-universal; popd + git clone --depth=1 -b master https://github.com/juce-framework/JUCE.git jucewrapper/JUCE + mkdir -p jucewrapper/build + pushd jucewrapper/build; cmake -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' -DCMAKE_OSX_DEPLOYMENT_TARGET=10.12 -DCMAKE_BUILD_TYPE=Release .. && make -j $(sysctl -n hw.logicalcpu); popd + mv jucewrapper/build/*_artefacts/Release/AU/*.component bin/ + - name: Build macOS universal (packaging) + run: | + pushd deps/PawPaw; source local.env macos-universal; popd + ./utils/create-macos-installer.sh - name: Set sha8 (non-release) if: startsWith(github.ref, 'refs/tags/') != true id: slug1 @@ -355,7 +554,7 @@ jobs: 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-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}.pkg + 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 with: name: ${{ github.event.repository.name }}-macOS-universal-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} @@ -495,10 +694,31 @@ jobs: with: submodules: recursive - name: Set up cache + id: cache uses: actions/cache@v2 with: path: | ~/PawPawBuilds + */*.a + bin/*.*/*.dll + bin/*.vst3/Contents/*/*.vst3 + bin/Cardinal.exe + build/Cardinal + build/CardinalFX + build/CardinalSynth + build/plugins + build/rack + carla/build + dpf/build + 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: win32-v${{ env.CACHE_VERSION }} - name: Fix GitHub's mess run: | @@ -509,15 +729,25 @@ jobs: 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 + sudo apt-get install -yqq binutils-mingw-w64-i686 g++-mingw-w64-i686 mingw-w64 wine-stable:i386 qttools5-dev qttools5-dev-tools xvfb - name: Build extra dependencies run: | - ./deps/PawPaw/bootstrap-cardinal.sh win32 - - name: Build win32 cross-compiled + ./deps/PawPaw/bootstrap-cardinal.sh win32 && ./deps/PawPaw/.cleanup.sh win32 + - name: Build win32 cross-compiled (base) run: | pushd deps/PawPaw; source local.env win32; popd make features - make NOOPT=true WITH_LTO=true -j $(nproc) + make CIBUILD=true NOOPT=true WITH_LTO=true -j $(nproc) + - name: Build win64 cross-compiled (carla) + run: | + 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_JUCE=false USING_JUCE_GUI_EXTRA=false -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) + run: | + pushd deps/PawPaw; source local.env win32; popd + xvfb-run ./utils/create-windows-installer.sh 32 - name: Set sha8 (non-release) if: startsWith(github.ref, 'refs/tags/') != true id: slug1 @@ -536,6 +766,7 @@ jobs: with: name: ${{ github.event.repository.name }}-win32-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} path: | + *.exe *.zip - uses: softprops/action-gh-release@v1 if: startsWith(github.ref, 'refs/tags/') @@ -545,6 +776,7 @@ jobs: draft: false prerelease: false files: | + *.exe *.zip win64: @@ -554,10 +786,31 @@ jobs: with: submodules: recursive - name: Set up cache + id: cache uses: actions/cache@v2 with: path: | ~/PawPawBuilds + */*.a + bin/*.*/*.dll + bin/*.vst3/Contents/*/*.vst3 + bin/Cardinal.exe + build/Cardinal + build/CardinalFX + build/CardinalSynth + build/plugins + build/rack + carla/build + dpf/build + 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 }} - name: Fix GitHub's mess run: | @@ -566,16 +819,27 @@ jobs: 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 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 + 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: Build extra dependencies run: | - ./deps/PawPaw/bootstrap-cardinal.sh win64 - - name: Build win64 cross-compiled + ./deps/PawPaw/bootstrap-cardinal.sh win64 && ./deps/PawPaw/.cleanup.sh win64 + - name: Build win64 cross-compiled (base) run: | pushd deps/PawPaw; source local.env win64; popd make features - make NOOPT=true WITH_LTO=true -j $(nproc) + make CIBUILD=true NOOPT=true WITH_LTO=true -j $(nproc) + - name: Build win64 cross-compiled (carla) + run: | + 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_JUCE=false USING_JUCE_GUI_EXTRA=false 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) + 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 @@ -594,6 +858,7 @@ jobs: 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/') @@ -603,6 +868,7 @@ jobs: draft: false prerelease: false files: | + *.exe *.zip source-tarball: @@ -662,17 +928,17 @@ jobs: sudo dpkg -i kxstudio-repos_10.0.3_all.deb sudo apt-get update -qq # build-deps - sudo apt-get install -yqq libgl1-mesa-dev liblo-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev + sudo apt-get install -yqq liblo-dev # runtime testing sudo apt-get install -yqq carla-git lilv-utils lv2-dev lv2lint valgrind - - name: Build plugins + - name: Build Cardinal env: CFLAGS: -g CXXFLAGS: -g -DDPF_ABORT_ON_ERROR LDFLAGS: -static-libgcc -static-libstdc++ run: | - make features - make NOOPT=true SKIP_STRIPPING=true -j $(nproc) + make HEADLESS=true features + make HEADLESS=true NOOPT=true NOPLUGINS=true STATIC_BUILD=true SKIP_STRIPPING=true -j $(nproc) - name: Validate LV2 ttl syntax run: | lv2_validate \ @@ -681,14 +947,14 @@ jobs: /usr/lib/lv2/kx-control-input-port-change-request.lv2/*.ttl \ /usr/lib/lv2/kx-programs.lv2/*.ttl \ ./bin/*.lv2/*.ttl - #- name: Validate LV2 metadata and binaries - #run: | - #export LV2_PATH=/tmp/lv2-path - #mkdir ${LV2_PATH} - #cp -r bin/*.lv2 \ - #/usr/lib/lv2/{atom,buf-size,core,data-access,kx-control-input-port-change-request,kx-programs,instance-access,midi,parameters,port-groups,port-props,options,patch,presets,resize-port,state,time,ui,units,urid,worker}.lv2 \ - #${LV2_PATH} - #lv2lint -s lv2_generate_ttl -l ld-linux-x86-64.so.2 -M nopack $(lv2ls) + - 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} + lv2lint -s lv2_generate_ttl -l ld-linux-x86-64.so.2 -M nopack $(lv2ls) - name: Test LV2 plugin run: | export LV2_PATH=/tmp/lv2-path @@ -701,27 +967,25 @@ jobs: --suppressions=./dpf/utils/valgrind-dpf.supp \ /usr/lib/carla/carla-bridge-native lv2 "" ${p} 1>/dev/null; \ done - # - name: Test VST2 plugin - # env: - # CARLA_DO_NOT_USE_JUCE_FOR_VST2: 1 - # run: | - # for p in $(ls bin/*.vst/*.so); do \ - # env CARLA_BRIDGE_DUMMY=1 CARLA_BRIDGE_TESTING=native \ - # valgrind \ - # --error-exitcode=255 \ - # --leak-check=no \ - # --track-origins=yes \ - # --suppressions=./dpf/utils/valgrind-dpf.supp \ - # /usr/lib/carla/carla-bridge-native vst2 ./${p} "" 1>/dev/null; \ - # done - # - name: Test VST3 plugin - # run: | - # for p in $(ls bin/ | grep vst3); do \ - # env CARLA_BRIDGE_DUMMY=1 CARLA_BRIDGE_TESTING=native \ - # valgrind \ - # --error-exitcode=255 \ - # --leak-check=no \ - # --track-origins=yes \ - # --suppressions=./dpf/utils/valgrind-dpf.supp \ - # /usr/lib/carla/carla-bridge-native vst3 ./bin/${p} "" 1>/dev/null; \ - # done + - name: Test VST2 plugin + run: | + for p in $(ls bin/*.vst/*.so); do \ + env CARLA_BRIDGE_DUMMY=1 CARLA_BRIDGE_TESTING=native \ + valgrind \ + --error-exitcode=255 \ + --leak-check=no \ + --track-origins=yes \ + --suppressions=./dpf/utils/valgrind-dpf.supp \ + /usr/lib/carla/carla-bridge-native vst2 ./${p} "" 1>/dev/null; \ + done + - name: Test VST3 plugin + run: | + for p in $(ls bin/ | grep vst3); do \ + env CARLA_BRIDGE_DUMMY=1 CARLA_BRIDGE_TESTING=native \ + valgrind \ + --error-exitcode=255 \ + --leak-check=no \ + --track-origins=yes \ + --suppressions=./dpf/utils/valgrind-dpf.supp \ + /usr/lib/carla/carla-bridge-native vst3 ./bin/${p} "" 1>/dev/null; \ + done diff --git a/.gitignore b/.gitignore index 135e906a..9e158373 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ bin/ build/ documentation.pdf +utils/inno/resources.iss +utils/inno/version.iss diff --git a/.gitmodules b/.gitmodules index 30bed9af..01450977 100644 --- a/.gitmodules +++ b/.gitmodules @@ -84,7 +84,7 @@ url = https://gitlab.com/sonusdept/sonusmodular.git [submodule "plugins/Mog"] path = plugins/Mog - url = https://github.com/CardinalModules/Mog-VCV.git + url = https://github.com/JustMog/Mog-VCV.git [submodule "plugins/ChowDSP"] path = plugins/ChowDSP url = https://github.com/jatinchowdhury18/ChowDSP-VCV.git @@ -130,9 +130,6 @@ [submodule "plugins/Autinn"] path = plugins/Autinn url = https://github.com/NikolaiVChr/Autinn.git -[submodule "plugins/substation-opensource"] - path = plugins/substation-opensource - url = https://gitlab.com/falktx/substation-opensource.git [submodule "plugins/MockbaModular"] path = plugins/MockbaModular url = https://github.com/MockbaTheBorg/MockbaModular.git @@ -169,9 +166,6 @@ [submodule "plugins/PathSet"] path = plugins/PathSet url = https://github.com/patheros/PathSetModules.git -[submodule "plugins/Dintree"] - path = plugins/Dintree - url = https://github.com/hires/Dintree-Virtual.git [submodule "plugins/Algoritmarte"] path = plugins/Algoritmarte url = https://github.com/algoritmarte/AlgoritmarteVCVPlugin.git @@ -184,6 +178,21 @@ [submodule "plugins/nonlinearcircuits"] path = plugins/nonlinearcircuits url = https://github.com/mhetrick/nonlinearcircuits.git +[submodule "plugins/voxglitch"] + path = plugins/voxglitch + url = https://github.com/clone45/voxglitch.git +[submodule "plugins/ArableInstruments"] + path = plugins/ArableInstruments + url = https://github.com/CardinalModules/ArableInstruments.git +[submodule "plugins/Fundamental"] + path = plugins/Fundamental + url = https://github.com/CardinalModules/Fundamental.git +[submodule "plugins/unless_modules"] + path = plugins/unless_modules + url = https://gitlab.com/unlessgames/unless_modules.git +[submodule "plugins/PinkTrombone"] + path = plugins/PinkTrombone + url = https://github.com/VegaDeftwing/PinkTromboneVCV.git [submodule "plugins/StarlingVia"] path = plugins/StarlingVia url = https://github.com/starlingcode/Via-for-Rack.git diff --git a/Makefile b/Makefile index 67f82eef..be7735c7 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ # also set in: # src/CardinalCommon.cpp `CARDINAL_VERSION` # src/CardinalPlugin.cpp `getVersion` -VERSION = 22.02 +VERSION = 22.04 # -------------------------------------------------------------- # Import base definitions @@ -57,6 +57,15 @@ endif CARLA_EXTRA_ARGS += USING_JUCE=false CARLA_EXTRA_ARGS += USING_JUCE_GUI_EXTRA=false +# -------------------------------------------------------------- +# DGL config + +DGL_EXTRA_ARGS = \ + NVG_DISABLE_SKIPPING_WHITESPACE=true \ + NVG_FONT_TEXTURE_FLAGS=NVG_IMAGE_NEAREST \ + USE_NANOVG_FBO=true \ + WINDOWS_ICON_ID=401 + # -------------------------------------------------------------- # Check for system-wide dependencies @@ -196,7 +205,7 @@ endif dgl: ifneq ($(HEADLESS),true) - $(MAKE) -C dpf/dgl opengl NVG_DISABLE_SKIPPING_WHITESPACE=true NVG_FONT_TEXTURE_FLAGS=NVG_IMAGE_NEAREST USE_NANOVG_FBO=true + $(MAKE) -C dpf/dgl opengl $(DGL_EXTRA_ARGS) endif plugins: deps @@ -255,8 +264,7 @@ install: install -d $(DESTDIR)$(PREFIX)/lib/lv2/Cardinal.lv2 install -d $(DESTDIR)$(PREFIX)/lib/lv2/CardinalFX.lv2 install -d $(DESTDIR)$(PREFIX)/lib/lv2/CardinalSynth.lv2 - install -d $(DESTDIR)$(PREFIX)/lib/vst/CardinalFX.vst - install -d $(DESTDIR)$(PREFIX)/lib/vst/CardinalSynth.vst + 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 @@ -269,8 +277,7 @@ endif install -m 644 bin/CardinalFX.lv2/*.* $(DESTDIR)$(PREFIX)/lib/lv2/CardinalFX.lv2/ install -m 644 bin/CardinalSynth.lv2/*.* $(DESTDIR)$(PREFIX)/lib/lv2/CardinalSynth.lv2/ - install -m 644 bin/CardinalFX.vst/*.* $(DESTDIR)$(PREFIX)/lib/vst/CardinalFX.vst/ - install -m 644 bin/CardinalSynth.vst/*.* $(DESTDIR)$(PREFIX)/lib/vst/CardinalSynth.vst/ + 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/ @@ -284,19 +291,6 @@ endif install -m 644 README.md $(DESTDIR)$(PREFIX)/share/doc/cardinal/ install -m 644 docs/*.md docs/*.png $(DESTDIR)$(PREFIX)/share/doc/cardinal/docs/ - ln -sf $(PREFIX)/share/cardinal $(DESTDIR)$(PREFIX)/lib/lv2/Cardinal.lv2/resources - ln -sf $(PREFIX)/share/cardinal $(DESTDIR)$(PREFIX)/lib/lv2/CardinalFX.lv2/resources - ln -sf $(PREFIX)/share/cardinal $(DESTDIR)$(PREFIX)/lib/lv2/CardinalSynth.lv2/resources - - ln -sf $(PREFIX)/share/cardinal $(DESTDIR)$(PREFIX)/lib/vst/CardinalFX.vst/resources - ln -sf $(PREFIX)/share/cardinal $(DESTDIR)$(PREFIX)/lib/vst/CardinalSynth.vst/resources - -ifeq ($(VST3_SUPPORTED),true) - ln -sf $(PREFIX)/share/cardinal $(DESTDIR)$(PREFIX)/lib/vst3/Cardinal.vst3/Contents/Resources - ln -sf $(PREFIX)/share/cardinal $(DESTDIR)$(PREFIX)/lib/vst3/CardinalFX.vst3/Contents/Resources - ln -sf $(PREFIX)/share/cardinal $(DESTDIR)$(PREFIX)/lib/vst3/CardinalSynth.vst3/Contents/Resources -endif - # -------------------------------------------------------------- # Tarball step, for releases @@ -404,6 +398,9 @@ tarball+deps: download rm -f ../cardinal+deps-$(VERSION).tar.xz tar -c --lzma $(TAR_ARGS) -f ../cardinal+deps-$(VERSION).tar.xz . +version: + @echo $(VERSION) + # -------------------------------------------------------------- .PHONY: carla deps plugins diff --git a/README.md b/README.md index a638c506..1fcdf3e4 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ *Cardinal, the Rack!* Cardinal is a free and open-source virtual modular synthesizer plugin, -available as JACK standalone and LV2, VST2 and VST3 audio plugin for FreeBSD, Linux, macOS and Windows. +available as JACK standalone and AU, LV2, VST2 and VST3 audio plugin for FreeBSD, Linux, macOS and Windows. 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/) @@ -19,10 +19,42 @@ All "Core" modules from Rack have been replaced by Cardinal equivalents, simplif Cardinal does not load external modules and does not connect to the official Rack library/store. All VCV branding has been removed (to the best of our knowledge) in order to avoid any trademark issues. -Because it is using DPF, Cardinal already supports LV2 and VST2 with an extra JACK standalone mode for some systems. The VST3 version is in progress, already part of the build but still experimental. +## Current status + +With the exception of a few bugs, Cardinal can be considered stable. +Though currently the following should be noted: + +- Keyboard input does not always work in some hosts [#24](https://github.com/DISTRHO/Cardinal/issues/24) +- VST3 support incomplete/experimental [#41](https://github.com/DISTRHO/Cardinal/issues/41) +- Windows 32bit builds do not work well [#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. +Both macOS and Windows builds have an installer. +Install instructions are available [here](https://github.com/DISTRHO/Cardinal/wiki/Install). + +Note: Neither the macOS or Windows builds are signed, so expect warnings saying they are from an "untrusted developer". + +### Nightly builds + +You can find builds for pretty much any recent Cardinal commit [here](https://github.com/DISTRHO/Cardinal/actions/workflows/build.yml). +Just click on any successful build, and scroll to the bottom to find the builds. +(note the canvas-like area in the middle prevents mouse wheel scrolling) + +A GitHub account is required in order to download these builds. + +### Building + +Basic building instructions are available in [BUILDING.md](docs/BUILDING.md). + + ## Plugin variants Cardinal provides 3 plugin variants - "main", Synth and FX. @@ -36,7 +68,7 @@ All variants have MIDI input and output support. This variant provides 8 audio inputs and outputs and 10 CV inputs and outputs. -NOTE: Due to VST2 format not supporting CV ports, this variant is not available for VST2. +NOTE: Due to AU and VST2 formats not supporting CV ports, this variant is not available for those formats. ### Synth @@ -70,33 +102,6 @@ But a couple of modules background's have their colors flipped, because damn we ![screenshot](docs/Screenshot_Carla+Ildaeil.png "Screenshot") -## Current status - -With the exception of a few bugs, Cardinal can be considered stable. -Though currently the following should be noted: - -- Keyboard input does not always work in some hosts [#24](https://github.com/DISTRHO/Cardinal/issues/24) -- VST3 support incomplete/experimental [#41](https://github.com/DISTRHO/Cardinal/issues/41) -- Windows 32bit builds do not work well [#80](https://github.com/DISTRHO/Cardinal/issues/80) - -### Current builds - -If you want to try this out early, checkout the [GitHub actions tab](https://github.com/DISTRHO/Cardinal/actions/workflows/build.yml). -There is absolutely no warranty, use at your own risk and all that... - -Basic building instructions are available in [BUILDING.md](docs/BUILDING.md) - -### 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. - - -## License - -Cardinal is licensed under GPLv3+, see [LICENSE](LICENSE) for more details. -An overview of the included code and linked submodules can be seen [here](docs/LICENSES.md#code-license--binary). - ## Included modules @@ -108,6 +113,7 @@ At the moment the following 3rd-party modules are provided: - AlgoritmArte - Amalgamated Harmonics - Animated Circuits +- Arable Instruments - Aria Salvatrice - Audible Instruments - Autinn @@ -119,12 +125,12 @@ At the moment the following 3rd-party modules are provided: - Catro/Modulo - cf - ChowDSP -- Dintree Virtual - DrumKit - E-Series - ExpertSleepers Encoders - Extratone - Fehler Fabrik +- Fundamental - Glue the Giant - GoodSheperd - Grande @@ -147,15 +153,18 @@ At the moment the following 3rd-party modules are provided: - MSM - Nonlinear Circuits - Orbits +- Parable Instruments - Path Set +- PinkTrombone - Prism - rackwindows - repelzen - Sonus Modular - Starling Via - stocaudio -- Substation Opensource +- unless_modules - Valley +- Voxglitch - ZetaCarinae - ZZC @@ -229,3 +238,15 @@ Cardinal and Rack should be able to co-exist friendly and peacefully, as they cl It is likely most people will prefer to use Rack Pro for its official support and its big module collection (including commercial ones). A feature comparison between Cardinal and Rack Pro can be seen [here](docs/DIFFERENCES.md). + + +## License + +Cardinal is licensed under GPLv3+, see [LICENSE](LICENSE) for more details. +An overview of the included code and linked submodules can be seen [here](docs/LICENSES.md#code-license--binary). + + +## 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. diff --git a/carla b/carla index 4b6010bd..04558b63 160000 --- a/carla +++ b/carla @@ -1 +1 @@ -Subproject commit 4b6010bd0adbbed5a0cb89a1253e52e72e648b18 +Subproject commit 04558b63101de55556733edfa4a369b51f36e9b3 diff --git a/deps/Makefile b/deps/Makefile index 1d77f370..56ba9a88 100644 --- a/deps/Makefile +++ b/deps/Makefile @@ -190,7 +190,10 @@ $(DEP_PATH)/libsamplerate-0.1.9/.stamp-patched: $(DEP_PATH)/lib/libspeexdsp.a: $(DEP_PATH)/speexdsp-SpeexDSP-1.2rc3/.stamp-patched $(DEP_PATH)/speexdsp-SpeexDSP-1.2rc3/.stamp-patched: - $(DEP_MAKE) -C $(DEP_PATH) speexdsp-SpeexDSP-1.2rc3 + $(DEP_MAKE) -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 touch $@ diff --git a/deps/PawPaw b/deps/PawPaw index b41a693b..01d07086 160000 --- a/deps/PawPaw +++ b/deps/PawPaw @@ -1 +1 @@ -Subproject commit b41a693b64cdba1abd8d278c9985fb690b522854 +Subproject commit 01d07086586818e427b2898d2d446d30b68f3139 diff --git a/docs/DIFFERENCES.md b/docs/DIFFERENCES.md index 60e4047b..3b404efe 100644 --- a/docs/DIFFERENCES.md +++ b/docs/DIFFERENCES.md @@ -21,6 +21,7 @@ Bellow follows a list of features comparing the official plugin to Cardinal. | 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 | | | Plugin in LV2 format | No | Yes | | | Plugin in VST2 format | Yes | Yes | | | Plugin in VST3 format | No | WIP | | @@ -30,24 +31,22 @@ Bellow follows a list of features comparing the official plugin to Cardinal. | Supports BSD systems | No | Yes | Available as FreeBSD port | | 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 VST2 | +| 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 | | 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 | CC-ND respected by leaving files intact, dark mode applied at runtime | +| Proper dark theme | No, only room brightness | 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: - * Amalgamated Harmonics * Aria Salvatrice modules (except Arcane related modules, due to their online requirement) * Mog (never updated to v2) * mscHack (never updated to v2) * rackwindows - * repelzen * Audio File * Carla Plugin Host * Ildaeil Host diff --git a/docs/FAQ.md b/docs/FAQ.md index 52206052..abdceff8 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -9,19 +9,6 @@ But basically we want an open-source plugin version of "Rack Pro", where we are free to change things as we see fit, work on new features and fix bugs. This is simply not possible with proprietary software, which is the case of "Rack Pro". -## Where is Fundamental? - -There are some artwork license issues that prevent us from using Fundamental exactly as we want. -We could in theory use it as-is, VCV logo and everything, but it looks out of place with Cardinal's general dark mode theme. -The artwork license does not allow modifications, and that VCV logo being present on the panels makes Cardinal's authors unease. -Cardinal is not a VCV product in any way, or endorsed by it. Would be quite bad to give that impression. - -Current plan is to redo Fundamental panel graphics in a more liberal license, so it then can be included in Cardinal. -In the mean time, check [this wiki page](https://github.com/DISTRHO/Cardinal/wiki/Fundamental-replacements) -for a list of module replacements for Fundamental stuff. - -PS: Don't forget to contribute back as well! ;) - ## Can I install extra modules? No, Cardinal is intentionally a fully self-contained plugin. @@ -64,9 +51,15 @@ As a plugin, the state will be saved together with the host/DAW project. ## On BSD/Linux/X11 the menu item "Save As/Export..." does nothing The save-file dialogs in Cardinal requires a working [xdg-desktop-portal](https://github.com/flatpak/xdg-desktop-portal) DBus implementation from your desktop environment. -Typically your desktop already provides this, if not consider looking for a package to install with "desktop-portal" in the name. +Typically your desktop already provides this, if not consider looking for a package to install with "desktop-portal" in the name. +If you are running a window manager without a "real" desktop environment (like custom X11 or i3 setups), +you will need to manually activate the systemd unit that provides these DBus services, like so: + +``` +systemctl enable xdg-desktop-portal --user --now +``` -The open-file dialogs in Cardinal do not have this restriction, with a fallback in case desktop portal is not available. +Note: The open-file dialogs in Cardinal do not have this restriction, with a fallback in case the desktop portal is not available. ## Why IRC and not Discord? diff --git a/docs/LICENSES.md b/docs/LICENSES.md index 81c0aacc..199fb697 100644 --- a/docs/LICENSES.md +++ b/docs/LICENSES.md @@ -19,6 +19,7 @@ Bellow follows a list of all code licenses used in Cardinal and linked submodule | AlgoritmArte | GPL-3.0-or-later | | | Amalgamated Harmonics | BSD-3-Clause | | | Animated Circuits | GPL-3.0-or-later | | +| Arable Instruments | GPL-3.0-or-later | | | Aria Salvatrice | GPL-3.0-or-later | | | Audible Instruments | GPL-3.0-or-later | | | Autinn | GPL-3.0-or-later | | @@ -30,12 +31,12 @@ 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 | | -| Dintree | GPL-3.0-or-later | | | DrumKit | CC0-1.0 | | | E-Series | GPL-3.0-or-later | | | ExpertSleepers Encoders | MIT | | | Extratone | GPL-3.0-or-later | | | Fehler Fabrik | GPL-3.0-or-later | | +| Fundamental | GPL-3.0-or-later | | | Glue the Giant | GPL-3.0-or-later | | | GoodSheperd | GPL-3.0-or-later | | | Grande | GPL-3.0-or-later | | @@ -58,15 +59,18 @@ Bellow follows a list of all code licenses used in Cardinal and linked submodule | MSM | MIT | Repo's [LICENSE-dist.md](https://github.com/netboy3/MSM-vcvrack-plugin/issues/10) includes wrong information | | Nonlinear Circuits | CC0-1.0 | | | Orbits | GPL-3.0-or-later | | +| Parable Instruments | GPL-3.0-or-later | | | Path Set | GPL-3.0-or-later | | +| PinkTrombone | GPL-3.0-or-later | | | Prism | BSD-3-Clause | | | Rackwindows | MIT | | | repelzen | GPL-3.0-or-later | | | Sonus Modular | GPL-3.0-or-later | | | Starling Via | MIT | | | stocaudio | GPL-3.0-or-later | | -| Substation Opensource | BSD-3-Clause-Attribution | Need to check full compatibility with GPLv3+ | +| unless_modules | GPL-3.0-or-later | | | Valley | GPL-3.0-or-later | | +| Voxglitch | GPL-3.0-or-later | | | ZetaCarinae | GPL-3.0-or-later | | | ZZC | GPL-3.0-or-later | | @@ -96,6 +100,7 @@ Below is a list of artwork licenses from plugins | AmalgamatedHarmonics/DSEG*.ttf | OFL-1.1-RFN | | | AmalgamatedHarmonics/Roboto*.ttf | Apache-2.0 | | | AnimatedCircuits/* | CC-BY-NC-SA-4.0 | | +| ArableInstruments/* | Custom | Copyright © Alex Brandt, [used and distributed with permission](https://github.com/adbrant/ArableInstruments/issues/21) | | AriaModules/* | CC-BY-SA-4.0 | | | AriaModules/Arcane/* | CC-BY-NC-SA-3.0 | Unused in Cardinal | | AriaModules/components/* | WTFPL | | @@ -113,6 +118,7 @@ Below is a list of artwork licenses from plugins | BaconPlugs/Keypunch029.json | OFL-1.1 | | | 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 | | | Befaco/panels/* | Custom | Copyright © [Befaco](https://www.befaco.org/), [used and distributed with permission](LICENSE-PERMISSIONS.md#befaco-manu-retamero--befaco) | | BogaudioModules/* | CC-BY-SA-4.0 | | | BogaudioModules/fonts/audiowide.ttf | OFL-1.1-RFN | | @@ -127,13 +133,13 @@ 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 | | -| Dintree/* | GPL-3.0-or-later | No artwork specific license provided | | DrumKit/* | CC0-1.0 | | | DrumKit/component/NovaMono.ttf | OFL-1.1-RFN | | | 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) | | FehlerFabrik/* | GPL-3.0-or-later | No artwork specific license provided, see [FehlerFabrik#17](https://github.com/RCameron93/FehlerFabrik/issues/17) | +| Fundamental/* | GPL-3.0-or-later | Same license as source code | | GlueTheGiant/* | GPL-3.0-or-later | Same license as source code | | GlueTheGiant/fonts/DSEG7-* | OFL-1.1-RFN | | | GoodSheperd/* | GPL-3.0-or-later | No artwork specific license provided | @@ -174,7 +180,9 @@ Below is a list of artwork licenses from plugins | nonlinearcircuits/Audiowide-Regular.ttf | OFL-1.1-RFN | | | Orbits/* | CC-BY-NC-ND-4.0 | | | Orbits/fonts/ShareTechMono-Regular.ttf | OFL-1.1-RFN | | +| ParableInstruments/* | Custom | Copyright © Alex Brandt, [used and distributed with permission](https://github.com/adbrant/ArableInstruments/issues/21) | | PathSet/* | GPL-3.0-or-later | No artwork specific license provided | +| PinkTrombone/* | GPL-3.0-or-later | No artwork specific license provided | | Prism/* | CC-BY-SA-4.0 | | | Prism/RobotoCondensed-Regular.ttf | Apache-2.0 | | | Rackwindows/* | MIT | [Same license as source code](https://github.com/n0jo/rackwindows/issues/15) | @@ -182,11 +190,15 @@ Below is a list of artwork licenses from plugins | 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 | -| substation-opensource/* | BSD-3-Clause-Attribution | No artwork specific license provided | +| 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) | | ValleyAudio/* | GPL-3.0-or-later | [Same license as source code](https://github.com/ValleyAudio/ValleyRackFree/issues/73) | | ValleyAudio/din1451alt.ttf | CC-BY-3.0-DE | | | ValleyAudio/DSEG14Classic-*.ttf | OFL-1.1-RFN | | | ValleyAudio/ShareTechMono-*.ttf | OFL-1.1-RFN | | +| voxglitch/* | GPL-3.0-or-later | No artwork specific license provided | +| voxglitch/ShareTechMono-Regular.ttf | OFL-1.1-RFN | | | ZetaCarinaeModules/* | GPL-3.0-or-later | [Same license as source code](https://github.com/mhampton/ZetaCarinaeModules/issues/8) | | ZZC/* | CC-BY-NC-SA-4.0 | | | ZZC/panels/* | CC-BY-NC-SA-4.0 | NOTE: The ZZC Logo is Copyright (c) 2019 Sergey Ukolov and cannot be used in derivative works; Cardinal's use does not officially constitute derivative work. | diff --git a/dpf b/dpf index af042cb6..68de732e 160000 --- a/dpf +++ b/dpf @@ -1 +1 @@ -Subproject commit af042cb682d693e9ce5b87a145e6c704be31adf8 +Subproject commit 68de732eecbd1d8febf94e15558c5adaa45dfa9b diff --git a/include/common.hpp b/include/common.hpp index 8593494b..6dd74703 100644 --- a/include/common.hpp +++ b/include/common.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 @@ -53,6 +53,19 @@ #include #define USING_CARDINAL_NOT_RACK +// OS separator macros +#ifdef ARCH_WIN +# define CARDINAL_OS_SEP '\\' +# define CARDINAL_OS_SEP_STR "\\" +# define CARDINAL_OS_SPLIT ';' +# define CARDINAL_OS_SPLIT_STR ";" +#else +# define CARDINAL_OS_SEP '/' +# define CARDINAL_OS_SEP_STR "/" +# define CARDINAL_OS_SPLIT ':' +# define CARDINAL_OS_SPLIT_STR ":" +#endif + // opens a file browser, startDir and title can be null // action is always triggered on close (path can be null), must be freed if not null void async_dialog_filebrowser(bool saving, const char* startDir, const char* title, diff --git a/plugins/substation-settings/Settings.cpp b/include/componentlibrary.hpp similarity index 58% rename from plugins/substation-settings/Settings.cpp rename to include/componentlibrary.hpp index 0f16ed16..5b0705f5 100644 --- a/plugins/substation-settings/Settings.cpp +++ b/include/componentlibrary.hpp @@ -15,21 +15,17 @@ * For a full copy of the GNU General Public License see the LICENSE file. */ -#include "../substation-opensource/src/Settings.hpp" +#pragma once -namespace slime { -namespace plugin { -namespace substation { +#define SCHEME_YELLOW SCHEME_YELLOW_OldVCV +#include_next "componentlibrary.hpp" +#undef SCHEME_YELLOW -PluginSettings::PluginSettings(void) {} -PluginSettings::~PluginSettings(void) {} -void PluginSettings::save() {} -void PluginSettings::load() {} -void PluginSettings::appendContextMenu(rack::ui::Menu* menu) {} -void PluginSettings::updateCableColors(const bool& value) {} +namespace rack { +namespace componentlibrary { -PluginSettings settings; +// Yellow? What's that? +static const NVGcolor SCHEME_YELLOW = nvgRGBf(0.76f, 0.11f, 0.22f); -} // namespace substation -} // namespace plugin -} // namespace slime +} +} diff --git a/include/dsp/fir.hpp b/include/dsp/fir.hpp new file mode 100644 index 00000000..7d1c737d --- /dev/null +++ b/include/dsp/fir.hpp @@ -0,0 +1,164 @@ +/* + * 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 + + +namespace rack { +namespace dsp { + + +/** Performs a direct sum convolution */ +inline float convolveNaive(const float* in, const float* kernel, int len) { + float y = 0.f; + for (int i = 0; i < len; i++) { + y += in[len - 1 - i] * kernel[i]; + } + return y; +} + +/** Computes the impulse response of a boxcar lowpass filter */ +inline void boxcarLowpassIR(float* out, int len, float cutoff = 0.5f) { + for (int i = 0; i < len; i++) { + float t = i - (len - 1) / 2.f; + out[i] = 2 * cutoff * sinc(2 * cutoff * t); + } +} + + +struct RealTimeConvolver { + // `kernelBlocks` number of contiguous FFT blocks of size `blockSize` + // indexed by [i * blockSize*2 + j] + float* kernelFfts = NULL; + float* inputFfts = NULL; + float* outputTail = NULL; + float* tmpBlock = NULL; + size_t blockSize; + size_t kernelBlocks = 0; + size_t inputPos = 0; + PFFFT_Setup* pffft; + + /** `blockSize` is the size of each FFT block. It should be >=32 and a power of 2. */ + RealTimeConvolver(size_t blockSize) { + this->blockSize = blockSize; + pffft = pffft_new_setup(blockSize * 2, PFFFT_REAL); + outputTail = (float*) pffft_aligned_malloc(sizeof(float) * blockSize); + std::memset(outputTail, 0, blockSize * sizeof(float)); + tmpBlock = (float*) pffft_aligned_malloc(sizeof(float) * blockSize * 2); + std::memset(tmpBlock, 0, blockSize * 2 * sizeof(float)); + } + + ~RealTimeConvolver() { + setKernel(NULL, 0); + pffft_aligned_free(outputTail); + pffft_aligned_free(tmpBlock); + pffft_destroy_setup(pffft); + } + + void setKernel(const float* kernel, size_t length) { + // Clear existing kernel + if (kernelFfts) { + pffft_aligned_free(kernelFfts); + kernelFfts = NULL; + } + if (inputFfts) { + pffft_aligned_free(inputFfts); + inputFfts = NULL; + } + kernelBlocks = 0; + inputPos = 0; + + if (kernel && length > 0) { + // Round up to the nearest factor of `blockSize` + kernelBlocks = (length - 1) / blockSize + 1; + + // Allocate blocks + kernelFfts = (float*) pffft_aligned_malloc(sizeof(float) * blockSize * 2 * kernelBlocks); + inputFfts = (float*) pffft_aligned_malloc(sizeof(float) * blockSize * 2 * kernelBlocks); + std::memset(inputFfts, 0, sizeof(float) * blockSize * 2 * kernelBlocks); + + for (size_t i = 0; i < kernelBlocks; i++) { + // Pad each block with zeros + std::memset(tmpBlock, 0, sizeof(float) * blockSize * 2); + size_t len = std::min((int) blockSize, (int)(length - i * blockSize)); + std::memcpy(tmpBlock, &kernel[i * blockSize], sizeof(float)*len); + // Compute fft + pffft_transform(pffft, tmpBlock, &kernelFfts[blockSize * 2 * i], NULL, PFFFT_FORWARD); + } + } + } + + /** Applies reverb to input + input and output must be of size `blockSize` + */ + void processBlock(const float* input, float* output) { + if (kernelBlocks == 0) { + std::memset(output, 0, sizeof(float) * blockSize); + return; + } + + // Step input position + inputPos = (inputPos + 1) % kernelBlocks; + // Pad block with zeros + std::memset(tmpBlock, 0, sizeof(float) * blockSize * 2); + std::memcpy(tmpBlock, input, sizeof(float) * blockSize); + // Compute input fft + pffft_transform(pffft, tmpBlock, &inputFfts[blockSize * 2 * inputPos], NULL, PFFFT_FORWARD); + // Create output fft + std::memset(tmpBlock, 0, sizeof(float) * blockSize * 2); + // convolve input fft by kernel fft + // Note: This is the CPU bottleneck loop + for (size_t i = 0; i < kernelBlocks; i++) { + size_t pos = (inputPos - i + kernelBlocks) % kernelBlocks; + pffft_zconvolve_accumulate(pffft, &kernelFfts[blockSize * 2 * i], &inputFfts[blockSize * 2 * pos], tmpBlock, 1.f); + } + // Compute output + pffft_transform(pffft, tmpBlock, tmpBlock, NULL, PFFFT_BACKWARD); + // Add block tail from last output block + for (size_t i = 0; i < blockSize; i++) { + tmpBlock[i] += outputTail[i]; + } + // Copy output block to output + float scale = 1.f / (blockSize * 2); + for (size_t i = 0; i < blockSize; i++) { + // Scale based on FFT + output[i] = tmpBlock[i] * scale; + } + // Set tail + for (size_t i = 0; i < blockSize; i++) { + outputTail[i] = tmpBlock[i + blockSize]; + } + } +}; + + +} // namespace dsp +} // namespace rack diff --git a/include/engine/Port.hpp b/include/engine/Port.hpp index 87c0e2a8..b5188703 100644 --- a/include/engine/Port.hpp +++ b/include/engine/Port.hpp @@ -48,7 +48,7 @@ struct Port { /** Voltage of the port. */ /** 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 alignas(PORT_MAX_CHANNELS) { + union alignas(32) { /** Unstable API. Use getVoltage() and setVoltage() instead. */ float voltages[PORT_MAX_CHANNELS] = {}; /** DEPRECATED. Unstable API. Use getVoltage() and setVoltage() instead. */ diff --git a/include/simd/Vector.hpp b/include/simd/Vector.hpp new file mode 100644 index 00000000..b1640cd1 --- /dev/null +++ b/include/simd/Vector.hpp @@ -0,0 +1,374 @@ +/* + * 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 + + +namespace rack { + + +/** Abstraction of aligned types for SIMD computation +*/ +namespace simd { + + +/** Generic class for vector types. + +This class is designed to be used just like you use scalars, with extra features for handling bitwise logic, conditions, loading, and storing. + +Example: + + float a[4], b[4]; + float_4 a = float_4::load(in); + float_4 b = 2.f * a / (1 - a); + b *= sin(2 * M_PI * a); + b.store(out); +*/ +template +struct Vector; + + +/** Wrapper for `__m128` representing an aligned vector of 4 single-precision float values. +*/ +template <> +struct Vector { + using type = float; + constexpr static int size = 4; + + /** NOTE alignas is required in order to allow SSE usage. */ + union alignas(32) { + __m128 v; + /** Accessing this array of scalars is slow and defeats the purpose of vectorizing. + */ + float s[4]; + }; + + /** Constructs an uninitialized vector. */ + Vector() = default; + + /** Constructs a vector from a native `__m128` type. */ + Vector(__m128 v) : v(v) {} + + /** Constructs a vector with all elements set to `x`. */ + Vector(float x) { + v = _mm_set1_ps(x); + } + + /** Constructs a vector from four scalars. */ + Vector(float x1, float x2, float x3, float x4) { + v = _mm_setr_ps(x1, x2, x3, x4); + } + + /** Returns a vector with all 0 bits. */ + static Vector zero() { + return Vector(_mm_setzero_ps()); + } + + /** Returns a vector with all 1 bits. */ + static Vector mask() { + return Vector(_mm_castsi128_ps(_mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128()))); + } + + /** Reads an array of 4 values. + On little-endian machines (e.g. x86_64), the order is reversed, so `x[0]` corresponds to `vector.s[3]`. + */ + static Vector load(const float* x) { + /* + My benchmarks show that _mm_loadu_ps() performs equally as fast as _mm_load_ps() when data is actually aligned. + This post seems to agree. https://stackoverflow.com/a/20265193/272642 + I therefore use _mm_loadu_ps() for generality, so you can load unaligned arrays using the same function (although load aligned arrays if you can for best performance). + */ + return Vector(_mm_loadu_ps(x)); + } + + /** Writes an array of 4 values. + On little-endian machines (e.g. x86_64), the order is reversed, so `x[0]` corresponds to `vector.s[3]`. + */ + void store(float* x) { + _mm_storeu_ps(x, v); + } + + /** Accessing vector elements individually is slow and defeats the purpose of vectorizing. + However, this operator is convenient when writing simple serial code in a non-bottlenecked section. + */ + float& operator[](int i) { + return s[i]; + } + const float& operator[](int i) const { + return s[i]; + } + + // Conversions + Vector(Vector a); + // Casts + static Vector cast(Vector a); +}; + + +template <> +struct Vector { + using type = int32_t; + constexpr static int size = 4; + + /** NOTE alignas is required in order to allow SSE usage. */ + union alignas(32) { + __m128i v; + int32_t s[4]; + }; + + Vector() = default; + Vector(__m128i v) : v(v) {} + Vector(int32_t x) { + v = _mm_set1_epi32(x); + } + Vector(int32_t x1, int32_t x2, int32_t x3, int32_t x4) { + v = _mm_setr_epi32(x1, x2, x3, x4); + } + static Vector zero() { + return Vector(_mm_setzero_si128()); + } + static Vector mask() { + return Vector(_mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128())); + } + static Vector load(const int32_t* x) { + // HACK + // Use _mm_loadu_si128() because GCC doesn't support _mm_loadu_si32() + return Vector(_mm_loadu_si128((const __m128i*) x)); + } + void store(int32_t* x) { + // HACK + // Use _mm_storeu_si128() because GCC doesn't support _mm_storeu_si32() + _mm_storeu_si128((__m128i*) x, v); + } + int32_t& operator[](int i) { + return s[i]; + } + const int32_t& operator[](int i) const { + return s[i]; + } + Vector(Vector a); + static Vector cast(Vector a); +}; + + +// Conversions and casts + + +inline Vector::Vector(Vector a) { + v = _mm_cvtepi32_ps(a.v); +} + +inline Vector::Vector(Vector a) { + v = _mm_cvttps_epi32(a.v); +} + +inline Vector Vector::cast(Vector a) { + return Vector(_mm_castsi128_ps(a.v)); +} + +inline Vector Vector::cast(Vector a) { + return Vector(_mm_castps_si128(a.v)); +} + + +// Operator overloads + + +/** `a @ b` */ +#define DECLARE_VECTOR_OPERATOR_INFIX(t, s, operator, func) \ + inline Vector operator(const Vector& a, const Vector& b) { \ + return Vector(func(a.v, b.v)); \ + } + +/** `a @= b` */ +#define DECLARE_VECTOR_OPERATOR_INCREMENT(t, s, operator, opfunc) \ + inline Vector& operator(Vector& a, const Vector& b) { \ + return a = opfunc(a, b); \ + } + +DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator+, _mm_add_ps) +DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator+, _mm_add_epi32) + +DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator-, _mm_sub_ps) +DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator-, _mm_sub_epi32) + +DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator*, _mm_mul_ps) +// DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator*, NOT AVAILABLE IN SSE3) + +DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator/, _mm_div_ps) +// DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator/, NOT AVAILABLE IN SSE3) + +/* Use these to apply logic, bit masks, and conditions to elements. +Boolean operators on vectors give 0x00000000 for false and 0xffffffff for true, for each vector element. + +Examples: + +Subtract 1 from value if greater than or equal to 1. + + x -= (x >= 1.f) & 1.f; +*/ +DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator^, _mm_xor_ps) +DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator^, _mm_xor_si128) + +DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator&, _mm_and_ps) +DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator&, _mm_and_si128) + +DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator|, _mm_or_ps) +DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator|, _mm_or_si128) + +DECLARE_VECTOR_OPERATOR_INCREMENT(float, 4, operator+=, operator+) +DECLARE_VECTOR_OPERATOR_INCREMENT(int32_t, 4, operator+=, operator+) + +DECLARE_VECTOR_OPERATOR_INCREMENT(float, 4, operator-=, operator-) +DECLARE_VECTOR_OPERATOR_INCREMENT(int32_t, 4, operator-=, operator-) + +DECLARE_VECTOR_OPERATOR_INCREMENT(float, 4, operator*=, operator*) +// DECLARE_VECTOR_OPERATOR_INCREMENT(int32_t, 4, operator*=, NOT AVAILABLE IN SSE3) + +DECLARE_VECTOR_OPERATOR_INCREMENT(float, 4, operator/=, operator/) +// DECLARE_VECTOR_OPERATOR_INCREMENT(int32_t, 4, operator/=, NOT AVAILABLE IN SSE3) + +DECLARE_VECTOR_OPERATOR_INCREMENT(float, 4, operator^=, operator^) +DECLARE_VECTOR_OPERATOR_INCREMENT(int32_t, 4, operator^=, operator^) + +DECLARE_VECTOR_OPERATOR_INCREMENT(float, 4, operator&=, operator&) +DECLARE_VECTOR_OPERATOR_INCREMENT(int32_t, 4, operator&=, operator&) + +DECLARE_VECTOR_OPERATOR_INCREMENT(float, 4, operator|=, operator|) +DECLARE_VECTOR_OPERATOR_INCREMENT(int32_t, 4, operator|=, operator|) + +DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator==, _mm_cmpeq_ps) +DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator==, _mm_cmpeq_epi32) + +DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator>=, _mm_cmpge_ps) +inline Vector operator>=(const Vector& a, const Vector& b) { + return Vector(_mm_cmpgt_epi32(a.v, b.v)) ^ Vector::mask(); +} + +DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator>, _mm_cmpgt_ps) +DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator>, _mm_cmpgt_epi32) + +DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator<=, _mm_cmple_ps) +inline Vector operator<=(const Vector& a, const Vector& b) { + return Vector(_mm_cmplt_epi32(a.v, b.v)) ^ Vector::mask(); +} + +DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator<, _mm_cmplt_ps) +DECLARE_VECTOR_OPERATOR_INFIX(int32_t, 4, operator<, _mm_cmplt_epi32) + +DECLARE_VECTOR_OPERATOR_INFIX(float, 4, operator!=, _mm_cmpneq_ps) +inline Vector operator!=(const Vector& a, const Vector& b) { + return Vector(_mm_cmpeq_epi32(a.v, b.v)) ^ Vector::mask(); +} + +/** `+a` */ +inline Vector operator+(const Vector& a) { + return a; +} +inline Vector operator+(const Vector& a) { + return a; +} + +/** `-a` */ +inline Vector operator-(const Vector& a) { + return 0.f - a; +} +inline Vector operator-(const Vector& a) { + return 0 - a; +} + +/** `++a` */ +inline Vector& operator++(Vector& a) { + return a += 1.f; +} +inline Vector& operator++(Vector& a) { + return a += 1; +} + +/** `--a` */ +inline Vector& operator--(Vector& a) { + return a -= 1.f; +} +inline Vector& operator--(Vector& a) { + return a -= 1; +} + +/** `a++` */ +inline Vector operator++(Vector& a, int) { + Vector b = a; + ++a; + return b; +} +inline Vector operator++(Vector& a, int) { + Vector b = a; + ++a; + return b; +} + +/** `a--` */ +inline Vector operator--(Vector& a, int) { + Vector b = a; + --a; + return b; +} +inline Vector operator--(Vector& a, int) { + Vector b = a; + --a; + return b; +} + +/** `~a` */ +inline Vector operator~(const Vector& a) { + return a ^ Vector::mask(); +} +inline Vector operator~(const Vector& a) { + return a ^ Vector::mask(); +} + +/** `a << b` */ +inline Vector operator<<(const Vector& a, const int& b) { + return Vector(_mm_slli_epi32(a.v, b)); +} + +/** `a >> b` */ +inline Vector operator>>(const Vector& a, const int& b) { + return Vector(_mm_srli_epi32(a.v, b)); +} + + +// Typedefs + + +using float_4 = Vector; +using int32_4 = Vector; + + +} // namespace simd +} // namespace rack diff --git a/jucewrapper/CMakeLists.txt b/jucewrapper/CMakeLists.txt index 4926dbba..8bab15f2 100644 --- a/jucewrapper/CMakeLists.txt +++ b/jucewrapper/CMakeLists.txt @@ -1,19 +1,124 @@ cmake_minimum_required(VERSION 3.15) -project(Cardinal VERSION 0.0.0) +project(Cardinal VERSION 22.03) add_subdirectory(JUCE) +# Config + +set(CMAKE_C_VISIBILITY_PRESET hidden) +set(CMAKE_CXX_VISIBILITY_PRESET hidden) + +# Define static libs + +add_library(dgl STATIC IMPORTED) +set_property(TARGET dgl PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../dpf/build/libdgl-opengl.a") + +add_library(carla_host_plugin STATIC IMPORTED) +set_property(TARGET carla_host_plugin PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../carla/build/plugin/Release/carla-host-plugin.cpp.o") + +add_library(carla_engine_plugin STATIC IMPORTED) +set_property(TARGET carla_engine_plugin PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../carla/build/modules/Release/carla_engine_plugin.a") + +add_library(carla_plugin STATIC IMPORTED) +set_property(TARGET carla_plugin PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../carla/build/modules/Release/carla_plugin.a") + +add_library(native_plugins STATIC IMPORTED) +set_property(TARGET native_plugins PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../carla/build/modules/Release/native-plugins.a") + +add_library(audio_decoder STATIC IMPORTED) +set_property(TARGET audio_decoder PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../carla/build/modules/Release/audio_decoder.a") + +add_library(jackbridge STATIC IMPORTED) +set_property(TARGET jackbridge PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../carla/build/modules/Release/jackbridge.min.a") + +add_library(lilv STATIC IMPORTED) +set_property(TARGET lilv PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../carla/build/modules/Release/lilv.a") + +add_library(rtmempool STATIC IMPORTED) +set_property(TARGET rtmempool PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../carla/build/modules/Release/rtmempool.a") + +add_library(sfzero STATIC IMPORTED) +set_property(TARGET sfzero PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../carla/build/modules/Release/sfzero.a") + +add_library(water STATIC IMPORTED) +set_property(TARGET water PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../carla/build/modules/Release/water.a") + +add_library(zita_resampler STATIC IMPORTED) +set_property(TARGET zita_resampler PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../carla/build/modules/Release/zita-resampler.a") + +add_library(sCardinalFX STATIC IMPORTED) +set_property(TARGET sCardinalFX PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../bin/CardinalFX.a") + +add_library(sCardinalSynth STATIC IMPORTED) +set_property(TARGET sCardinalSynth PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../bin/CardinalSynth.a") + +add_library(sPlugins STATIC IMPORTED) +set_property(TARGET sPlugins PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../plugins/plugins.a") + +add_library(sRack STATIC IMPORTED) +set_property(TARGET sRack PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../src/rack.a") + +add_library(libarchive STATIC IMPORTED) +if (WIN32) +set_property(TARGET libarchive PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../src/Rack/dep/lib/libarchive_static.a") +else (WIN32) +set_property(TARGET libarchive PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../src/Rack/dep/lib/libarchive.a") +endif (WIN32) + +add_library(libjansson STATIC IMPORTED) +set_property(TARGET libjansson PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../src/Rack/dep/lib/libjansson.a") + +add_library(libquickjs STATIC IMPORTED) +set_property(TARGET libquickjs PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../src/Rack/dep/lib/libquickjs.a") + +add_library(libsamplerate STATIC IMPORTED) +set_property(TARGET libsamplerate PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../src/Rack/dep/lib/libsamplerate.a") + +add_library(libspeexdsp STATIC IMPORTED) +set_property(TARGET libspeexdsp PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../src/Rack/dep/lib/libspeexdsp.a") + +add_library(libzstd STATIC IMPORTED) +set_property(TARGET libzstd PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../src/Rack/dep/lib/libzstd.a") + +# dependencies + +find_package(PkgConfig REQUIRED) +pkg_check_modules(LIBLO REQUIRED liblo) +pkg_check_modules(SNDFILE REQUIRED sndfile) + +if (APPLE) +set(EXTRA_LIBS "-lz") +set(GL_LIBRARIES "-framework OpenGL") +set(PLUGIN_FORMATS AU) +else (APPLE) +pkg_check_modules(DBUS REQUIRED dbus-1) +pkg_check_modules(GL REQUIRED gl) +pkg_check_modules(X11 REQUIRED x11) +pkg_check_modules(XCURSOR REQUIRED xcursor) +pkg_check_modules(XEXT REQUIRED xext) +pkg_check_modules(XRANDR REQUIRED xrandr) +set(EXTRA_LIBS "-lrt") +set(STATIC_LIBS_START "-Wl,--whole-archive") +set(STATIC_LIBS_END "-Wl,--no-whole-archive") +set(PLUGIN_FORMATS Standalone VST3) +endif (APPLE) + # FX variant juce_add_plugin(CardinalFX - IS_SYNTH FALSE - NEEDS_MIDI_INPUT FALSE - NEEDS_MIDI_OUTPUT FALSE - IS_MIDI_EFFECT FALSE + AU_MAIN_TYPE kAudioUnitType_MusicEffect + 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 TRUE + FORMATS ${PLUGIN_FORMATS} + IS_MIDI_EFFECT FALSE + IS_SYNTH FALSE + NEEDS_MIDI_INPUT TRUE + NEEDS_MIDI_OUTPUT TRUE + PLUGIN_CODE DcnF PLUGIN_MANUFACTURER_CODE Dstr - PLUGIN_CODE dCnF - FORMATS VST3 AU PRODUCT_NAME "CardinalFX") target_sources(CardinalFX @@ -22,26 +127,152 @@ target_sources(CardinalFX target_include_directories(CardinalFX PRIVATE - . - ../dpf/distrho) + ../dpf/distrho + ../src/CardinalFX) target_compile_definitions(CardinalFX PUBLIC + 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=1 + JUCE_DIRECTSOUND=0 + JUCE_JACK=1 + JUCE_WASAPI=0 JUCE_WEB_BROWSER=0) -target_link_options(CardinalFX - PRIVATE - "-l/Shared/Personal/FOSS/GIT/DISTRHO/DISTRHO_Cardinal/bin/CardinalFX.so" - "-Wl,-rpath,." -) - target_link_libraries(CardinalFX PRIVATE juce::juce_audio_utils + ${STATIC_LIBS_START} + sCardinalFX + sPlugins + sRack + carla_host_plugin + carla_engine_plugin + carla_plugin + native_plugins + audio_decoder + jackbridge + lilv + rtmempool + sfzero + water + zita_resampler + dgl + libarchive + libjansson + libquickjs + libsamplerate + libspeexdsp + libzstd + ${STATIC_LIBS_END} + ${GL_LIBRARIES} + ${DBUS_LIBRARIES} + -L${LIBLO_LIBRARY_DIRS} + ${LIBLO_LIBRARIES} + ${SNDFILE_LIBRARIES} + ${X11_LIBRARIES} + ${XCURSOR_LIBRARIES} + ${XEXT_LIBRARIES} + ${XRANDR_LIBRARIES} + ${EXTRA_LIBS} + -lmagic PUBLIC juce::juce_recommended_config_flags juce::juce_recommended_lto_flags juce::juce_recommended_warning_flags) # Synth variant + +juce_add_plugin(CardinalSynth + AU_MAIN_TYPE kAudioUnitType_MusicDevice + 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 TRUE + FORMATS ${PLUGIN_FORMATS} + IS_MIDI_EFFECT FALSE + IS_SYNTH TRUE + NEEDS_MIDI_INPUT TRUE + NEEDS_MIDI_OUTPUT TRUE + PLUGIN_CODE DcnS + PLUGIN_MANUFACTURER_CODE Dstr + PRODUCT_NAME "CardinalSynth") + +target_sources(CardinalSynth + PRIVATE + CardinalWrapper.cpp) + +target_include_directories(CardinalSynth + PRIVATE + ../dpf/distrho + ../src/CardinalSynth) + +target_compile_definitions(CardinalSynth + PUBLIC + JucePlugin_PreferredChannelConfigurations=0,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=1 + JUCE_DIRECTSOUND=0 + JUCE_JACK=1 + JUCE_WASAPI=0 + JUCE_WEB_BROWSER=0) + +target_link_libraries(CardinalSynth + PRIVATE + juce::juce_audio_utils + ${STATIC_LIBS_START} + sCardinalSynth + sPlugins + sRack + carla_host_plugin + carla_engine_plugin + carla_plugin + native_plugins + audio_decoder + jackbridge + lilv + rtmempool + sfzero + water + zita_resampler + dgl + libarchive + libjansson + libquickjs + libsamplerate + libspeexdsp + libzstd + ${STATIC_LIBS_END} + ${GL_LIBRARIES} + ${DBUS_LIBRARIES} + -L${LIBLO_LIBRARY_DIRS} + ${LIBLO_LIBRARIES} + ${SNDFILE_LIBRARIES} + ${X11_LIBRARIES} + ${XCURSOR_LIBRARIES} + ${XEXT_LIBRARIES} + ${XRANDR_LIBRARIES} + ${EXTRA_LIBS} + -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 4d3a435f..c4da989a 100644 --- a/jucewrapper/CardinalWrapper.cpp +++ b/jucewrapper/CardinalWrapper.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 @@ -17,46 +17,62 @@ #include -#include "DistrhoPlugin.hpp" -#include "DistrhoUI.hpp" - -DISTRHO_PLUGIN_EXPORT DISTRHO_NAMESPACE::Plugin* createSharedPlugin(); -#define createPlugin ::createSharedPlugin +#define createPlugin createStaticPlugin #include "src/DistrhoPluginInternal.hpp" +#include "src/DistrhoUIInternal.hpp" START_NAMESPACE_DISTRHO -// ----------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- -class ParameterForDPF : public juce::AudioProcessorParameter +class ParameterFromDPF : public juce::AudioProcessorParameter { PluginExporter& plugin; + const ParameterEnumerationValues& enumValues; + const ParameterRanges& ranges; + const uint32_t hints; const uint index; + bool* const updatedPtr; + mutable juce::StringArray dpfValueStrings; public: - ParameterForDPF(PluginExporter& plugin_, const uint index_) + ParameterFromDPF(PluginExporter& plugin_, const uint index_, bool* const updatedPtr_) : plugin(plugin_), - index(index_) {} + enumValues(plugin_.getParameterEnumValues(index_)), + ranges(plugin_.getParameterRanges(index_)), + hints(plugin_.getParameterHints(index_)), + index(index_), + updatedPtr(updatedPtr_) {} + + void setValueNotifyingHostFromDPF(const float newValue) + { + setValueNotifyingHost(ranges.getNormalizedValue(newValue)); + *updatedPtr = false; + } protected: float getValue() const override { - return plugin.getParameterRanges(index).getNormalizedValue(plugin.getParameterValue(index)); + return ranges.getNormalizedValue(plugin.getParameterValue(index)); } void setValue(const float newValue) override { - plugin.setParameterValue(index, plugin.getParameterRanges(index).getUnnormalizedValue(newValue)); + *updatedPtr = true; + plugin.setParameterValue(index, ranges.getUnnormalizedValue(newValue)); } float getDefaultValue() const override { - return plugin.getParameterDefault(index); + return ranges.getNormalizedValue(plugin.getParameterDefault(index)); } - juce::String getName(int) const override + juce::String getName(const int maximumStringLength) const override { - return plugin.getParameterName(index).buffer(); + if (maximumStringLength <= 0) + return juce::String(plugin.getParameterName(index).buffer()); + + return juce::String(plugin.getParameterName(index).buffer(), static_cast(maximumStringLength)); } juce::String getLabel() const override @@ -64,40 +80,219 @@ class ParameterForDPF : public juce::AudioProcessorParameter return plugin.getParameterUnit(index).buffer(); } - float getValueForText(const juce::String& text) const override + int getNumSteps() const override { - return 0.0f; - } -}; + if (hints & kParameterIsBoolean) + return 2; -// ----------------------------------------------------------------------------------------------------------- + if (enumValues.restrictedMode) + return enumValues.count; -class CardinalWrapperProcessor : public juce::AudioProcessor -{ - PluginExporter plugin; + if (hints & kParameterIsInteger) + return ranges.max - ranges.min; - static bool writeMidiCb(void* ptr, const MidiEvent& midiEvent) + return juce::AudioProcessorParameter::getNumSteps(); + } + + bool isDiscrete() const override { + if (hints & (kParameterIsBoolean|kParameterIsInteger)) + return true; + + if (enumValues.restrictedMode) + return true; + return false; } - static bool requestParameterValueChangeCb(void* ptr, uint32_t index, float value) + bool isBoolean() const override { - return false; + return (hints & kParameterIsBoolean) != 0x0; + } + + juce::String getText(const float normalizedValue, const int maximumStringLength) const override + { + float value = ranges.getUnnormalizedValue(normalizedValue); + + if (hints & kParameterIsBoolean) + { + const float midRange = ranges.min + (ranges.max - ranges.min) * 0.5f; + value = value > midRange ? ranges.max : ranges.min; + } + else if (hints & kParameterIsInteger) + { + value = std::round(value); + } + + if (enumValues.restrictedMode) + { + for (uint32_t i=0; i < enumValues.count; ++i) + { + if (d_isEqual(enumValues.values[i].value, value)) + { + if (maximumStringLength <= 0) + return juce::String(enumValues.values[i].label); + + return juce::String(enumValues.values[i].label, static_cast(maximumStringLength)); + } + } + } + + juce::String text; + if (hints & kParameterIsInteger) + text = juce::String(static_cast(value)); + else + text = juce::String(value); + + if (maximumStringLength <= 0) + return text; + + return juce::String(text.toRawUTF8(), static_cast(maximumStringLength)); + } + + float getValueForText(const juce::String& text) const override + { + if (enumValues.restrictedMode) + { + for (uint32_t i=0; i < enumValues.count; ++i) + { + if (text == enumValues.values[i].label.buffer()) + return ranges.getNormalizedValue(enumValues.values[i].value); + } + } + + float value; + if (hints & kParameterIsInteger) + value = std::atoi(text.toRawUTF8()); + else + value = std::atof(text.toRawUTF8()); + + return ranges.getFixedAndNormalizedValue(value); + } + + bool isAutomatable() const override + { + return (hints & kParameterIsAutomatable) != 0x0; + } + + juce::String getCurrentValueAsText() const override + { + const float value = plugin.getParameterValue(index); + + if (enumValues.restrictedMode) + { + for (uint32_t i=0; i < enumValues.count; ++i) + { + if (d_isEqual(enumValues.values[i].value, value)) + return juce::String(enumValues.values[i].label); + } + } + + if (hints & kParameterIsInteger) + return juce::String(static_cast(value)); + + return juce::String(value); + } + + juce::StringArray getAllValueStrings() const override + { + if (dpfValueStrings.size() != 0) + return dpfValueStrings; + + if (enumValues.restrictedMode) + { + for (uint32_t i=0; i < enumValues.count; ++i) + dpfValueStrings.add(enumValues.values[i].label.buffer()); + + return dpfValueStrings; + } + + if (hints & kParameterIsBoolean) + { + if (hints & kParameterIsInteger) + { + dpfValueStrings.add(juce::String(static_cast(ranges.min))); + dpfValueStrings.add(juce::String(static_cast(ranges.max))); + } + else + { + dpfValueStrings.add(juce::String(ranges.min)); + dpfValueStrings.add(juce::String(ranges.max)); + } + } + else if (hints & kParameterIsInteger) + { + const int imin = static_cast(ranges.min); + const int imax = static_cast(ranges.max); + + for (int i=imin; i<=imax; ++i) + dpfValueStrings.add(juce::String(i)); + } + + return dpfValueStrings; } +}; + +// -------------------------------------------------------------------------------------------------------------------- + +// unused in cardinal +static constexpr const requestParameterValueChangeFunc nullRequestParameterValueChangeFunc = nullptr; + +// only needed for headless builds, which this wrapper never builds for +static constexpr const updateStateValueFunc nullUpdateStateValueFunc = nullptr; + +// DSP/processor implementation +class CardinalWrapperProcessor : public juce::AudioProcessor +{ + friend class CardinalWrapperEditor; + + PluginExporter plugin; + MidiEvent midiEvents[kMaxMidiEvents]; + TimePosition timePosition; + const uint32_t parameterCount; + + juce::AudioProcessorParameter* bypassParameter; + juce::MidiBuffer* currentMidiMessages; + bool* updatedParameters; public: CardinalWrapperProcessor() - : plugin(this, writeMidiCb, requestParameterValueChangeCb) + : plugin(this, writeMidiFunc, nullRequestParameterValueChangeFunc, nullUpdateStateValueFunc), + parameterCount(plugin.getParameterCount()), + bypassParameter(nullptr), + currentMidiMessages(nullptr), + updatedParameters(nullptr) { - for (uint i=0; i 0.0) + plugin.setSampleRate(sampleRate); + + if (const int samplesPerBlock = getBlockSize()) + if (samplesPerBlock > 0) + plugin.setBufferSize(static_cast(samplesPerBlock)); + + if (parameterCount != 0) + { + updatedParameters = new bool[parameterCount]; + std::memset(updatedParameters, 0, sizeof(bool)*parameterCount); + + for (uint i=0; i 0,); + plugin.deactivateIfNeeded(); plugin.setSampleRate(sampleRate); - plugin.setBufferSize(samplesPerBlock); + plugin.setBufferSize(static_cast(samplesPerBlock)); plugin.activate(); } @@ -123,13 +320,100 @@ class CardinalWrapperProcessor : public juce::AudioProcessor void processBlock(juce::AudioBuffer& buffer, juce::MidiBuffer& midiMessages) override { + const int numSamples = buffer.getNumSamples(); + DISTRHO_SAFE_ASSERT_INT_RETURN(numSamples > 0, numSamples, midiMessages.clear()); + + uint32_t midiEventCount = 0; + + for (const juce::MidiMessageMetadata midiMessage : midiMessages) + { + DISTRHO_SAFE_ASSERT_CONTINUE(midiMessage.numBytes > 0); + DISTRHO_SAFE_ASSERT_CONTINUE(midiMessage.samplePosition >= 0); + + if (midiMessage.numBytes > static_cast(MidiEvent::kDataSize)) + continue; + + MidiEvent& midiEvent(midiEvents[midiEventCount++]); + + midiEvent.frame = static_cast(midiMessage.samplePosition); + midiEvent.size = (static_cast(midiMessage.numBytes)); + std::memcpy(midiEvent.data, midiMessage.data, midiEvent.size); + + if (midiEventCount == kMaxMidiEvents) + break; + } + midiMessages.clear(); - // AudioPlayHead* getPlayHead() + + const juce::ScopedValueSetter cvs(currentMidiMessages, &midiMessages, nullptr); + + juce::AudioPlayHead* const playhead = getPlayHead(); + juce::AudioPlayHead::CurrentPositionInfo posInfo; + + if (playhead != nullptr && playhead->getCurrentPosition(posInfo)) + { + timePosition.playing = posInfo.isPlaying; + timePosition.bbt.valid = true; + + // ticksPerBeat is not possible with JUCE + timePosition.bbt.ticksPerBeat = 1920.0; + + if (posInfo.timeInSamples >= 0) + timePosition.frame = static_cast(posInfo.timeInSamples); + else + timePosition.frame = 0; + + timePosition.bbt.beatsPerMinute = posInfo.bpm; + + const double ppqPos = std::abs(posInfo.ppqPosition); + const int ppqPerBar = posInfo.timeSigNumerator * 4 / posInfo.timeSigDenominator; + const double barBeats = (std::fmod(ppqPos, ppqPerBar) / ppqPerBar) * posInfo.timeSigNumerator; + const double rest = std::fmod(barBeats, 1.0); + + timePosition.bbt.bar = static_cast(ppqPos) / ppqPerBar + 1; + timePosition.bbt.beat = static_cast(barBeats - rest + 0.5) + 1; + timePosition.bbt.tick = rest * timePosition.bbt.ticksPerBeat; + timePosition.bbt.beatsPerBar = posInfo.timeSigNumerator; + timePosition.bbt.beatType = posInfo.timeSigDenominator; + + if (posInfo.ppqPosition < 0.0) + { + --timePosition.bbt.bar; + timePosition.bbt.beat = posInfo.timeSigNumerator - timePosition.bbt.beat + 1; + timePosition.bbt.tick = timePosition.bbt.ticksPerBeat - timePosition.bbt.tick - 1; + } + + timePosition.bbt.barStartTick = timePosition.bbt.ticksPerBeat* + timePosition.bbt.beatsPerBar* + (timePosition.bbt.bar-1); + } + else + { + timePosition.frame = 0; + timePosition.playing = false; + timePosition.bbt.valid = false; + } + + plugin.setTimePosition(timePosition); + + DISTRHO_SAFE_ASSERT_RETURN(buffer.getNumChannels() == 2,); + + const float* audioBufferIn[2]; + float* audioBufferOut[2]; + audioBufferIn[0] = buffer.getReadPointer(0); + audioBufferIn[1] = buffer.getReadPointer(1); + audioBufferOut[0] = buffer.getWritePointer(0); + audioBufferOut[1] = buffer.getWritePointer(1); + + plugin.run(audioBufferIn, audioBufferOut, static_cast(numSamples), midiEvents, midiEventCount); } + // fix compiler warning + void processBlock(juce::AudioBuffer&, juce::MidiBuffer&) override {} + double getTailLengthSeconds() const override { - return true; + return 0.0; } bool acceptsMidi() const override @@ -142,6 +426,11 @@ class CardinalWrapperProcessor : public juce::AudioProcessor return true; } + juce::AudioProcessorParameter* getBypassParameter() const override + { + return bypassParameter; + } + juce::AudioProcessorEditor* createEditor() override; bool hasEditor() const override @@ -151,7 +440,7 @@ class CardinalWrapperProcessor : public juce::AudioProcessor int getNumPrograms() override { - return 0; + return 1; } int getCurrentProgram() override @@ -165,7 +454,7 @@ class CardinalWrapperProcessor : public juce::AudioProcessor const juce::String getProgramName(int) override { - return {}; + return "Default"; } void changeProgramName(int, const juce::String&) override @@ -174,37 +463,219 @@ class CardinalWrapperProcessor : public juce::AudioProcessor void getStateInformation(juce::MemoryBlock& destData) override { + juce::XmlElement xmlState("CardinalState"); + + for (uint32_t i=0; i xmlState(getXmlFromBinary(data, sizeInBytes)); + DISTRHO_SAFE_ASSERT_RETURN(xmlState.get() != nullptr,); + + const juce::Array& parameters(getParameters()); + + for (uint32_t i=0; igetDoubleAttribute(plugin.getParameterSymbol(i).buffer(), + plugin.getParameterDefault(i)); + const float normalizedValue = plugin.getParameterRanges(i).getFixedAndNormalizedValue(value); + parameters.getUnchecked(static_cast(i))->setValueNotifyingHost(normalizedValue); + } + + for (uint32_t i=0, stateCount=plugin.getStateCount(); igetStringAttribute(key.buffer(), + plugin.getStateDefaultValue(i).buffer()); + plugin.setState(key, value.toRawUTF8()); + } } - void setStateInformation(const void* data, int sizeInBytes) override +private: + static bool writeMidiFunc(void* const ptr, const MidiEvent& midiEvent) { + CardinalWrapperProcessor* const processor = static_cast(ptr); + DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, false); + + juce::MidiBuffer* const currentMidiMessages = processor->currentMidiMessages; + DISTRHO_SAFE_ASSERT_RETURN(currentMidiMessages != nullptr, false); + + const uint8_t* const data = midiEvent.size > MidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data; + return currentMidiMessages->addEvent(data, + static_cast(midiEvent.size), + static_cast(midiEvent.frame)); } }; -class CardinalWrapperEditor : public juce::AudioProcessorEditor +// -------------------------------------------------------------------------------------------------------------------- + +// unused in cardinal +static constexpr const sendNoteFunc nullSendNoteFunc = nullptr; + +// unwanted, juce file dialogs are ugly +static constexpr const fileRequestFunc nullFileRequestFunc = nullptr; + +// UI/editor implementation +class CardinalWrapperEditor : public juce::AudioProcessorEditor, + private juce::Timer { + CardinalWrapperProcessor& cardinalProcessor; + + UIExporter* ui; + void* const dspPtr; + public: - CardinalWrapperEditor(CardinalWrapperProcessor& processor) - : juce::AudioProcessorEditor(processor) - {} + CardinalWrapperEditor(CardinalWrapperProcessor& cardinalProc) + : juce::AudioProcessorEditor(cardinalProc), + cardinalProcessor(cardinalProc), + ui(nullptr), + dspPtr(cardinalProc.plugin.getInstancePointer()) + { + setOpaque(true); + setResizable(true, false); + // setResizeLimits(648, 538, -1, -1); + setSize(1228, 666); + + startTimer(1000.0 / 60.0); + } ~CardinalWrapperEditor() override - {} + { + stopTimer(); + delete ui; + } + +protected: + void timerCallback() override + { + if (ui == nullptr) + return; + + for (uint32_t i=0; iparameterChanged(i, cardinalProcessor.plugin.getParameterValue(i)); + } + } + + repaint(); + } + + void paint(juce::Graphics&) override + { + if (ui == nullptr) + { + juce::ComponentPeer* const peer = getPeer(); + DISTRHO_SAFE_ASSERT_RETURN(peer != nullptr,); + + void* const nativeHandle = peer->getNativeHandle(); + DISTRHO_SAFE_ASSERT_RETURN(nativeHandle != nullptr,); + + ui = new UIExporter(this, + (uintptr_t)nativeHandle, + cardinalProcessor.getSampleRate(), + editParamFunc, + setParamFunc, + setStateFunc, + nullSendNoteFunc, + setSizeFunc, + nullFileRequestFunc, + nullptr, // bundlePath + dspPtr, + 0.0 // scaleFactor + ); + + if (cardinalProcessor.wrapperType == juce::AudioProcessor::wrapperType_Standalone) + { + const double scaleFactor = ui->getScaleFactor(); + ui->setWindowOffset(4 * scaleFactor, 30 * scaleFactor); + } + } + + ui->plugin_idle(); + } + +private: + static void editParamFunc(void* const ptr, const uint32_t index, const bool started) + { + CardinalWrapperEditor* const editor = static_cast(ptr); + DISTRHO_SAFE_ASSERT_RETURN(editor != nullptr,); + + CardinalWrapperProcessor& cardinalProcessor(editor->cardinalProcessor); + + if (started) + cardinalProcessor.getParameters().getUnchecked(static_cast(index))->beginChangeGesture(); + else + cardinalProcessor.getParameters().getUnchecked(static_cast(index))->endChangeGesture(); + } + + static void setParamFunc(void* const ptr, const uint32_t index, const float value) + { + CardinalWrapperEditor* const editor = static_cast(ptr); + DISTRHO_SAFE_ASSERT_RETURN(editor != nullptr,); + + CardinalWrapperProcessor& cardinalProcessor(editor->cardinalProcessor); + const juce::Array& parameters(cardinalProcessor.getParameters()); + juce::AudioProcessorParameter* const parameter = parameters.getUnchecked(static_cast(index)); + static_cast(parameter)->setValueNotifyingHostFromDPF(value); + } + + static void setStateFunc(void* const ptr, const char* const key, const char* const value) + { + CardinalWrapperEditor* const editor = static_cast(ptr); + DISTRHO_SAFE_ASSERT_RETURN(editor != nullptr,); + + CardinalWrapperProcessor& cardinalProcessor(editor->cardinalProcessor); + cardinalProcessor.plugin.setState(key, value); + } + + static void setSizeFunc(void* const ptr, uint width, uint height) + { + CardinalWrapperEditor* const editor = static_cast(ptr); + DISTRHO_SAFE_ASSERT_RETURN(editor != nullptr,); + + #ifdef DISTRHO_OS_MAC + UIExporter* const ui = editor->ui; + DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); + + const double scaleFactor = ui->getScaleFactor(); + width /= scaleFactor; + height /= scaleFactor; + #endif + + editor->setSize(static_cast(width), static_cast(height)); + } }; -// ----------------------------------------------------------------------------------------------------------- +juce::AudioProcessorEditor* CardinalWrapperProcessor::createEditor() +{ + return new CardinalWrapperEditor(*this); +} + +// -------------------------------------------------------------------------------------------------------------------- END_NAMESPACE_DISTRHO -// ----------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- juce::AudioProcessor* createPluginFilter() { + // set valid but dummy values + d_nextBufferSize = 512; + d_nextSampleRate = 48000.0; return new DISTRHO_NAMESPACE::CardinalWrapperProcessor; } -// ----------------------------------------------------------------------------------------------------------- - -#define DISTRHO_IS_STANDALONE 0 -#include "src/DistrhoPlugin.cpp" -#include "src/DistrhoUtils.cpp" +// -------------------------------------------------------------------------------------------------------------------- diff --git a/patches/DRMR_-_Interverb.vcv b/patches/DRMR_-_Interverb.vcv new file mode 100644 index 00000000..6a6fa18a --- /dev/null +++ b/patches/DRMR_-_Interverb.vcv @@ -0,0 +1,657 @@ +{ + "version": "2.0", + "zoom": 1.0, + "gridOffset": [ + -3.4424479007720947, + 0.86171877384185791 + ], + "modules": [ + { + "id": 1184757612963547, + "plugin": "Valley", + "model": "Interzone", + "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": 1.0, + "id": 4 + }, + { + "value": 0.0, + "id": 5 + }, + { + "value": 0.26100000739097595, + "id": 6 + }, + { + "value": 0.26799961924552917, + "id": 7 + }, + { + "value": 0.0, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + }, + { + "value": 0.0, + "id": 10 + }, + { + "value": 0.23399992287158966, + "id": 11 + }, + { + "value": 1.8360022306442261, + "id": 12 + }, + { + "value": 0.0, + "id": 13 + }, + { + "value": 1.0, + "id": 14 + }, + { + "value": 0.24399974942207336, + "id": 15 + }, + { + "value": 0.92999976873397827, + "id": 16 + }, + { + "value": 0.48200002312660217, + "id": 17 + }, + { + "value": 0.0, + "id": 18 + }, + { + "value": 0.0, + "id": 19 + }, + { + "value": 8.0599746704101562, + "id": 20 + }, + { + "value": 3.6200008392333984, + "id": 21 + }, + { + "value": 0.0, + "id": 22 + }, + { + "value": 1.0, + "id": 23 + }, + { + "value": 0.24999970197677612, + "id": 24 + }, + { + "value": 0.058000005781650543, + "id": 25 + }, + { + "value": 0.45800071954727173, + "id": 26 + }, + { + "value": 0.0, + "id": 27 + }, + { + "value": 0.0, + "id": 28 + }, + { + "value": 0.46746969223022461, + "id": 29 + }, + { + "value": 0.0, + "id": 30 + }, + { + "value": 0.0, + "id": 31 + }, + { + "value": 0.20722892880439758, + "id": 32 + }, + { + "value": 1.0, + "id": 33 + }, + { + "value": 0.60399961471557617, + "id": 34 + }, + { + "value": 0.24399995803833008, + "id": 35 + }, + { + "value": 0.85800004005432129, + "id": 36 + }, + { + "value": 0.25000002980232239, + "id": 37 + }, + { + "value": 0.0, + "id": 38 + }, + { + "value": 0.0, + "id": 39 + }, + { + "value": 0.0, + "id": 40 + }, + { + "value": 1.0, + "id": 41 + }, + { + "value": 0.0, + "id": 42 + } + ], + "data": { + "panelStyle": 0 + }, + "pos": [ + 12, + 1 + ] + }, + { + "id": 7479062205976098, + "plugin": "repelzen", + "model": "rexmix", + "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": -11.855396270751953, + "id": 4 + }, + { + "value": -10.481927871704102, + "id": 5 + }, + { + "value": 0.0, + "id": 6 + }, + { + "value": -60.0, + "id": 7 + }, + { + "value": -60.0, + "id": 8 + }, + { + "value": -60.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.21927711367607117, + "id": 34 + }, + { + "value": 0.26265060901641846, + "id": 35 + }, + { + "value": 0.0, + "id": 36 + }, + { + "value": 0.0, + "id": 37 + }, + { + "value": 0.0, + "id": 38 + }, + { + "value": 0.0, + "id": 39 + }, + { + "value": 0.66747087240219116, + "id": 40 + }, + { + "value": 0.31686747074127197, + "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 + } + ], + "rightModuleId": 1, + "pos": [ + 47, + 1 + ] + }, + { + "id": 5265678395554143, + "plugin": "ihtsyn", + "model": "MVerb", + "version": "2.0", + "params": [ + { + "value": 1.0, + "id": 0 + }, + { + "value": 0.31204831600189209, + "id": 1 + }, + { + "value": 0.69638609886169434, + "id": 2 + }, + { + "value": 0.50963789224624634, + "id": 3 + }, + { + "value": 0.5, + "id": 4 + }, + { + "value": 0.68000000715255737, + "id": 5 + }, + { + "value": 0.60000002384185791, + "id": 6 + }, + { + "value": 0.80000001192092896, + "id": 7 + }, + { + "value": 0.5, + "id": 8 + }, + { + "value": 0.0, + "id": 9 + } + ], + "pos": [ + 50, + 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", + "model": "TextEditor", + "version": "2.0", + "params": [], + "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", + "width": 27 + }, + "pos": [ + 2, + 2 + ] + }, + { + "id": 1, + "plugin": "Cardinal", + "model": "HostAudio2", + "version": "2.0", + "params": [ + { + "value": 1.0, + "id": 0 + } + ], + "leftModuleId": 7479062205976098, + "data": { + "dcFilter": true + }, + "pos": [ + 75, + 1 + ] + }, + { + "id": 2, + "plugin": "Cardinal", + "model": "HostMIDI", + "version": "2.0", + "params": [], + "data": { + "smooth": true, + "channels": 4, + "polyMode": 0, + "lastPitch": 8192, + "lastMod": 0, + "inputChannel": 0, + "outputChannel": 0 + }, + "pos": [ + 0, + 1 + ] + }, + { + "id": 4, + "plugin": "Cardinal", + "model": "HostParameters", + "version": "2.0", + "params": [], + "pos": [ + 32, + 2 + ] + } + ], + "cables": [ + { + "id": 6433670563492534, + "outputModuleId": 7479062205976098, + "outputId": 1, + "inputModuleId": 1, + "inputId": 1, + "color": "#67ff52" + }, + { + "id": 7811632878270413, + "outputModuleId": 7479062205976098, + "outputId": 0, + "inputModuleId": 1, + "inputId": 0, + "color": "#52ff7d" + }, + { + "id": 5639365994348230, + "outputModuleId": 1184757612963547, + "outputId": 5, + "inputModuleId": 7479062205976098, + "inputId": 4, + "color": "#6752ff" + }, + { + "id": 4697080526212779, + "outputModuleId": 7479062205976098, + "outputId": 3, + "inputModuleId": 5265678395554143, + "inputId": 1, + "color": "#527dff" + }, + { + "id": 749068877206824, + "outputModuleId": 7479062205976098, + "outputId": 2, + "inputModuleId": 5265678395554143, + "inputId": 0, + "color": "#52beff" + }, + { + "id": 385489337409134, + "outputModuleId": 5265678395554143, + "outputId": 1, + "inputModuleId": 7479062205976098, + "inputId": 1, + "color": "#52ffff" + }, + { + "id": 6967686280457428, + "outputModuleId": 5265678395554143, + "outputId": 0, + "inputModuleId": 7479062205976098, + "inputId": 0, + "color": "#52ffbe" + }, + { + "id": 8997840924253604, + "outputModuleId": 4, + "outputId": 0, + "inputModuleId": 1184757612963547, + "inputId": 2, + "color": "#a852ff" + }, + { + "id": 2740863142747665, + "outputModuleId": 4, + "outputId": 1, + "inputModuleId": 1184757612963547, + "inputId": 7, + "color": "#e952ff" + }, + { + "id": 5297103153509182, + "outputModuleId": 2, + "outputId": 1, + "inputModuleId": 1184757612963547, + "inputId": 3, + "color": "#ff9352" + }, + { + "id": 7340028675801259, + "outputModuleId": 4, + "outputId": 2, + "inputModuleId": 1184757612963547, + "inputId": 8, + "color": "#ff5252" + }, + { + "id": 5629473447667825, + "outputModuleId": 2, + "outputId": 0, + "inputModuleId": 1184757612963547, + "inputId": 0, + "color": "#ff5252" + } + ] +} diff --git a/plugins/AmalgamatedHarmonics b/plugins/AmalgamatedHarmonics index 35b89c93..21a03187 160000 --- a/plugins/AmalgamatedHarmonics +++ b/plugins/AmalgamatedHarmonics @@ -1 +1 @@ -Subproject commit 35b89c93152ac2194eecffbd4aa39e71caa90cc0 +Subproject commit 21a031870db2068a98d9690eaffc24bbbfc99c2e diff --git a/plugins/ArableInstruments b/plugins/ArableInstruments new file mode 160000 index 00000000..890448f0 --- /dev/null +++ b/plugins/ArableInstruments @@ -0,0 +1 @@ +Subproject commit 890448f087e3ab47eac391f9bcfe03f7bbd2123e diff --git a/plugins/BaconPlugs b/plugins/BaconPlugs index 0a6c390e..9d35b745 160000 --- a/plugins/BaconPlugs +++ b/plugins/BaconPlugs @@ -1 +1 @@ -Subproject commit 0a6c390eedf98884393f82cb066038a78a316ea5 +Subproject commit 9d35b745af8569d6a9d6bc5c3f2c3e64c852d8e0 diff --git a/plugins/Befaco b/plugins/Befaco index ec406ce1..7e0b0200 160000 --- a/plugins/Befaco +++ b/plugins/Befaco @@ -1 +1 @@ -Subproject commit ec406ce181f340bce8e475cb508c4db0db02fdc6 +Subproject commit 7e0b020000225e3d2aecba3f09054595339fe540 diff --git a/plugins/Bidoo b/plugins/Bidoo index e55fcd2e..f771bf27 160000 --- a/plugins/Bidoo +++ b/plugins/Bidoo @@ -1 +1 @@ -Subproject commit e55fcd2e1d7c0fef69d4919baac6f791172c89ca +Subproject commit f771bf270393b8587516329614ba76e2894355b7 diff --git a/plugins/BidooDark/plugin.cpp b/plugins/BidooDark/plugin.cpp new file mode 100644 index 00000000..f0a0c0ce --- /dev/null +++ b/plugins/BidooDark/plugin.cpp @@ -0,0 +1,34 @@ +#include "../Bidoo/src/plugin.hpp" +#undef ModuleWidget + +void InstantiateExpanderItem::onAction(const event::Action &e) { + engine::Module* module = model->createModule(); + APP->engine->addModule(module); + ModuleWidget* mw = model->createModuleWidget(module); + if (mw) { + APP->scene->rack->setModulePosNearest(mw, posit); + APP->scene->rack->addModule(mw); + history::ModuleAdd *h = new history::ModuleAdd; + h->name = "create expander module"; + h->setModule(mw); + APP->history->push(h); + } +} + +json_t* BidooModule::dataToJson() { + return nullptr; +} + +void BidooModule::dataFromJson(json_t*) { +} + +void BidooWidget::appendContextMenu(Menu*) { +} + +void BidooWidget::prepareThemes(const std::string& filename) { + setPanel(APP->window->loadSvg(filename)); +} + +void BidooWidget::step() { + CardinalModuleWidget::step(); +} diff --git a/plugins/BogaudioModules b/plugins/BogaudioModules index 8e982f46..a86e7d7b 160000 --- a/plugins/BogaudioModules +++ b/plugins/BogaudioModules @@ -1 +1 @@ -Subproject commit 8e982f462c4117f84794cbf6a13740992ff17d92 +Subproject commit a86e7d7b18e0c7cb6e857df36263b0e85bf85566 diff --git a/plugins/Cardinal/src/AudioFile.cpp b/plugins/Cardinal/src/AudioFile.cpp index ed72126b..a76d4126 100644 --- a/plugins/Cardinal/src/AudioFile.cpp +++ b/plugins/Cardinal/src/AudioFile.cpp @@ -99,7 +99,7 @@ struct CarlaInternalPluginModule : Module, Thread { float dataOut[NUM_OUTPUTS][BUFFER_SIZE]; float* dataOutPtr[NUM_OUTPUTS]; unsigned audioDataFill = 0; - int64_t lastBlockFrame = -1; + uint32_t lastProcessCounter = 0; bool fileChanged = false; std::string currentFile; @@ -300,12 +300,12 @@ struct CarlaInternalPluginModule : Module, Thread { if (audioDataFill == BUFFER_SIZE) { - const int64_t blockFrame = pcontext->engine->getBlockFrame(); + const uint32_t processCounter = pcontext->processCounter; // Update time position if running a new audio block - if (lastBlockFrame != blockFrame) + if (lastProcessCounter != processCounter) { - lastBlockFrame = blockFrame; + lastProcessCounter = processCounter; fCarlaTimeInfo.playing = pcontext->playing; fCarlaTimeInfo.frame = pcontext->frame; } diff --git a/plugins/Cardinal/src/Carla.cpp b/plugins/Cardinal/src/Carla.cpp index cdd32568..30fef47f 100644 --- a/plugins/Cardinal/src/Carla.cpp +++ b/plugins/Cardinal/src/Carla.cpp @@ -95,10 +95,15 @@ struct CarlaModule : Module { float* dataInPtr[NUM_INPUTS]; float* dataOutPtr[NUM_OUTPUTS]; unsigned audioDataFill = 0; - int64_t lastBlockFrame = -1; + uint32_t lastProcessCounter = 0; CardinalExpanderFromCarlaMIDIToCV* midiOutExpander = nullptr; std::string patchStorage; +#ifdef CARLA_OS_WIN + // must keep string pointer valid + std::string winResourceDir; +#endif + CarlaModule() : pcontext(static_cast(APP)) { @@ -138,10 +143,14 @@ struct CarlaModule : Module { binaryDir = "/Applications/Carla.app/Contents/MacOS"; resourceDir = "/Applications/Carla.app/Contents/MacOS/resources"; } -#elif defined(CARLA_OS_WINDOWS) - // Carla does not support system-wide install on Windows right now - if (false) +#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")) @@ -318,12 +327,12 @@ struct CarlaModule : Module { if (audioDataFill == BUFFER_SIZE) { - const int64_t blockFrame = pcontext->engine->getBlockFrame(); + const uint32_t processCounter = pcontext->processCounter; // Update time position if running a new audio block - if (lastBlockFrame != blockFrame) + if (lastProcessCounter != processCounter) { - lastBlockFrame = blockFrame; + lastProcessCounter = processCounter; fCarlaTimeInfo.playing = pcontext->playing; fCarlaTimeInfo.frame = pcontext->frame; fCarlaTimeInfo.bbt.valid = pcontext->bbtValid; diff --git a/plugins/Cardinal/src/HostAudio.cpp b/plugins/Cardinal/src/HostAudio.cpp index 68459aeb..d5f4c647 100644 --- a/plugins/Cardinal/src/HostAudio.cpp +++ b/plugins/Cardinal/src/HostAudio.cpp @@ -29,18 +29,16 @@ struct HostAudio : TerminalModule { const int numParams; const int numInputs; const int numOutputs; - int dataFrame = 0; - int64_t lastBlockFrame = -1; + bool bypassed = false; + bool in1connected = false; + bool in2connected = false; + uint32_t dataFrame = 0; + uint32_t lastProcessCounter = 0; // for rack core audio module compatibility dsp::RCFilter dcFilters[numIO]; bool dcFilterEnabled = (numIO == 2); - // for stereo meter - volatile bool resetMeters = true; - float gainMeterL = 0.0f; - float gainMeterR = 0.0f; - HostAudio() : pcontext(static_cast(APP)), numParams(numIO == 2 ? 1 : 0), @@ -63,35 +61,39 @@ struct HostAudio : TerminalModule { void onReset() override { dcFilterEnabled = (numIO == 2); - resetMeters = true; } void onSampleRateChange(const SampleRateChangeEvent& e) override { - resetMeters = true; - for (int i=0; iengine->getBlockFrames(); - const int64_t blockFrame = pcontext->engine->getBlockFrame(); + const uint32_t bufferSize = pcontext->bufferSize; + const uint32_t processCounter = pcontext->processCounter; // only checked on input - if (lastBlockFrame != blockFrame) + if (lastProcessCounter != processCounter) { + bypassed = isBypassed(); dataFrame = 0; - lastBlockFrame = blockFrame; + lastProcessCounter = processCounter; + + if (numIO == 2) + { + in1connected = inputs[0].isConnected(); + in2connected = inputs[1].isConnected(); + } } // only incremented on output - const int k = dataFrame; - DISTRHO_SAFE_ASSERT_INT2_RETURN(k < blockFrames, k, blockFrames,); + const uint32_t k = dataFrame; + DISTRHO_SAFE_ASSERT_INT2_RETURN(k < bufferSize, k, bufferSize,); // from host into cardinal, shows as output plug - if (isBypassed()) + if (bypassed) { for (int i=0; i { +#ifndef HEADLESS + // for stereo meter + uint32_t internalDataFrame = 0; + float internalDataBuffer[2][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 + { + HostAudio<2>::onReset(); + resetMeters = true; + } + + void onSampleRateChange(const SampleRateChangeEvent& e) override + { + HostAudio<2>::onSampleRateChange(e); + resetMeters = true; + } +#endif + void processTerminalOutput(const ProcessArgs&) override { - const int blockFrames = pcontext->engine->getBlockFrames(); + if (!in1connected && !in2connected) + return; + + const uint32_t bufferSize = pcontext->bufferSize; // only incremented on output - const int k = dataFrame++; - DISTRHO_SAFE_ASSERT_INT2_RETURN(k < blockFrames, k, blockFrames,); + const uint32_t k = dataFrame++; + DISTRHO_SAFE_ASSERT_INT2_RETURN(k < bufferSize, k, bufferSize,); - if (isBypassed()) + if (bypassed) return; float** const dataOuts = pcontext->dataOuts; - // stereo version gain - const float gain = numParams != 0 ? std::pow(params[0].getValue(), 2.f) : 1.0f; + // gain (stereo variant only) + const float gain = std::pow(params[0].getValue(), 2.f); - // read first value, special case for mono mode - float valueL = inputs[0].getVoltageSum() * 0.1f; + // read stereo values + float valueL, valueR; - // Apply DC filter - if (dcFilterEnabled) + if (in1connected) { - dcFilters[0].process(valueL); - valueL = dcFilters[0].highpass(); - } + valueL = inputs[0].getVoltageSum() * 0.1f; - valueL = clamp(valueL * gain, -1.0f, 1.0f); - dataOuts[0][k] += valueL; + if (dcFilterEnabled) + { + dcFilters[0].process(valueL); + valueL = dcFilters[0].highpass(); + } - // read everything else - for (int i=1; i { + // no meters in this variant + + void processTerminalOutput(const ProcessArgs&) override { - json_t* const rootJ = json_object(); - DISTRHO_SAFE_ASSERT_RETURN(rootJ != nullptr, nullptr); + const uint32_t bufferSize = pcontext->bufferSize; - json_object_set_new(rootJ, "dcFilter", json_boolean(dcFilterEnabled)); - return rootJ; + // only incremented on output + const uint32_t k = dataFrame++; + DISTRHO_SAFE_ASSERT_INT2_RETURN(k < bufferSize, k, bufferSize,); + + if (bypassed) + return; + + float** const dataOuts = pcontext->dataOuts; + + for (int i=0; i +struct HostAudioWidget : ModuleWidgetWith8HP { + HostAudio* const module; + + HostAudioWidget(HostAudio* const m) + : module(m) { - json_t* const dcFilterJ = json_object_get(rootJ, "dcFilter"); - DISTRHO_SAFE_ASSERT_RETURN(dcFilterJ != nullptr,); + setModule(m); + setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostAudio.svg"))); - dcFilterEnabled = json_boolean_value(dcFilterJ); + createAndAddScrews(); + + for (uint i=0; iaddChild(new MenuSeparator); + menu->addChild(createBoolPtrMenuItem("DC blocker", "", &module->dcFilterEnabled)); } }; -template +// -------------------------------------------------------------------------------------------------------------------- + struct HostAudioNanoMeter : NanoMeter { - HostAudio* const module; + HostAudio2* const module; - HostAudioNanoMeter(HostAudio* const m) + HostAudioNanoMeter(HostAudio2* const m) : module(m) { hasGainKnob = true; @@ -211,69 +326,81 @@ struct HostAudioNanoMeter : NanoMeter { } }; -template -struct HostAudioWidget : ModuleWidgetWith8HP { - HostAudio* const module; +// -------------------------------------------------------------------------------------------------------------------- - HostAudioWidget(HostAudio* const m) - : module(m) +struct HostAudioWidget2 : HostAudioWidget<2> { + HostAudioWidget2(HostAudio2* const m) + : HostAudioWidget<2>(m) { - setModule(m); - setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostAudio.svg"))); + // FIXME + const float middleX = box.size.x * 0.5f; + addParam(createParamCentered(Vec(middleX, 310.0f), m, 0)); + + HostAudioNanoMeter* const meter = new HostAudioNanoMeter(m); + meter->box.pos = Vec(middleX - padding + 2.75f, startY + padding * 2); + meter->box.size = Vec(padding * 2.0f - 4.0f, 136.0f); + addChild(meter); + } - createAndAddScrews(); + void draw(const DrawArgs& args) override + { + drawBackground(args.vg); + drawOutputJacksArea(args.vg, 2); + setupTextLines(args.vg); - for (uint i=0; i(Vec(middleX, 310.0f), m, 0)); - - HostAudioNanoMeter* const meter = new HostAudioNanoMeter(m); - meter->box.pos = Vec(middleX - padding + 2.75f, startY + padding * 2); - meter->box.size = Vec(padding * 2.0f - 4.0f, 136.0f); - addChild(meter); - } + ModuleWidgetWith8HP::draw(args); } +}; + +struct HostAudioWidget8 : HostAudioWidget<8> { + HostAudioWidget8(HostAudio8* const m) + : HostAudioWidget<8>(m) {} void draw(const DrawArgs& args) override { drawBackground(args.vg); - drawOutputJacksArea(args.vg, numIO); + drawOutputJacksArea(args.vg, 8); setupTextLines(args.vg); - if (numIO == 2) + for (int i=0; i<8; ++i) { - drawTextLine(args.vg, 0, "Left/M"); - drawTextLine(args.vg, 1, "Right"); - } - else - { - for (int i=0; i('0'+i+1),'\0'}; - drawTextLine(args.vg, i, text); - } + char text[] = {'A','u','d','i','o',' ',static_cast('0'+i+1),'\0'}; + drawTextLine(args.vg, i, text); } ModuleWidgetWith8HP::draw(args); } +}; - void appendContextMenu(Menu* const menu) override { - menu->addChild(new MenuSeparator); - menu->addChild(createBoolPtrMenuItem("DC blocker", "", &module->dcFilterEnabled)); +#else +// -------------------------------------------------------------------------------------------------------------------- + +struct HostAudioWidget2 : ModuleWidget { + HostAudioWidget2(HostAudio2* const module) { + setModule(module); + for (uint i=0; i<2; ++i) { + addInput(createInput({}, module, i)); + addOutput(createOutput({}, module, i)); + } + } +}; +struct HostAudioWidget8 : ModuleWidget { + HostAudioWidget8(HostAudio8* const module) { + setModule(module); + for (uint i=0; i<8; ++i) { + addInput(createInput({}, module, i)); + addOutput(createOutput({}, module, i)); + } } }; // -------------------------------------------------------------------------------------------------------------------- +#endif -Model* modelHostAudio2 = createModel, HostAudioWidget<2>>("HostAudio2"); -Model* modelHostAudio8 = createModel, HostAudioWidget<8>>("HostAudio8"); +Model* modelHostAudio2 = createModel("HostAudio2"); +Model* modelHostAudio8 = createModel("HostAudio8"); // -------------------------------------------------------------------------------------------------------------------- diff --git a/plugins/Cardinal/src/HostCV.cpp b/plugins/Cardinal/src/HostCV.cpp index e2e61ae0..9626219f 100644 --- a/plugins/Cardinal/src/HostCV.cpp +++ b/plugins/Cardinal/src/HostCV.cpp @@ -27,7 +27,7 @@ USE_NAMESPACE_DISTRHO; struct HostCV : TerminalModule { CardinalPluginContext* const pcontext; int dataFrame = 0; - int64_t lastBlockFrame = -1; + uint32_t lastProcessCounter = 0; enum ParamIds { BIPOLAR_INPUTS_1_5, @@ -64,18 +64,19 @@ struct HostCV : TerminalModule { if (pcontext->variant != kCardinalVariantMain) return; - const int64_t blockFrame = pcontext->engine->getBlockFrame(); + const uint32_t bufferSize = pcontext->bufferSize; + const uint32_t processCounter = pcontext->processCounter; // only checked on input - if (lastBlockFrame != blockFrame) + if (lastProcessCounter != processCounter) { dataFrame = 0; - lastBlockFrame = blockFrame; + lastProcessCounter = processCounter; } // only incremented on output - const int k = dataFrame; - DISTRHO_SAFE_ASSERT_RETURN(k < pcontext->engine->getBlockFrames(),); + const uint32_t k = dataFrame; + DISTRHO_SAFE_ASSERT_RETURN(k < bufferSize,); if (isBypassed()) { @@ -102,9 +103,11 @@ struct HostCV : TerminalModule { if (pcontext->variant != kCardinalVariantMain) return; + const uint32_t bufferSize = pcontext->bufferSize; + // only incremented on output - const int k = dataFrame++; - DISTRHO_SAFE_ASSERT_RETURN(k < pcontext->engine->getBlockFrames(),); + const uint32_t k = dataFrame++; + DISTRHO_SAFE_ASSERT_RETURN(k < bufferSize,); if (isBypassed()) return; @@ -124,6 +127,7 @@ struct HostCV : TerminalModule { } }; +#ifndef HEADLESS struct HostCVWidget : ModuleWidgetWith8HP { HostCVWidget(HostCV* const module) { @@ -184,6 +188,17 @@ struct HostCVWidget : ModuleWidgetWith8HP { )); } }; +#else +struct HostCVWidget : ModuleWidget { + HostCVWidget(HostCV* const module) { + setModule(module); + for (uint i=0; i({}, module, i)); + for (uint i=0; i({}, module, i)); + } +}; +#endif // -------------------------------------------------------------------------------------------------------------------- diff --git a/plugins/Cardinal/src/HostMIDI-CC.cpp b/plugins/Cardinal/src/HostMIDI-CC.cpp index 505fc7d7..96b58d5a 100644 --- a/plugins/Cardinal/src/HostMIDI-CC.cpp +++ b/plugins/Cardinal/src/HostMIDI-CC.cpp @@ -62,13 +62,13 @@ struct HostMIDICC : TerminalModule { const MidiEvent* midiEvents; uint32_t midiEventsLeft; uint32_t midiEventFrame; - int64_t lastBlockFrame; + uint32_t lastProcessCounter; uint8_t channel; uint8_t chPressure[16]; uint16_t pitchbend[16]; - // stuff from Rack + // adapted from Rack /** [cc][channel] */ uint8_t ccValues[128][16]; /** When LSB is enabled for CC 0-31, the MSB is stored here until the LSB is received. @@ -85,10 +85,11 @@ struct HostMIDICC : TerminalModule { MidiInput(CardinalPluginContext* const pc) : pcontext(pc) { - for (int i = 0; i < NUM_OUTPUTS; i++) { - for (int c = 0; c < 16; c++) { - valueFilters[i][c].setTau(1 / 30.f); - } + // adapted from Rack + for (int id = 0; id < NUM_OUTPUTS; ++id) + { + for (int c = 0; c < 16; ++c) + valueFilters[id][c].setTau(1 / 30.f); } reset(); } @@ -98,40 +99,33 @@ struct HostMIDICC : TerminalModule { midiEvents = nullptr; midiEventsLeft = 0; midiEventFrame = 0; - lastBlockFrame = -1; + lastProcessCounter = 0; channel = 0; - for (int cc = 0; cc < 128; cc++) { - for (int c = 0; c < 16; c++) { - ccValues[cc][c] = 0; - } - } - for (int cc = 0; cc < 32; cc++) { - for (int c = 0; c < 16; c++) { - msbValues[cc][c] = 0; - } - } - for (int c = 0; c < 16; c++) { - chPressure[c] = 0; + // adapted from Rack + std::memset(ccValues, 0, sizeof(ccValues)); + std::memset(msbValues, 0, sizeof(msbValues)); + std::memset(chPressure, 0, sizeof(chPressure)); + + for (int c = 0; c < 16; ++c) pitchbend[c] = 8192; - } + learningId = -1; smooth = true; mpeMode = false; lsbMode = false; } - bool process(const ProcessArgs& args, std::vector& outputs, int learnedCcs[16], + bool process(const ProcessArgs& args, std::vector& outputs, int8_t learnedCcs[16], const bool isBypassed) { // Cardinal specific - const int64_t blockFrame = pcontext->engine->getBlockFrame(); - const bool blockFrameChanged = lastBlockFrame != blockFrame; + const uint32_t processCounter = pcontext->processCounter; + const bool processCounterChanged = lastProcessCounter != processCounter; - if (blockFrameChanged) + if (processCounterChanged) { - lastBlockFrame = blockFrame; - + lastProcessCounter = processCounter; midiEvents = pcontext->midiEvents; midiEventsLeft = pcontext->midiEventCount; midiEventFrame = 0; @@ -166,27 +160,38 @@ struct HostMIDICC : TerminalModule { const uint8_t status = data[0] & 0xF0; const uint8_t chan = data[0] & 0x0F; - /**/ if (status == 0xD0) + if (status == 0xD0) { chPressure[chan] = data[1]; + continue; } - else if (status == 0xE0) + if (status == 0xE0) { pitchbend[chan] = (data[2] << 7) | data[1]; + continue; } - else if (status != 0xB0) + if (status != 0xB0) { continue; } - // adapted from Rack + // adapted from Rack `processCC` const uint8_t c = mpeMode ? chan : 0; - const uint8_t cc = data[1]; + const int8_t cc = data[1]; const uint8_t value = data[2]; // Learn if (learningId >= 0 && ccValues[cc][c] != value) { + // NOTE: does the same as `setLearnedCc` + if (cc >= 0) + { + for (int id = 0; id < 16; ++id) + { + if (learnedCcs[id] == cc) + learnedCcs[id] = -1; + } + } learnedCcs[learningId] = cc; learningId = -1; } @@ -196,7 +201,7 @@ struct HostMIDICC : TerminalModule { // Don't set MSB yet. Wait for LSB to be received. msbValues[cc][c] = value; } - else if (lsbMode && 32 <= cc && cc < 64) + else if (lsbMode && cc >= 32 && cc < 64) { // Apply MSB when LSB is received ccValues[cc - 32][c] = msbValues[cc - 32][c]; @@ -213,15 +218,21 @@ struct HostMIDICC : TerminalModule { // Rack stuff const int channels = mpeMode ? 16 : 1; - for (int i = 0; i < 16; i++) + for (int id = 0; id < 16; ++id) { - if (!outputs[CC_OUTPUT + i].isConnected()) + if (!outputs[CC_OUTPUT + id].isConnected()) continue; - outputs[CC_OUTPUT + i].setChannels(channels); + outputs[CC_OUTPUT + id].setChannels(channels); - int cc = learnedCcs[i]; + const int8_t cc = learnedCcs[id]; - for (int c = 0; c < channels; c++) + if (cc < 0) + { + outputs[CC_OUTPUT + id].clearVoltages(); + continue; + } + + for (int c = 0; c < channels; ++c) { int16_t cellValue = int16_t(ccValues[cc][c]) * 128; if (lsbMode && cc < 32) @@ -231,18 +242,18 @@ struct HostMIDICC : TerminalModule { const float value = static_cast(cellValue) / (128.0f * 127.0f); // Detect behavior from MIDI buttons. - if (smooth && std::fabs(valueFilters[i][c].out - value) < 1.f) + if (smooth && std::fabs(valueFilters[id][c].out - value) < 1.f) { // Smooth value with filter - valueFilters[i][c].process(args.sampleTime, value); + valueFilters[id][c].process(args.sampleTime, value); } else { // Jump value - valueFilters[i][c].out = value; + valueFilters[id][c].out = value; } - outputs[CC_OUTPUT + i].setVoltage(valueFilters[i][c].out * 10.f, c); + outputs[CC_OUTPUT + id].setVoltage(valueFilters[id][c].out * 10.f, c); } } @@ -250,7 +261,7 @@ struct HostMIDICC : TerminalModule { { outputs[CC_OUTPUT_CH_PRESSURE].setChannels(channels); - for (int c = 0; c < channels; c++) + for (int c = 0; c < channels; ++c) { const float value = static_cast(chPressure[c]) / 128.0f; @@ -274,7 +285,7 @@ struct HostMIDICC : TerminalModule { { outputs[CC_OUTPUT_PITCHBEND].setChannels(channels); - for (int c = 0; c < channels; c++) + for (int c = 0; c < channels; ++c) { const float value = static_cast(pitchbend[c]) / 16384.0f; @@ -294,7 +305,7 @@ struct HostMIDICC : TerminalModule { } } - return blockFrameChanged; + return processCounterChanged; } } midiInput; @@ -365,7 +376,7 @@ struct HostMIDICC : TerminalModule { } midiOutput; - int learnedCcs[16]; + int8_t learnedCcs[16]; HostMIDICC() : pcontext(static_cast(APP)), @@ -377,14 +388,14 @@ struct HostMIDICC : TerminalModule { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); - for (int i = 0; i < 16; i++) - configInput(CC_INPUTS + i, string::f("Cell %d", i + 1)); + for (int id = 0; id < 16; ++id) + configInput(CC_INPUTS + id, string::f("Cell %d", id + 1)); configInput(CC_INPUT_CH_PRESSURE, "Channel pressure"); configInput(CC_INPUT_PITCHBEND, "Pitchbend"); - for (int i = 0; i < 16; i++) - configOutput(CC_OUTPUT + i, string::f("Cell %d", i + 1)); + for (int id = 0; id < 16; ++id) + configOutput(CC_OUTPUT + id, string::f("Cell %d", id + 1)); configOutput(CC_OUTPUT_CH_PRESSURE, "Channel pressure"); configOutput(CC_OUTPUT_PITCHBEND, "Pitchbend"); @@ -394,9 +405,8 @@ struct HostMIDICC : TerminalModule { void onReset() override { - for (int i = 0; i < 16; i++) { - learnedCcs[i] = i + 1; - } + for (int id = 0; id < 16; ++id) + learnedCcs[id] = id + 1; midiInput.reset(); midiOutput.reset(); } @@ -414,11 +424,13 @@ struct HostMIDICC : TerminalModule { if (isBypassed()) return; - for (int i = 0; i < 16; i++) + for (int id = 0; id < 16; ++id) { - int value = (int) std::round(inputs[CC_INPUTS + i].getVoltage() / 10.f * 127); - value = clamp(value, 0, 127); - midiOutput.sendCC(learnedCcs[i], value); + if (learnedCcs[id] < 0) + continue; + + uint8_t value = (uint8_t) clamp(std::round(inputs[CC_INPUTS + id].getVoltage() / 10.f * 127), 0.f, 127.f); + midiOutput.sendCC(learnedCcs[id], value); } { @@ -434,6 +446,20 @@ struct HostMIDICC : TerminalModule { } } + void setLearnedCc(const int id, const int8_t cc) + { + // Unset IDs of similar CCs + if (cc >= 0) + { + for (int idx = 0; idx < 16; ++idx) + { + if (learnedCcs[idx] == cc) + learnedCcs[idx] = -1; + } + } + learnedCcs[id] = cc; + } + json_t* dataToJson() override { json_t* const rootJ = json_object(); @@ -442,8 +468,8 @@ struct HostMIDICC : TerminalModule { // input and output if (json_t* const ccsJ = json_array()) { - for (int i = 0; i < 16; i++) - json_array_append_new(ccsJ, json_integer(learnedCcs[i])); + for (int id = 0; id < 16; ++id) + json_array_append_new(ccsJ, json_integer(learnedCcs[id])); json_object_set_new(rootJ, "ccs", ccsJ); } @@ -473,12 +499,12 @@ struct HostMIDICC : TerminalModule { // input and output if (json_t* const ccsJ = json_object_get(rootJ, "ccs")) { - for (int i = 0; i < 16; i++) + for (int id = 0; id < 16; ++id) { - if (json_t* const ccJ = json_array_get(ccsJ, i)) - learnedCcs[i] = json_integer_value(ccJ); + if (json_t* const ccJ = json_array_get(ccsJ, id)) + setLearnedCc(id, json_integer_value(ccJ)); else - learnedCcs[i] = i + 1; + learnedCcs[id] = -1; } } @@ -524,7 +550,7 @@ struct HostMIDICC : TerminalModule { struct CardinalCcChoice : CardinalLedDisplayChoice { HostMIDICC* const module; const int id; - int focusCc = -1; + int8_t focusCc = -1; CardinalCcChoice(HostMIDICC* const m, const int i) : CardinalLedDisplayChoice(), @@ -540,7 +566,7 @@ struct CardinalCcChoice : CardinalLedDisplayChoice { void step() override { - int cc; + int8_t cc; if (module == nullptr) { @@ -583,8 +609,8 @@ struct CardinalCcChoice : CardinalLedDisplayChoice { if (module->midiInput.learningId == id) { - if (0 <= focusCc && focusCc < 128) - module->learnedCcs[id] = focusCc; + if (focusCc >= 0) + module->setLearnedCc(id, focusCc); module->midiInput.learningId = -1; } } @@ -600,7 +626,7 @@ struct CardinalCcChoice : CardinalLedDisplayChoice { focusCc = focusCc * 10 + (c - '0'); } - if (focusCc >= 128) + if (focusCc < 0) focusCc = -1; e.consume(this); diff --git a/plugins/Cardinal/src/HostMIDI-Gate.cpp b/plugins/Cardinal/src/HostMIDI-Gate.cpp index 7232c9a8..3dfed9a6 100644 --- a/plugins/Cardinal/src/HostMIDI-Gate.cpp +++ b/plugins/Cardinal/src/HostMIDI-Gate.cpp @@ -58,7 +58,7 @@ struct HostMIDIGate : TerminalModule { const MidiEvent* midiEvents; uint32_t midiEventsLeft; uint32_t midiEventFrame; - int64_t lastBlockFrame; + uint32_t lastProcessCounter; uint8_t channel; // stuff from Rack @@ -84,7 +84,7 @@ struct HostMIDIGate : TerminalModule { midiEvents = nullptr; midiEventsLeft = 0; midiEventFrame = 0; - lastBlockFrame = -1; + lastProcessCounter = 0; channel = 0; learningId = -1; mpeMode = false; @@ -104,16 +104,15 @@ struct HostMIDIGate : TerminalModule { } bool process(const ProcessArgs& args, std::vector& outputs, - const bool velocityMode, uint8_t learnedNotes[18], const bool isBypassed) + const bool velocityMode, int8_t learnedNotes[18], const bool isBypassed) { // Cardinal specific - const int64_t blockFrame = pcontext->engine->getBlockFrame(); - const bool blockFrameChanged = lastBlockFrame != blockFrame; + const uint32_t processCounter = pcontext->processCounter; + const bool processCounterChanged = lastProcessCounter != processCounter; - if (blockFrameChanged) + if (processCounterChanged) { - lastBlockFrame = blockFrame; - + lastProcessCounter = processCounter; midiEvents = pcontext->midiEvents; midiEventsLeft = pcontext->midiEventCount; midiEventFrame = 0; @@ -122,7 +121,7 @@ struct HostMIDIGate : TerminalModule { if (isBypassed) { ++midiEventFrame; - return blockFrameChanged; + return processCounterChanged; } while (midiEventsLeft != 0) @@ -153,17 +152,30 @@ struct HostMIDIGate : TerminalModule { if (data[2] > 0) { const int c = mpeMode ? (data[0] & 0x0F) : 0; + const int8_t note = data[1]; // Learn - if (learningId >= 0) { - learnedNotes[learningId] = data[1]; + if (learningId >= 0) + { + // NOTE: does the same as `setLearnedNote` + if (note >= 0) + { + for (int id = 0; id < 18; ++id) + { + if (learnedNotes[id] == note) + learnedNotes[id] = -1; + } + } + learnedNotes[learningId] = note; learningId = -1; } // Find id - for (int i = 0; i < 18; i++) { - if (learnedNotes[i] == data[1]) { - gates[i][c] = true; - gateTimes[i][c] = 1e-3f; - velocities[i][c] = data[2]; + for (int id = 0; id < 18; ++id) + { + if (learnedNotes[id] == note) + { + gates[id][c] = true; + gateTimes[id][c] = 1e-3f; + velocities[id][c] = data[2]; } } break; @@ -172,11 +184,12 @@ struct HostMIDIGate : TerminalModule { // note off case 0x80: const int c = mpeMode ? (data[0] & 0x0F) : 0; + const int8_t note = data[1]; // Find id - for (int i = 0; i < 18; i++) { - if (learnedNotes[i] == data[1]) { - gates[i][c] = false; - } + for (int id = 0; id < 18; ++id) + { + if (learnedNotes[id] == note) + gates[id][c] = false; } break; } @@ -206,7 +219,7 @@ struct HostMIDIGate : TerminalModule { } } - return blockFrameChanged; + return processCounterChanged; } } midiInput; @@ -217,7 +230,7 @@ struct HostMIDIGate : TerminalModule { uint8_t channel = 0; // base class vars - int vels[128]; + uint8_t vels[128]; bool lastGates[128]; int64_t frame = 0; @@ -230,7 +243,7 @@ struct HostMIDIGate : TerminalModule { void reset() { // base class vars - for (int note = 0; note < 128; ++note) + for (uint8_t note = 0; note < 128; ++note) { vels[note] = 100; lastGates[note] = false; @@ -245,7 +258,7 @@ struct HostMIDIGate : TerminalModule { // TODO send all notes off CC // Send all note off commands - for (int note = 0; note < 128; note++) + for (uint8_t note = 0; note < 128; note++) { // Note off midi::Message m; @@ -258,12 +271,12 @@ struct HostMIDIGate : TerminalModule { } } - void setVelocity(int vel, int note) + void setVelocity(uint8_t note, uint8_t vel) { vels[note] = vel; } - void setGate(bool gate, int note) + void setGate(uint8_t note, bool gate) { if (gate && !lastGates[note]) { @@ -296,7 +309,8 @@ struct HostMIDIGate : TerminalModule { } midiOutput; bool velocityMode = false; - uint8_t learnedNotes[18] = {}; + int8_t learnedNotes[18] = {}; + dsp::SchmittTrigger cellTriggers[18]; HostMIDIGate() : pcontext(static_cast(APP)), @@ -308,19 +322,19 @@ struct HostMIDIGate : TerminalModule { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); - for (int i = 0; i < 18; i++) - configInput(GATE_INPUTS + i, string::f("Gate %d", i + 1)); + for (int id = 0; id < 18; ++id) + configInput(GATE_INPUTS + id, string::f("Gate %d", id + 1)); - for (int i = 0; i < 18; i++) - configOutput(GATE_OUTPUTS + i, string::f("Gate %d", i + 1)); + for (int id = 0; id < 18; ++id) + configOutput(GATE_OUTPUTS + id, string::f("Gate %d", id + 1)); onReset(); } void onReset() override { - for (int i = 0; i < 18; ++i) - learnedNotes[i] = 36 + i; + for (int id = 0; id < 18; ++id) + learnedNotes[id] = 36 + id; velocityMode = false; @@ -341,24 +355,39 @@ struct HostMIDIGate : TerminalModule { if (isBypassed()) return; - for (int i = 0; i < 18; ++i) + for (int id = 0; id < 18; ++id) { - const int note = learnedNotes[i]; + const int8_t note = learnedNotes[id]; + + if (note < 0) + continue; if (velocityMode) { - int vel = (int) std::round(inputs[GATE_INPUTS + i].getVoltage() / 10.f * 127); - vel = clamp(vel, 0, 127); - midiOutput.setVelocity(vel, note); - midiOutput.setGate(vel > 0, note); + uint8_t vel = (uint8_t) clamp(std::round(inputs[GATE_INPUTS + id].getVoltage() / 10.f * 127), 0.f, 127.f); + midiOutput.setVelocity(note, vel); + midiOutput.setGate(note, vel > 0); } else { - const bool gate = inputs[GATE_INPUTS + i].getVoltage() >= 1.f; - midiOutput.setVelocity(100, note); - midiOutput.setGate(gate, note); + const bool gate = inputs[GATE_INPUTS + id].getVoltage() >= 1.f; + midiOutput.setVelocity(note, 100); + midiOutput.setGate(note, gate); + } + } + } + + void setLearnedNote(const int id, const int8_t note) { + // Unset IDs of similar note + if (note >= 0) + { + for (int idx = 0; idx < 18; ++idx) + { + if (learnedNotes[idx] == note) + learnedNotes[idx] = -1; } } + learnedNotes[id] = note; } json_t* dataToJson() override @@ -369,8 +398,8 @@ struct HostMIDIGate : TerminalModule { // input and output if (json_t* const notesJ = json_array()) { - for (int i = 0; i < 18; i++) - json_array_append_new(notesJ, json_integer(learnedNotes[i])); + for (int id = 0; id < 18; ++id) + json_array_append_new(notesJ, json_integer(learnedNotes[id])); json_object_set_new(rootJ, "notes", notesJ); } json_object_set_new(rootJ, "velocity", json_boolean(velocityMode)); @@ -390,12 +419,12 @@ struct HostMIDIGate : TerminalModule { // input and output if (json_t* const notesJ = json_object_get(rootJ, "notes")) { - for (int i = 0; i < 18; i++) + for (int id = 0; id < 18; ++id) { - if (json_t* const noteJ = json_array_get(notesJ, i)) - learnedNotes[i] = json_integer_value(noteJ); + if (json_t* const noteJ = json_array_get(notesJ, id)) + setLearnedNote(id, json_integer_value(noteJ)); else - learnedNotes[i] = -1; + learnedNotes[id] = -1; } } @@ -430,7 +459,7 @@ struct HostMIDIGate : TerminalModule { struct CardinalNoteChoice : CardinalLedDisplayChoice { HostMIDIGate* const module; const int id; - int focusNote = -1; + int8_t focusNote = -1; CardinalNoteChoice(HostMIDIGate* const m, const int i) : CardinalLedDisplayChoice(), @@ -439,7 +468,7 @@ struct CardinalNoteChoice : CardinalLedDisplayChoice { void step() override { - int note; + int8_t note; if (module == nullptr) { @@ -489,8 +518,8 @@ struct CardinalNoteChoice : CardinalLedDisplayChoice { if (module->midiInput.learningId == id) { - if (0 <= focusNote && focusNote < 128) - module->learnedNotes[id] = focusNote; + if (focusNote >= 0) + module->setLearnedNote(id, focusNote); module->midiInput.learningId = -1; } } @@ -518,7 +547,7 @@ struct CardinalNoteChoice : CardinalLedDisplayChoice { } } - if (focusNote >= 128) + if (focusNote < 0) focusNote = -1; e.consume(this); diff --git a/plugins/Cardinal/src/HostMIDI-Map.cpp b/plugins/Cardinal/src/HostMIDI-Map.cpp index 9f8a480c..40b43747 100644 --- a/plugins/Cardinal/src/HostMIDI-Map.cpp +++ b/plugins/Cardinal/src/HostMIDI-Map.cpp @@ -55,7 +55,7 @@ struct HostMIDIMap : TerminalModule { const MidiEvent* midiEvents; uint32_t midiEventsLeft; uint32_t midiEventFrame; - int64_t lastBlockFrame; + uint32_t lastProcessCounter; int nextLearningId; uint8_t channel; @@ -117,7 +117,7 @@ struct HostMIDIMap : TerminalModule { midiEvents = nullptr; midiEventsLeft = 0; midiEventFrame = 0; - lastBlockFrame = -1; + lastProcessCounter = 0; nextLearningId = -1; channel = 0; @@ -134,13 +134,12 @@ struct HostMIDIMap : TerminalModule { void processTerminalInput(const ProcessArgs& args) override { // Cardinal specific - const int64_t blockFrame = pcontext->engine->getBlockFrame(); - const bool blockFrameChanged = lastBlockFrame != blockFrame; + const uint32_t processCounter = pcontext->processCounter; + const bool processCounterChanged = lastProcessCounter != processCounter; - if (blockFrameChanged) + if (processCounterChanged) { - lastBlockFrame = blockFrame; - + lastProcessCounter = processCounter; midiEvents = pcontext->midiEvents; midiEventsLeft = pcontext->midiEventCount; midiEventFrame = 0; diff --git a/plugins/Cardinal/src/HostMIDI.cpp b/plugins/Cardinal/src/HostMIDI.cpp index 3a66ad07..7469a8ea 100644 --- a/plugins/Cardinal/src/HostMIDI.cpp +++ b/plugins/Cardinal/src/HostMIDI.cpp @@ -81,11 +81,13 @@ struct HostMIDI : TerminalModule { const MidiEvent* midiEvents; uint32_t midiEventsLeft; uint32_t midiEventFrame; - int64_t lastBlockFrame; + uint32_t lastProcessCounter; bool wasPlaying; uint8_t channel; // stuff from Rack + /** Number of semitones to bend up/down by pitch wheel */ + float pwRange; bool smooth; int channels; enum PolyMode { @@ -120,6 +122,7 @@ struct HostMIDI : TerminalModule { dsp::PulseGenerator startPulse; dsp::PulseGenerator stopPulse; dsp::PulseGenerator continuePulse; + dsp::PulseGenerator retriggerPulses[16]; MidiInput(CardinalPluginContext* const pc) : pcontext(pc) @@ -138,12 +141,13 @@ struct HostMIDI : TerminalModule { midiEvents = nullptr; midiEventsLeft = 0; midiEventFrame = 0; - lastBlockFrame = -1; + lastProcessCounter = 0; wasPlaying = false; channel = 0; - smooth = true; + smooth = false; channels = 1; polyMode = ROTATE_MODE; + pwRange = 0; panic(); } @@ -168,12 +172,12 @@ struct HostMIDI : TerminalModule { bool process(const ProcessArgs& args, std::vector& outputs, const bool isBypassed) { // Cardinal specific - const int64_t blockFrame = pcontext->engine->getBlockFrame(); - const bool blockFrameChanged = lastBlockFrame != blockFrame; + const uint32_t processCounter = pcontext->processCounter; + const bool processCounterChanged = lastProcessCounter != processCounter; - if (blockFrameChanged) + if (processCounterChanged) { - lastBlockFrame = blockFrame; + lastProcessCounter = processCounter; midiEvents = pcontext->midiEvents; midiEventsLeft = pcontext->midiEventCount; @@ -246,30 +250,20 @@ struct HostMIDI : TerminalModule { ++midiEventFrame; // Rack stuff - outputs[PITCH_OUTPUT].setChannels(channels); - outputs[GATE_OUTPUT].setChannels(channels); - outputs[VELOCITY_OUTPUT].setChannels(channels); - outputs[AFTERTOUCH_OUTPUT].setChannels(channels); - - for (int c = 0; c < channels; c++) { - outputs[PITCH_OUTPUT].setVoltage((notes[c] - 60.f) / 12.f, c); - outputs[GATE_OUTPUT].setVoltage(gates[c] ? 10.f : 0.f, c); - outputs[VELOCITY_OUTPUT].setVoltage(rescale(velocities[c], 0, 127, 0.f, 10.f), c); - outputs[AFTERTOUCH_OUTPUT].setVoltage(rescale(aftertouches[c], 0, 127, 0.f, 10.f), c); - } - // Set pitch and mod wheel const int wheelChannels = (polyMode == MPE_MODE) ? 16 : 1; + float pwValues[16] = {}; outputs[PITCHBEND_OUTPUT].setChannels(wheelChannels); outputs[MODWHEEL_OUTPUT].setChannels(wheelChannels); for (int c = 0; c < wheelChannels; c++) { - float pw = ((int) pws[c] - 8192) / 8191.f; + float pw = (int16_t(pws[c]) - 8192) / 8191.f; pw = clamp(pw, -1.f, 1.f); if (smooth) pw = pwFilters[c].process(args.sampleTime, pw); else pwFilters[c].out = pw; - outputs[PITCHBEND_OUTPUT].setVoltage(pw * 5.f); + pwValues[c] = pw; + outputs[PITCHBEND_OUTPUT].setVoltage(pw * 5.f, c); float mod = mods[c] / 127.f; mod = clamp(mod, 0.f, 1.f); @@ -277,14 +271,31 @@ struct HostMIDI : TerminalModule { mod = modFilters[c].process(args.sampleTime, mod); else modFilters[c].out = mod; - outputs[MODWHEEL_OUTPUT].setVoltage(mod * 10.f); + outputs[MODWHEEL_OUTPUT].setVoltage(mod * 10.f, c); + } + + // Set note outputs + outputs[PITCH_OUTPUT].setChannels(channels); + outputs[GATE_OUTPUT].setChannels(channels); + outputs[VELOCITY_OUTPUT].setChannels(channels); + outputs[AFTERTOUCH_OUTPUT].setChannels(channels); + outputs[RETRIGGER_OUTPUT].setChannels(channels); + + for (int c = 0; c < channels; c++) { + float pw = pwValues[(polyMode == MPE_MODE) ? c : 0]; + float pitch = (notes[c] - 60.f + pw * pwRange) / 12.f; + outputs[PITCH_OUTPUT].setVoltage(pitch, c); + outputs[GATE_OUTPUT].setVoltage(gates[c] ? 10.f : 0.f, c); + outputs[VELOCITY_OUTPUT].setVoltage(rescale(velocities[c], 0, 127, 0.f, 10.f), c); + outputs[AFTERTOUCH_OUTPUT].setVoltage(rescale(aftertouches[c], 0, 127, 0.f, 10.f), c); + outputs[RETRIGGER_OUTPUT].setVoltage(retriggerPulses[c].process(args.sampleTime) ? 10.f : 0.f, c); } outputs[START_OUTPUT].setVoltage(startPulse.process(args.sampleTime) ? 10.f : 0.f); outputs[STOP_OUTPUT].setVoltage(stopPulse.process(args.sampleTime) ? 10.f : 0.f); outputs[CONTINUE_OUTPUT].setVoltage(continuePulse.process(args.sampleTime) ? 10.f : 0.f); - return blockFrameChanged; + return processCounterChanged; } void processMessage(const midi::Message& msg) @@ -452,6 +463,7 @@ struct HostMIDI : TerminalModule { // Set note notes[*channel] = note; gates[*channel] = true; + retriggerPulses[*channel].trigger(1e-3); } void releaseNote(uint8_t note) { @@ -533,6 +545,18 @@ struct HostMIDI : TerminalModule { CardinalPluginContext* const pcontext; uint8_t channel = 0; + // caching + struct { + bool gate = false; + bool velocity = false; + bool aftertouch = false; + bool pitchbend = false; + bool modwheel = false; + bool start = false; + bool stop = false; + bool cont = false; + } connected; + MidiOutput(CardinalPluginContext* const pc) : pcontext(pc) {} @@ -587,9 +611,21 @@ struct HostMIDI : TerminalModule { void processTerminalInput(const ProcessArgs& args) override { if (midiInput.process(args, outputs, isBypassed())) + { midiOutput.frame = 0; + midiOutput.connected.gate = inputs[GATE_INPUT].isConnected(); + midiOutput.connected.velocity = inputs[VELOCITY_INPUT].isConnected(); + midiOutput.connected.aftertouch = inputs[AFTERTOUCH_INPUT].isConnected(); + midiOutput.connected.pitchbend = inputs[PITCHBEND_INPUT].isConnected(); + midiOutput.connected.modwheel = inputs[MODWHEEL_INPUT].isConnected(); + midiOutput.connected.start = inputs[START_INPUT].isConnected(); + midiOutput.connected.stop = inputs[STOP_INPUT].isConnected(); + midiOutput.connected.cont = inputs[CONTINUE_INPUT].isConnected(); + } else + { ++midiOutput.frame; + } } void processTerminalOutput(const ProcessArgs&) override @@ -597,37 +633,67 @@ struct HostMIDI : TerminalModule { if (isBypassed()) return; + auto connected = midiOutput.connected; + for (int c = 0; c < inputs[PITCH_INPUT].getChannels(); ++c) { - int vel = (int) std::round(inputs[VELOCITY_INPUT].getNormalPolyVoltage(10.f * 100 / 127, c) / 10.f * 127); - vel = clamp(vel, 0, 127); - midiOutput.setVelocity(vel, c); + if (connected.velocity) + { + const constexpr float n = 10.f * 100.f / 127.f; + const int vel = clamp( + static_cast(inputs[VELOCITY_INPUT].getNormalPolyVoltage(n, c) / 10.f * 127.f + 0.5f), 0, 127); + midiOutput.setVelocity(vel, c); + } + else + { + midiOutput.setVelocity(100, c); + } - int note = (int) std::round(inputs[PITCH_INPUT].getVoltage(c) * 12.f + 60.f); - note = clamp(note, 0, 127); - bool gate = inputs[GATE_INPUT].getPolyVoltage(c) >= 1.f; + const int note = clamp(static_cast(inputs[PITCH_INPUT].getVoltage(c) * 12.f + 60.5f), 0, 127); + const bool gate = connected.gate ? inputs[GATE_INPUT].getPolyVoltage(c) >= 1.f : false; midiOutput.setNoteGate(note, gate, c); - int aft = (int) std::round(inputs[AFTERTOUCH_INPUT].getPolyVoltage(c) / 10.f * 127); - aft = clamp(aft, 0, 127); - midiOutput.setKeyPressure(aft, c); + if (connected.aftertouch) + { + const int aft = clamp( + static_cast(inputs[AFTERTOUCH_INPUT].getPolyVoltage(c) / 10.f * 127.f + 0.5f), 0, 127); + midiOutput.setKeyPressure(aft, c); + } + else + { + midiOutput.setKeyPressure(0, c); + } } - int pw = (int) std::round((inputs[PITCHBEND_INPUT].getVoltage() + 5.f) / 10.f * 16383); - pw = clamp(pw, 0, 16383); - midiOutput.setPitchWheel(pw); + if (connected.pitchbend) + { + const int pw = clamp( + static_cast((inputs[PITCHBEND_INPUT].getVoltage() + 5.f) / 10.f * 16383.f + 0.5f), 0, 16383); + midiOutput.setPitchWheel(pw); + } + else + { + midiOutput.setPitchWheel(0); + } - int mw = (int) std::round(inputs[MODWHEEL_INPUT].getVoltage() / 10.f * 127); - mw = clamp(mw, 0, 127); - midiOutput.setModWheel(mw); + if (connected.modwheel) + { + const int mw = clamp( + static_cast(inputs[MODWHEEL_INPUT].getVoltage() / 10.f * 127.f + 0.5f), 0, 127); + midiOutput.setModWheel(mw); + } + else + { + midiOutput.setModWheel(0); + } - bool start = inputs[START_INPUT].getVoltage() >= 1.f; + const bool start = connected.start ? inputs[START_INPUT].getVoltage() >= 1.f : false; midiOutput.setStart(start); - bool stop = inputs[STOP_INPUT].getVoltage() >= 1.f; + const bool stop = connected.stop ? inputs[STOP_INPUT].getVoltage() >= 1.f : false; midiOutput.setStop(stop); - bool cont = inputs[CONTINUE_INPUT].getVoltage() >= 1.f; + const bool cont = connected.cont ? inputs[CONTINUE_INPUT].getVoltage() >= 1.f : false; midiOutput.setContinue(cont); } @@ -636,6 +702,7 @@ struct HostMIDI : TerminalModule { json_t* const rootJ = json_object(); DISTRHO_SAFE_ASSERT_RETURN(rootJ != nullptr, nullptr); + json_object_set_new(rootJ, "pwRange", json_real(midiInput.pwRange)); json_object_set_new(rootJ, "smooth", json_boolean(midiInput.smooth)); json_object_set_new(rootJ, "channels", json_integer(midiInput.channels)); json_object_set_new(rootJ, "polyMode", json_integer(midiInput.polyMode)); @@ -655,6 +722,12 @@ struct HostMIDI : TerminalModule { void dataFromJson(json_t* const rootJ) override { + if (json_t* const pwRangeJ = json_object_get(rootJ, "pwRange")) + midiInput.pwRange = json_number_value(pwRangeJ); + // For backwards compatibility, set to 0 if undefined in JSON. + else + midiInput.pwRange = 0; + if (json_t* const smoothJ = json_object_get(rootJ, "smooth")) midiInput.smooth = json_boolean_value(smoothJ); @@ -680,6 +753,7 @@ struct HostMIDI : TerminalModule { // -------------------------------------------------------------------------------------------------------------------- +#ifndef HEADLESS struct HostMIDIWidget : ModuleWidgetWith9HP { HostMIDI* const module; @@ -710,12 +784,13 @@ struct HostMIDIWidget : ModuleWidgetWith9HP { createAndAddOutput(6, HostMIDI::START_OUTPUT); createAndAddOutput(7, HostMIDI::STOP_OUTPUT); createAndAddOutput(8, HostMIDI::CONTINUE_OUTPUT); + createAndAddOutput(9, HostMIDI::RETRIGGER_OUTPUT); } void draw(const DrawArgs& args) override { drawBackground(args.vg); - drawOutputJacksArea(args.vg, 9); + drawOutputJacksArea(args.vg, 10); setupTextLines(args.vg); drawTextLine(args.vg, 0, "V/Oct"); @@ -727,6 +802,7 @@ struct HostMIDIWidget : ModuleWidgetWith9HP { drawTextLine(args.vg, 6, "Start"); drawTextLine(args.vg, 7, "Stop"); drawTextLine(args.vg, 8, "Cont"); + drawTextLine(args.vg, 9, "Retrigger"); ModuleWidgetWith9HP::draw(args); } @@ -738,6 +814,16 @@ struct HostMIDIWidget : ModuleWidgetWith9HP { menu->addChild(createBoolPtrMenuItem("Smooth pitch/mod wheel", "", &module->midiInput.smooth)); + static const std::vector pwRanges = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 24, 36, 48}; + menu->addChild(createSubmenuItem("Pitch bend range", string::f("%g", module->midiInput.pwRange), [=](Menu* menu) { + for (size_t i = 0; i < pwRanges.size(); i++) { + menu->addChild(createCheckMenuItem(string::f("%g", pwRanges[i]), "", + [=]() {return module->midiInput.pwRange == pwRanges[i];}, + [=]() {module->midiInput.pwRange = pwRanges[i];} + )); + } + })); + struct InputChannelItem : MenuItem { HostMIDI* module; Menu* createChildMenu() override { @@ -758,24 +844,14 @@ struct HostMIDIWidget : ModuleWidgetWith9HP { inputChannelItem->module = module; menu->addChild(inputChannelItem); - struct PolyphonyChannelItem : MenuItem { - HostMIDI* module; - Menu* createChildMenu() override { - Menu* menu = new Menu; - for (int c = 1; c <= 16; c++) { - menu->addChild(createCheckMenuItem((c == 1) ? "Monophonic" : string::f("%d", c), "", - [=]() {return module->midiInput.channels == c;}, - [=]() {module->midiInput.setChannels(c);} - )); - } - return menu; + menu->addChild(createSubmenuItem("Polyphony channels", string::f("%d", module->midiInput.channels), [=](Menu* menu) { + for (int c = 1; c <= 16; c++) { + menu->addChild(createCheckMenuItem((c == 1) ? "Monophonic" : string::f("%d", c), "", + [=]() {return module->midiInput.channels == c;}, + [=]() {module->midiInput.setChannels(c);} + )); } - }; - PolyphonyChannelItem* const polyphonyChannelItem = new PolyphonyChannelItem; - polyphonyChannelItem->text = "Polyphony channels"; - polyphonyChannelItem->rightText = string::f("%d", module->midiInput.channels) + " " + RIGHT_ARROW; - polyphonyChannelItem->module = module; - menu->addChild(polyphonyChannelItem); + })); menu->addChild(createIndexPtrSubmenuItem("Polyphony mode", { "Rotate", @@ -814,6 +890,17 @@ struct HostMIDIWidget : ModuleWidgetWith9HP { )); } }; +#else +struct HostMIDIWidget : ModuleWidget { + HostMIDIWidget(HostMIDI* const module) { + setModule(module); + for (uint i=0; i({}, module, i)); + for (uint i=0; i({}, module, i)); + } +}; +#endif // -------------------------------------------------------------------------------------------------------------------- diff --git a/plugins/Cardinal/src/HostParameters.cpp b/plugins/Cardinal/src/HostParameters.cpp index a46f6591..0bea835d 100644 --- a/plugins/Cardinal/src/HostParameters.cpp +++ b/plugins/Cardinal/src/HostParameters.cpp @@ -20,8 +20,6 @@ // ----------------------------------------------------------------------------------------------------------- -USE_NAMESPACE_DISTRHO; - struct HostParameters : TerminalModule { enum ParamIds { NUM_PARAMS @@ -91,6 +89,8 @@ struct HostParameters : TerminalModule { } }; +// -------------------------------------------------------------------------------------------------------------------- + #ifndef HEADLESS struct CardinalParameterPJ301MPort : PJ301MPort { void onDragStart(const DragStartEvent& e) override { @@ -159,11 +159,14 @@ struct HostParametersWidget : ModuleWidgetWith9HP { struct HostParametersWidget : ModuleWidget { HostParametersWidget(HostParameters* const module) { setModule(module); - - for (int i=0; i<24; ++i) + for (uint i=0; i({}, module, i)); } }; #endif +// -------------------------------------------------------------------------------------------------------------------- + Model* modelHostParameters = createModel("HostParameters"); + +// -------------------------------------------------------------------------------------------------------------------- diff --git a/plugins/Cardinal/src/HostTime.cpp b/plugins/Cardinal/src/HostTime.cpp index e49b8552..da3fd5ad 100644 --- a/plugins/Cardinal/src/HostTime.cpp +++ b/plugins/Cardinal/src/HostTime.cpp @@ -17,6 +17,8 @@ #include "plugincontext.hpp" +// -------------------------------------------------------------------------------------------------------------------- + struct HostTime : TerminalModule { enum ParamIds { NUM_PARAMS @@ -39,7 +41,7 @@ struct HostTime : TerminalModule { rack::dsp::PulseGenerator pulseReset, pulseBar, pulseBeat, pulseClock; float sampleTime = 0.0f; - int64_t lastBlockFrame = -1; + uint32_t lastProcessCounter = 0; // cached time values struct { bool reset = true; @@ -61,15 +63,15 @@ struct HostTime : TerminalModule { void processTerminalInput(const ProcessArgs& args) override { - const int64_t blockFrame = pcontext->engine->getBlockFrame(); + const uint32_t processCounter = pcontext->processCounter; // local variables for faster access double tick, tickClock; // Update time position if running a new audio block - if (lastBlockFrame != blockFrame) + if (lastProcessCounter != processCounter) { - lastBlockFrame = blockFrame; + lastProcessCounter = processCounter; timeInfo.reset = pcontext->reset; timeInfo.bar = pcontext->bar; timeInfo.beat = pcontext->beat; @@ -127,6 +129,13 @@ struct HostTime : TerminalModule { } } + // store back the local values + timeInfo.tick = tick; + timeInfo.tickClock = tickClock; + + if (isBypassed()) + return; + const bool hasReset = pulseReset.process(args.sampleTime); const bool hasBar = pulseBar.process(args.sampleTime); const bool hasBeat = pulseBeat.process(args.sampleTime); @@ -138,13 +147,6 @@ struct HostTime : TerminalModule { ? ((float) (timeInfo.beat - 1) + beatPhase) / pcontext->beatsPerBar : 0.0f; - // store back the local values - timeInfo.tick = tick; - timeInfo.tickClock = tickClock; - - if (isBypassed()) - return; - lights[kHostTimeRolling].setBrightness(playing ? 1.0f : 0.0f); lights[kHostTimeReset].setBrightnessSmooth(hasReset ? 1.0f : 0.0f, args.sampleTime * 0.5f); lights[kHostTimeBar].setBrightnessSmooth(hasBar ? 1.0f : 0.0f, args.sampleTime * 0.5f); @@ -166,6 +168,9 @@ struct HostTime : TerminalModule { {} }; +// -------------------------------------------------------------------------------------------------------------------- + +#ifndef HEADLESS struct HostTimeWidget : ModuleWidget { static constexpr const float startX = 10.0f; static constexpr const float startY_top = 71.0f; @@ -285,5 +290,18 @@ struct HostTimeWidget : ModuleWidget { ModuleWidget::drawLayer(args, layer); } }; +#else +struct HostTimeWidget : ModuleWidget { + HostTimeWidget(HostTime* const module) { + setModule(module); + for (uint i=0; i({}, module, i)); + } +}; +#endif + +// -------------------------------------------------------------------------------------------------------------------- Model* modelHostTime = createModel("HostTime"); + +// -------------------------------------------------------------------------------------------------------------------- diff --git a/plugins/Cardinal/src/Ildaeil.cpp b/plugins/Cardinal/src/Ildaeil.cpp index b7d10395..60d86a68 100644 --- a/plugins/Cardinal/src/Ildaeil.cpp +++ b/plugins/Cardinal/src/Ildaeil.cpp @@ -97,12 +97,14 @@ static void projectLoadedFromDSP(void* ui); static Mutex sPluginInfoLoadMutex; +/* #ifndef HEADLESS struct JuceInitializer { JuceInitializer() { carla_juce_init(); } ~JuceInitializer() { carla_juce_cleanup(); } }; #endif +*/ struct IldaeilModule : Module { enum ParamIds { @@ -122,9 +124,11 @@ struct IldaeilModule : Module { NUM_LIGHTS }; + /* #ifndef HEADLESS SharedResourcePointer juceInitializer; #endif + */ const CardinalPluginContext* const pcontext; @@ -144,7 +148,7 @@ struct IldaeilModule : Module { float audioDataOut1[BUFFER_SIZE]; float audioDataOut2[BUFFER_SIZE]; unsigned audioDataFill = 0; - int64_t lastBlockFrame = -1; + uint32_t lastProcessCounter = 0; CardinalExpanderFromCarlaMIDIToCV* midiOutExpander = nullptr; volatile bool resetMeterIn = true; @@ -209,10 +213,14 @@ struct IldaeilModule : Module { 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_WINDOWS) - // Carla does not support system-wide install on Windows right now - if (false) +#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")) @@ -351,12 +359,12 @@ struct IldaeilModule : Module { if (audioDataFill == BUFFER_SIZE) { - const int64_t blockFrame = pcontext->engine->getBlockFrame(); + const uint32_t processCounter = pcontext->processCounter; // Update time position if running a new audio block - if (lastBlockFrame != blockFrame) + if (lastProcessCounter != processCounter) { - lastBlockFrame = blockFrame; + lastProcessCounter = processCounter; fCarlaTimeInfo.playing = pcontext->playing; fCarlaTimeInfo.frame = pcontext->frame; fCarlaTimeInfo.bbt.valid = pcontext->bbtValid; @@ -973,7 +981,9 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Thread { const CarlaHostHandle handle = module->fCarlaHostHandle; DISTRHO_SAFE_ASSERT_RETURN(handle != nullptr,); + /* carla_juce_idle(); + */ if (fileBrowserHandle != nullptr && fileBrowserIdle(fileBrowserHandle)) { diff --git a/plugins/Cardinal/src/Widgets.hpp b/plugins/Cardinal/src/Widgets.hpp index a727e989..730262a0 100644 --- a/plugins/Cardinal/src/Widgets.hpp +++ b/plugins/Cardinal/src/Widgets.hpp @@ -25,6 +25,7 @@ using namespace rack; +#ifndef HEADLESS struct CardinalLedDisplayChoice : LedDisplayChoice { bool alignTextCenter = true; @@ -403,3 +404,4 @@ struct OpenGlWidgetWithBrowserPreview : OpenGlWidget { virtual void drawFramebufferForBrowserPreview() = 0; }; +#endif diff --git a/plugins/Cardinal/src/plugincontext.hpp b/plugins/Cardinal/src/plugincontext.hpp index 2d0eeba6..1d25256a 100644 --- a/plugins/Cardinal/src/plugincontext.hpp +++ b/plugins/Cardinal/src/plugincontext.hpp @@ -51,11 +51,11 @@ struct MidiEvent { }; struct CardinalPluginContext : rack::Context { - uint32_t bufferSize; + uint32_t bufferSize, processCounter; double sampleRate; float parameters[kModuleParameters]; CardinalVariant variant; - bool playing, reset, bbtValid; + bool bypassed, playing, reset, bbtValid; int32_t bar, beat, beatsPerBar, beatType; uint64_t frame; double barStartTick, beatsPerMinute; diff --git a/plugins/ChowDSP b/plugins/ChowDSP index 80f61cd0..52f89b94 160000 --- a/plugins/ChowDSP +++ b/plugins/ChowDSP @@ -1 +1 @@ -Subproject commit 80f61cd0171bb7d988c9ec3a144e0566d62c767c +Subproject commit 52f89b94a25828f9debf8bca4d58854fb1e70228 diff --git a/plugins/Dintree b/plugins/Dintree deleted file mode 160000 index 8d28da2a..00000000 --- a/plugins/Dintree +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8d28da2a6083eb6af4b8d559e001fc9afbe2d41f diff --git a/plugins/Fundamental b/plugins/Fundamental new file mode 160000 index 00000000..48bf3c84 --- /dev/null +++ b/plugins/Fundamental @@ -0,0 +1 @@ +Subproject commit 48bf3c84ebafc9effe7e565d8cdbf8a46b9d503c diff --git a/plugins/GlueTheGiant b/plugins/GlueTheGiant index 54fed7f7..2c535bc3 160000 --- a/plugins/GlueTheGiant +++ b/plugins/GlueTheGiant @@ -1 +1 @@ -Subproject commit 54fed7f78bbaac1f1d6275aa737acc39aebc6e72 +Subproject commit 2c535bc38d61fd4d776aad7307c1dfbbed062b66 diff --git a/plugins/GrandeModular b/plugins/GrandeModular index 33f445d1..b0d8a6fc 160000 --- a/plugins/GrandeModular +++ b/plugins/GrandeModular @@ -1 +1 @@ -Subproject commit 33f445d1e3f78aa1f62c8995010303bdb42e0163 +Subproject commit b0d8a6fcdb28d2e56d6b024326a7378a2c8ee45d diff --git a/plugins/ImpromptuModular b/plugins/ImpromptuModular index 368cbd6e..2bd5691c 160000 --- a/plugins/ImpromptuModular +++ b/plugins/ImpromptuModular @@ -1 +1 @@ -Subproject commit 368cbd6ee17398c7329b263dde0409bf7a57ce3b +Subproject commit 2bd5691c8f12e21e1e6db33e42fe2fe3db7726a3 diff --git a/plugins/LyraeModules b/plugins/LyraeModules index 1c32b02b..b21cbe8e 160000 --- a/plugins/LyraeModules +++ b/plugins/LyraeModules @@ -1 +1 @@ -Subproject commit 1c32b02bd11a549d28da0620719541ac6f966652 +Subproject commit b21cbe8ee25ddf2a927e0b4ec9f2c97c115857af diff --git a/plugins/MSM b/plugins/MSM index 80b4a5aa..abe3c24d 160000 --- a/plugins/MSM +++ b/plugins/MSM @@ -1 +1 @@ -Subproject commit 80b4a5aa06d9c4a58f62d90fe567b28b01f6312d +Subproject commit abe3c24d40b11d31f9f38b2125eff9280c77ad1b diff --git a/plugins/Makefile b/plugins/Makefile index 1176d561..09db238c 100644 --- a/plugins/Makefile +++ b/plugins/Makefile @@ -222,6 +222,15 @@ PLUGIN_FILES += $(wildcard Cardinal/src/DearImGui/*.cpp) PLUGIN_FILES += $(wildcard Cardinal/src/DearImGuiColorTextEditor/*.cpp) endif +# -------------------------------------------------------------- +# Fundamental (always enabled) + +PLUGIN_FILES += $(filter-out Fundamental/src/plugin.cpp,$(wildcard Fundamental/src/*.cpp)) +PLUGIN_FILES += Fundamental/src/dr_wav.c + +# modules/types which are present in other plugins +FUNDAMENTAL_CUSTOM = $(DRWAV) + ifneq ($(NOPLUGINS),true) # -------------------------------------------------------------- # 21kHz @@ -231,7 +240,7 @@ PLUGIN_FILES += $(filter-out 21kHz/src/21kHz.cpp,$(wildcard 21kHz/src/*.cpp)) # -------------------------------------------------------------- # 8Mode -PLUGIN_FILES += $(filter-out 8Mode/src/plugin.cpp,$(wildcard 8Mode/src/*.cpp)) +PLUGIN_FILES += $(filter-out 8Mode/src/8mode.cpp,$(wildcard 8Mode/src/*.cpp)) # -------------------------------------------------------------- # AlgoritmArte @@ -261,6 +270,24 @@ AMALGAMATEDHARMONICS_CUSTOM += bogaudio PLUGIN_FILES += $(wildcard AnimatedCircuits/src/Folding/*.cpp) PLUGIN_FILES += $(wildcard AnimatedCircuits/src/LFold/*.cpp) +# -------------------------------------------------------------- +# ArableInstruments + +PLUGIN_FILES += ArableInstruments/src/Clouds.cpp +PLUGIN_FILES += ArableInstruments/eurorack/clouds/dsp/correlator.cc +PLUGIN_FILES += ArableInstruments/eurorack/clouds/dsp/granular_processor.cc +PLUGIN_FILES += ArableInstruments/eurorack/clouds/dsp/mu_law.cc +PLUGIN_FILES += ArableInstruments/eurorack/clouds/dsp/pvoc/frame_transformation.cc +PLUGIN_FILES += ArableInstruments/eurorack/clouds/dsp/pvoc/phase_vocoder.cc +PLUGIN_FILES += ArableInstruments/eurorack/clouds/dsp/pvoc/stft.cc +PLUGIN_FILES += ArableInstruments/eurorack/clouds/resources.cc +PLUGIN_FILES += ArableInstruments/eurorack/stmlib/utils/random.cc +PLUGIN_FILES += ArableInstruments/eurorack/stmlib/dsp/atan.cc +PLUGIN_FILES += ArableInstruments/eurorack/stmlib/dsp/units.cc + +# modules/types which are present in other plugins +ARABLE_CUSTOM = Clouds FreezeLight clouds stmlib + # -------------------------------------------------------------- # Aria @@ -404,6 +431,7 @@ PLUGIN_FILES += $(wildcard BaconPlugs/libs/open303-code/Source/DSPCode/*.cpp) # Befaco PLUGIN_FILES += $(filter-out Befaco/src/plugin.cpp,$(wildcard Befaco/src/*.cpp)) +PLUGIN_FILES += $(wildcard Befaco/src/noise-plethora/*/*.cpp) PLUGIN_BINARIES += Befaco/src/SpringReverbIR.pcm # modules/types which are present in other plugins @@ -418,9 +446,10 @@ PLUGIN_FILES += $(wildcard Bidoo/src/dep/filters/*.cpp) PLUGIN_FILES += $(wildcard Bidoo/src/dep/freeverb/*.cpp) PLUGIN_FILES += $(wildcard Bidoo/src/dep/lodepng/*.cpp) PLUGIN_FILES += $(filter-out Bidoo/src/dep/resampler/main.cpp,$(wildcard Bidoo/src/dep/resampler/*.cpp)) +PLUGIN_FILES += BidooDark/plugin.cpp # modules/types which are present in other plugins -BIDOO_CUSTOM = ChannelDisplay LadderFilter $(DRWAV) +BIDOO_CUSTOM = ChannelDisplay InstantiateExpanderItem LadderFilter $(DRWAV) BIDOO_CUSTOM_PER_FILE = channel channel filterType # -------------------------------------------------------------- @@ -437,15 +466,14 @@ BOGAUDIO_CUSTOM_PER_FILE = ARQuantity AttackMenuItem ReleaseMenuItem # -------------------------------------------------------------- # ChowDSP -# Credit module crashes on save, see https://github.com/DISTRHO/Cardinal/issues/98 -PLUGIN_FILES += $(filter-out ChowDSP/src/Credit.cpp,$(wildcard ChowDSP/src/*/*.cpp)) +PLUGIN_FILES += $(wildcard ChowDSP/src/*/*.cpp) PLUGIN_FILES += $(wildcard ChowDSP/src/*/*/*.cpp) PLUGIN_FILES += $(wildcard ChowDSP/lib/r8lib/*.cpp) # -------------------------------------------------------------- # CatroModulo -PLUGIN_FILES += $(wildcard CatroModulo/src/*.cpp) +PLUGIN_FILES += $(filter-out CatroModulo/src/CatroModulo.cpp,$(wildcard CatroModulo/src/*.cpp)) # modules/types which are present in other plugins CATROMODULO_CUSTOM = LowFrequencyOscillator NumDisplayWidget @@ -455,13 +483,6 @@ CATROMODULO_CUSTOM = LowFrequencyOscillator NumDisplayWidget PLUGIN_FILES += $(filter-out cf/src/plugin.cpp,$(wildcard cf/src/*.cpp)) -# -------------------------------------------------------------- -# Dintree - -PLUGIN_FILES += $(wildcard Dintree/src/*.cpp) -PLUGIN_FILES += $(wildcard Dintree/src/components/*.cpp) -PLUGIN_FILES += $(wildcard Dintree/src/utils/*.cpp) - # -------------------------------------------------------------- # DrumKit @@ -498,19 +519,6 @@ PLUGIN_FILES += $(filter-out FehlerFabrik/src/plugin.cpp,$(wildcard FehlerFabrik # modules/types which are present in other plugins FEHLERFABRIK_CUSTOM = Operator Sequencer SlewLimiter -# -------------------------------------------------------------- -# Fundamental - -ifeq ($(WITH_FUNDAMENTAL),true) -BASE_FLAGS += -DWITH_FUNDAMENTAL - -PLUGIN_FILES += $(filter-out Fundamental/src/plugin.cpp,$(wildcard Fundamental/src/*.cpp)) -PLUGIN_FILES += Fundamental/src/dr_wav.c - -# modules/types which are present in other plugins -FUNDAMENTAL_CUSTOM = $(DRWAV) -endif - # -------------------------------------------------------------- # GlueTheGiant @@ -519,7 +527,7 @@ PLUGIN_FILES += $(filter-out GlueTheGiant/src/plugin.cpp,$(wildcard GlueTheGiant # -------------------------------------------------------------- # GoodSheperd -PLUGIN_FILES += $(wildcard GoodSheperd/src/*.cpp) +PLUGIN_FILES += $(filter-out GoodSheperd/src/plugin.cpp,$(wildcard GoodSheperd/src/*.cpp)) # -------------------------------------------------------------- # GrandeModular @@ -529,7 +537,7 @@ PLUGIN_FILES += $(filter-out GrandeModular/src/plugin.cpp,$(wildcard GrandeModul # -------------------------------------------------------------- # Hampton Harmonics -PLUGIN_FILES += $(wildcard HamptonHarmonics/src/*.cpp) +PLUGIN_FILES += $(filter-out HamptonHarmonics/src/plugin.cpp,$(wildcard HamptonHarmonics/src/*.cpp)) # modules/types which are present in other plugins HAMPTONHARMONICS_CUSTOM = Arp Progress @@ -537,7 +545,7 @@ HAMPTONHARMONICS_CUSTOM = Arp Progress # -------------------------------------------------------------- # HetrickCV -PLUGIN_FILES += $(wildcard HetrickCV/src/*.cpp) +PLUGIN_FILES += $(filter-out HetrickCV/src/HetrickCV.cpp,$(wildcard HetrickCV/src/*.cpp)) PLUGIN_FILES += $(wildcard HetrickCV/src/DSP/*.cpp) PLUGIN_FILES += $(wildcard HetrickCV/Gamma/src/arr.cpp) PLUGIN_FILES += $(wildcard HetrickCV/Gamma/src/Domain.cpp) @@ -592,7 +600,7 @@ JW_CUSTOM = PlayHead Quantizer # -------------------------------------------------------------- # kocmoc -PLUGIN_FILES += $(wildcard kocmoc/src/*.cpp) +PLUGIN_FILES += $(filter-out kocmoc/src/plugin.cpp,$(wildcard kocmoc/src/*.cpp)) # modules/types which are present in other plugins KOCMOC_CUSTOM = Phasor __ct_base __ct_comp @@ -608,7 +616,7 @@ LIFEFORMMODULAR_CUSTOM = IO MS __ct_base __ct_comp # -------------------------------------------------------------- # Lilac Loop -PLUGIN_FILES += $(wildcard LilacLoop/src/*.cpp) +PLUGIN_FILES += $(filter-out LilacLoop/src/plugin.cpp,$(wildcard LilacLoop/src/*.cpp)) # modules/types which are present in other plugins LILACLOOP_CUSTOM = AudioFile Mode @@ -653,7 +661,7 @@ MINDMELD_CUSTOM = printNote # -------------------------------------------------------------- # ML_modules -PLUGIN_FILES += $(filter-out ML_modules/src/plugin.cpp,$(wildcard ML_modules/src/*.cpp)) +PLUGIN_FILES += $(filter-out ML_modules/src/ML_modules.cpp,$(wildcard ML_modules/src/*.cpp)) PLUGIN_FILES += ML_modules/freeverb/revmodel.cpp # modules/types which are present in other plugins @@ -697,12 +705,36 @@ PLUGIN_FILES += $(filter-out nonlinearcircuits/src/NLC.cpp,$(wildcard nonlinearc # -------------------------------------------------------------- # Orbits -PLUGIN_FILES += $(wildcard Orbits/src/*.cpp) +PLUGIN_FILES += $(filter-out Orbits/src/plugin.cpp,$(wildcard Orbits/src/*.cpp)) + +# -------------------------------------------------------------- +# ParableInstruments + +PLUGIN_FILES += ParableInstruments/src/Clouds.cpp +PLUGIN_FILES += ParableInstruments/parasites/clouds/dsp/correlator.cc +PLUGIN_FILES += ParableInstruments/parasites/clouds/dsp/granular_processor.cc +PLUGIN_FILES += ParableInstruments/parasites/clouds/dsp/mu_law.cc +PLUGIN_FILES += ParableInstruments/parasites/clouds/dsp/pvoc/frame_transformation.cc +PLUGIN_FILES += ParableInstruments/parasites/clouds/dsp/pvoc/phase_vocoder.cc +PLUGIN_FILES += ParableInstruments/parasites/clouds/dsp/pvoc/stft.cc +PLUGIN_FILES += ParableInstruments/parasites/clouds/resources.cc +PLUGIN_FILES += ParableInstruments/parasites/stmlib/utils/random.cc +PLUGIN_FILES += ParableInstruments/parasites/stmlib/dsp/atan.cc +PLUGIN_FILES += ParableInstruments/parasites/stmlib/dsp/units.cc + +# modules/types which are present in other plugins +PARABLE_CUSTOM = Clouds CustomPanel CloudsWidget FreezeLight clouds stmlib # -------------------------------------------------------------- # Path Set -PLUGIN_FILES += $(wildcard PathSet/src/*.cpp) +PLUGIN_FILES += $(filter-out PathSet/src/plugin.cpp,$(wildcard PathSet/src/*.cpp)) + +# -------------------------------------------------------------- +# PinkTrombone + +PLUGIN_FILES += $(filter-out PinkTrombone/src/plugin.cpp,$(wildcard PinkTrombone/src/*.cpp)) +PLUGIN_FILES += $(wildcard PinkTrombone/src/PinkTrombone/*.cpp) # -------------------------------------------------------------- # Prism @@ -729,7 +761,7 @@ REPELZEN_CUSTOM = Blank Mixer Werner tanh_pade # -------------------------------------------------------------- # sonusmodular -PLUGIN_FILES += $(filter-out sonusmodular/src/sonusmodular,$(wildcard sonusmodular/src/*.cpp)) +PLUGIN_FILES += $(filter-out sonusmodular/src/sonusmodular.cpp,$(wildcard sonusmodular/src/*.cpp)) # -------------------------------------------------------------- # Starling Via @@ -744,15 +776,16 @@ STARLINGVIA_CUSTOM = Scanner # -------------------------------------------------------------- # stocaudio -PLUGIN_FILES += $(wildcard stocaudio/src/*.cpp) +PLUGIN_FILES += $(filter-out stocaudio/src/plugin.cpp,$(wildcard stocaudio/src/*.cpp)) # -------------------------------------------------------------- -# Substation (Open source release) -PLUGIN_FILES += $(wildcard substation-opensource/dep/slime4rack/src/slime/*.cpp) -PLUGIN_FILES += $(wildcard substation-opensource/dep/slime4rack/src/slime/**/*.cpp) -PLUGIN_FILES += $(filter-out substation-opensource/src/_plugin.cpp substation-opensource/src/Settings.cpp,$(wildcard substation-opensource/src/*.cpp)) -PLUGIN_FILES += substation-settings/Settings.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 # -------------------------------------------------------------- # ValleyAudio @@ -830,6 +863,15 @@ PLUGIN_BINARIES += ValleyAudio/src/XFADE.bin VALLEYAUDIO_CUSTOM = $(DRWAV) DigitalDisplay VALLEYAUDIO_CUSTOM_PER_FILE = TempoKnob +# -------------------------------------------------------------- +# Voxglitch + +PLUGIN_FILES += $(filter-out voxglitch/src/plugin.cpp,$(wildcard voxglitch/src/*.cpp)) + +# modules/types which are present in other plugins +VOXGLITCH_CUSTOM = $(DRWAV) AudioFile Looper Readout +VOXGLITCH_CUSTOM_PER_FILE = AudioBuffer GateSequencer Grain Sequencer SequencerDisplay VoltageSequencer + # -------------------------------------------------------------- # ZetaCarinaeModules @@ -933,7 +975,7 @@ 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 +BUILD_CXX_FLAGS += -fno-finite-math-only -fno-strict-aliasing -faligned-new # Rack code is not tested for this flag, unset it BUILD_CXX_FLAGS += -U_GLIBCXX_ASSERTIONS -Wp,-U_GLIBCXX_ASSERTIONS @@ -973,30 +1015,25 @@ PLUGIN_LIST = $(subst /plugin.json,,$(wildcard */plugin.json)) endif UNWANTED_FILES = HetrickCV/res/illustrator - deprecated/MyModule.svg -UNWANTED_FILES += nonlinearcircuits/res/NLC - 1050 MIXER SEQUENCER.svg -UNWANTED_FILES += 1050 MIXER SEQUENCER.svg -UNWANTED_FILES += 32to1.svg -UNWANTED_FILES += 4seq.svg -UNWANTED_FILES += 8 BIT CIPHER.svg -UNWANTED_FILES += DIVIDE & CONQUER.svg -UNWANTED_FILES += DIVINE CMOS.svg -UNWANTED_FILES += GENiE.svg -UNWANTED_FILES += NEURON.svg -UNWANTED_FILES += NUMBERWANG.svg -UNWANTED_FILES += ROUTER.svg -UNWANTED_FILES += SEGUE.svg -UNWANTED_FILES += STATUES.svg +UNWANTED_FILES += $(wildcard Mog/res/*) +UNWANTED_FILES += $(wildcard Mog/res/*/*) +UNWANTED_FILES += $(wildcard nonlinearcircuits/res/*) RESOURCE_FILES = \ $(filter-out $(UNWANTED_FILES), \ $(wildcard */res/*.svg) \ $(wildcard */res/*/*.svg) \ $(wildcard */res/*/*/*.svg) \ + $(wildcard */res/*.otf) \ + $(wildcard */res/*/*.otf) \ + $(wildcard */res/*/*/*.otf) \ $(wildcard */res/*.ttf) \ $(wildcard */res/*/*.ttf) \ $(wildcard */res/*/*/*.ttf)) RESOURCE_FILES += $(wildcard */presets) +RESOURCE_FILES += $(wildcard Orbits/res/*.json) +RESOURCE_FILES += ArableInstruments/res/Joni.png RESOURCE_FILES += BaconPlugs/res/Keypunch029.json RESOURCE_FILES += BaconPlugs/res/midi/chopin RESOURCE_FILES += BaconPlugs/res/midi/debussy @@ -1008,7 +1045,13 @@ RESOURCE_FILES += MindMeldModular/res/ShapeMaster/CommunityPresets RESOURCE_FILES += MindMeldModular/res/ShapeMaster/CommunityShapes RESOURCE_FILES += MindMeldModular/res/ShapeMaster/MindMeldPresets RESOURCE_FILES += MindMeldModular/res/ShapeMaster/MindMeldShapes +RESOURCE_FILES += Mog/res RESOURCE_FILES += nonlinearcircuits/res +RESOURCE_FILES += ParableInstruments/res/Neil.png +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/*) # MOD builds only have LV2 FX variant for now ifeq ($(MOD_BUILD),true) @@ -1028,10 +1071,8 @@ VST2_RESOURCES += $(PLUGIN_LIST:%=../bin/CardinalSynth.vst/Contents/Resources/Pl VST2_RESOURCES += $(RESOURCE_FILES:%=../bin/CardinalFX.vst/Contents/Resources/%) VST2_RESOURCES += $(RESOURCE_FILES:%=../bin/CardinalSynth.vst/Contents/Resources/%) else -VST2_RESOURCES = $(PLUGIN_LIST:%=../bin/CardinalFX.vst/resources/PluginManifests/%.json) -VST2_RESOURCES += $(PLUGIN_LIST:%=../bin/CardinalSynth.vst/resources/PluginManifests/%.json) -VST2_RESOURCES += $(RESOURCE_FILES:%=../bin/CardinalFX.vst/resources/%) -VST2_RESOURCES += $(RESOURCE_FILES:%=../bin/CardinalSynth.vst/resources/%) +VST2_RESOURCES = $(PLUGIN_LIST:%=../bin/Cardinal.vst/resources/PluginManifests/%.json) +VST2_RESOURCES += $(RESOURCE_FILES:%=../bin/Cardinal.vst/resources/%) endif VST3_RESOURCES = $(PLUGIN_LIST:%=../bin/Cardinal.vst3/Contents/Resources/PluginManifests/%.json) @@ -1115,19 +1156,11 @@ ifeq ($(MACOS),true) -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ else -../bin/CardinalFX.vst/resources/%: % - -@mkdir -p "$(shell dirname $@)" - $(SILENT)ln -sf $(abspath $<) $@ - -../bin/CardinalSynth.vst/resources/%: % - -@mkdir -p "$(shell dirname $@)" - $(SILENT)ln -sf $(abspath $<) $@ - -../bin/CardinalFX.vst/resources/PluginManifests/%.json: %/plugin.json +../bin/Cardinal.vst/resources/%: % -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ -../bin/CardinalSynth.vst/resources/PluginManifests/%.json: %/plugin.json +../bin/Cardinal.vst/resources/PluginManifests/%.json: %/plugin.json -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ endif @@ -1225,6 +1258,17 @@ $(BUILD_DIR)/AnimatedCircuits/%.cpp.o: AnimatedCircuits/%.cpp $(foreach m,$(ANIMATEDCIRCUITS_CUSTOM),$(call custom_module_names,$(m),AnimatedCircuits)) \ -DpluginInstance=pluginInstance__AnimatedCircuits +$(BUILD_DIR)/ArableInstruments/%.o: ArableInstruments/% + -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" + @echo "Compiling $<" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(foreach m,$(ARABLE_CUSTOM),$(call custom_module_names,$(m),Arable)) \ + -DpluginInstance=pluginInstance__ArableInstruments \ + -DTEST \ + -IArableInstruments/eurorack \ + -Wno-class-memaccess \ + -Wno-unused-local-typedefs + $(BUILD_DIR)/AriaModules/%.cpp.o: AriaModules/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" @@ -1279,7 +1323,7 @@ $(BUILD_DIR)/Befaco/%.cpp.o: Befaco/%.cpp $(foreach m,$(BEFACO_CUSTOM),$(call custom_module_names,$(m),Befaco)) \ -DpluginInstance=pluginInstance__Befaco -$(BUILD_DIR)/Bidoo/%.cpp.o: Bidoo/%.cpp +$(BUILD_DIR)/Bidoo%.cpp.o: Bidoo%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ @@ -1343,14 +1387,6 @@ $(BUILD_DIR)/ChowDSP/%.cpp.o: ChowDSP/%.cpp -IChowDSP/lib/chowdsp_utils/DSP/WDF \ -Wno-deprecated-copy -$(BUILD_DIR)/Dintree/%.cpp.o: Dintree/%.cpp - -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" - @echo "Compiling $<" - $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ - $(foreach m,$(DINTREE_CUSTOM),$(call custom_module_names,$(m),Dintree)) \ - -DpluginInstance=pluginInstance__Dintree \ - -DSKIP_MINGW_FORMAT - $(BUILD_DIR)/DrumKit/%.cpp.o: DrumKit/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" @@ -1432,6 +1468,7 @@ $(BUILD_DIR)/GrandeModular/%.cpp.o: GrandeModular/%.cpp $(foreach m,$(GRANDEMODULAR_CUSTOM),$(call custom_module_names,$(m),GrandeModular)) \ -DpluginInstance=pluginInstance__GrandeModular \ -Wno-missing-braces \ + -Wno-narrowing \ -Wno-self-assign $(BUILD_DIR)/HamptonHarmonics/%.cpp.o: HamptonHarmonics/%.cpp @@ -1553,7 +1590,7 @@ $(BUILD_DIR)/LyraeModules/%.cpp.o: LyraeModules/%.cpp $(foreach m,$(LYRAE_CUSTOM),$(call custom_module_names,$(m),Lyrae)) \ -DpluginInstance=pluginInstance__Lyrae -$(BUILD_DIR)/MindMeldModular/MindMeldModular.cpp.o: MindMeldModular/src/MindMeldModular.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 $@ \ @@ -1624,6 +1661,18 @@ $(BUILD_DIR)/Orbits/%.cpp.o: Orbits/%.cpp $(foreach m,$(ORBITS_CUSTOM),$(call custom_module_names,$(m),Orbits)) \ -DpluginInstance=pluginInstance__Orbits +$(BUILD_DIR)/ParableInstruments/%.o: ParableInstruments/% + -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" + @echo "Compiling $<" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(foreach m,$(PARABLE_CUSTOM),$(call custom_module_names,$(m),Parable)) \ + -DpluginInstance=pluginInstance__ParableInstruments \ + -DPARASITES \ + -DTEST \ + -IArableInstruments/parasites \ + -Wno-class-memaccess \ + -Wno-unused-local-typedefs + $(BUILD_DIR)/PathSet/%.cpp.o: PathSet/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" @@ -1631,6 +1680,13 @@ $(BUILD_DIR)/PathSet/%.cpp.o: PathSet/%.cpp $(foreach m,$(PATHSET_CUSTOM),$(call custom_module_names,$(m),PathSet)) \ -DpluginInstance=pluginInstance__PathSet +$(BUILD_DIR)/PinkTrombone/%.cpp.o: PinkTrombone/%.cpp + -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" + @echo "Compiling $<" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(foreach m,$(PINKTROMBONE_CUSTOM),$(call custom_module_names,$(m),PinkTrombone)) \ + -DpluginInstance=pluginInstance__PinkTrombone + $(BUILD_DIR)/Prism/%.cpp.o: Prism/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" @@ -1683,14 +1739,12 @@ $(BUILD_DIR)/stocaudio/%.cpp.o: stocaudio/%.cpp $(foreach m,$(STOCAUDIO_CUSTOM),$(call custom_module_names,$(m),stocaudio)) \ -DpluginInstance=pluginInstance__stocaudio -$(BUILD_DIR)/substation-%.cpp.o: substation-%.cpp +$(BUILD_DIR)/unless_modules/%.cpp.o: unless_modules/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ - $(foreach m,$(SUBSTATION_CUSTOM),$(call custom_module_names,$(m),substation)) \ - -DpluginInstance=pluginInstance__substation \ - -D'PRIVATE=__attribute__((error("Using internal Rack function or symbol")))' \ - -Isubstation-opensource/dep/slime4rack/include + $(foreach m,$(UNLESS_MODULES_CUSTOM),$(call custom_module_names,$(m),unless_modules)) \ + -DpluginInstance=pluginInstance__unless_modules $(BUILD_DIR)/ValleyAudio/%.cpp.o: ValleyAudio/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @@ -1703,6 +1757,15 @@ $(BUILD_DIR)/ValleyAudio/%.cpp.o: ValleyAudio/%.cpp -Wno-sign-compare \ -Wno-unused-but-set-variable +$(BUILD_DIR)/voxglitch/%.cpp.o: voxglitch/%.cpp + -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" + @echo "Compiling $<" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ + $(foreach m,$(VOXGLITCH_CUSTOM),$(call custom_module_names,$(m),Voxglitch)) \ + $(foreach m,$(VOXGLITCH_CUSTOM_PER_FILE),$(call custom_per_file_names,$(m),Voxglitch_$(shell basename $*))) \ + -DpluginInstance=pluginInstance__Voxglitch \ + -DSKIP_MINGW_FORMAT + $(BUILD_DIR)/ZetaCarinaeModules/%.cpp.o: ZetaCarinaeModules/%.cpp -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" @echo "Compiling $<" diff --git a/plugins/MindMeldModular b/plugins/MindMeldModular index 38e72d45..a721e381 160000 --- a/plugins/MindMeldModular +++ b/plugins/MindMeldModular @@ -1 +1 @@ -Subproject commit 38e72d454ddb1197ec8225224656135abe6b6609 +Subproject commit a721e381fa1d72d738c9c2daae08c740107e3d5e diff --git a/plugins/Mog b/plugins/Mog index 01c4fac9..00a7e3b0 160000 --- a/plugins/Mog +++ b/plugins/Mog @@ -1 +1 @@ -Subproject commit 01c4fac9f2e91f60125d36767224f457b2057fb7 +Subproject commit 00a7e3b01f56da5cfc86720ae6951ecdf8953ee5 diff --git a/plugins/ParableInstruments/parasites b/plugins/ParableInstruments/parasites new file mode 120000 index 00000000..8e79925b --- /dev/null +++ b/plugins/ParableInstruments/parasites @@ -0,0 +1 @@ +../ArableInstruments/parasites \ No newline at end of file diff --git a/plugins/ParableInstruments/plugin.json b/plugins/ParableInstruments/plugin.json new file mode 100644 index 00000000..a32ff376 --- /dev/null +++ b/plugins/ParableInstruments/plugin.json @@ -0,0 +1,25 @@ +{ + "slug": "ParableInstruments", + "name": "Parable Instruments", + "version": "2.0.0", + "license": "GPL-3.0-or-later", + "brand": "Parable Instruments", + "author": "adbrant", + "authorEmail": "", + "authorUrl": "https://github.com/adbrant/ArableInstruments/blob/master/README.md", + "pluginUrl": "https://github.com/adbrant/ArableInstruments/blob/master/README.md", + "manualUrl": "https://github.com/adbrant/ArableInstruments/blob/master/README.md", + "sourceUrl": "https://github.com/adbrant/ArableInstruments.git", + "donateUrl": "", + "modules": [ + { + "slug": "Neil", + "name": "Neil", + "description": "", + "tags": [ + "Granular", + "Reverb" + ] + } + ] +} diff --git a/plugins/ParableInstruments/res/CKSS_rot_0.svg b/plugins/ParableInstruments/res/CKSS_rot_0.svg new file mode 120000 index 00000000..585ac1f3 --- /dev/null +++ b/plugins/ParableInstruments/res/CKSS_rot_0.svg @@ -0,0 +1 @@ +../../ArableInstruments/res/CKSS_rot_0.svg \ No newline at end of file diff --git a/plugins/ParableInstruments/res/CKSS_rot_1.svg b/plugins/ParableInstruments/res/CKSS_rot_1.svg new file mode 120000 index 00000000..58a2ff0a --- /dev/null +++ b/plugins/ParableInstruments/res/CKSS_rot_1.svg @@ -0,0 +1 @@ +../../ArableInstruments/res/CKSS_rot_1.svg \ No newline at end of file diff --git a/plugins/ParableInstruments/res/Neil.png b/plugins/ParableInstruments/res/Neil.png new file mode 120000 index 00000000..26dbedb8 --- /dev/null +++ b/plugins/ParableInstruments/res/Neil.png @@ -0,0 +1 @@ +../../ArableInstruments/res/Neil.png \ No newline at end of file diff --git a/plugins/ParableInstruments/res/Neil.svg b/plugins/ParableInstruments/res/Neil.svg new file mode 120000 index 00000000..04bfc607 --- /dev/null +++ b/plugins/ParableInstruments/res/Neil.svg @@ -0,0 +1 @@ +../../ArableInstruments/res/Neil.svg \ No newline at end of file diff --git a/plugins/ParableInstruments/src/ArableInstruments.hpp b/plugins/ParableInstruments/src/ArableInstruments.hpp new file mode 120000 index 00000000..d44ebde3 --- /dev/null +++ b/plugins/ParableInstruments/src/ArableInstruments.hpp @@ -0,0 +1 @@ +../../ArableInstruments/src/ArableInstruments.hpp \ No newline at end of file diff --git a/plugins/ParableInstruments/src/Clouds.cpp b/plugins/ParableInstruments/src/Clouds.cpp new file mode 120000 index 00000000..924a7f2b --- /dev/null +++ b/plugins/ParableInstruments/src/Clouds.cpp @@ -0,0 +1 @@ +../../ArableInstruments/src/Clouds.cpp \ No newline at end of file diff --git a/plugins/PinkTrombone b/plugins/PinkTrombone new file mode 160000 index 00000000..ea6ab0c6 --- /dev/null +++ b/plugins/PinkTrombone @@ -0,0 +1 @@ +Subproject commit ea6ab0c6887102ebbf6e3534e0e891b867b130cc diff --git a/plugins/Prism b/plugins/Prism index 453da225..8a9cc034 160000 --- a/plugins/Prism +++ b/plugins/Prism @@ -1 +1 @@ -Subproject commit 453da225742f3829ba037770245333a28751fbb8 +Subproject commit 8a9cc034d905079f156ed6c64efaeb4baf81490f diff --git a/plugins/ValleyAudio b/plugins/ValleyAudio index c05209a6..98698dc2 160000 --- a/plugins/ValleyAudio +++ b/plugins/ValleyAudio @@ -1 +1 @@ -Subproject commit c05209a6ad74e8b99703a033842797f06515f865 +Subproject commit 98698dc28e6ed7aec56e4ab8280171a160d673ef diff --git a/plugins/ihtsyn b/plugins/ihtsyn index 31c4229e..1b77e3c3 160000 --- a/plugins/ihtsyn +++ b/plugins/ihtsyn @@ -1 +1 @@ -Subproject commit 31c4229eb328f6aaa4024f76c595b55213cdf1cf +Subproject commit 1b77e3c3ba12734bbd29a4aa59dd408e679b5cf7 diff --git a/plugins/nonlinearcircuits b/plugins/nonlinearcircuits index d7c3763b..57eb090f 160000 --- a/plugins/nonlinearcircuits +++ b/plugins/nonlinearcircuits @@ -1 +1 @@ -Subproject commit d7c3763ba3f801a3cfe98c49dfb7419a1477fd46 +Subproject commit 57eb090f233c21b2edee541ea17d800f22045d91 diff --git a/plugins/plugins.cpp b/plugins/plugins.cpp index 5302e28e..0d12be0c 100644 --- a/plugins/plugins.cpp +++ b/plugins/plugins.cpp @@ -23,6 +23,9 @@ // Cardinal (built-in) #include "Cardinal/src/plugin.hpp" +// Fundamental (always enabled) +#include "Fundamental/src/plugin.hpp" + #ifndef NOPLUGINS // 21kHz #include "21kHz/src/21kHz.hpp" @@ -42,6 +45,11 @@ // AnimatedCircuits #include "AnimatedCircuits/src/plugin.hpp" +// ArableInstruments +#define modelClouds modelArableClouds +#include "ArableInstruments/src/ArableInstruments.hpp" +#undef modelClouds + // Aria /* NOTE too much noise in original include, do this a different way // #include "AriaModules/src/plugin.hpp" @@ -285,9 +293,6 @@ extern Model* modelTestVCF; #include "ChowDSP/src/plugin.cpp" #undef init -// Dintree -#include "Dintree/src/plugin.hpp" - // DrumKit #include "DrumKit/src/DrumKit.hpp" void setupSamples(); @@ -304,11 +309,6 @@ void setupSamples(); // FehlerFabrik #include "FehlerFabrik/src/plugin.hpp" -// Fundamental -#ifdef WITH_FUNDAMENTAL -#include "Fundamental/src/plugin.hpp" -#endif - // GlueTheGiant #include "GlueTheGiant/src/plugin.hpp" bool audition_mixer = false; @@ -616,11 +616,19 @@ extern Model* modelBlankPanel; // Orbits #include "Orbits/src/plugin.hpp" +// ParableInstruments +#define modelClouds modelParableClouds +#include "ParableInstruments/src/ArableInstruments.hpp" +#undef modelClouds + // Path Set -# include "PathSet/src/plugin.hpp" +#include "PathSet/src/plugin.hpp" + +// PinkTrombone +#include "PinkTrombone/src/plugin.hpp" // Prism -# include "Prism/src/plugin.hpp" +#include "Prism/src/plugin.hpp" // rackwindows #include "rackwindows/src/plugin.hpp" @@ -648,29 +656,17 @@ extern Model* modelBlankPanel; // stocaudio #include "stocaudio/src/plugin.hpp" -// substation -/* NOTE too much noise in original include, do this a different way -// "substation-opensource/src/_plugin.hpp" -*/ -namespace slime { -namespace plugin { -namespace substation { -extern Model* modelClock; -extern Model* modelPolySequencer; -extern Model* modelSubOscillator; -extern Model* modelMixer; -extern Model* modelFilter; -extern Model* modelEnvelopes; -extern Model* modelQuantizer; -extern Model* modelVCA; -extern Model* modelBlank4; -extern Model* modelBlank7; -extern Model* modelFilterPlus; -}}} +// unless_modules +#include "unless_modules/src/unless.hpp" // ValleyAudio #include "ValleyAudio/src/Valley.hpp" +// Voxglitch +#define modelLooper modelVoxglitchLooper +#include "voxglitch/src/plugin.hpp" +#undef modelLooper + // ZetaCarinaeModules #include "ZetaCarinaeModules/src/plugin.hpp" @@ -697,12 +693,14 @@ void saveHighQualityAsDefault(bool) {} // plugin instances Plugin* pluginInstance__Cardinal; +Plugin* pluginInstance__Fundamental; #ifndef NOPLUGINS Plugin* pluginInstance__21kHz; Plugin* pluginInstance__8Mode; extern Plugin* pluginInstance__AaronStatic; Plugin* pluginInstance__Algoritmarte; Plugin* pluginInstance__AmalgamatedHarmonics; +Plugin* pluginInstance__ArableInstruments; Plugin* pluginInstance__AnimatedCircuits; Plugin* pluginInstance__Aria; Plugin* pluginInstance__AudibleInstruments; @@ -715,15 +713,11 @@ Plugin* pluginInstance__BogaudioModules; Plugin* pluginInstance__CatroModulo; Plugin* pluginInstance__cf; Plugin* pluginInstance__ChowDSP; -Plugin* pluginInstance__Dintree; extern Plugin* pluginInstance__DrumKit; Plugin* pluginInstance__ESeries; Plugin* pluginInstance__ExpertSleepersEncoders; Plugin* pluginInstance__Extratone; Plugin* pluginInstance__FehlerFabrik; -#ifdef WITH_FUNDAMENTAL -Plugin* pluginInstance__Fundamental; -#endif Plugin* pluginInstance__GlueTheGiant; Plugin* pluginInstance__GoodSheperd; Plugin* pluginInstance__GrandeModular; @@ -746,15 +740,18 @@ extern Plugin* pluginInstance__mscHack; Plugin* pluginInstance__MSM; Plugin* pluginInstance__nonlinearcircuits; Plugin* pluginInstance__Orbits; +Plugin* pluginInstance__ParableInstruments; Plugin* pluginInstance__PathSet; +Plugin* pluginInstance__PinkTrombone; Plugin* pluginInstance__Prism; Plugin* pluginInstance__rackwindows; Plugin* pluginInstance__repelzen; Plugin* pluginInstance__sonusmodular; Plugin* pluginInstance__StarlingVia; Plugin* pluginInstance__stocaudio; -Plugin* pluginInstance__substation; +Plugin* pluginInstance__unless_modules; Plugin* pluginInstance__ValleyAudio; +Plugin* pluginInstance__Voxglitch; Plugin* pluginInstance__ZetaCarinaeModules; Plugin* pluginInstance__ZZC; #endif // NOPLUGINS @@ -898,6 +895,43 @@ static void initStatic__Cardinal() } } +static void initStatic__Fundamental() +{ + Plugin* const p = new Plugin; + pluginInstance__Fundamental = p; + + const StaticPluginLoader spl(p, "Fundamental"); + if (spl.ok()) + { + p->addModel(model_8vert); + p->addModel(modelADSR); + p->addModel(modelDelay); + p->addModel(modelLFO); + p->addModel(modelLFO2); + p->addModel(modelMerge); + p->addModel(modelMidSide); + p->addModel(modelMixer); + p->addModel(modelMutes); + p->addModel(modelNoise); + p->addModel(modelOctave); + p->addModel(modelPulses); + p->addModel(modelQuantizer); + p->addModel(modelRandom); + p->addModel(modelScope); + p->addModel(modelSEQ3); + p->addModel(modelSequentialSwitch1); + p->addModel(modelSequentialSwitch2); + p->addModel(modelSplit); + p->addModel(modelSum); + p->addModel(modelVCA); + p->addModel(modelVCA_1); + p->addModel(modelVCF); + p->addModel(modelVCMixer); + p->addModel(modelVCO); + p->addModel(modelVCO2); + } +} + #ifndef NOPLUGINS static void initStatic__21kHz() { @@ -1003,6 +1037,20 @@ static void initStatic__AnimatedCircuits() } } +static void initStatic__ArableInstruments() +{ + Plugin* const p = new Plugin; + pluginInstance__ArableInstruments = p; + + const StaticPluginLoader spl(p, "ArableInstruments"); + if (spl.ok()) + { +#define modelClouds modelArableClouds + p->addModel(modelClouds); +#undef modelClouds + } +} + static void initStatic__Aria() { Plugin* const p = new Plugin; @@ -1184,6 +1232,7 @@ static void initStatic__Befaco() p->addModel(modelSTMix); p->addModel(modelMuxlicer); p->addModel(modelMex); + p->addModel(modelNoisePlethora); #undef modelADSR #undef modelMixer } @@ -1203,6 +1252,7 @@ static void initStatic__Bidoo() p->addModel(modelDTROY); p->addModel(modelBORDL); p->addModel(modelZOUMAI); + p->addModel(modelZOUMAIExpander); p->addModel(modelMU); p->addModel(modelCHUTE); p->addModel(modelLOURDE); @@ -1473,36 +1523,13 @@ static void initStatic__ChowDSP() p->addModel(modelChowDer); p->addModel(modelWarp); p->addModel(modelWerner); + p->addModel(modelCredit); p->addModel(modelChowPulse); p->addModel(modelChowTapeCompression); p->addModel(modelChowTapeChew); p->addModel(modelChowTapeDegrade); p->addModel(modelChowTapeLoss); p->addModel(modelChowChorus); - - // Credit crashes on save, see https://github.com/DISTRHO/Cardinal/issues/98 - // p->addModel(modelCredit); - spl.removeModule("Credit"); - } -} - -static void initStatic__Dintree() -{ - Plugin* const p = new Plugin; - pluginInstance__Dintree = p; - - const StaticPluginLoader spl(p, "Dintree"); - if (spl.ok()) - { - p->addModel(modelV100_Scanner); - p->addModel(modelV101_Dual_Envelope); - p->addModel(modelV102_Output_Mixer); - p->addModel(modelV103_Reverb_Delay); - p->addModel(modelV104_Four_Vs); - p->addModel(modelV105_Quad_CV_Proc); - p->addModel(modelV107_Dual_Slew); - p->addModel(modelV201_Tri_Comparator); - p->addModel(modelV218_SH_Clock_Noise); } } @@ -1607,58 +1634,6 @@ static void initStatic__FehlerFabrik() } } -#ifdef WITH_FUNDAMENTAL -static void initStatic__Fundamental() -{ - Plugin* const p = new Plugin; - pluginInstance__Fundamental = p; - - const StaticPluginLoader spl(p, "Fundamental"); - if (spl.ok()) - { - p->addModel(modelVCO); - p->addModel(modelVCO2); - p->addModel(modelVCF); - p->addModel(modelVCA_1); - p->addModel(modelVCA); - p->addModel(modelLFO); - p->addModel(modelLFO2); - p->addModel(modelDelay); - p->addModel(modelADSR); - p->addModel(modelMixer); - p->addModel(modelVCMixer); - p->addModel(model_8vert); - p->addModel(modelUnity); - p->addModel(modelMutes); - p->addModel(modelPulses); - p->addModel(modelScope); - p->addModel(modelSEQ3); - p->addModel(modelSequentialSwitch1); - p->addModel(modelSequentialSwitch2); - p->addModel(modelOctave); - p->addModel(modelQuantizer); - p->addModel(modelSplit); - p->addModel(modelMerge); - p->addModel(modelSum); - p->addModel(modelViz); - p->addModel(modelMidSide); - p->addModel(modelNoise); - p->addModel(modelRandom); - - // show all plugins, helping those familiar with v1 Rack modules - if (json_t* const modules = json_object_get(spl.rootJ, "modules")) - { - size_t i; - json_t* v; - json_array_foreach(modules, i, v) - { - json_object_set(v, "hidden", json_false()); - } - } - } -} -#endif - static void initStatic__GlueTheGiant() { Plugin* const p = new Plugin; @@ -1706,6 +1681,7 @@ static void initStatic__GrandeModular() { p->addModel(modelClip); p->addModel(modelLFO3); + p->addModel(modelLFO4); p->addModel(modelLogic); p->addModel(modelMerge8); p->addModel(modelMergeSplit4); @@ -1715,6 +1691,7 @@ static void initStatic__GrandeModular() p->addModel(modelPeak); p->addModel(modelPolyMergeResplit); p->addModel(modelPolySplit); + p->addModel(modelPush); p->addModel(modelQuant); p->addModel(modelQuantIntervals); p->addModel(modelQuantMT); @@ -2263,6 +2240,20 @@ static void initStatic__Orbits() } } +static void initStatic__ParableInstruments() +{ + Plugin* const p = new Plugin; + pluginInstance__ParableInstruments = p; + + const StaticPluginLoader spl(p, "ParableInstruments"); + if (spl.ok()) + { +#define modelClouds modelParableClouds + p->addModel(modelClouds); +#undef modelClouds + } +} + static void initStatic__PathSet() { Plugin* const p = new Plugin; @@ -2277,6 +2268,18 @@ static void initStatic__PathSet() } } +static void initStatic__PinkTrombone() +{ + Plugin* const p = new Plugin; + pluginInstance__PinkTrombone = p; + + const StaticPluginLoader spl(p, "PinkTrombone"); + if (spl.ok()) + { + p->addModel(modelPinkTrombone); + } +} + static void initStatic__Prism() { Plugin* const p = new Plugin; @@ -2419,25 +2422,26 @@ static void initStatic__stocaudio() } } -static void initStatic__substation() +static void initStatic__unless_modules() { Plugin* const p = new Plugin; - pluginInstance__substation = p; + pluginInstance__unless_modules = p; - const StaticPluginLoader spl(p, "substation-opensource"); + const StaticPluginLoader spl(p, "unless_modules"); if (spl.ok()) { - p->addModel(slime::plugin::substation::modelClock); - p->addModel(slime::plugin::substation::modelEnvelopes); - p->addModel(slime::plugin::substation::modelFilter); - p->addModel(slime::plugin::substation::modelMixer); - p->addModel(slime::plugin::substation::modelQuantizer); - p->addModel(slime::plugin::substation::modelPolySequencer); - p->addModel(slime::plugin::substation::modelVCA); - p->addModel(slime::plugin::substation::modelSubOscillator); - p->addModel(slime::plugin::substation::modelBlank4); - p->addModel(slime::plugin::substation::modelBlank7); - p->addModel(slime::plugin::substation::modelFilterPlus); + // unless_modules::init_theme(); + // theme = _less::Theme(); + p->addModel(modelPiong); + p->addModel(modelChainkov); + p->addModel(modelAtoms); + p->addModel(modelCantor); + p->addModel(modelRoom); + p->addModel(modelSnake); + p->addModel(modelTowers); + p->addModel(modelPianoid); + p->addModel(modelPremuter); + p->addModel(modelAvoider); } } @@ -2460,6 +2464,39 @@ static void initStatic__ValleyAudio() } } +static void initStatic__Voxglitch() +{ + Plugin* p = new Plugin; + pluginInstance__Voxglitch = p; + + const StaticPluginLoader spl(p, "voxglitch"); + if (spl.ok()) + { +#define modelLooper modelVoxglitchLooper + p->addModel(modelAutobreak); + p->addModel(modelByteBeat); + p->addModel(modelDigitalProgrammer); + p->addModel(modelDigitalSequencer); + 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(modelHazumi); + p->addModel(modelLooper); + p->addModel(modelRepeater); + p->addModel(modelSamplerX8); + p->addModel(modelSatanonaut); + p->addModel(modelWavBank); + p->addModel(modelWavBankMC); + p->addModel(modelXY); +#undef modelLooper + } +} + static void initStatic__ZetaCarinaeModules() { Plugin* p = new Plugin; @@ -2505,6 +2542,7 @@ static void initStatic__ZZC() void initStaticPlugins() { initStatic__Cardinal(); + initStatic__Fundamental(); #ifndef NOPLUGINS initStatic__21kHz(); initStatic__8Mode(); @@ -2512,6 +2550,7 @@ void initStaticPlugins() initStatic__Algoritmarte(); initStatic__AmalgamatedHarmonics(); initStatic__AnimatedCircuits(); + initStatic__ArableInstruments(); initStatic__Aria(); initStatic__AudibleInstruments(); initStatic__Autinn(); @@ -2523,15 +2562,11 @@ void initStaticPlugins() initStatic__CatroModulo(); initStatic__cf(); initStatic__ChowDSP(); - initStatic__Dintree(); initStatic__DrumKit(); initStatic__ESeries(); initStatic__ExpertSleepersEncoders(); initStatic__Extratone(); initStatic__FehlerFabrik(); - #ifdef WITH_FUNDAMENTAL - initStatic__Fundamental(); - #endif initStatic__GlueTheGiant(); initStatic__GoodSheperd(); initStatic__GrandeModular(); @@ -2554,15 +2589,18 @@ void initStaticPlugins() initStatic__MSM(); initStatic__nonlinearcircuits(); initStatic__Orbits(); + initStatic__ParableInstruments(); initStatic__PathSet(); + initStatic__PinkTrombone(); initStatic__Prism(); initStatic__rackwindows(); initStatic__repelzen(); initStatic__sonusmodular(); initStatic__StarlingVia(); initStatic__stocaudio(); - initStatic__substation(); + initStatic__unless_modules(); initStatic__ValleyAudio(); + initStatic__Voxglitch(); initStatic__ZetaCarinaeModules(); initStatic__ZZC(); #endif // NOPLUGINS diff --git a/plugins/repelzen b/plugins/repelzen index 185e07ea..f812cc56 160000 --- a/plugins/repelzen +++ b/plugins/repelzen @@ -1 +1 @@ -Subproject commit 185e07ea94086a04b3daacb4bf94c0fbd3544725 +Subproject commit f812cc56b7fe9e41bb13da99ef23f014015c86c1 diff --git a/plugins/substation-opensource b/plugins/substation-opensource deleted file mode 160000 index cbc09d4d..00000000 --- a/plugins/substation-opensource +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cbc09d4db02d038493689c192d63b746d453d18f diff --git a/plugins/unless_modules b/plugins/unless_modules new file mode 160000 index 00000000..3f895c76 --- /dev/null +++ b/plugins/unless_modules @@ -0,0 +1 @@ +Subproject commit 3f895c7663e3e54c4e30c406c56d420ea407133e diff --git a/plugins/voxglitch b/plugins/voxglitch new file mode 160000 index 00000000..03f4fc5c --- /dev/null +++ b/plugins/voxglitch @@ -0,0 +1 @@ +Subproject commit 03f4fc5cebb5d8eb152ac59d3a51ce0ec87a2740 diff --git a/src/CardinalCommon.cpp b/src/CardinalCommon.cpp index e738cee7..c5414baa 100644 --- a/src/CardinalCommon.cpp +++ b/src/CardinalCommon.cpp @@ -29,6 +29,7 @@ #include "AsyncDialog.hpp" #include "PluginContext.hpp" +#include "DistrhoPluginUtils.hpp" #include #include @@ -43,18 +44,50 @@ # undef DEBUG #endif -// for finding home dir -#ifndef ARCH_WIN +// for finding special paths +#ifdef ARCH_WIN +# include +#else # include # include #endif -const std::string CARDINAL_VERSION = "22.02"; +const std::string CARDINAL_VERSION = "22.04"; namespace rack { namespace settings { int rateLimit = 0; } + +bool isStandalone() +{ + return std::strstr(getPluginFormatName(), "JACK") != nullptr; +} + +#ifdef ARCH_WIN +std::string getSpecialPath(const SpecialPath type) +{ + int csidl; + switch (type) + { + case kSpecialPathUserProfile: + csidl = CSIDL_PROFILE; + break; + case kSpecialPathCommonProgramFiles: + csidl = CSIDL_PROGRAM_FILES_COMMON; + break; + default: + return {}; + } + + WCHAR path[MAX_PATH + 256]; + + if (SHGetSpecialFolderPathW(nullptr, path, csidl, FALSE)) + return string::UTF16toUTF8(path); + + return {}; +} +#endif } namespace patchUtils @@ -74,19 +107,11 @@ static void promptClear(const char* const message, const std::function a static std::string homeDir() { # ifdef ARCH_WIN - if (const char* const userprofile = getenv("USERPROFILE")) - { - return userprofile; - } - else if (const char* const homedrive = getenv("HOMEDRIVE")) - { - if (const char* const homepath = getenv("HOMEPATH")) - return system::join(homedrive, homepath); - } + return getSpecialPath(kSpecialPathUserProfile); # else if (const char* const home = getenv("HOME")) return home; - else if (struct passwd* const pwd = getpwuid(getuid())) + if (struct passwd* const pwd = getpwuid(getuid())) return pwd->pw_dir; # endif return {}; @@ -112,6 +137,7 @@ void loadDialog() FileBrowserOptions opts; opts.startDir = dir.c_str(); opts.saving = ui->saving = false; + opts.title = "Open patch"; ui->openFileBrowser(opts); }); #endif @@ -208,6 +234,7 @@ static void saveAsDialog(const bool uncompressed) FileBrowserOptions opts; opts.startDir = dir.c_str(); opts.saving = ui->saving = true; + opts.title = "Save patch"; ui->savingUncompressed = uncompressed; ui->openFileBrowser(opts); } diff --git a/src/CardinalCommon.hpp b/src/CardinalCommon.hpp index 7c9a74ff..e7584c85 100644 --- a/src/CardinalCommon.hpp +++ b/src/CardinalCommon.hpp @@ -41,6 +41,16 @@ namespace window { void generateScreenshot(); } +bool isStandalone(); + +#ifdef ARCH_WIN +enum SpecialPath { + kSpecialPathUserProfile, + kSpecialPathCommonProgramFiles, +}; +std::string getSpecialPath(SpecialPath type); +#endif + } // namespace rack namespace patchUtils { diff --git a/src/CardinalModuleWidget.cpp b/src/CardinalModuleWidget.cpp index be173ec9..57f3ec32 100644 --- a/src/CardinalModuleWidget.cpp +++ b/src/CardinalModuleWidget.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 @@ -37,6 +37,7 @@ #include #include #include +#include #include namespace rack { @@ -54,7 +55,6 @@ struct ModuleWidget::Internal { math::Vec dragOffset; math::Vec dragRackPos; bool dragEnabled; - math::Vec oldPos; widget::Widget* panel; }; @@ -300,36 +300,65 @@ static void CardinalModuleWidget__saveSelectionDialog(RackWidget* const w) void CardinalModuleWidget::onButton(const ButtonEvent& e) { - bool selected = APP->scene->rack->isSelected(this); + const bool selected = APP->scene->rack->isSelected(this); if (selected) { - if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) { - ui::Menu* menu = createMenu(); - patchUtils::appendSelectionContextMenu(menu); + 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); } - 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; + } + + internal->dragOffset = e.pos; + } + + e.consume(this); + } + + return; } - OpaqueWidget::onButton(e); + // 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; + } - if (e.getTarget() == this) { - // Set starting drag position - if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT) { internal->dragOffset = e.pos; } - // Toggle selection on Shift-click - if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT && (e.mods & RACK_MOD_MASK) == GLFW_MOD_SHIFT) { - APP->scene->rack->select(this, !selected); - } + e.consume(this); } - if (!e.isConsumed() && !selected) { - // Open context menu on right-click - if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) { - CardinalModuleWidget__createContextMenu(this, model, module); - 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/CardinalPlugin.cpp b/src/CardinalPlugin.cpp index 653991bf..80514052 100644 --- a/src/CardinalPlugin.cpp +++ b/src/CardinalPlugin.cpp @@ -49,12 +49,22 @@ #include "extra/Base64.hpp" #include "extra/SharedResourcePointer.hpp" +static const constexpr uint kCardinalStateBaseCount = 3; // patch, screenshot, comment + #ifndef HEADLESS # include "WindowParameters.hpp" -static const constexpr uint kCardinalStateCount = 4; // patch, screenshot, comment, windowSize +static const constexpr uint kCardinalStateCount = kCardinalStateBaseCount + 2; // moduleInfos, windowSize #else # define kWindowParameterCount 0 -static const constexpr uint kCardinalStateCount = 3; // patch, screenshot, comment +static const constexpr uint kCardinalStateCount = kCardinalStateBaseCount; +#endif + +#if CARDINAL_VARIANT_FX +# define CARDINAL_TEMPLATE_NAME "template-fx.vcv" +#elif CARDINAL_VARIANT_SYNTH +# define CARDINAL_TEMPLATE_NAME "template-synth.vcv" +#else +# define CARDINAL_TEMPLATE_NAME "template.vcv" #endif namespace rack { @@ -134,11 +144,11 @@ struct Initializer { asset::bundlePath = system::join(resourcePath, "PluginManifests"); asset::systemDir = resourcePath; - templatePath = system::join(asset::systemDir, "template.vcv"); + templatePath = system::join(asset::systemDir, CARDINAL_TEMPLATE_NAME); } } - if (asset::systemDir.empty()) + if (asset::systemDir.empty() || ! system::exists(asset::systemDir)) { #ifdef CARDINAL_PLUGIN_SOURCE_DIR // Make system dir point to source code location as fallback @@ -146,16 +156,27 @@ struct Initializer if (system::exists(system::join(asset::systemDir, "res"))) { - templatePath = CARDINAL_PLUGIN_SOURCE_DIR DISTRHO_OS_SEP_STR "template.vcv"; + templatePath = CARDINAL_PLUGIN_SOURCE_DIR DISTRHO_OS_SEP_STR CARDINAL_TEMPLATE_NAME; } // If source code dir does not exist use install target prefix as system dir else #endif - if (system::exists(CARDINAL_PLUGIN_PREFIX "/share/cardinal")) { - asset::bundlePath = CARDINAL_PLUGIN_PREFIX "/share/cardinal/PluginManifests"; + #if 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"; - templatePath = system::join(asset::systemDir, "template.vcv"); + #endif + + if (! asset::systemDir.empty()) + { + asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); + templatePath = system::join(asset::systemDir, CARDINAL_TEMPLATE_NAME); + } } } @@ -333,6 +354,9 @@ struct Initializer 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,); @@ -425,9 +449,18 @@ class CardinalPlugin : public CardinalBasePlugin std::string fAutosavePath; uint64_t fPreviousFrame; - String fStateComment; - String fStateScreenshot; - String fWindowSize; + + struct { + String comment; + String screenshot; + #ifndef HEADLESS + String windowSize; + #endif + } fState; + + // bypass handling + bool fWasBypassed; + MidiEvent bypassMidiEvents[16]; #ifndef HEADLESS // real values, not VCV interpreted ones @@ -441,7 +474,8 @@ class CardinalPlugin : public CardinalBasePlugin #if DISTRHO_PLUGIN_NUM_INPUTS != 0 fAudioBufferCopy(nullptr), #endif - fPreviousFrame(0) + fPreviousFrame(0), + fWasBypassed(false) { #ifndef HEADLESS fWindowParameters[kWindowParameterShowTooltips] = 1.0f; @@ -454,6 +488,9 @@ class CardinalPlugin : public CardinalBasePlugin fWindowParameters[kWindowParameterWheelSensitivity] = 1.0f; fWindowParameters[kWindowParameterLockModulePositions] = 0.0f; fWindowParameters[kWindowParameterUpdateRateLimit] = 0.0f; + fWindowParameters[kWindowParameterBrowserSort] = 3.0f; + fWindowParameters[kWindowParameterBrowserZoom] = 50.0f; + fWindowParameters[kWindowParameterInvertZoom] = 0.0f; #endif // create unique temporary path for this instance @@ -475,6 +512,16 @@ class CardinalPlugin : public CardinalBasePlugin } } DISTRHO_SAFE_EXCEPTION("create unique temporary path"); + // initialize midi events used when entering bypassed state + std::memset(bypassMidiEvents, 0, sizeof(bypassMidiEvents)); + + for (uint8_t i=0; i<16; ++i) + { + bypassMidiEvents[i].size = 3; + bypassMidiEvents[i].data[0] = 0xB0 + i; + bypassMidiEvents[i].data[1] = 0x7B; + } + const float sampleRate = getSampleRate(); rack::settings::sampleRate = sampleRate; @@ -564,7 +611,7 @@ class CardinalPlugin : public CardinalBasePlugin uint32_t getVersion() const override { - return d_version(0, 22, 2); + return d_version(0, 22, 4); } int64_t getUniqueId() const override @@ -721,6 +768,63 @@ class CardinalPlugin : public CardinalBasePlugin 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; + parameter.ranges.def = 3.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; + 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; + break; + case kWindowParameterInvertZoom: + parameter.name = "Invert zoom"; + parameter.symbol = "invertZoom"; + parameter.hints = kParameterIsAutomatable|kParameterIsInteger|kParameterIsBoolean; + parameter.ranges.def = 0.0f; + parameter.ranges.min = 0.0f; + parameter.ranges.max = 1.0f; + break; } #endif } @@ -745,6 +849,11 @@ class CardinalPlugin : public CardinalBasePlugin state.label = "Comment"; break; case 3: + state.hints = kStateIsOnlyForUI; + state.key = "moduleInfos"; + state.label = "moduleInfos"; + break; + case 4: state.hints = kStateIsOnlyForUI; state.key = "windowSize"; state.label = "Window size"; @@ -763,7 +872,7 @@ class CardinalPlugin : public CardinalBasePlugin // bypass if (index == kModuleParameters) - return 0.0f; + return context->bypassed ? 1.0f : 0.0f; #ifndef HEADLESS // window related parameters @@ -787,7 +896,10 @@ class CardinalPlugin : public CardinalBasePlugin // bypass if (index == kModuleParameters) + { + context->bypassed = value > 0.5f; return; + } #ifndef HEADLESS // window related parameters @@ -804,14 +916,57 @@ 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 (std::strcmp(key, "windowSize") == 0) - return fWindowSize; + return fState.windowSize; #endif if (std::strcmp(key, "comment") == 0) - return fStateComment; + return fState.comment; if (std::strcmp(key, "screenshot") == 0) - return fStateScreenshot; + return fState.screenshot; if (std::strcmp(key, "patch") != 0) return String(); @@ -839,22 +994,56 @@ class CardinalPlugin : public CardinalBasePlugin void setState(const char* const key, const char* const value) override { #ifndef HEADLESS + if (std::strcmp(key, "moduleInfos") == 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) + { + 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; + } + } + + json_decref(rootJ); + return; + } if (std::strcmp(key, "windowSize") == 0) { - fWindowSize = value; + fState.windowSize = value; return; } #endif if (std::strcmp(key, "comment") == 0) { - fStateComment = value; + fState.comment = value; return; } if (std::strcmp(key, "screenshot") == 0) { - fStateScreenshot = value; + fState.screenshot = value; #if defined(HAVE_LIBLO) && !defined(HEADLESS) patchUtils::sendScreenshotToRemote(value); #endif @@ -914,6 +1103,8 @@ class CardinalPlugin : public CardinalBasePlugin { rack::contextSet(context); + const bool bypassed = context->bypassed; + { const TimePosition& timePos(getTimePosition()); @@ -967,10 +1158,29 @@ class CardinalPlugin : public CardinalBasePlugin for (int i=0; imidiEvents = midiEvents; - context->midiEventCount = midiEventCount; + if (bypassed) + { + if (fWasBypassed != bypassed) + { + context->midiEvents = bypassMidiEvents; + context->midiEventCount = 16; + } + else + { + context->midiEvents = nullptr; + context->midiEventCount = 0; + } + } + else + { + context->midiEvents = midiEvents; + context->midiEventCount = midiEventCount; + } + ++context->processCounter; context->engine->stepBlock(frames); + + fWasBypassed = bypassed; } void bufferSizeChanged(const uint32_t newBufferSize) override diff --git a/src/CardinalUI.cpp b/src/CardinalUI.cpp index 4ba028d8..c7875559 100644 --- a/src/CardinalUI.cpp +++ b/src/CardinalUI.cpp @@ -304,9 +304,7 @@ class CardinalUI : public CardinalBaseUI, // 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 favoriteButton = *std::next(headerLayout->children.begin(), 3); rack::widget::Widget* const libraryButton = headerLayout->children.back(); - favoriteButton->hide(); libraryButton->hide(); // Report to user if something is wrong with the installation @@ -325,7 +323,15 @@ class CardinalUI : public CardinalBaseUI, } if (! errorMessage.empty()) - asyncDialog::create(errorMessage.c_str()); + { + static bool shown = false; + + if (! shown) + { + shown = true; + asyncDialog::create(errorMessage.c_str()); + } + } context->window->step(); @@ -382,13 +388,11 @@ class CardinalUI : public CardinalBaseUI, filebrowserhandle = nullptr; } - #ifndef DISTRHO_OS_MAC if (windowParameters.rateLimit != 0 && ++rateLimitStep % (windowParameters.rateLimit * 2)) return; rateLimitStep = 0; repaint(); - #endif } void WindowParametersChanged(const WindowParameterList param, float value) override @@ -447,6 +451,16 @@ class CardinalUI : public CardinalBaseUI, 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; default: return; } @@ -512,6 +526,37 @@ class CardinalUI : public CardinalBaseUI, 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; default: return; } @@ -519,7 +564,7 @@ class CardinalUI : public CardinalBaseUI, WindowParametersSetValues(context->window, windowParameters); } - void stateChanged(const char* key, const char* value) override + void stateChanged(const char* const key, const char* const value) override { if (std::strcmp(key, "windowSize") != 0) return; diff --git a/src/Makefile b/src/Makefile index f5c196eb..d9e5ee69 100644 --- a/src/Makefile +++ b/src/Makefile @@ -95,7 +95,7 @@ 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 +BUILD_CXX_FLAGS += -fno-finite-math-only -fno-strict-aliasing -faligned-new # use our custom function to invert some colors BUILD_CXX_FLAGS += -DnsvgParseFromFile=nsvgParseFromFileCardinal @@ -115,6 +115,7 @@ RACK_FILES += custom/network.cpp RACK_FILES += custom/osdialog.cpp RACK_FILES += override/blendish.c 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 @@ -144,6 +145,7 @@ IGNORED_FILES += Rack/src/app/MenuBar.cpp IGNORED_FILES += Rack/src/app/MidiDisplay.cpp IGNORED_FILES += Rack/src/app/Scene.cpp IGNORED_FILES += Rack/src/app/TipWindow.cpp +IGNORED_FILES += Rack/src/dsp/minblep.cpp IGNORED_FILES += Rack/src/engine/Engine.cpp IGNORED_FILES += Rack/src/plugin/Model.cpp IGNORED_FILES += Rack/src/window/Window.cpp @@ -171,21 +173,43 @@ endif TARGET = rack.a +ifneq ($(MACOS),true) +CARDINAL_FX_ARGS = VST2_FILENAME=Cardinal.vst/CardinalFX$(LIB_EXT) +CARDINAL_SYNTH_ARGS = VST2_FILENAME=Cardinal.vst/CardinalSynth$(LIB_EXT) +endif + all: $(TARGET) ifeq ($(MOD_BUILD),true) $(MAKE) -C CardinalFX lv2 else $(MAKE) -C Cardinal - $(MAKE) -C CardinalFX - $(MAKE) -C CardinalSynth + $(MAKE) -C CardinalFX $(CARDINAL_FX_ARGS) + $(MAKE) -C CardinalSynth $(CARDINAL_SYNTH_ARGS) endif +jack: $(TARGET) + $(MAKE) jack -C Cardinal + +lv2: $(TARGET) + $(MAKE) lv2 -C Cardinal + $(MAKE) lv2 -C CardinalFX $(CARDINAL_FX_ARGS) + $(MAKE) lv2 -C CardinalSynth $(CARDINAL_SYNTH_ARGS) + +vst2: $(TARGET) + $(MAKE) vst2 -C CardinalFX $(CARDINAL_FX_ARGS) + $(MAKE) vst2 -C CardinalSynth $(CARDINAL_SYNTH_ARGS) + +vst3: $(TARGET) + $(MAKE) vst3 -C Cardinal + $(MAKE) vst3 -C CardinalFX $(CARDINAL_FX_ARGS) + $(MAKE) vst3 -C CardinalSynth $(CARDINAL_SYNTH_ARGS) + clean: rm -f $(TARGET) rm -rf $(BUILD_DIR) $(MAKE) clean -C Cardinal - $(MAKE) clean -C CardinalFX - $(MAKE) clean -C CardinalSynth + $(MAKE) clean -C CardinalFX $(CARDINAL_FX_ARGS) + $(MAKE) clean -C CardinalSynth $(CARDINAL_SYNTH_ARGS) # -------------------------------------------------------------- # Build commands diff --git a/src/Makefile.cardinal.mk b/src/Makefile.cardinal.mk index fe4022fa..45661a2a 100644 --- a/src/Makefile.cardinal.mk +++ b/src/Makefile.cardinal.mk @@ -85,6 +85,10 @@ FILES_UI = CardinalUI.cpp FILES_UI += Window.cpp endif +ifeq ($(WINDOWS),true) +FILES_UI += distrho.rc +endif + # -------------------------------------------------------------- # Extra libraries to link against @@ -170,7 +174,7 @@ 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 +BUILD_CXX_FLAGS += -fno-finite-math-only -fno-strict-aliasing -faligned-new # Rack code is not tested for this flag, unset it BUILD_CXX_FLAGS += -U_GLIBCXX_ASSERTIONS -Wp,-U_GLIBCXX_ASSERTIONS @@ -206,7 +210,7 @@ ifeq ($(MACOS),true) LINK_FLAGS += -framework IOKit else ifeq ($(WINDOWS),true) # needed by VCVRack -EXTRA_LIBS += -ldbghelp -lshlwapi +EXTRA_LIBS += -ldbghelp -lshlwapi -Wl,--stack,0x100000 # needed by JW-Modules EXTRA_LIBS += -lws2_32 -lwinmm endif @@ -235,6 +239,7 @@ endif # -------------------------------------------------------------- # fallback path to resource files +ifneq ($(CIBUILD),true) ifneq ($(SYSDEPS),true) ifeq ($(EXE_WRAPPER),wine) @@ -245,6 +250,7 @@ endif BUILD_CXX_FLAGS += -DCARDINAL_PLUGIN_SOURCE_DIR='"$(SOURCE_DIR)"' +endif endif # -------------------------------------------------------------- @@ -256,13 +262,17 @@ BUILD_CXX_FLAGS += -DCARDINAL_PLUGIN_PREFIX='"$(PREFIX)"' # Enable all possible plugin types and setup resources ifeq ($(CARDINAL_VARIANT),main) +ifneq ($(STATIC_BUILD),true) all: jack lv2 vst3 else -all: lv2 vst2 vst3 +all: lv2 vst3 +endif # STATIC_BUILD +else +all: lv2 vst2 vst3 static endif CORE_RESOURCES = $(subst ../Rack/res/,,$(wildcard ../Rack/res/ComponentLibrary/*.svg ../Rack/res/fonts/*.ttf)) -CORE_RESOURCES += template.vcv +CORE_RESOURCES += $(subst ../,,$(wildcard ../template*.vcv)) LV2_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).lv2/resources/%) VST3_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst3/Contents/Resources/%) @@ -284,7 +294,7 @@ ifneq ($(CARDINAL_VARIANT),main) ifeq ($(MACOS),true) VST2_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst/Contents/Resources/%) else -VST2_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst/resources/%) +VST2_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/Cardinal.vst/resources/%) endif endif @@ -293,8 +303,28 @@ vst2: $(VST2_RESOURCES) vst3: $(VST3_RESOURCES) # -------------------------------------------------------------- +# Extra rules for Windows icon + +ifeq ($(WINDOWS),true) +JACK_LIBS += -Wl,-subsystem,windows + +$(BUILD_DIR)/distrho.rc.o: ../../utils/distrho.rc ../../utils/distrho.ico + -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" + @echo "Compiling distrho.rc" + $(SILENT)$(WINDRES) $< -O coff -o $@ +endif + +# -------------------------------------------------------------- + +$(TARGET_DIR)/%/template.vcv: ../template.vcv + -@mkdir -p "$(shell dirname $@)" + $(SILENT)ln -sf $(abspath $<) $@ + +$(TARGET_DIR)/%/template-fx.vcv: ../template-fx.vcv + -@mkdir -p "$(shell dirname $@)" + $(SILENT)ln -sf $(abspath $<) $@ -$(TARGET_DIR)/$(NAME).%/template.vcv: ../template.vcv +$(TARGET_DIR)/%/template-synth.vcv: ../template-synth.vcv -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ @@ -315,7 +345,7 @@ $(TARGET_DIR)/$(NAME).lv2/modgui/documentation.pdf: ../../docs/MODDEVICES.md $(T (cd ../../docs/ && pandoc MODDEVICES.md -f markdown+implicit_figures -o $(abspath $@)) endif -$(TARGET_DIR)/$(NAME).vst/resources/%: ../Rack/res/% +$(TARGET_DIR)/Cardinal.vst/resources/%: ../Rack/res/% -@mkdir -p "$(shell dirname $@)" $(SILENT)ln -sf $(abspath $<) $@ diff --git a/src/PluginContext.hpp b/src/PluginContext.hpp index da29fa41..0aa9edc9 100644 --- a/src/PluginContext.hpp +++ b/src/PluginContext.hpp @@ -48,11 +48,11 @@ enum CardinalVariant { // ----------------------------------------------------------------------------------------------------------- struct CardinalPluginContext : rack::Context { - uint32_t bufferSize; + uint32_t bufferSize, processCounter; double sampleRate; float parameters[kModuleParameters]; CardinalVariant variant; - bool playing, reset, bbtValid; + bool bypassed, playing, reset, bbtValid; int32_t bar, beat, beatsPerBar, beatType; uint64_t frame; double barStartTick, beatsPerMinute; @@ -69,6 +69,7 @@ struct CardinalPluginContext : rack::Context { CardinalPluginContext(Plugin* const p) : bufferSize(p->getBufferSize()), + processCounter(0), sampleRate(p->getSampleRate()), #if CARDINAL_VARIANT_MAIN variant(kCardinalVariantMain), @@ -79,6 +80,7 @@ struct CardinalPluginContext : rack::Context { #else #error cardinal variant not set #endif + bypassed(false), playing(false), reset(false), bbtValid(false), diff --git a/src/Rack b/src/Rack index 0d003b96..30665d62 160000 --- a/src/Rack +++ b/src/Rack @@ -1 +1 @@ -Subproject commit 0d003b96476af45102117c2bb958aeb59eb523cf +Subproject commit 30665d62801c2ced7260a37a2d0214edfe6528a9 diff --git a/src/WindowParameters.hpp b/src/WindowParameters.hpp index b41f16ae..58bd83ee 100644 --- a/src/WindowParameters.hpp +++ b/src/WindowParameters.hpp @@ -44,6 +44,9 @@ enum WindowParameterList { kWindowParameterWheelSensitivity, kWindowParameterLockModulePositions, kWindowParameterUpdateRateLimit, + kWindowParameterBrowserSort, + kWindowParameterBrowserZoom, + kWindowParameterInvertZoom, kWindowParameterCount, }; @@ -53,10 +56,13 @@ struct WindowParameters { float rackBrightness = 1.0f; float haloBrightness = 0.25f; float knobScrollSensitivity = 0.001f; + float browserZoom = -1.0f; int knobMode = 0; + int browserSort = 3; bool tooltips = true; bool knobScroll = false; bool lockModules = false; + bool invertZoom = false; // cardinal specific int rateLimit = 0; }; diff --git a/src/custom/RemoteWindow.cpp b/src/custom/RemoteWindow.cpp index e73c41b5..29a3cff4 100644 --- a/src/custom/RemoteWindow.cpp +++ b/src/custom/RemoteWindow.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 @@ -51,16 +51,10 @@ static const math::Vec minWindowSize = math::Vec(1228, 666); void Font::loadFile(const std::string& filename, NVGcontext* vg) { - this->vg = vg; - handle = nvgCreateFont(vg, filename.c_str(), filename.c_str()); - if (handle < 0) - throw Exception("Failed to load font %s", filename.c_str()); - INFO("Loaded font %s", filename.c_str()); } Font::~Font() { - // There is no NanoVG deleteFont() function yet, so do nothing } @@ -70,18 +64,10 @@ std::shared_ptr Font::load(const std::string& filename) { void Image::loadFile(const std::string& filename, NVGcontext* vg) { - this->vg = vg; - handle = nvgCreateImage(vg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); - if (handle <= 0) - throw Exception("Failed to load image %s", filename.c_str()); - INFO("Loaded image %s", filename.c_str()); } Image::~Image() { - // TODO What if handle is invalid? - if (handle >= 0) - nvgDeleteImage(vg, handle); } @@ -90,115 +76,39 @@ std::shared_ptr Image::load(const std::string& filename) { } -struct WindowParams { - float rackBrightness = 1.0f; -}; - -struct Window::Internal -{ - Context* context = nullptr; - Window* self = nullptr; - - math::Vec size = minWindowSize; - std::string lastWindowTitle; - - int mods = 0; - int frame = 0; - int frameSwapInterval = 1; - double monitorRefreshRate = 60.0; // FIXME - double frameTime = 0.0; - double lastFrameDuration = 0.0; - - std::map> fontCache; - std::map> imageCache; - - bool fbDirtyOnSubpixelChange = true; - int fbCount = 0; -}; - Window::Window() { - internal = new Internal; - internal->context = APP; - internal->self = this; + windowRatio = minWindowSize.x / minWindowSize.y; + widget::Widget::ContextCreateEvent e; + APP->scene->onContextCreate(e); } -Window::~Window() { - // internal->stopThread(5000); +Window::~Window() { if (APP->scene) { widget::Widget::ContextDestroyEvent e; APP->scene->onContextDestroy(e); } - - // Fonts and Images in the cache must be deleted before the NanoVG context is deleted - internal->fontCache.clear(); - internal->imageCache.clear(); - - delete internal; } math::Vec Window::getSize() { - return internal->size; + return minWindowSize; } -void Window::setSize(math::Vec size) { - internal->size = size.max(minWindowSize); +void Window::setSize(math::Vec) { } void Window::run() { - internal->frame = 0; } void Window::step() { - 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); - - // Make event handlers and step() have a clean NanoVG context - nvgReset(vg); - - if (uiFont != nullptr) - bndSetFont(uiFont->handle); - - // Get framebuffer/window ratio - windowRatio = internal->size.x / internal->size.y; - - if (APP->scene) { - // Resize scene - APP->scene->box.size = internal->size; - - // Step scene - APP->scene->step(); - - // Update and render - nvgBeginFrame(vg, internal->size.x, internal->size.y, pixelRatio); - nvgScale(vg, pixelRatio, pixelRatio); - - // Draw scene - widget::Widget::DrawArgs args; - args.vg = vg; - args.clipBox = APP->scene->box.zeroPos(); - APP->scene->draw(args); - - glViewport(0, 0, internal->size.x, internal->size.y); - glClearColor(0.0, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - nvgEndFrame(vg); - } - - internal->frame++; } void Window::activateContext() { - // glfwMakeContextCurrent(win); } @@ -228,7 +138,7 @@ bool Window::isCursorLocked() { int Window::getMods() { - return internal->mods; + return 0; } @@ -242,73 +152,44 @@ bool Window::isFullScreen() { double Window::getMonitorRefreshRate() { - return internal->monitorRefreshRate; + return 60; } double Window::getFrameTime() { - return internal->frameTime; + return 0; } double Window::getLastFrameDuration() { - return internal->lastFrameDuration; + return 0.0; } double Window::getFrameDurationRemaining() { - double frameDurationDesired = internal->frameSwapInterval / internal->monitorRefreshRate; - return frameDurationDesired - (system::getTime() - internal->frameTime); + return 0.0; } std::shared_ptr Window::loadFont(const std::string& filename) { - const auto& pair = internal->fontCache.find(filename); - if (pair != internal->fontCache.end()) - return pair->second; - - // Load font - std::shared_ptr font; - try { - font = std::make_shared(); - font->loadFile(filename, vg); - } - catch (Exception& e) { - WARN("%s", e.what()); - font = NULL; - } - internal->fontCache[filename] = font; - return font; + return std::make_shared(); } std::shared_ptr Window::loadImage(const std::string& filename) { - const auto& pair = internal->imageCache.find(filename); - if (pair != internal->imageCache.end()) - return pair->second; - - // Load image - std::shared_ptr image; - try { - image = std::make_shared(); - image->loadFile(filename, vg); - } - catch (Exception& e) { - WARN("%s", e.what()); - image = NULL; - } - internal->imageCache[filename] = image; - return image; + return std::make_shared(); } bool& Window::fbDirtyOnSubpixelChange() { - return internal->fbDirtyOnSubpixelChange; + static bool _fbDirtyOnSubpixelChange; + return _fbDirtyOnSubpixelChange; } int& Window::fbCount() { - return internal->fbCount; + static int _fbCount; + return _fbCount; } diff --git a/src/custom/dep.cpp b/src/custom/dep.cpp index 8154f7eb..6e26b1f8 100644 --- a/src/custom/dep.cpp +++ b/src/custom/dep.cpp @@ -70,6 +70,8 @@ static const struct { { "/Algoritmarte/res/Planetz.svg", {}, -1 }, { "/Algoritmarte/res/Zefiro.svg", {}, -1 }, // Custom, runtime dark mode used with permission + { "/ArableInstruments/res/Joni.svg", {}, -1 }, + // Custom, runtime dark mode used with permission { "/AudibleInstruments/res/Blinds.svg", {}, -1 }, { "/AudibleInstruments/res/Braids.svg", {}, -1 }, { "/AudibleInstruments/res/Branches.svg", {}, -1 }, @@ -138,6 +140,7 @@ static const struct { { "/Bidoo/res/VOID.svg", {}, -1 }, { "/Bidoo/res/ZINC.svg", {}, -1 }, { "/Bidoo/res/ZOUMAI.svg", {}, -1 }, + { "/Bidoo/res/ZOUMAIExpander.svg", {}, -1 }, // BSD-3-Clause { "/cf/res/ALGEBRA.svg", {}, -1 }, { "/cf/res/BUFFER.svg", {}, -1 }, @@ -279,10 +282,32 @@ static const struct { { "/nonlinearcircuits/res/NLC - SEGUE.svg", {}, -1 }, { "/nonlinearcircuits/res/squid-axon-papernoise-panel2.svg", {}, -1 }, { "/nonlinearcircuits/res/NLC - STATUES.svg", {}, -1 }, + // Custom, runtime dark mode used with permission + { "/ParableInstruments/res/Neil.svg", {}, -1 }, // GPL-3.0-or-later { "/PathSet/res/AstroVibe.svg", {}, -1 }, { "/PathSet/res/IceTray.svg", {}, -1 }, { "/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 }, }; static inline bool invertPaint(NSVGshape* const shape, NSVGpaint& paint, const char* const svgFileToInvert = nullptr) @@ -311,10 +336,25 @@ static inline bool invertPaint(NSVGshape* const shape, NSVGpaint& paint, const c return false; // Special case for Bidoo red color - if (paint.color == 0xff001fcd && svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/Bidoo/", 7) == 0) + if (svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/Bidoo/", 7) == 0) { - paint.color = 0xcf8b94c4; - return true; + if (paint.color == 0xff001fcd) + { + paint.color = 0xcf8b94c4; + return true; + } + if (paint.color == 0xff000000 && shape->stroke.type == NSVG_PAINT_COLOR) + { + switch (shape->stroke.color) + { + case 0xff777777: + case 0xff7c7c7c: + case 0xff828282: + case 0xffb1b1b1: + case 0xffb2b2b2: + return false; + } + } } // Special case for JW-Modules colors @@ -458,6 +498,24 @@ static inline bool invertPaint(NSVGshape* const shape, NSVGpaint& paint, const c } } + // Special case for voxglitch colors + if (svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/voxglitch/", 11) == 0) + { + switch (paint.color) + { + // wavbank blue + case 0xffc5ae8a: + // various black + case 0xff121212: + case 0xff2a2828: + return false; + // satanonaut + case 0xff595959: + paint.color = 0x7f3219ac; + return true; + } + } + switch (paint.color) { // scopes or other special things (do nothing) diff --git a/src/override/MenuBar.cpp b/src/override/MenuBar.cpp index d9e179e6..ae98ddfe 100644 --- a/src/override/MenuBar.cpp +++ b/src/override/MenuBar.cpp @@ -479,7 +479,8 @@ struct ViewButton : MenuButton { menu->addChild(createBoolPtrMenuItem("Lock module positions", "", &settings::lockModules)); -#ifndef DISTRHO_OS_MAC + menu->addChild(createBoolPtrMenuItem("Invert zoom", "", &settings::invertZoom)); + menu->addChild(new ui::MenuSeparator); static const std::vector rateLimitLabels = { @@ -496,7 +497,6 @@ struct ViewButton : MenuButton { )); } })); -#endif } }; @@ -534,7 +534,7 @@ struct HelpButton : MenuButton { menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); menu->addChild(createMenuItem("Rack User manual", "F1", [=]() { - system::openBrowser("https://vcvrack.com/manual/"); + system::openBrowser("https://vcvrack.com/manual"); })); menu->addChild(createMenuItem("Cardinal Project page", "", [=]() { diff --git a/src/override/Model.cpp b/src/override/Model.cpp index e548454a..7ddafb02 100644 --- a/src/override/Model.cpp +++ b/src/override/Model.cpp @@ -117,7 +117,7 @@ std::string Model::getManualUrl() { } -void Model::appendContextMenu(ui::Menu* menu, bool) { +void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) { // plugin menu->addChild(createMenuItem("Plugin: " + plugin->name, "", [=]() { system::openBrowser(plugin->pluginUrl); @@ -182,15 +182,28 @@ void Model::appendContextMenu(ui::Menu* menu, bool) { system::openBrowser(plugin->changelogUrl); })); } + + // Favorite + std::string favoriteRightText = inBrowser ? (RACK_MOD_CTRL_NAME "+click") : ""; + if (isFavorite()) + favoriteRightText += " " CHECKMARK_STRING; + menu->addChild(createMenuItem("Favorite", favoriteRightText, + [=]() { + setFavorite(!isFavorite()); + } + )); } bool Model::isFavorite() { - return false; + const settings::ModuleInfo* mi = settings::getModuleInfo(plugin->slug, slug); + return mi && mi->favorite; } -void Model::setFavorite(bool) { +void Model::setFavorite(bool favorite) { + settings::ModuleInfo& mi = settings::moduleInfos[plugin->slug][slug]; + mi.favorite = favorite; } diff --git a/src/override/Scene.cpp b/src/override/Scene.cpp index ea6b108c..03c4354e 100644 --- a/src/override/Scene.cpp +++ b/src/override/Scene.cpp @@ -46,6 +46,10 @@ # undef DEBUG #endif +#ifdef STATIC_BUILD +# undef HAVE_LIBLO +#endif + #ifdef HAVE_LIBLO # include #endif @@ -123,7 +127,7 @@ struct ResizeHandle : widget::OpaqueWidget { struct Scene::Internal { - ResizeHandle* resizeHandle; + ResizeHandle* resizeHandle = nullptr; bool heldArrowKeys[4] = {}; @@ -169,6 +173,9 @@ Scene::Scene() { browser->hide(); addChild(browser); + if (isStandalone()) + return; + internal->resizeHandle = new ResizeHandle; internal->resizeHandle->box.size = math::Vec(16, 16); addChild(internal->resizeHandle); @@ -196,7 +203,8 @@ void Scene::step() { rackScroll->box.pos.y = menuBar->box.size.y; } - internal->resizeHandle->box.pos = box.size.minus(internal->resizeHandle->box.size); + if (internal->resizeHandle != nullptr) + internal->resizeHandle->box.pos = box.size.minus(internal->resizeHandle->box.size); // Resize owned descendants menuBar->box.size.x = box.size.x; diff --git a/src/override/Window.cpp b/src/override/Window.cpp index 1f11ca03..ff8f969d 100644 --- a/src/override/Window.cpp +++ b/src/override/Window.cpp @@ -718,6 +718,13 @@ void WindowParametersSave(rack::window::Window* const window) window->internal->callback->WindowParametersChanged(kWindowParameterWheelSensitivity, rack::settings::knobScrollSensitivity); } + if (d_isNotEqual(window->internal->params.browserZoom, rack::settings::browserZoom)) + { + window->internal->params.browserZoom = rack::settings::browserZoom; + if (window->internal->callback != nullptr) + window->internal->callback->WindowParametersChanged(kWindowParameterBrowserZoom, + rack::settings::browserZoom); + } if (window->internal->params.knobMode != rack::settings::knobMode) { window->internal->params.knobMode = rack::settings::knobMode; @@ -725,6 +732,13 @@ void WindowParametersSave(rack::window::Window* const window) window->internal->callback->WindowParametersChanged(kWindowParameterKnobMode, rack::settings::knobMode); } + if (window->internal->params.browserSort != rack::settings::browserSort) + { + window->internal->params.browserSort = rack::settings::browserSort; + if (window->internal->callback != nullptr) + window->internal->callback->WindowParametersChanged(kWindowParameterBrowserSort, + rack::settings::browserSort); + } if (window->internal->params.tooltips != rack::settings::tooltips) { window->internal->params.tooltips = rack::settings::tooltips; @@ -746,6 +760,13 @@ void WindowParametersSave(rack::window::Window* const window) window->internal->callback->WindowParametersChanged(kWindowParameterLockModulePositions, rack::settings::lockModules); } + if (window->internal->params.invertZoom != rack::settings::invertZoom) + { + window->internal->params.invertZoom = rack::settings::invertZoom; + if (window->internal->callback != nullptr) + window->internal->callback->WindowParametersChanged(kWindowParameterInvertZoom, + rack::settings::invertZoom); + } if (window->internal->params.rateLimit != rack::settings::rateLimit) { window->internal->params.rateLimit = rack::settings::rateLimit; @@ -762,10 +783,13 @@ void WindowParametersRestore(rack::window::Window* const window) rack::settings::rackBrightness = window->internal->params.rackBrightness; rack::settings::haloBrightness = window->internal->params.haloBrightness; rack::settings::knobScrollSensitivity = window->internal->params.knobScrollSensitivity; + rack::settings::browserZoom = window->internal->params.browserZoom; rack::settings::knobMode = static_cast(window->internal->params.knobMode); + rack::settings::browserSort = static_cast(window->internal->params.browserSort); rack::settings::tooltips = window->internal->params.tooltips; rack::settings::knobScroll = window->internal->params.knobScroll; rack::settings::lockModules = window->internal->params.lockModules; + rack::settings::invertZoom = window->internal->params.invertZoom; rack::settings::rateLimit = window->internal->params.rateLimit; } diff --git a/src/override/common.cpp b/src/override/common.cpp index 941dc6a2..c1c9e709 100644 --- a/src/override/common.cpp +++ b/src/override/common.cpp @@ -50,10 +50,10 @@ 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.0"; +const std::string APP_VERSION = "2.1"; #if defined ARCH_WIN const std::string APP_OS = "win"; -#elif ARCH_MAC +#elif defined ARCH_MAC const std::string APP_OS = "mac"; #elif defined ARCH_LIN const std::string APP_OS = "lin"; diff --git a/src/override/diffs/Engine.cpp.diff b/src/override/diffs/Engine.cpp.diff index 93ae09b6..bd223789 100644 --- a/src/override/diffs/Engine.cpp.diff +++ b/src/override/diffs/Engine.cpp.diff @@ -1,5 +1,5 @@ ---- ../Rack/src/engine/Engine.cpp 2022-01-15 11:59:46.188414546 +0000 -+++ Engine.cpp 2022-02-09 02:13:37.829435608 +0000 +--- ../Rack/src/engine/Engine.cpp 2022-02-05 22:30:09.253393116 +0000 ++++ Engine.cpp 2022-02-10 18:51:20.077011285 +0000 @@ -1,3 +1,30 @@ +/* + * DISTRHO Cardinal Plugin diff --git a/src/override/diffs/MenuBar.cpp.diff b/src/override/diffs/MenuBar.cpp.diff index bb57f4e0..d4b9535f 100644 --- a/src/override/diffs/MenuBar.cpp.diff +++ b/src/override/diffs/MenuBar.cpp.diff @@ -1,5 +1,5 @@ ---- ../Rack/src/app/MenuBar.cpp 2022-01-15 11:59:46.188414546 +0000 -+++ MenuBar.cpp 2022-02-14 03:38:00.935519007 +0000 +--- ../Rack/src/app/MenuBar.cpp 2022-02-26 23:08:06.697192725 +0000 ++++ MenuBar.cpp 2022-04-27 17:30:16.653341980 +0100 @@ -1,8 +1,33 @@ +/* + * DISTRHO Cardinal Plugin @@ -218,35 +218,20 @@ static const std::vector knobModeLabels = { "Linear", -@@ -467,6 +478,25 @@ +@@ -467,56 +478,34 @@ menu->addChild(knobScrollSensitivitySlider); menu->addChild(createBoolPtrMenuItem("Lock module positions", "", &settings::lockModules)); -+ -+#ifndef DISTRHO_OS_MAC -+ menu->addChild(new ui::MenuSeparator); -+ -+ static const std::vector rateLimitLabels = { -+ "None", -+ "2x", -+ "4x", -+ }; -+ static const std::vector rateLimits = {0, 1, 2}; -+ menu->addChild(createSubmenuItem("Update rate limit", rateLimitLabels[settings::rateLimit], [=](ui::Menu* menu) { -+ for (int rateLimit : rateLimits) { -+ menu->addChild(createCheckMenuItem(rateLimitLabels[rateLimit], "", -+ [=]() {return settings::rateLimit == rateLimit;}, -+ [=]() {settings::rateLimit = rateLimit;} -+ )); -+ } -+ })); -+#endif - } - }; +- } +-}; +- -@@ -476,47 +506,6 @@ - //////////////////// +-//////////////////// +-// Engine +-//////////////////// ++ menu->addChild(createBoolPtrMenuItem("Invert zoom", "", &settings::invertZoom)); ++ menu->addChild(new ui::MenuSeparator); -struct SampleRateItem : ui::MenuItem { - ui::Menu* createChildMenu() override { @@ -281,14 +266,31 @@ - menu->addChild(createCheckMenuItem(text, rightText, - [=]() {return settings::sampleRate == sampleRate;}, - [=]() {settings::sampleRate = sampleRate;} -- )); -- } ++ static const std::vector rateLimitLabels = { ++ "None", ++ "2x", ++ "4x", ++ }; ++ static const std::vector rateLimits = {0, 1, 2}; ++ menu->addChild(createSubmenuItem("Update rate limit", rateLimitLabels[settings::rateLimit], [=](ui::Menu* menu) { ++ for (int rateLimit : rateLimits) { ++ menu->addChild(createCheckMenuItem(rateLimitLabels[rateLimit], "", ++ [=]() {return settings::rateLimit == rateLimit;}, ++ [=]() {settings::rateLimit = rateLimit;} + )); + } - } - return menu; -- } --}; -- -- ++ })); + } + }; + + ++//////////////////// ++// Engine ++//////////////////// ++ ++ struct EngineButton : MenuButton { void onAction(const ActionEvent& e) override { ui::Menu* menu = createMenu(); @@ -562,7 +564,7 @@ } }; -@@ -802,63 +528,23 @@ +@@ -802,65 +528,23 @@ struct HelpButton : MenuButton { @@ -584,29 +586,35 @@ - - menu->addChild(createMenuItem("User manual", "F1", [=]() { + menu->addChild(createMenuItem("Rack User manual", "F1", [=]() { - system::openBrowser("https://vcvrack.com/manual/"); + 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", "", [=]() { + system::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("")); - })); - -- if (library::isAppUpdateAvailable()) { -- menu->addChild(new ui::MenuSeparator); +- menu->addChild(createMenuItem("Changelog", "", [=]() { +- system::openBrowser("https://github.com/VCVRack/Rack/blob/v2/CHANGELOG.md"); +- })); - +- if (library::isAppUpdateAvailable()) { - menu->addChild(createMenuItem("Update " + APP_NAME, APP_VERSION + " → " + library::appVersion, [=]() { - system::openBrowser(library::appDownloadUrl); - })); -- -- menu->addChild(createMenuItem("Review changelog", "", [=]() { -- system::openBrowser(library::appChangelogUrl); -- })); - } - else if (!settings::autoCheckUpdates && !settings::devMode) { - menu->addChild(createMenuItem("Check for " + APP_NAME + " update", "", [=]() { @@ -616,10 +624,6 @@ - t.detach(); - }, false, true)); - } -- - menu->addChild(new ui::MenuSeparator); - -- menu->addChild(createMenuLabel(APP_NAME + " " + APP_EDITION_NAME + " " + APP_VERSION)); - } - - void step() override { @@ -631,7 +635,7 @@ } }; -@@ -908,7 +594,9 @@ +@@ -910,7 +594,9 @@ struct MenuBar : widget::OpaqueWidget { MeterLabel* meterLabel; @@ -642,7 +646,7 @@ const float margin = 5; box.size.y = BND_WIDGET_HEIGHT + 2 * margin; -@@ -917,7 +605,7 @@ +@@ -919,7 +605,7 @@ layout->spacing = math::Vec(0, 0); addChild(layout); @@ -651,7 +655,7 @@ fileButton->text = "File"; layout->addChild(fileButton); -@@ -933,10 +621,6 @@ +@@ -935,10 +621,6 @@ engineButton->text = "Engine"; layout->addChild(engineButton); @@ -662,7 +666,7 @@ HelpButton* helpButton = new HelpButton; helpButton->text = "Help"; layout->addChild(helpButton); -@@ -971,7 +655,11 @@ +@@ -973,7 +655,11 @@ widget::Widget* createMenuBar() { diff --git a/src/override/diffs/Model.cpp.diff b/src/override/diffs/Model.cpp.diff index 7bf764b4..50c88176 100644 --- a/src/override/diffs/Model.cpp.diff +++ b/src/override/diffs/Model.cpp.diff @@ -1,5 +1,5 @@ ---- ../Rack/src/plugin/Model.cpp 2021-10-20 03:28:14.516922788 +0100 -+++ Model.cpp 2022-01-24 00:11:36.628498885 +0000 +--- ../Rack/src/plugin/Model.cpp 2021-10-17 13:57:23.257633662 +0100 ++++ Model.cpp 2022-04-27 17:55:57.362107553 +0100 @@ -1,3 +1,30 @@ +/* + * DISTRHO Cardinal Plugin @@ -61,15 +61,6 @@ return plugin->getBrand() + " " + name; } -@@ -95,7 +117,7 @@ - } - - --void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) { -+void Model::appendContextMenu(ui::Menu* menu, bool) { - // plugin - menu->addChild(createMenuItem("Plugin: " + plugin->name, "", [=]() { - system::openBrowser(plugin->pluginUrl); @@ -132,18 +154,6 @@ menu->addChild(new ui::MenuSeparator); @@ -89,11 +80,10 @@ // manual std::string manualUrl = getManualUrl(); if (manualUrl != "") { -@@ -172,35 +182,15 @@ - system::openBrowser(plugin->changelogUrl); +@@ -173,13 +183,6 @@ })); } -- + - // plugin folder - if (plugin->path != "") { - menu->addChild(createMenuItem("Open plugin folder", "", [=]() { @@ -101,29 +91,6 @@ - })); - } - -- // Favorite -- std::string favoriteRightText = inBrowser ? (RACK_MOD_CTRL_NAME "+click") : ""; -- if (isFavorite()) -- favoriteRightText += " " CHECKMARK_STRING; -- menu->addChild(createMenuItem("Favorite", favoriteRightText, -- [=]() { -- setFavorite(!isFavorite()); -- } -- )); - } - - - bool Model::isFavorite() { -- const settings::ModuleInfo* mi = settings::getModuleInfo(plugin->slug, slug); -- return mi && mi->favorite; -+ return false; - } - - --void Model::setFavorite(bool favorite) { -- settings::ModuleInfo& mi = settings::moduleInfos[plugin->slug][slug]; -- mi.favorite = favorite; -+void Model::setFavorite(bool) { - } - - + // Favorite + std::string favoriteRightText = inBrowser ? (RACK_MOD_CTRL_NAME "+click") : ""; + if (isFavorite()) diff --git a/src/override/diffs/Scene.cpp.diff b/src/override/diffs/Scene.cpp.diff index c0ba2414..cb11e92c 100644 --- a/src/override/diffs/Scene.cpp.diff +++ b/src/override/diffs/Scene.cpp.diff @@ -1,5 +1,5 @@ ---- ../Rack/src/app/Scene.cpp 2021-12-04 09:46:43.912932319 +0000 -+++ Scene.cpp 2022-02-11 05:30:49.567801073 +0000 +--- ../Rack/src/app/Scene.cpp 2022-02-26 23:08:06.701192797 +0000 ++++ Scene.cpp 2022-04-02 03:13:14.856813800 +0100 @@ -1,3 +1,30 @@ +/* + * DISTRHO Cardinal Plugin @@ -39,7 +39,7 @@ #include #include #include -@@ -14,6 +42,18 @@ +@@ -14,6 +42,22 @@ #include #include @@ -47,6 +47,10 @@ +# undef DEBUG +#endif + ++#ifdef STATIC_BUILD ++# undef HAVE_LIBLO ++#endif ++ +#ifdef HAVE_LIBLO +# include +#endif @@ -58,7 +62,7 @@ namespace rack { namespace app { -@@ -23,16 +63,55 @@ +@@ -23,32 +67,94 @@ math::Vec size; void draw(const DrawArgs& args) override { @@ -120,12 +124,20 @@ size = APP->window->getSize(); } -@@ -46,9 +125,32 @@ - struct Scene::Internal { - ResizeHandle* resizeHandle; + void onDragMove(const DragMoveEvent& e) override { +- size = size.plus(e.mouseDelta); ++ size = size.plus(e.mouseDelta.mult(APP->window->pixelRatio)); + APP->window->setSize(size.round()); + } + }; -- double lastAutosaveTime = 0.0; + + struct Scene::Internal { +- ResizeHandle* resizeHandle; - +- double lastAutosaveTime = 0.0; ++ ResizeHandle* resizeHandle = nullptr; + bool heldArrowKeys[4] = {}; + +#ifdef HAVE_LIBLO @@ -155,14 +167,16 @@ }; -@@ -67,13 +169,8 @@ +@@ -67,13 +173,11 @@ browser->hide(); addChild(browser); - if (settings::showTipsOnLaunch) { - addChild(tipWindowCreate()); - } -- ++ if (isStandalone()) ++ return; + internal->resizeHandle = new ResizeHandle; - internal->resizeHandle->box.size = math::Vec(15, 15); - internal->resizeHandle->hide(); @@ -170,7 +184,15 @@ addChild(internal->resizeHandle); } -@@ -105,16 +202,6 @@ +@@ -99,22 +203,13 @@ + rackScroll->box.pos.y = menuBar->box.size.y; + } + +- internal->resizeHandle->box.pos = box.size.minus(internal->resizeHandle->box.size); ++ if (internal->resizeHandle != nullptr) ++ internal->resizeHandle->box.pos = box.size.minus(internal->resizeHandle->box.size); + + // Resize owned descendants menuBar->box.size.x = box.size.x; rackScroll->box.size = box.size.minus(rackScroll->box.pos); @@ -187,7 +209,7 @@ // Scroll RackScrollWidget with arrow keys math::Vec arrowDelta; if (internal->heldArrowKeys[0]) { -@@ -143,6 +230,23 @@ +@@ -143,6 +238,23 @@ rackScroll->offset += arrowDelta * arrowSpeed; } @@ -211,7 +233,7 @@ Widget::step(); } -@@ -172,7 +276,7 @@ +@@ -172,7 +284,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) { @@ -220,7 +242,7 @@ e.consume(this); } if (e.keyName == "q" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { -@@ -180,19 +284,20 @@ +@@ -180,19 +292,20 @@ e.consume(this); } if (e.keyName == "o" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { @@ -245,7 +267,7 @@ e.consume(this); } if (e.keyName == "z" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { -@@ -220,10 +325,14 @@ +@@ -220,10 +333,14 @@ APP->scene->rackScroll->setZoom(std::pow(2.f, zoom)); e.consume(this); } @@ -261,7 +283,7 @@ if (e.key == GLFW_KEY_F1 && (e.mods & RACK_MOD_MASK) == 0) { system::openBrowser("https://vcvrack.com/manual/"); e.consume(this); -@@ -232,10 +341,13 @@ +@@ -232,10 +349,13 @@ settings::cpuMeter ^= true; e.consume(this); } @@ -279,11 +301,11 @@ e.consume(this); } -@@ -326,13 +438,6 @@ +@@ -326,13 +446,6 @@ // Key commands that can be overridden by children if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { -- // Alternate key command for exiting fullscreen, since F11 doesn't work reliably on Mac due to "Show desktop" OS binding. +- // Alternative key command for exiting fullscreen, since F11 doesn't work reliably on Mac due to "Show desktop" OS binding. - if (e.key == GLFW_KEY_ESCAPE && (e.mods & RACK_MOD_MASK) == 0) { - if (APP->window->isFullScreen()) { - APP->window->setFullScreen(false); @@ -293,7 +315,7 @@ if (e.keyName == "v" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { rack->pasteClipboardAction(); e.consume(this); -@@ -351,7 +456,7 @@ +@@ -351,7 +464,7 @@ std::string extension = system::getExtension(path); if (extension == ".vcv") { @@ -302,7 +324,7 @@ e.consume(this); return; } -@@ -368,3 +473,94 @@ +@@ -368,3 +481,94 @@ } // namespace app } // namespace rack diff --git a/src/override/diffs/Window.cpp.diff b/src/override/diffs/Window.cpp.diff index 72d9b62c..0f6d5bfc 100644 --- a/src/override/diffs/Window.cpp.diff +++ b/src/override/diffs/Window.cpp.diff @@ -1,5 +1,5 @@ ---- ../Rack/src/window/Window.cpp 2022-01-01 15:50:17.777305924 +0000 -+++ Window.cpp 2022-02-13 02:07:46.554983286 +0000 +--- ../Rack/src/window/Window.cpp 2022-02-09 15:35:19.238863170 +0000 ++++ Window.cpp 2022-04-27 16:53:59.743671091 +0100 @@ -1,33 +1,83 @@ +/* + * DISTRHO Cardinal Plugin @@ -162,8 +162,12 @@ bool fbDirtyOnSubpixelChange = true; int fbCount = 0; --}; -- ++ ++ Internal() ++ : hiddenApp(false), ++ hiddenWindow(hiddenApp) { hiddenApp.idle(); } + }; + -static void windowPosCallback(GLFWwindow* win, int x, int y) { - if (glfwGetWindowAttrib(win, GLFW_MAXIMIZED)) @@ -175,11 +179,14 @@ - settings::windowPos = math::Vec(x, y); - // DEBUG("windowPosCallback %d %d", x, y); -} -+ Internal() -+ : hiddenApp(false), -+ hiddenWindow(hiddenApp) { hiddenApp.idle(); } -+}; ++#ifndef DGL_NO_SHARED_RESOURCES ++static int loadFallbackFont(NVGcontext* const vg) ++{ ++ const int font = nvgFindFont(vg, NANOVG_DEJAVU_SANS_TTF); ++ if (font >= 0) ++ return font; ++ using namespace dpf_resources; -static void windowSizeCallback(GLFWwindow* win, int width, int height) { - if (glfwGetWindowAttrib(win, GLFW_MAXIMIZED)) @@ -190,24 +197,17 @@ - return; - settings::windowSize = math::Vec(width, height); - // DEBUG("windowSizeCallback %d %d", width, height); --} -+#ifndef DGL_NO_SHARED_RESOURCES -+static int loadFallbackFont(NVGcontext* const vg) -+{ -+ const int font = nvgFindFont(vg, NANOVG_DEJAVU_SANS_TTF); -+ if (font >= 0) -+ return font; - -+ using namespace dpf_resources; - --static void windowMaximizeCallback(GLFWwindow* win, int maximized) { -- settings::windowMaximized = maximized; -- // DEBUG("windowMaximizeCallback %d", maximized); + return nvgCreateFontMem(vg, NANOVG_DEJAVU_SANS_TTF, + (uchar*)dejavusans_ttf, dejavusans_ttf_size, 0); } - - +-static void windowMaximizeCallback(GLFWwindow* win, int maximized) { +- settings::windowMaximized = maximized; +- // DEBUG("windowMaximizeCallback %d", maximized); +-} +- +- -static void mouseButtonCallback(GLFWwindow* win, int button, int action, int mods) { - contextSet((Context*) glfwGetWindowUserPointer(win)); -#if defined ARCH_MAC @@ -225,15 +225,15 @@ - APP->event->handleButton(APP->window->internal->lastMousePos, button, action, mods); -} - -+Window::Window() { -+ internal = new Internal; +- -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; @@ -435,8 +435,8 @@ +#endif } -} - - + -static void dropCallback(GLFWwindow* win, int count, const char** paths) { - contextSet((Context*) glfwGetWindowUserPointer(win)); - std::vector pathsVec; @@ -1069,7 +1069,7 @@ } internal->imageCache[filename] = image; return image; -@@ -766,28 +662,122 @@ +@@ -766,28 +662,146 @@ } @@ -1143,6 +1143,13 @@ + window->internal->callback->WindowParametersChanged(kWindowParameterWheelSensitivity, + rack::settings::knobScrollSensitivity); + } ++ if (d_isNotEqual(window->internal->params.browserZoom, rack::settings::browserZoom)) ++ { ++ window->internal->params.browserZoom = rack::settings::browserZoom; ++ if (window->internal->callback != nullptr) ++ window->internal->callback->WindowParametersChanged(kWindowParameterBrowserZoom, ++ rack::settings::browserZoom); ++ } + if (window->internal->params.knobMode != rack::settings::knobMode) + { + window->internal->params.knobMode = rack::settings::knobMode; @@ -1150,6 +1157,13 @@ + window->internal->callback->WindowParametersChanged(kWindowParameterKnobMode, + rack::settings::knobMode); + } ++ if (window->internal->params.browserSort != rack::settings::browserSort) ++ { ++ window->internal->params.browserSort = rack::settings::browserSort; ++ if (window->internal->callback != nullptr) ++ window->internal->callback->WindowParametersChanged(kWindowParameterBrowserSort, ++ rack::settings::browserSort); ++ } + if (window->internal->params.tooltips != rack::settings::tooltips) + { + window->internal->params.tooltips = rack::settings::tooltips; @@ -1171,6 +1185,13 @@ + window->internal->callback->WindowParametersChanged(kWindowParameterLockModulePositions, + rack::settings::lockModules); + } ++ if (window->internal->params.invertZoom != rack::settings::invertZoom) ++ { ++ window->internal->params.invertZoom = rack::settings::invertZoom; ++ if (window->internal->callback != nullptr) ++ window->internal->callback->WindowParametersChanged(kWindowParameterInvertZoom, ++ rack::settings::invertZoom); ++ } + if (window->internal->params.rateLimit != rack::settings::rateLimit) + { + window->internal->params.rateLimit = rack::settings::rateLimit; @@ -1187,10 +1208,13 @@ + rack::settings::rackBrightness = window->internal->params.rackBrightness; + rack::settings::haloBrightness = window->internal->params.haloBrightness; + rack::settings::knobScrollSensitivity = window->internal->params.knobScrollSensitivity; ++ rack::settings::browserZoom = window->internal->params.browserZoom; + rack::settings::knobMode = static_cast(window->internal->params.knobMode); ++ rack::settings::browserSort = static_cast(window->internal->params.browserSort); + rack::settings::tooltips = window->internal->params.tooltips; + rack::settings::knobScroll = window->internal->params.knobScroll; + rack::settings::lockModules = window->internal->params.lockModules; ++ rack::settings::invertZoom = window->internal->params.invertZoom; + rack::settings::rateLimit = window->internal->params.rateLimit; +} + diff --git a/src/override/diffs/blendish.c.diff b/src/override/diffs/blendish.c.diff index dbc4bbee..79696cdd 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 2021-12-12 16:59:23.714275191 +0000 -+++ blendish.c 2021-12-12 16:51:37.956349106 +0000 +--- ../Rack/dep/oui-blendish/blendish.c 2021-10-17 13:57:24.613620711 +0100 ++++ blendish.c 2021-12-13 09:36:22.182673256 +0000 @@ -61,7 +61,7 @@ } diff --git a/src/override/diffs/common.cpp.diff b/src/override/diffs/common.cpp.diff index 0dc78a36..ac85f16b 100644 --- a/src/override/diffs/common.cpp.diff +++ b/src/override/diffs/common.cpp.diff @@ -1,5 +1,5 @@ ---- ../Rack/src/common.cpp 2021-12-04 09:46:43.912932319 +0000 -+++ common.cpp 2022-01-24 00:11:36.628498885 +0000 +--- ../Rack/src/common.cpp 2021-11-23 19:57:23.719015894 +0000 ++++ common.cpp 2022-03-14 23:25:17.492322806 +0000 @@ -1,6 +1,38 @@ +/* + * DISTRHO Cardinal Plugin @@ -52,10 +52,11 @@ +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.0"; ++const std::string APP_VERSION = "2.1"; #if defined ARCH_WIN const std::string APP_OS = "win"; - #elif ARCH_MAC +-#elif ARCH_MAC ++#elif defined ARCH_MAC const std::string APP_OS = "mac"; #elif defined ARCH_LIN const std::string APP_OS = "lin"; diff --git a/src/override/diffs/context.cpp.diff b/src/override/diffs/context.cpp.diff index 1499c049..72729b9d 100644 --- a/src/override/diffs/context.cpp.diff +++ b/src/override/diffs/context.cpp.diff @@ -1,5 +1,5 @@ ---- ../Rack/src/context.cpp 2022-01-15 11:59:46.188414546 +0000 -+++ context.cpp 2022-01-24 00:11:36.628498885 +0000 +--- ../Rack/src/context.cpp 2022-02-05 22:30:09.253393116 +0000 ++++ context.cpp 2022-01-23 17:13:11.652514338 +0000 @@ -1,3 +1,30 @@ +/* + * DISTRHO Cardinal Plugin diff --git a/src/override/diffs/plugin.cpp.diff b/src/override/diffs/plugin.cpp.diff index 7da6c3c5..73c7cb70 100644 --- a/src/override/diffs/plugin.cpp.diff +++ b/src/override/diffs/plugin.cpp.diff @@ -1,5 +1,5 @@ ---- ../Rack/src/plugin.cpp 2022-01-15 11:59:46.188414546 +0000 -+++ plugin.cpp 2022-01-30 02:49:08.228488442 +0000 +--- ../Rack/src/plugin.cpp 2022-02-05 22:30:09.265393248 +0000 ++++ plugin.cpp 2022-01-30 00:24:49.375329910 +0000 @@ -1,308 +1,40 @@ -#include -#include diff --git a/src/override/minblep.cpp b/src/override/minblep.cpp new file mode 100644 index 00000000..6242b0df --- /dev/null +++ b/src/override/minblep.cpp @@ -0,0 +1,111 @@ +/* + * 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/minblep.cpp + * 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 +#include + + +namespace rack { +namespace dsp { + + +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 = (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); + } + + // Apply window + blackmanHarrisWindow(x, n); + + // Real cepstrum + 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); + rfft.rfft(x, fx); + // fx = log(abs(fx)) + fx[0] = std::log(std::fabs(fx[0])); + for (int i = 1; i < n; i++) { + fx[2 * i] = std::log(std::hypot(fx[2 * i], fx[2 * i + 1])); + fx[2 * i + 1] = 0.f; + } + fx[1] = std::log(std::fabs(fx[1])); + // Clamp values in case we have -inf + for (int i = 0; i < 2 * n; i++) { + fx[i] = std::fmax(-30.f, fx[i]); + } + rfft.irfft(fx, x); + rfft.scale(x); + + // Minimum-phase reconstruction + for (int i = 1; i < n / 2; i++) { + x[i] *= 2.f; + } + for (int i = (n + 1) / 2; i < n; i++) { + x[i] = 0.f; + } + rfft.rfft(x, fx); + // fx = exp(fx) + fx[0] = std::exp(fx[0]); + for (int i = 1; i < n; i++) { + float re = std::exp(fx[2 * i]); + float im = fx[2 * i + 1]; + fx[2 * i] = re * std::cos(im); + fx[2 * i + 1] = re * std::sin(im); + } + fx[1] = std::exp(fx[1]); + rfft.irfft(fx, x); + rfft.scale(x); + + // Integrate + float total = 0.f; + for (int i = 0; i < n; i++) { + total += x[i]; + x[i] = total; + } + + // Normalize + float norm = 1.f / x[n - 1]; + for (int i = 0; i < n; i++) { + x[i] *= norm; + } + + std::memcpy(output, x, n * sizeof(float)); + + // Cleanup + pffft_aligned_free(x); + pffft_aligned_free(fx); +} + + +} // namespace dsp +} // namespace rack diff --git a/src/template-fx.vcv b/src/template-fx.vcv new file mode 100644 index 00000000..ee13a7ac --- /dev/null +++ b/src/template-fx.vcv @@ -0,0 +1,161 @@ +{ + "version": "2.1", + "path": "/Shared/Personal/FOSS/GIT/DISTRHO/DISTRHO_Cardinal/src/template-fx.vcv", + "unsaved": true, + "zoom": 1.0, + "modules": [ + { + "id": 8712245256622475, + "plugin": "Cardinal", + "model": "TextEditor", + "version": "2.0", + "params": [], + "leftModuleId": 4, + "data": { + "filepath": "", + "lang": "None", + "etext": "Welcome to Cardinal!\n\nThis is the FX variant\nIt has 2 audio ports, plus MIDI\n\nAudio and MIDI is pass-through in\nthe default patch\n\n", + "width": 19 + }, + "pos": [ + 34, + 0 + ] + }, + { + "id": 1, + "plugin": "Cardinal", + "model": "HostAudio2", + "version": "2.0", + "params": [ + { + "value": 1.0, + "id": 0 + } + ], + "rightModuleId": 2, + "data": { + "dcFilter": true + }, + "pos": [ + 0, + 0 + ] + }, + { + "id": 2, + "plugin": "Cardinal", + "model": "HostMIDI", + "version": "2.0", + "params": [], + "leftModuleId": 1, + "rightModuleId": 3, + "data": { + "pwRange": 0.0, + "smooth": false, + "channels": 1, + "polyMode": 0, + "lastPitch": 8192, + "lastMod": 0, + "inputChannel": 0, + "outputChannel": 0 + }, + "pos": [ + 8, + 0 + ] + }, + { + "id": 3, + "plugin": "Cardinal", + "model": "HostTime", + "version": "2.0", + "params": [], + "leftModuleId": 2, + "rightModuleId": 4, + "pos": [ + 17, + 0 + ] + }, + { + "id": 4, + "plugin": "Cardinal", + "model": "HostParameters", + "version": "2.0", + "params": [], + "leftModuleId": 3, + "rightModuleId": 8712245256622475, + "pos": [ + 25, + 0 + ] + } + ], + "cables": [ + { + "id": 4678253779474352, + "outputModuleId": 2, + "outputId": 0, + "inputModuleId": 2, + "inputId": 0, + "color": "#ff5252" + }, + { + "id": 7683580154025470, + "outputModuleId": 2, + "outputId": 1, + "inputModuleId": 2, + "inputId": 1, + "color": "#ff9352" + }, + { + "id": 8430980435213069, + "outputModuleId": 2, + "outputId": 2, + "inputModuleId": 2, + "inputId": 2, + "color": "#ffd452" + }, + { + "id": 4583111412242866, + "outputModuleId": 2, + "outputId": 3, + "inputModuleId": 2, + "inputId": 3, + "color": "#e8ff52" + }, + { + "id": 4427623524544856, + "outputModuleId": 2, + "outputId": 4, + "inputModuleId": 2, + "inputId": 4, + "color": "#a8ff52" + }, + { + "id": 6950452937672903, + "outputModuleId": 2, + "outputId": 5, + "inputModuleId": 2, + "inputId": 5, + "color": "#67ff52" + }, + { + "id": 3491422883476882, + "outputModuleId": 1, + "outputId": 0, + "inputModuleId": 1, + "inputId": 0, + "color": "#52beff" + }, + { + "id": 4569757452962581, + "outputModuleId": 1, + "outputId": 1, + "inputModuleId": 1, + "inputId": 1, + "color": "#527dff" + } + ] +} diff --git a/src/template-synth.vcv b/src/template-synth.vcv new file mode 100644 index 00000000..a83399ca --- /dev/null +++ b/src/template-synth.vcv @@ -0,0 +1,238 @@ +{ + "version": "2.1", + "path": "/Shared/Personal/FOSS/GIT/DISTRHO/DISTRHO_Cardinal/src/template-fx.vcv", + "unsaved": true, + "zoom": 1.0, + "modules": [ + { + "id": 8712245256622475, + "plugin": "Cardinal", + "model": "TextEditor", + "version": "2.0", + "params": [], + "leftModuleId": 4, + "data": { + "filepath": "", + "lang": "None", + "etext": "Welcome to Cardinal!\n\nThis is the Synth variant\nIt has 2 audio outputs, plus MIDI\n\nA basic VCO + ADSR + VCA is\nthe default patch\n\n", + "width": 19 + }, + "pos": [ + 43, + 0 + ] + }, + { + "id": 674529428127255, + "plugin": "Bogaudio", + "model": "Bogaudio-ADSR", + "version": "2.0", + "params": [ + { + "value": 0.069131895899772644, + "id": 0 + }, + { + "value": 0.31622999906539917, + "id": 1 + }, + { + "value": 1.0, + "id": 2 + }, + { + "value": 0.31622999906539917, + "id": 3 + }, + { + "value": 0.0, + "id": 4 + } + ], + "leftModuleId": 331777374771466, + "rightModuleId": 3281475959768191, + "data": { + "invert": 1.0 + }, + "pos": [ + 12, + 0 + ] + }, + { + "id": 3281475959768191, + "plugin": "Bogaudio", + "model": "Bogaudio-VCAmp", + "version": "2.0", + "params": [ + { + "value": 0.83333331346511841, + "id": 0 + } + ], + "leftModuleId": 674529428127255, + "rightModuleId": 1, + "data": {}, + "pos": [ + 15, + 0 + ] + }, + { + "id": 331777374771466, + "plugin": "Bogaudio", + "model": "Bogaudio-LVCO", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.02500000037252903, + "id": 3 + } + ], + "leftModuleId": 2, + "rightModuleId": 674529428127255, + "data": { + "poly_input": 0, + "dc_correction": true, + "fm_mode": false, + "linear_mode": false, + "reset_on_wave_change": false + }, + "pos": [ + 9, + 0 + ] + }, + { + "id": 1, + "plugin": "Cardinal", + "model": "HostAudio2", + "version": "2.0", + "params": [ + { + "value": 1.0, + "id": 0 + } + ], + "leftModuleId": 3281475959768191, + "rightModuleId": 3, + "data": { + "dcFilter": true + }, + "pos": [ + 18, + 0 + ] + }, + { + "id": 2, + "plugin": "Cardinal", + "model": "HostMIDI", + "version": "2.0", + "params": [], + "rightModuleId": 331777374771466, + "data": { + "pwRange": 0.0, + "smooth": false, + "channels": 1, + "polyMode": 0, + "lastPitch": 8192, + "lastMod": 0, + "inputChannel": 0, + "outputChannel": 0 + }, + "pos": [ + 0, + 0 + ] + }, + { + "id": 3, + "plugin": "Cardinal", + "model": "HostTime", + "version": "2.0", + "params": [], + "leftModuleId": 1, + "rightModuleId": 4, + "pos": [ + 26, + 0 + ] + }, + { + "id": 4, + "plugin": "Cardinal", + "model": "HostParameters", + "version": "2.0", + "params": [], + "leftModuleId": 3, + "rightModuleId": 8712245256622475, + "pos": [ + 34, + 0 + ] + } + ], + "cables": [ + { + "id": 4819926075235968, + "outputModuleId": 2, + "outputId": 0, + "inputModuleId": 331777374771466, + "inputId": 0, + "color": "#ff5252" + }, + { + "id": 2420818759782995, + "outputModuleId": 331777374771466, + "outputId": 0, + "inputModuleId": 3281475959768191, + "inputId": 1, + "color": "#67ff52" + }, + { + "id": 5329555665685235, + "outputModuleId": 674529428127255, + "outputId": 0, + "inputModuleId": 3281475959768191, + "inputId": 0, + "color": "#52ffff" + }, + { + "id": 4079786865533706, + "outputModuleId": 2, + "outputId": 1, + "inputModuleId": 674529428127255, + "inputId": 0, + "color": "#ff9352" + }, + { + "id": 3101737648049587, + "outputModuleId": 3281475959768191, + "outputId": 0, + "inputModuleId": 1, + "inputId": 0, + "color": "#52beff" + }, + { + "id": 537659689081948, + "outputModuleId": 2, + "outputId": 2, + "inputModuleId": 331777374771466, + "inputId": 1, + "color": "#ffd452" + } + ] +} diff --git a/src/template.vcv b/src/template.vcv index 0ddaf290..91bf456d 100644 --- a/src/template.vcv +++ b/src/template.vcv @@ -1,24 +1,23 @@ { - "version": "2.0", + "version": "2.1", + "unsaved": true, "zoom": 1.0, "modules": [ { - "id": 1, + "id": 2799203590388841, "plugin": "Cardinal", - "model": "HostAudio2", + "model": "TextEditor", "version": "2.0", - "params": [ - { - "value": 1.0, - "id": 0 - } - ], - "rightModuleId": 2, + "params": [], + "leftModuleId": 4, "data": { - "dcFilter": true + "filepath": "", + "lang": "None", + "etext": "Welcome to Cardinal!\n\nThis is the main variant\nIt has 8 audio ports, 10 CV ports, plus MIDI\n\nThe most relevant modules for host\nintegration are in this default patch\n\nHave fun!\n\n", + "width": 23 }, "pos": [ - 0, + 42, 0 ] }, @@ -28,10 +27,20 @@ "model": "HostMIDI", "version": "2.0", "params": [], - "leftModuleId": 1, + "leftModuleId": 7249509538355161, "rightModuleId": 3, + "data": { + "pwRange": 0.0, + "smooth": false, + "channels": 1, + "polyMode": 0, + "lastPitch": 8192, + "lastMod": 0, + "inputChannel": 0, + "outputChannel": 0 + }, "pos": [ - 8, + 16, 0 ] }, @@ -44,7 +53,7 @@ "leftModuleId": 2, "rightModuleId": 4, "pos": [ - 17, + 25, 0 ] }, @@ -55,12 +64,57 @@ "version": "2.0", "params": [], "leftModuleId": 3, + "rightModuleId": 2799203590388841, "pos": [ - 25, + 33, + 0 + ] + }, + { + "id": 7249509538355161, + "plugin": "Cardinal", + "model": "HostCV", + "version": "2.0", + "params": [ + { + "value": 0.0, + "id": 0 + }, + { + "value": 0.0, + "id": 1 + }, + { + "value": 0.0, + "id": 2 + }, + { + "value": 0.0, + "id": 3 + } + ], + "leftModuleId": 3606136179759592, + "rightModuleId": 2, + "pos": [ + 8, + 0 + ] + }, + { + "id": 3606136179759592, + "plugin": "Cardinal", + "model": "HostAudio8", + "version": "2.0", + "params": [], + "rightModuleId": 7249509538355161, + "data": { + "dcFilter": false + }, + "pos": [ + 0, 0 ] } ], - "cables": [], - "masterModuleId": 1 + "cables": [] } diff --git a/utils/create-macos-installer.sh b/utils/create-macos-installer.sh new file mode 100755 index 00000000..4ab84dd1 --- /dev/null +++ b/utils/create-macos-installer.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +set -e + +if [ -d bin ]; then + cd bin +else + echo "Please run this script from the root folder" + exit +fi + +rm -rf res +rm -rf au +rm -rf lv2 +rm -rf vst2 +rm -rf vst3 + +mkdir au lv2 vst2 vst3 +mv *.component au/ +mv *.lv2 lv2/ +mv *.vst vst2/ +mv *.vst3 vst3/ +cp -RL lv2/Cardinal.lv2/resources res +rm -rf lv2/*.lv2/resources +rm -rf vst2/*.vst/Contents/Resources +rm -rf vst3/*.vst3/Contents/Resources + +pkgbuild \ + --identifier "studio.kx.distrho.cardinal.resources" \ + --install-location "/Library/Application Support/Cardinal/" \ + --root "${PWD}/res/" \ + ../dpf-cardinal-resources.pkg + +pkgbuild \ + --identifier "studio.kx.distrho.plugins.cardinal.components" \ + --install-location "/Library/Audio/Plug-Ins/Components/" \ + --root "${PWD}/au/" \ + ../dpf-cardinal-components.pkg + +pkgbuild \ + --identifier "studio.kx.distrho.plugins.cardinal.lv2bundles" \ + --install-location "/Library/Audio/Plug-Ins/LV2/" \ + --root "${PWD}/lv2/" \ + ../dpf-cardinal-lv2bundles.pkg + +pkgbuild \ + --identifier "studio.kx.distrho.plugins.cardinal.vst2bundles" \ + --install-location "/Library/Audio/Plug-Ins/VST/" \ + --root "${PWD}/vst2/" \ + ../dpf-cardinal-vst2bundles.pkg + +pkgbuild \ + --identifier "studio.kx.distrho.plugins.cardinal.vst3bundles" \ + --install-location "/Library/Audio/Plug-Ins/VST3/" \ + --root "${PWD}/vst3/" \ + ../dpf-cardinal-vst3bundles.pkg + +cd .. + +sed -e "s|@builddir@|${PWD}/build|" utils/macOS/package.xml.in > build/package.xml + +productbuild \ + --distribution build/package.xml \ + --identifier "studio.kx.distrho.cardinal" \ + --package-path "${PWD}" \ + --version 0 \ + Cardinal-macOS.pkg diff --git a/utils/create-windows-installer.sh b/utils/create-windows-installer.sh new file mode 100755 index 00000000..a8b9c587 --- /dev/null +++ b/utils/create-windows-installer.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +set -e + +if [ ! -d bin ]; then + echo "Please run this script from the root folder" + exit +fi + +# args +bit=${1} +bit=${bit:=64} + +# setup innosetup +dlfile="${PWD}/bin/innosetup-6.0.5.exe" +innodir="${PWD}/build/innosetup-6.0.5" +iscc="${innodir}/drive_c/InnoSetup/ISCC.exe" + +# download it +if [ ! -f "${dlfile}" ]; then + # FIXME proper dl version + curl -L https://jrsoftware.org/download.php/is.exe?site=2 -o "${dlfile}" +fi + +# initialize wine +if [ ! -d "${innodir}"/drive_c ]; then + env WINEPREFIX="${innodir}" wineboot -u +fi + +# install innosetup in custom wineprefix +if [ ! -f "${innodir}"/drive_c/InnoSetup/ISCC.exe ]; then + env WINEPREFIX="${innodir}" wine "${dlfile}" /allusers /dir=C:\\InnoSetup /nocancel /norestart /verysilent +fi + +# generate resources +echo -n "" > utils/inno/resources.iss +IFS=' +' +for f in $(find -L bin/Cardinal.lv2/resources/ -type f); do + d=$(dirname $(echo ${f} | sed "s|bin/Cardinal.lv2/resources/||")) + echo "Source: \"..\\..\\$(echo ${f} | tr '/' '\\')\"; DestDir: \"{commoncf${bit}}\\Cardinal\\$(echo ${d} | tr '/' '\\')\"; Components: resources; Flags: ignoreversion;" >> utils/inno/resources.iss +done + +# generate version +echo "#define VERSION \"$(make version)\"" > utils/inno/version.iss + +# create the installer file +pushd "utils/inno" +env WINEPREFIX="${innodir}" wine "${iscc}" "win${bit}.iss" +popd + +# move installer file where CI expects it to be +mv utils/inno/*.exe . diff --git a/utils/distrho.ico b/utils/distrho.ico new file mode 100644 index 00000000..85d2fd7b Binary files /dev/null and b/utils/distrho.ico differ diff --git a/utils/distrho.rc b/utils/distrho.rc new file mode 100644 index 00000000..e75698d7 --- /dev/null +++ b/utils/distrho.rc @@ -0,0 +1 @@ +401 ICON "distrho.ico" diff --git a/utils/inno/win32.iss b/utils/inno/win32.iss new file mode 100644 index 00000000..402ca24b --- /dev/null +++ b/utils/inno/win32.iss @@ -0,0 +1,61 @@ +#include "version.iss" + +[Setup] +AppName=Cardinal +AppPublisher=DISTRHO +AppPublisherURL=https://github.com/DISTRHO/Cardinal/ +AppSupportURL=https://github.com/DISTRHO/Cardinal/issues/ +AppUpdatesURL=https://github.com/DISTRHO/Cardinal/releases/ +AppVersion={#VERSION} +DefaultDirName={commonpf32}\Cardinal +DisableDirPage=yes +DisableWelcomePage=no +LicenseFile=..\..\LICENSE +OutputBaseFilename=Cardinal-win32-{#VERSION}-installer +OutputDir=. +UsePreviousAppDir=no + +[Types] +Name: "full"; Description: "Full installation"; +Name: "custom"; Description: "Custom installation"; Flags: iscustom; + +[Components] +Name: resources; Description: "Resources"; Types: full custom; Flags: fixed; +Name: carla; Description: "Carla/Ildaeil host tools"; Types: full; +Name: jack; Description: "JACK Standalone"; Types: full; +Name: lv2; Description: "LV2 plugin"; Types: full; +Name: vst2; Description: "VST2 plugin"; Types: full; +Name: vst3; Description: "VST3 plugin"; Types: full; + +[Files] +#include "resources.iss" +; icon +Source: "..\..\utils\distrho.ico"; DestDir: "{app}"; Components: resources; Flags: ignoreversion; +; 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_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; +Source: "..\..\carla\build\Carla\resources\*.*"; DestDir: "{commoncf32}\Cardinal\Carla\resources"; Components: carla; Flags: ignoreversion; +Source: "..\..\carla\build\Carla\iconengines\*.*"; DestDir: "{commoncf32}\Cardinal\Carla\resources\iconengines"; Components: carla; Flags: ignoreversion; +Source: "..\..\carla\build\Carla\imageformats\*.*"; DestDir: "{commoncf32}\Cardinal\Carla\resources\imageformats"; Components: carla; Flags: ignoreversion; +Source: "..\..\carla\build\Carla\platforms\*.*"; DestDir: "{commoncf32}\Cardinal\Carla\resources\platforms"; Components: carla; Flags: ignoreversion; +Source: "..\..\carla\build\Carla\styles\*.*"; DestDir: "{commoncf32}\Cardinal\Carla\resources\styles"; Components: carla; Flags: ignoreversion; +Source: "..\..\carla\build\Carla\resources\lib\*.*"; DestDir: "{commoncf32}\Cardinal\Carla\resources\lib"; Components: carla; Flags: ignoreversion; +Source: "..\..\carla\build\Carla\resources\lib\PyQt5\*.*"; DestDir: "{commoncf32}\Cardinal\Carla\resources\lib\PyQt5"; Components: carla; Flags: ignoreversion; +; jack +Source: "..\..\bin\Cardinal.exe"; DestDir: "{app}"; Components: jack; Flags: ignoreversion; +; lv2 +Source: "..\..\bin\Cardinal.lv2\*.*"; DestDir: "{commoncf32}\LV2\Cardinal.lv2"; Components: lv2; Flags: ignoreversion; +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; +; 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; + +[Icons] +Name: "{commonprograms}\Cardinal"; Filename: "{app}\Cardinal.exe"; IconFilename: "{app}\distrho.ico"; WorkingDir: "{app}"; Comment: "Virtual modular synthesizer plugin"; Components: jack; diff --git a/utils/inno/win64.iss b/utils/inno/win64.iss new file mode 100644 index 00000000..88fc0c9b --- /dev/null +++ b/utils/inno/win64.iss @@ -0,0 +1,62 @@ +#include "version.iss" + +[Setup] +ArchitecturesInstallIn64BitMode=x64 +AppName=Cardinal +AppPublisher=DISTRHO +AppPublisherURL=https://github.com/DISTRHO/Cardinal/ +AppSupportURL=https://github.com/DISTRHO/Cardinal/issues/ +AppUpdatesURL=https://github.com/DISTRHO/Cardinal/releases/ +AppVersion={#VERSION} +DefaultDirName={commonpf64}\Cardinal +DisableDirPage=yes +DisableWelcomePage=no +LicenseFile=..\..\LICENSE +OutputBaseFilename=Cardinal-win64-{#VERSION}-installer +OutputDir=. +UsePreviousAppDir=no + +[Types] +Name: "full"; Description: "Full installation"; +Name: "custom"; Description: "Custom installation"; Flags: iscustom; + +[Components] +Name: resources; Description: "Resources"; Types: full custom; Flags: fixed; +Name: carla; Description: "Carla/Ildaeil host tools"; Types: full; +Name: jack; Description: "JACK Standalone"; Types: full; +Name: lv2; Description: "LV2 plugin"; Types: full; +Name: vst2; Description: "VST2 plugin"; Types: full; +Name: vst3; Description: "VST3 plugin"; Types: full; + +[Files] +#include "resources.iss" +; icon +Source: "..\..\utils\distrho.ico"; DestDir: "{app}"; Components: resources; Flags: ignoreversion; +; carla +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\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; +Source: "..\..\carla\build\Carla\iconengines\*.*"; DestDir: "{commoncf64}\Cardinal\Carla\resources\iconengines"; Components: carla; Flags: ignoreversion; +Source: "..\..\carla\build\Carla\imageformats\*.*"; DestDir: "{commoncf64}\Cardinal\Carla\resources\imageformats"; Components: carla; Flags: ignoreversion; +Source: "..\..\carla\build\Carla\platforms\*.*"; DestDir: "{commoncf64}\Cardinal\Carla\resources\platforms"; Components: carla; Flags: ignoreversion; +Source: "..\..\carla\build\Carla\styles\*.*"; DestDir: "{commoncf64}\Cardinal\Carla\resources\styles"; Components: carla; Flags: ignoreversion; +Source: "..\..\carla\build\Carla\resources\lib\*.*"; DestDir: "{commoncf64}\Cardinal\Carla\resources\lib"; Components: carla; Flags: ignoreversion; +Source: "..\..\carla\build\Carla\resources\lib\PyQt5\*.*"; DestDir: "{commoncf64}\Cardinal\Carla\resources\lib\PyQt5"; Components: carla; Flags: ignoreversion; +; jack +Source: "..\..\bin\Cardinal.exe"; DestDir: "{app}"; Components: jack; Flags: ignoreversion; +; lv2 +Source: "..\..\bin\Cardinal.lv2\*.*"; DestDir: "{commoncf64}\LV2\Cardinal.lv2"; Components: lv2; Flags: ignoreversion; +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; +; 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; + +[Icons] +Name: "{commonprograms}\Cardinal"; Filename: "{app}\Cardinal.exe"; IconFilename: "{app}\distrho.ico"; WorkingDir: "{app}"; Comment: "Virtual modular synthesizer plugin"; Components: jack; diff --git a/utils/macOS/package.xml.in b/utils/macOS/package.xml.in new file mode 100644 index 00000000..b2c8d9cb --- /dev/null +++ b/utils/macOS/package.xml.in @@ -0,0 +1,31 @@ + + + Cardinal + + + + + + + dpf-cardinal-resources.pkg + + + dpf-cardinal-components.pkg + + + dpf-cardinal-lv2bundles.pkg + + + dpf-cardinal-vst2bundles.pkg + + + dpf-cardinal-vst3bundles.pkg + + + + + + + + + diff --git a/utils/macOS/welcome.txt b/utils/macOS/welcome.txt new file mode 100644 index 00000000..3fa7d291 --- /dev/null +++ b/utils/macOS/welcome.txt @@ -0,0 +1,14 @@ +Cardinal is a free and open-source virtual modular synthesizer plugin. +It is based on the popular VCV Rack but with a focus on being a fully self-contained plugin version. + +Cardinal provides 3 plugin variants - "main", Synth and FX. +They are all equivalent in performance and behaviour, with only the IO and metadata that changes. + +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 for macOS. + +Notes: + - Due to AU and VST2 not supporting CV ports, the main variant is not available for these formats. + - The VST3 version is in progress, already part of the build but still experimental.