| @@ -4,7 +4,7 @@ on: | |||||
| push: | push: | ||||
| env: | env: | ||||
| CACHE_VERSION: 6 | |||||
| CACHE_VERSION: 19 | |||||
| DEBIAN_FRONTEND: noninteractive | DEBIAN_FRONTEND: noninteractive | ||||
| HOMEBREW_NO_AUTO_UPDATE: 1 | HOMEBREW_NO_AUTO_UPDATE: 1 | ||||
| LIBGL_ALWAYS_SOFTWARE: 'true' | LIBGL_ALWAYS_SOFTWARE: 'true' | ||||
| @@ -17,10 +17,31 @@ jobs: | |||||
| with: | with: | ||||
| submodules: recursive | submodules: recursive | ||||
| - name: Set up cache | - name: Set up cache | ||||
| id: cache | |||||
| uses: actions/cache@v2 | uses: actions/cache@v2 | ||||
| with: | with: | ||||
| path: | | path: | | ||||
| ~/PawPawBuilds | ~/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 }} | key: linux-arm64-v${{ env.CACHE_VERSION }} | ||||
| - name: Fix GitHub's mess | - name: Fix GitHub's mess | ||||
| run: | | run: | | ||||
| @@ -40,12 +61,12 @@ jobs: | |||||
| env: | env: | ||||
| PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig | PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig | ||||
| run: | | 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 | - name: Build linux arm64 cross-compiled | ||||
| run: | | run: | | ||||
| pushd deps/PawPaw; source local.env linux-aarch64; popd | pushd deps/PawPaw; source local.env linux-aarch64; popd | ||||
| make features | make features | ||||
| make NOOPT=true WITH_LTO=true -j $(nproc) | |||||
| make CIBUILD=true NOOPT=true WITH_LTO=true -j $(nproc) | |||||
| make unzipfx | make unzipfx | ||||
| - name: Set sha8 (non-release) | - name: Set sha8 (non-release) | ||||
| if: startsWith(github.ref, 'refs/tags/') != true | if: startsWith(github.ref, 'refs/tags/') != true | ||||
| @@ -83,10 +104,31 @@ jobs: | |||||
| with: | with: | ||||
| submodules: recursive | submodules: recursive | ||||
| - name: Set up cache | - name: Set up cache | ||||
| id: cache | |||||
| uses: actions/cache@v2 | uses: actions/cache@v2 | ||||
| with: | with: | ||||
| path: | | path: | | ||||
| ~/PawPawBuilds | ~/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 }} | key: linux-armhf-v${{ env.CACHE_VERSION }} | ||||
| - name: Fix GitHub's mess | - name: Fix GitHub's mess | ||||
| run: | | run: | | ||||
| @@ -106,12 +148,12 @@ jobs: | |||||
| env: | env: | ||||
| PKG_CONFIG_PATH: /usr/lib/arm-linux-gnueabihf/pkgconfig | PKG_CONFIG_PATH: /usr/lib/arm-linux-gnueabihf/pkgconfig | ||||
| run: | | 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 | - name: Build linux armhf cross-compiled | ||||
| run: | | run: | | ||||
| pushd deps/PawPaw; source local.env linux-armhf; popd | pushd deps/PawPaw; source local.env linux-armhf; popd | ||||
| make features | make features | ||||
| make NOOPT=true WITH_LTO=true -j $(nproc) | |||||
| make CIBUILD=true NOOPT=true WITH_LTO=true -j $(nproc) | |||||
| make unzipfx | make unzipfx | ||||
| - name: Set sha8 (non-release) | - name: Set sha8 (non-release) | ||||
| if: startsWith(github.ref, 'refs/tags/') != true | if: startsWith(github.ref, 'refs/tags/') != true | ||||
| @@ -149,10 +191,31 @@ jobs: | |||||
| with: | with: | ||||
| submodules: recursive | submodules: recursive | ||||
| - name: Set up cache | - name: Set up cache | ||||
| id: cache | |||||
| uses: actions/cache@v2 | uses: actions/cache@v2 | ||||
| with: | with: | ||||
| path: | | path: | | ||||
| ~/PawPawBuilds | ~/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 }} | key: linux-i686-v${{ env.CACHE_VERSION }} | ||||
| - name: Fix GitHub's mess | - name: Fix GitHub's mess | ||||
| run: | | run: | | ||||
| @@ -168,12 +231,12 @@ jobs: | |||||
| env: | env: | ||||
| PKG_CONFIG_PATH: /usr/lib/i386-linux-gnu/pkgconfig | PKG_CONFIG_PATH: /usr/lib/i386-linux-gnu/pkgconfig | ||||
| run: | | 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 | - name: Build linux i686 | ||||
| run: | | run: | | ||||
| pushd deps/PawPaw; source local.env linux-i686; popd | pushd deps/PawPaw; source local.env linux-i686; popd | ||||
| make features | make features | ||||
| make NOOPT=true WITH_LTO=true -j $(nproc) | |||||
| make CIBUILD=true NOOPT=true WITH_LTO=true -j $(nproc) | |||||
| make unzipfx | make unzipfx | ||||
| - name: Set sha8 (non-release) | - name: Set sha8 (non-release) | ||||
| if: startsWith(github.ref, 'refs/tags/') != true | if: startsWith(github.ref, 'refs/tags/') != true | ||||
| @@ -211,10 +274,31 @@ jobs: | |||||
| with: | with: | ||||
| submodules: recursive | submodules: recursive | ||||
| - name: Set up cache | - name: Set up cache | ||||
| id: cache | |||||
| uses: actions/cache@v2 | uses: actions/cache@v2 | ||||
| with: | with: | ||||
| path: | | path: | | ||||
| ~/PawPawBuilds | ~/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 }} | key: linux-x86_64-v${{ env.CACHE_VERSION }} | ||||
| - name: Set up dependencies | - name: Set up dependencies | ||||
| run: | | 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 | 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 | - name: Build extra dependencies | ||||
| run: | | run: | | ||||
| ./deps/PawPaw/bootstrap-cardinal.sh linux | |||||
| ./deps/PawPaw/bootstrap-cardinal.sh linux && ./deps/PawPaw/.cleanup.sh linux | |||||
| - name: Build linux x86_64 | - name: Build linux x86_64 | ||||
| run: | | run: | | ||||
| pushd deps/PawPaw; source local.env linux; popd | pushd deps/PawPaw; source local.env linux; popd | ||||
| make features | make features | ||||
| make NOOPT=true WITH_LTO=true -j $(nproc) | |||||
| make CIBUILD=true NOOPT=true WITH_LTO=true -j $(nproc) | |||||
| make unzipfx | make unzipfx | ||||
| - name: Set sha8 (non-release) | - name: Set sha8 (non-release) | ||||
| if: startsWith(github.ref, 'refs/tags/') != true | if: startsWith(github.ref, 'refs/tags/') != true | ||||
| @@ -317,6 +401,89 @@ jobs: | |||||
| make features | make features | ||||
| make SYSDEPS=true -j $(nproc) | 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: | macos-universal: | ||||
| runs-on: macos-10.15 | runs-on: macos-10.15 | ||||
| steps: | steps: | ||||
| @@ -324,10 +491,32 @@ jobs: | |||||
| with: | with: | ||||
| submodules: recursive | submodules: recursive | ||||
| - name: Set up cache | - name: Set up cache | ||||
| id: cache | |||||
| uses: actions/cache@v2 | uses: actions/cache@v2 | ||||
| with: | with: | ||||
| path: | | path: | | ||||
| ~/PawPawBuilds | ~/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 }} | key: macos-universal-v${{ env.CACHE_VERSION }} | ||||
| - name: Fix up Xcode | - name: Fix up Xcode | ||||
| run: | | run: | | ||||
| @@ -335,13 +524,23 @@ jobs: | |||||
| sudo xcode-select -s "/Applications/Xcode_12.3.app" | sudo xcode-select -s "/Applications/Xcode_12.3.app" | ||||
| - name: Build extra dependencies | - name: Build extra dependencies | ||||
| run: | | 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: | | run: | | ||||
| pushd deps/PawPaw; source local.env macos-universal; popd | pushd deps/PawPaw; source local.env macos-universal; popd | ||||
| make features | 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) | - name: Set sha8 (non-release) | ||||
| if: startsWith(github.ref, 'refs/tags/') != true | if: startsWith(github.ref, 'refs/tags/') != true | ||||
| id: slug1 | id: slug1 | ||||
| @@ -355,7 +554,7 @@ jobs: | |||||
| run: echo "::set-output name=sha8::$(echo ${{ steps.slug1.outputs.sha8 || steps.slug2.outputs.sha8 }})" | run: echo "::set-output name=sha8::$(echo ${{ steps.slug1.outputs.sha8 || steps.slug2.outputs.sha8 }})" | ||||
| - name: Rename macOS bundle | - name: Rename macOS bundle | ||||
| run: | | 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 | - uses: actions/upload-artifact@v2 | ||||
| with: | with: | ||||
| name: ${{ github.event.repository.name }}-macOS-universal-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} | name: ${{ github.event.repository.name }}-macOS-universal-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} | ||||
| @@ -495,10 +694,31 @@ jobs: | |||||
| with: | with: | ||||
| submodules: recursive | submodules: recursive | ||||
| - name: Set up cache | - name: Set up cache | ||||
| id: cache | |||||
| uses: actions/cache@v2 | uses: actions/cache@v2 | ||||
| with: | with: | ||||
| path: | | path: | | ||||
| ~/PawPawBuilds | ~/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 }} | key: win32-v${{ env.CACHE_VERSION }} | ||||
| - name: Fix GitHub's mess | - name: Fix GitHub's mess | ||||
| run: | | run: | | ||||
| @@ -509,15 +729,25 @@ jobs: | |||||
| run: | | run: | | ||||
| sudo dpkg --add-architecture i386 | sudo dpkg --add-architecture i386 | ||||
| sudo apt-get update -qq | 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 | - name: Build extra dependencies | ||||
| run: | | 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: | | run: | | ||||
| pushd deps/PawPaw; source local.env win32; popd | pushd deps/PawPaw; source local.env win32; popd | ||||
| make features | 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) | - name: Set sha8 (non-release) | ||||
| if: startsWith(github.ref, 'refs/tags/') != true | if: startsWith(github.ref, 'refs/tags/') != true | ||||
| id: slug1 | id: slug1 | ||||
| @@ -536,6 +766,7 @@ jobs: | |||||
| with: | with: | ||||
| name: ${{ github.event.repository.name }}-win32-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} | name: ${{ github.event.repository.name }}-win32-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} | ||||
| path: | | path: | | ||||
| *.exe | |||||
| *.zip | *.zip | ||||
| - uses: softprops/action-gh-release@v1 | - uses: softprops/action-gh-release@v1 | ||||
| if: startsWith(github.ref, 'refs/tags/') | if: startsWith(github.ref, 'refs/tags/') | ||||
| @@ -545,6 +776,7 @@ jobs: | |||||
| draft: false | draft: false | ||||
| prerelease: false | prerelease: false | ||||
| files: | | files: | | ||||
| *.exe | |||||
| *.zip | *.zip | ||||
| win64: | win64: | ||||
| @@ -554,10 +786,31 @@ jobs: | |||||
| with: | with: | ||||
| submodules: recursive | submodules: recursive | ||||
| - name: Set up cache | - name: Set up cache | ||||
| id: cache | |||||
| uses: actions/cache@v2 | uses: actions/cache@v2 | ||||
| with: | with: | ||||
| path: | | path: | | ||||
| ~/PawPawBuilds | ~/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 }} | key: win64-v${{ env.CACHE_VERSION }} | ||||
| - name: Fix GitHub's mess | - name: Fix GitHub's mess | ||||
| run: | | 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 | 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 | - name: Set up dependencies | ||||
| run: | | run: | | ||||
| sudo dpkg --add-architecture i386 | |||||
| sudo apt-get update -qq | 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 | - name: Build extra dependencies | ||||
| run: | | 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: | | run: | | ||||
| pushd deps/PawPaw; source local.env win64; popd | pushd deps/PawPaw; source local.env win64; popd | ||||
| make features | 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) | - name: Set sha8 (non-release) | ||||
| if: startsWith(github.ref, 'refs/tags/') != true | if: startsWith(github.ref, 'refs/tags/') != true | ||||
| id: slug1 | id: slug1 | ||||
| @@ -594,6 +858,7 @@ jobs: | |||||
| with: | with: | ||||
| name: ${{ github.event.repository.name }}-win64-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} | name: ${{ github.event.repository.name }}-win64-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} | ||||
| path: | | path: | | ||||
| *.exe | |||||
| *.zip | *.zip | ||||
| - uses: softprops/action-gh-release@v1 | - uses: softprops/action-gh-release@v1 | ||||
| if: startsWith(github.ref, 'refs/tags/') | if: startsWith(github.ref, 'refs/tags/') | ||||
| @@ -603,6 +868,7 @@ jobs: | |||||
| draft: false | draft: false | ||||
| prerelease: false | prerelease: false | ||||
| files: | | files: | | ||||
| *.exe | |||||
| *.zip | *.zip | ||||
| source-tarball: | source-tarball: | ||||
| @@ -662,17 +928,17 @@ jobs: | |||||
| sudo dpkg -i kxstudio-repos_10.0.3_all.deb | sudo dpkg -i kxstudio-repos_10.0.3_all.deb | ||||
| sudo apt-get update -qq | sudo apt-get update -qq | ||||
| # build-deps | # 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 | # runtime testing | ||||
| sudo apt-get install -yqq carla-git lilv-utils lv2-dev lv2lint valgrind | sudo apt-get install -yqq carla-git lilv-utils lv2-dev lv2lint valgrind | ||||
| - name: Build plugins | |||||
| - name: Build Cardinal | |||||
| env: | env: | ||||
| CFLAGS: -g | CFLAGS: -g | ||||
| CXXFLAGS: -g -DDPF_ABORT_ON_ERROR | CXXFLAGS: -g -DDPF_ABORT_ON_ERROR | ||||
| LDFLAGS: -static-libgcc -static-libstdc++ | LDFLAGS: -static-libgcc -static-libstdc++ | ||||
| run: | | 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 | - name: Validate LV2 ttl syntax | ||||
| run: | | run: | | ||||
| lv2_validate \ | lv2_validate \ | ||||
| @@ -681,14 +947,14 @@ jobs: | |||||
| /usr/lib/lv2/kx-control-input-port-change-request.lv2/*.ttl \ | /usr/lib/lv2/kx-control-input-port-change-request.lv2/*.ttl \ | ||||
| /usr/lib/lv2/kx-programs.lv2/*.ttl \ | /usr/lib/lv2/kx-programs.lv2/*.ttl \ | ||||
| ./bin/*.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 | - name: Test LV2 plugin | ||||
| run: | | run: | | ||||
| export LV2_PATH=/tmp/lv2-path | export LV2_PATH=/tmp/lv2-path | ||||
| @@ -701,27 +967,25 @@ jobs: | |||||
| --suppressions=./dpf/utils/valgrind-dpf.supp \ | --suppressions=./dpf/utils/valgrind-dpf.supp \ | ||||
| /usr/lib/carla/carla-bridge-native lv2 "" ${p} 1>/dev/null; \ | /usr/lib/carla/carla-bridge-native lv2 "" ${p} 1>/dev/null; \ | ||||
| done | 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 | |||||
| @@ -15,3 +15,5 @@ | |||||
| bin/ | bin/ | ||||
| build/ | build/ | ||||
| documentation.pdf | documentation.pdf | ||||
| utils/inno/resources.iss | |||||
| utils/inno/version.iss | |||||
| @@ -84,7 +84,7 @@ | |||||
| url = https://gitlab.com/sonusdept/sonusmodular.git | url = https://gitlab.com/sonusdept/sonusmodular.git | ||||
| [submodule "plugins/Mog"] | [submodule "plugins/Mog"] | ||||
| path = plugins/Mog | path = plugins/Mog | ||||
| url = https://github.com/CardinalModules/Mog-VCV.git | |||||
| url = https://github.com/JustMog/Mog-VCV.git | |||||
| [submodule "plugins/ChowDSP"] | [submodule "plugins/ChowDSP"] | ||||
| path = plugins/ChowDSP | path = plugins/ChowDSP | ||||
| url = https://github.com/jatinchowdhury18/ChowDSP-VCV.git | url = https://github.com/jatinchowdhury18/ChowDSP-VCV.git | ||||
| @@ -130,9 +130,6 @@ | |||||
| [submodule "plugins/Autinn"] | [submodule "plugins/Autinn"] | ||||
| path = plugins/Autinn | path = plugins/Autinn | ||||
| url = https://github.com/NikolaiVChr/Autinn.git | 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"] | [submodule "plugins/MockbaModular"] | ||||
| path = plugins/MockbaModular | path = plugins/MockbaModular | ||||
| url = https://github.com/MockbaTheBorg/MockbaModular.git | url = https://github.com/MockbaTheBorg/MockbaModular.git | ||||
| @@ -142,6 +139,60 @@ | |||||
| [submodule "plugins/Axioma"] | [submodule "plugins/Axioma"] | ||||
| path = plugins/Axioma | path = plugins/Axioma | ||||
| url = https://github.com/kauewerner/Axioma.git | url = https://github.com/kauewerner/Axioma.git | ||||
| [submodule "plugins/GoodSheperd"] | |||||
| path = plugins/GoodSheperd | |||||
| url = https://github.com/jensschulze/GoodSheperd.git | |||||
| [submodule "plugins/HamptonHarmonics"] | |||||
| path = plugins/HamptonHarmonics | |||||
| url = https://gitlab.com/hampton-harmonics/hampton-harmonics-modules.git | |||||
| [submodule "plugins/ML_modules"] | |||||
| path = plugins/ML_modules | |||||
| url = https://github.com/martin-lueders/ML_modules.git | |||||
| [submodule "plugins/Orbits"] | |||||
| path = plugins/Orbits | |||||
| url = https://github.com/RareBreeds/Orbits.git | |||||
| [submodule "plugins/stocaudio"] | |||||
| path = plugins/stocaudio | |||||
| url = https://github.com/aptrn/stocaudio-modules.git | |||||
| [submodule "plugins/CatroModulo"] | |||||
| path = plugins/CatroModulo | |||||
| url = https://github.com/catronomix/catro-modulo.git | |||||
| [submodule "plugins/LilacLoop"] | |||||
| path = plugins/LilacLoop | |||||
| url = https://github.com/grough/lilac-loop-vcv.git | |||||
| [submodule "plugins/kocmoc"] | |||||
| path = plugins/kocmoc | |||||
| url = https://github.com/janne808/kocmoc-rack-modules.git | |||||
| [submodule "plugins/PathSet"] | |||||
| path = plugins/PathSet | |||||
| url = https://github.com/patheros/PathSetModules.git | |||||
| [submodule "plugins/Algoritmarte"] | |||||
| path = plugins/Algoritmarte | |||||
| url = https://github.com/algoritmarte/AlgoritmarteVCVPlugin.git | |||||
| [submodule "plugins/AaronStatic"] | |||||
| path = plugins/AaronStatic | |||||
| url = https://github.com/aaronstatic/AaronStatic_modules.git | |||||
| [submodule "plugins/MSM"] | |||||
| path = plugins/MSM | |||||
| url = https://github.com/netboy3/MSM-vcvrack-plugin.git | |||||
| [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/dBiz"] | [submodule "plugins/dBiz"] | ||||
| path = plugins/dBiz | path = plugins/dBiz | ||||
| url = https://github.com/dBiz/dBiz.git | url = https://github.com/dBiz/dBiz.git | ||||
| @@ -7,7 +7,7 @@ | |||||
| # also set in: | # also set in: | ||||
| # src/CardinalCommon.cpp `CARDINAL_VERSION` | # src/CardinalCommon.cpp `CARDINAL_VERSION` | ||||
| # src/CardinalPlugin.cpp `getVersion` | # src/CardinalPlugin.cpp `getVersion` | ||||
| VERSION = 22.02 | |||||
| VERSION = 22.04 | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # Import base definitions | # Import base definitions | ||||
| @@ -57,6 +57,15 @@ endif | |||||
| CARLA_EXTRA_ARGS += USING_JUCE=false | CARLA_EXTRA_ARGS += USING_JUCE=false | ||||
| CARLA_EXTRA_ARGS += USING_JUCE_GUI_EXTRA=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 | # Check for system-wide dependencies | ||||
| @@ -196,7 +205,7 @@ endif | |||||
| dgl: | dgl: | ||||
| ifneq ($(HEADLESS),true) | 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 | endif | ||||
| plugins: deps | plugins: deps | ||||
| @@ -255,8 +264,7 @@ install: | |||||
| install -d $(DESTDIR)$(PREFIX)/lib/lv2/Cardinal.lv2 | install -d $(DESTDIR)$(PREFIX)/lib/lv2/Cardinal.lv2 | ||||
| install -d $(DESTDIR)$(PREFIX)/lib/lv2/CardinalFX.lv2 | install -d $(DESTDIR)$(PREFIX)/lib/lv2/CardinalFX.lv2 | ||||
| install -d $(DESTDIR)$(PREFIX)/lib/lv2/CardinalSynth.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) | ifeq ($(VST3_SUPPORTED),true) | ||||
| install -d $(DESTDIR)$(PREFIX)/lib/vst3/Cardinal.vst3/Contents | install -d $(DESTDIR)$(PREFIX)/lib/vst3/Cardinal.vst3/Contents | ||||
| install -d $(DESTDIR)$(PREFIX)/lib/vst3/CardinalFX.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/CardinalFX.lv2/*.* $(DESTDIR)$(PREFIX)/lib/lv2/CardinalFX.lv2/ | ||||
| install -m 644 bin/CardinalSynth.lv2/*.* $(DESTDIR)$(PREFIX)/lib/lv2/CardinalSynth.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) | ifeq ($(VST3_SUPPORTED),true) | ||||
| cp -rL bin/Cardinal.vst3/Contents/*-* $(DESTDIR)$(PREFIX)/lib/vst3/Cardinal.vst3/Contents/ | 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 README.md $(DESTDIR)$(PREFIX)/share/doc/cardinal/ | ||||
| install -m 644 docs/*.md docs/*.png $(DESTDIR)$(PREFIX)/share/doc/cardinal/docs/ | 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 | # Tarball step, for releases | ||||
| @@ -404,6 +398,9 @@ tarball+deps: download | |||||
| rm -f ../cardinal+deps-$(VERSION).tar.xz | rm -f ../cardinal+deps-$(VERSION).tar.xz | ||||
| tar -c --lzma $(TAR_ARGS) -f ../cardinal+deps-$(VERSION).tar.xz . | tar -c --lzma $(TAR_ARGS) -f ../cardinal+deps-$(VERSION).tar.xz . | ||||
| version: | |||||
| @echo $(VERSION) | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| .PHONY: carla deps plugins | .PHONY: carla deps plugins | ||||
| @@ -3,7 +3,7 @@ | |||||
| *Cardinal, the Rack!* | *Cardinal, the Rack!* | ||||
| Cardinal is a free and open-source virtual modular synthesizer plugin, | 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. | 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/) | 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. | 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. | 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. | 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 | ## Plugin variants | ||||
| Cardinal provides 3 plugin variants - "main", Synth and FX. | 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. | 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 | ### Synth | ||||
| @@ -70,33 +102,6 @@ But a couple of modules background's have their colors flipped, because damn we | |||||
|  |  | ||||
| ## 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 | ## Included modules | ||||
| @@ -104,8 +109,11 @@ At the moment the following 3rd-party modules are provided: | |||||
| - 21kHz | - 21kHz | ||||
| - 8Mode | - 8Mode | ||||
| - Aaron Static | |||||
| - AlgoritmArte | |||||
| - Amalgamated Harmonics | - Amalgamated Harmonics | ||||
| - Animated Circuits | - Animated Circuits | ||||
| - Arable Instruments | |||||
| - Aria Salvatrice | - Aria Salvatrice | ||||
| - Audible Instruments | - Audible Instruments | ||||
| - Autinn | - Autinn | ||||
| @@ -114,6 +122,7 @@ At the moment the following 3rd-party modules are provided: | |||||
| - Befaco | - Befaco | ||||
| - Bidoo | - Bidoo | ||||
| - Bogaudio | - Bogaudio | ||||
| - Catro/Modulo | |||||
| - cf | - cf | ||||
| - ChowDSP | - ChowDSP | ||||
| - dBiz | - dBiz | ||||
| @@ -122,26 +131,40 @@ At the moment the following 3rd-party modules are provided: | |||||
| - ExpertSleepers Encoders | - ExpertSleepers Encoders | ||||
| - Extratone | - Extratone | ||||
| - Fehler Fabrik | - Fehler Fabrik | ||||
| - Fundamental | |||||
| - Glue the Giant | - Glue the Giant | ||||
| - GoodSheperd | |||||
| - Grande | - Grande | ||||
| - Hampton Harmonics | |||||
| - HetrickCV | - HetrickCV | ||||
| - ihtsyn | - ihtsyn | ||||
| - Impromptu | - Impromptu | ||||
| - JW-Modules | - JW-Modules | ||||
| - kocmoc | |||||
| - LifeFormModular | - LifeFormModular | ||||
| - Lilac Loop | |||||
| - Little Utils | - Little Utils | ||||
| - Lomas Modules | - Lomas Modules | ||||
| - Lyrae Modules | - Lyrae Modules | ||||
| - MindMeld | - MindMeld | ||||
| - ML Modules | |||||
| - Mockba Modular | - Mockba Modular | ||||
| - Mog | - Mog | ||||
| - mscHack | - mscHack | ||||
| - MSM | |||||
| - Nonlinear Circuits | |||||
| - Orbits | |||||
| - Parable Instruments | |||||
| - Path Set | |||||
| - PinkTrombone | |||||
| - Prism | - Prism | ||||
| - rackwindows | - rackwindows | ||||
| - repelzen | - repelzen | ||||
| - Sonus Modular | - Sonus Modular | ||||
| - Substation Opensource | |||||
| - stocaudio | |||||
| - unless_modules | |||||
| - Valley | - Valley | ||||
| - Voxglitch | |||||
| - ZetaCarinae | - ZetaCarinae | ||||
| - ZZC | - ZZC | ||||
| @@ -215,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). | 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). | 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. | |||||
| @@ -1 +1 @@ | |||||
| Subproject commit 4b6010bd0adbbed5a0cb89a1253e52e72e648b18 | |||||
| Subproject commit 04558b63101de55556733edfa4a369b51f36e9b3 | |||||
| @@ -54,8 +54,8 @@ BASE_FLAGS += -I../include/mingw-compat | |||||
| BASE_FLAGS += -I../include/mingw-std-threads | BASE_FLAGS += -I../include/mingw-std-threads | ||||
| endif | endif | ||||
| BUILD_C_FLAGS += -fno-finite-math-only | |||||
| BUILD_CXX_FLAGS += -fno-finite-math-only | |||||
| BUILD_C_FLAGS += -fno-finite-math-only -fno-strict-aliasing | |||||
| BUILD_CXX_FLAGS += -fno-finite-math-only -fno-strict-aliasing | |||||
| # Rack code is not tested for this flag, unset it | # Rack code is not tested for this flag, unset it | ||||
| BUILD_CXX_FLAGS += -U_GLIBCXX_ASSERTIONS -Wp,-U_GLIBCXX_ASSERTIONS | BUILD_CXX_FLAGS += -U_GLIBCXX_ASSERTIONS -Wp,-U_GLIBCXX_ASSERTIONS | ||||
| @@ -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)/lib/libspeexdsp.a: $(DEP_PATH)/speexdsp-SpeexDSP-1.2rc3/.stamp-patched | ||||
| $(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 | sed -i -e "s/#pragma GCC visibility push/#error we dont want this/" $(DEP_PATH)/speexdsp-SpeexDSP-1.2rc3/configure | ||||
| touch $@ | touch $@ | ||||
| @@ -1 +1 @@ | |||||
| Subproject commit b41a693b64cdba1abd8d278c9985fb690b522854 | |||||
| Subproject commit 01d07086586818e427b2898d2d446d30b68f3139 | |||||
| @@ -21,6 +21,7 @@ Bellow follows a list of features comparing the official plugin to Cardinal. | |||||
| | Loads external modules | Yes | No | | | | Loads external modules | Yes | No | | | ||||
| | Supports closed-source 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 | | | 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 LV2 format | No | Yes | | | ||||
| | Plugin in VST2 format | Yes | Yes | | | | Plugin in VST2 format | Yes | Yes | | | ||||
| | Plugin in VST3 format | No | WIP | | | | 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 | | | Supports BSD systems | No | Yes | Available as FreeBSD port | | ||||
| | Synth plugin variant | 16 ins, 16 outs | 2 ins, 2 outs | | | | Synth plugin variant | 16 ins, 16 outs | 2 ins, 2 outs | | | ||||
| | FX 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 | | | 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 | | | | Integrated plugin host | No, Host payed separately | Yes, using Carla or Ildaeil | | | ||||
| | Host sync/timing | Using MIDI signals | Using dedicated module | | | | Host sync/timing | Using MIDI signals | Using dedicated module | | | ||||
| | Linux/X11 event handling | Runs on 2nd thread | Runs on main/GUI thread | | | | 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 | | | 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 | | | 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 | | | | 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: | 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) | * Aria Salvatrice modules (except Arcane related modules, due to their online requirement) | ||||
| * Mog (never updated to v2) | * Mog (never updated to v2) | ||||
| * mscHack (never updated to v2) | * mscHack (never updated to v2) | ||||
| * rackwindows | * rackwindows | ||||
| * repelzen | |||||
| * Audio File | * Audio File | ||||
| * Carla Plugin Host | * Carla Plugin Host | ||||
| * Ildaeil Host | * Ildaeil Host | ||||
| @@ -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. | 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". | 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? | ## Can I install extra modules? | ||||
| No, Cardinal is intentionally a fully self-contained plugin. | 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 | ## 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. | 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? | ## Why IRC and not Discord? | ||||
| @@ -4,7 +4,7 @@ | |||||
| While Cardinal itself is licensed under GPLv3+, some modules/plugins used by it are not. | While Cardinal itself is licensed under GPLv3+, some modules/plugins used by it are not. | ||||
| And since Cardinal builds the entire Rack and modules as a static library, | And since Cardinal builds the entire Rack and modules as a static library, | ||||
| the more restrictive of the **code licenses** will apply to the final binary. | |||||
| the more restrictive of the **code licenses** will apply to the final binary. | |||||
| Bellow follows a list of all code licenses used in Cardinal and linked submodules. | Bellow follows a list of all code licenses used in Cardinal and linked submodules. | ||||
| @@ -15,8 +15,11 @@ Bellow follows a list of all code licenses used in Cardinal and linked submodule | |||||
| | Rack | GPL-3.0-or-later | The actual Rack code, internal dependencies are compatible with GPLv3+ | | | Rack | GPL-3.0-or-later | The actual Rack code, internal dependencies are compatible with GPLv3+ | | ||||
| | 21kHz | MIT | | | | 21kHz | MIT | | | ||||
| | 8Mode | BSD-3-Clause | | | | 8Mode | BSD-3-Clause | | | ||||
| | Aaron Static | MIT | | | |||||
| | AlgoritmArte | GPL-3.0-or-later | | | |||||
| | Amalgamated Harmonics | BSD-3-Clause | | | | Amalgamated Harmonics | BSD-3-Clause | | | ||||
| | Animated Circuits | GPL-3.0-or-later | | | | Animated Circuits | GPL-3.0-or-later | | | ||||
| | Arable Instruments | GPL-3.0-or-later | | | |||||
| | Aria Salvatrice | GPL-3.0-or-later | | | | Aria Salvatrice | GPL-3.0-or-later | | | ||||
| | Audible Instruments | GPL-3.0-or-later | | | | Audible Instruments | GPL-3.0-or-later | | | ||||
| | Autinn | GPL-3.0-or-later | | | | Autinn | GPL-3.0-or-later | | | ||||
| @@ -25,6 +28,7 @@ Bellow follows a list of all code licenses used in Cardinal and linked submodule | |||||
| | Befaco | GPL-3.0-or-later | | | | Befaco | GPL-3.0-or-later | | | ||||
| | Bidoo | GPL-3.0-or-later | | | | Bidoo | GPL-3.0-or-later | | | ||||
| | Bogaudio | GPL-3.0-or-later | | | | Bogaudio | GPL-3.0-or-later | | | ||||
| | Catro/Modulo | BSD-3-Clause | | | |||||
| | cf | BSD-3-Clause | | | | cf | BSD-3-Clause | | | ||||
| | ChowDSP | GPL-3.0-or-later | | | | ChowDSP | GPL-3.0-or-later | | | ||||
| | dBiz | GPL-3.0-or-later | | | | dBiz | GPL-3.0-or-later | | | ||||
| @@ -33,26 +37,40 @@ Bellow follows a list of all code licenses used in Cardinal and linked submodule | |||||
| | ExpertSleepers Encoders | MIT | | | | ExpertSleepers Encoders | MIT | | | ||||
| | Extratone | GPL-3.0-or-later | | | | Extratone | GPL-3.0-or-later | | | ||||
| | Fehler Fabrik | 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 | | | | Glue the Giant | GPL-3.0-or-later | | | ||||
| | GoodSheperd | GPL-3.0-or-later | | | |||||
| | Grande | GPL-3.0-or-later | | | | Grande | GPL-3.0-or-later | | | ||||
| | Hampton Harmonics | MIT | | | |||||
| | HetrickCV | CC0-1.0 | | | | HetrickCV | CC0-1.0 | | | ||||
| | ihtsyn | GPL-3.0-or-later | | | | ihtsyn | GPL-3.0-or-later | | | ||||
| | Impromptu | GPL-3.0-or-later | | | | Impromptu | GPL-3.0-or-later | | | ||||
| | JW-Modules | BSD-3-Clause | | | | JW-Modules | BSD-3-Clause | | | ||||
| | kocmoc | GPL-3.0-or-later | | | |||||
| | LifeFormModular | MIT | | | | LifeFormModular | MIT | | | ||||
| | Lilac Loop | GPL-3.0-or-later | | | |||||
| | Little Utils | EUPL-1.2 | | | | Little Utils | EUPL-1.2 | | | ||||
| | Lomas Modules | GPL-3.0-or-later | | | | Lomas Modules | GPL-3.0-or-later | | | ||||
| | Lyrae Modules | GPL-3.0-or-later | | | | Lyrae Modules | GPL-3.0-or-later | | | ||||
| | MindMeld | GPL-3.0-or-later | | | | MindMeld | GPL-3.0-or-later | | | ||||
| | ML Modules | BSD-3-Clause | | | |||||
| | Mockba Modular | MIT | | | | Mockba Modular | MIT | | | ||||
| | Mog | CC0-1.0 | | | | Mog | CC0-1.0 | | | ||||
| | mscHack | BSD-3-Clause | | | | mscHack | BSD-3-Clause | | | ||||
| | 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 | | | | Prism | BSD-3-Clause | | | ||||
| | Rackwindows | MIT | | | | Rackwindows | MIT | | | ||||
| | repelzen | GPL-3.0-or-later | | | | repelzen | GPL-3.0-or-later | | | ||||
| | Substation Opensource | BSD-3-Clause-Attribution | Need to check full compatibility with GPLv3+ | | |||||
| | Sonus Modular | GPL-3.0-or-later | | | | Sonus Modular | GPL-3.0-or-later | | | ||||
| | stocaudio | GPL-3.0-or-later | | | |||||
| | unless_modules | GPL-3.0-or-later | | | |||||
| | Valley | GPL-3.0-or-later | | | | Valley | GPL-3.0-or-later | | | ||||
| | Voxglitch | GPL-3.0-or-later | | | |||||
| | ZetaCarinae | GPL-3.0-or-later | | | | ZetaCarinae | GPL-3.0-or-later | | | ||||
| | ZZC | GPL-3.0-or-later | | | | ZZC | GPL-3.0-or-later | | | ||||
| @@ -74,10 +92,15 @@ Below is a list of artwork licenses from plugins | |||||
| |-----------------------------------------|------------------|------------------| | |-----------------------------------------|------------------|------------------| | ||||
| | 21kHz | MIT | No artwork specific license provided | | | 21kHz | MIT | No artwork specific license provided | | ||||
| | 8Mode | BSD-3-Clause | No artwork specific license provided | | | 8Mode | BSD-3-Clause | No artwork specific license provided | | ||||
| | AaronStatic/* | MIT | No artwork specific license provided | | |||||
| | AaronStatic/fonts/PixelOperator.ttf | CC0-1.0 | | | |||||
| | Algoritmarte/* | GPL-3.0-or-later | No artwork specific license provided | | |||||
| | Algoritmarte/LEDSliderGreenHandle.svg | CC-BY-NC-4.0 | | | |||||
| | AmalgamatedHarmonics/* | BSD-3-Clause | No artwork specific license provided | | | AmalgamatedHarmonics/* | BSD-3-Clause | No artwork specific license provided | | ||||
| | AmalgamatedHarmonics/DSEG*.ttf | OFL-1.1-RFN | | | | AmalgamatedHarmonics/DSEG*.ttf | OFL-1.1-RFN | | | ||||
| | AmalgamatedHarmonics/Roboto*.ttf | Apache-2.0 | | | | AmalgamatedHarmonics/Roboto*.ttf | Apache-2.0 | | | ||||
| | AnimatedCircuits/* | CC-BY-NC-SA-4.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/* | CC-BY-SA-4.0 | | | ||||
| | AriaModules/Arcane/* | CC-BY-NC-SA-3.0 | Unused in Cardinal | | | AriaModules/Arcane/* | CC-BY-NC-SA-3.0 | Unused in Cardinal | | ||||
| | AriaModules/components/* | WTFPL | | | | AriaModules/components/* | WTFPL | | | ||||
| @@ -95,12 +118,15 @@ Below is a list of artwork licenses from plugins | |||||
| | BaconPlugs/Keypunch029.json | OFL-1.1 | | | | 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) | | | 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/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) | | | 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/* | CC-BY-SA-4.0 | | | ||||
| | BogaudioModules/fonts/audiowide.ttf | OFL-1.1-RFN | | | | BogaudioModules/fonts/audiowide.ttf | OFL-1.1-RFN | | | ||||
| | BogaudioModules/fonts/inconsolata*.ttf | OFL-1.1-no-RFN | | | | BogaudioModules/fonts/inconsolata*.ttf | OFL-1.1-no-RFN | | | ||||
| | Cardinal/* | CC0-1.0 | | | | Cardinal/* | CC0-1.0 | | | ||||
| | Cardinal/Miku/Miku.png | CC-BY-NC-3.0 | https://piapro.net/intl/en_for_creators.html | | | Cardinal/Miku/Miku.png | CC-BY-NC-3.0 | https://piapro.net/intl/en_for_creators.html | | ||||
| | CatroModulo/* | BSD-3-Clause | No artwork specific license provided | | |||||
| | CatroModulo/Segment7Standard.ttf | OFL-1.1-RFN | | | |||||
| | cf/* | BSD-3-Clause | No artwork specific license provided | | | cf/* | BSD-3-Clause | No artwork specific license provided | | ||||
| | cf/DejaVuSansMono.ttf | Bitstream-Vera | | | | cf/DejaVuSansMono.ttf | Bitstream-Vera | | | ||||
| | cf/Segment7Standard.ttf | OFL-1.1-RFN | | | | cf/Segment7Standard.ttf | OFL-1.1-RFN | | | ||||
| @@ -119,16 +145,22 @@ Below is a list of artwork licenses from plugins | |||||
| | ExpertSleepers-Encoders/* | MIT | [Same license as source code](https://github.com/expertsleepersltd/vcvrack-encoders/issues/3) | | | 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) | | | 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) | | | 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/* | GPL-3.0-or-later | Same license as source code | | ||||
| | GlueTheGiant/fonts/DSEG7-* | OFL-1.1-RFN | | | | GlueTheGiant/fonts/DSEG7-* | OFL-1.1-RFN | | | ||||
| | GoodSheperd/* | GPL-3.0-or-later | No artwork specific license provided | | |||||
| | GrandeModular/* | CC-BY-NC-ND-4.0 | | | | GrandeModular/* | CC-BY-NC-ND-4.0 | | | ||||
| | HamptonHarmonics/* | MIT | No artwork specific license provided | | |||||
| | HamptonHarmonics/PixelOperator.ttf | CC0-1.0 | | | |||||
| | HetrickCV/* | CC0-1.0 | | | | HetrickCV/* | CC0-1.0 | | | ||||
| | ihtsyn/* | GPL-3.0-or-later | [Same license as source code](https://github.com/nysthi/nysthi/issues/379#issuecomment-1027873902) | | | ihtsyn/* | GPL-3.0-or-later | [Same license as source code](https://github.com/nysthi/nysthi/issues/379#issuecomment-1027873902) | | ||||
| | ImpromptuModular/* | CC-BY-NC-ND-4.0 | | | | ImpromptuModular/* | CC-BY-NC-ND-4.0 | | | ||||
| | ImpromptuModular/res/comp/complib/* | CC-BY-NC-4.0 | | | | ImpromptuModular/res/comp/complib/* | CC-BY-NC-4.0 | | | ||||
| | JW-Modules/* | BSD-3-Clause | No artwork specific license provided | | | JW-Modules/* | BSD-3-Clause | No artwork specific license provided | | ||||
| | JW-Modules/DejaVuSansMono.ttf | Bitstream-Vera | Unused in Cardinal | | | JW-Modules/DejaVuSansMono.ttf | Bitstream-Vera | Unused in Cardinal | | ||||
| | kocmoc/* | GPL-3.0-or-later | No artwork specific license provided | | |||||
| | LifeFormModular/* | MIT | No artwork specific license provided | | | LifeFormModular/* | MIT | No artwork specific license provided | | ||||
| | LilacLoop/* | GPL-3.0-or-later | No artwork specific license provided | | |||||
| | LittleUtils/* | EUPL-1.2 | Same license as source code | | | LittleUtils/* | EUPL-1.2 | Same license as source code | | ||||
| | LittleUtils/fonts/CooperHewitt-*.ttf | OFL-1.1-RFN | | | | LittleUtils/fonts/CooperHewitt-*.ttf | OFL-1.1-RFN | | | ||||
| | LittleUtils/fonts/Overpass-*.ttf | OFL-1.1-RFN | | | | LittleUtils/fonts/Overpass-*.ttf | OFL-1.1-RFN | | | ||||
| @@ -138,21 +170,40 @@ Below is a list of artwork licenses from plugins | |||||
| | LyraeModules/* | CC-BY-NC-SA-4.0 | | | | LyraeModules/* | CC-BY-NC-SA-4.0 | | | ||||
| | MindMeld/* | CC-BY-NC-ND-4.0 | | | | MindMeld/* | CC-BY-NC-ND-4.0 | | | ||||
| | MindMeld/fonts/RobotoCondensed-*.ttf | Apache-2.0 | | | | MindMeld/fonts/RobotoCondensed-*.ttf | Apache-2.0 | | | ||||
| | ML_modules/* | BSD-3-Clause | No artwork specific license provided | | |||||
| | ML_modules/DejaVuSansMono.ttf | Bitstream-Vera | | | |||||
| | ML_modules/Segment7Standard.ttf | OFL-1.1-RFN | | | |||||
| | MockbaModular/* | MIT | No artwork specific license provided | | | MockbaModular/* | MIT | No artwork specific license provided | | ||||
| | Mog/* | CC0-1.0 | | | | Mog/* | CC0-1.0 | | | ||||
| | Mog/components/* | CC-BY-NC-4.0 | | | | Mog/components/* | CC-BY-NC-4.0 | | | ||||
| | Mog/Exo2-BoldItalic.ttf | OFL-1.1-RFN | | | | Mog/Exo2-BoldItalic.ttf | OFL-1.1-RFN | | | ||||
| | mscHack/* | BSD-3-Clause | No artwork specific license provided, see [mschack#108](https://github.com/mschack/VCV-Rack-Plugins/issues/108) | | | mscHack/* | BSD-3-Clause | No artwork specific license provided, see [mschack#108](https://github.com/mschack/VCV-Rack-Plugins/issues/108) | | ||||
| | MSM/* | MIT | No artwork specific license provided | | |||||
| | MSM/Fonts/DejaVuSansMono.ttf | Bitstream-Vera | | | |||||
| | MSM/Fonts/Segment7Standard.ttf | OFL-1.1-RFN | | | |||||
| | MSM/Fonts/Sudo.ttf | OFL-1.1-no-RFN | | | |||||
| | nonlinearcircuits/* | CC0-1.0 | No artwork specific license provided | | |||||
| | 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/* | CC-BY-SA-4.0 | | | ||||
| | Prism/RobotoCondensed-Regular.ttf | Apache-2.0 | | | | Prism/RobotoCondensed-Regular.ttf | Apache-2.0 | | | ||||
| | Rackwindows/* | MIT | [Same license as source code](https://github.com/n0jo/rackwindows/issues/15) | | | Rackwindows/* | MIT | [Same license as source code](https://github.com/n0jo/rackwindows/issues/15) | | ||||
| | repelzen/* | CC-BY-SA-4.0 | | | | repelzen/* | CC-BY-SA-4.0 | | | ||||
| | substation-opensource/* | BSD-3-Clause-Attribution | No artwork specific license provided | | |||||
| | sonusmodular/* | GPL-3.0-or-later | [Same license as source code](https://gitlab.com/sonusdept/sonusmodular/-/issues/14) | | | sonusmodular/* | GPL-3.0-or-later | [Same license as source code](https://gitlab.com/sonusdept/sonusmodular/-/issues/14) | | ||||
| | stocaudio/* | GPL-3.0-or-later | 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/* | 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/din1451alt.ttf | CC-BY-3.0-DE | | | ||||
| | ValleyAudio/DSEG14Classic-*.ttf | OFL-1.1-RFN | | | | ValleyAudio/DSEG14Classic-*.ttf | OFL-1.1-RFN | | | ||||
| | ValleyAudio/ShareTechMono-*.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) | | | 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/* | 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. | | | 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. | | ||||
| @@ -1 +1 @@ | |||||
| Subproject commit af042cb682d693e9ce5b87a145e6c704be31adf8 | |||||
| Subproject commit 68de732eecbd1d8febf94e15558c5adaa45dfa9b | |||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
| * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
| * modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
| @@ -53,6 +53,19 @@ | |||||
| #include <functional> | #include <functional> | ||||
| #define USING_CARDINAL_NOT_RACK | #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 | // 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 | // 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, | void async_dialog_filebrowser(bool saving, const char* startDir, const char* title, | ||||
| @@ -15,21 +15,17 @@ | |||||
| * For a full copy of the GNU General Public License see the LICENSE file. | * 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 | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,164 @@ | |||||
| /* | |||||
| * DISTRHO Cardinal Plugin | |||||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * 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 <pffft.h> | |||||
| #include <dsp/common.hpp> | |||||
| 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 | |||||
| @@ -48,7 +48,7 @@ struct Port { | |||||
| /** Voltage of the port. */ | /** Voltage of the port. */ | ||||
| /** NOTE alignas is required in order to allow SSE usage. | /** 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. */ | 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. */ | /** Unstable API. Use getVoltage() and setVoltage() instead. */ | ||||
| float voltages[PORT_MAX_CHANNELS] = {}; | float voltages[PORT_MAX_CHANNELS] = {}; | ||||
| /** DEPRECATED. Unstable API. Use getVoltage() and setVoltage() instead. */ | /** DEPRECATED. Unstable API. Use getVoltage() and setVoltage() instead. */ | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
| * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
| * modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
| @@ -15,4 +15,6 @@ | |||||
| * For a full copy of the GNU General Public License see the LICENSE file. | * For a full copy of the GNU General Public License see the LICENSE file. | ||||
| */ | */ | ||||
| #pragma once | |||||
| #include <shlobj.h> | #include <shlobj.h> | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
| * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
| * modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
| @@ -15,4 +15,6 @@ | |||||
| * For a full copy of the GNU General Public License see the LICENSE file. | * For a full copy of the GNU General Public License see the LICENSE file. | ||||
| */ | */ | ||||
| #pragma once | |||||
| #include <shlwapi.h> | #include <shlwapi.h> | ||||
| @@ -0,0 +1,25 @@ | |||||
| /* | |||||
| * DISTRHO Cardinal Plugin | |||||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License as | |||||
| * published by the Free Software Foundation; either version 3 of | |||||
| * the License, or any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * For a full copy of the GNU General Public License see the LICENSE file. | |||||
| */ | |||||
| #pragma once | |||||
| #include_next <future> | |||||
| #include "mingw.future.h" | |||||
| #undef IN | |||||
| #undef OUT | |||||
| #undef far | |||||
| #undef near | |||||
| @@ -0,0 +1,374 @@ | |||||
| /* | |||||
| * DISTRHO Cardinal Plugin | |||||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * 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 <cstring> | |||||
| #include <pmmintrin.h> | |||||
| 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 <typename TYPE, int SIZE> | |||||
| struct Vector; | |||||
| /** Wrapper for `__m128` representing an aligned vector of 4 single-precision float values. | |||||
| */ | |||||
| template <> | |||||
| struct Vector<float, 4> { | |||||
| 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<int32_t, 4> a); | |||||
| // Casts | |||||
| static Vector cast(Vector<int32_t, 4> a); | |||||
| }; | |||||
| template <> | |||||
| struct Vector<int32_t, 4> { | |||||
| 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<float, 4> a); | |||||
| static Vector cast(Vector<float, 4> a); | |||||
| }; | |||||
| // Conversions and casts | |||||
| inline Vector<float, 4>::Vector(Vector<int32_t, 4> a) { | |||||
| v = _mm_cvtepi32_ps(a.v); | |||||
| } | |||||
| inline Vector<int32_t, 4>::Vector(Vector<float, 4> a) { | |||||
| v = _mm_cvttps_epi32(a.v); | |||||
| } | |||||
| inline Vector<float, 4> Vector<float, 4>::cast(Vector<int32_t, 4> a) { | |||||
| return Vector(_mm_castsi128_ps(a.v)); | |||||
| } | |||||
| inline Vector<int32_t, 4> Vector<int32_t, 4>::cast(Vector<float, 4> a) { | |||||
| return Vector(_mm_castps_si128(a.v)); | |||||
| } | |||||
| // Operator overloads | |||||
| /** `a @ b` */ | |||||
| #define DECLARE_VECTOR_OPERATOR_INFIX(t, s, operator, func) \ | |||||
| inline Vector<t, s> operator(const Vector<t, s>& a, const Vector<t, s>& b) { \ | |||||
| return Vector<t, s>(func(a.v, b.v)); \ | |||||
| } | |||||
| /** `a @= b` */ | |||||
| #define DECLARE_VECTOR_OPERATOR_INCREMENT(t, s, operator, opfunc) \ | |||||
| inline Vector<t, s>& operator(Vector<t, s>& a, const Vector<t, s>& 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<int32_t, 4> operator>=(const Vector<int32_t, 4>& a, const Vector<int32_t, 4>& b) { | |||||
| return Vector<int32_t, 4>(_mm_cmpgt_epi32(a.v, b.v)) ^ Vector<int32_t, 4>::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<int32_t, 4> operator<=(const Vector<int32_t, 4>& a, const Vector<int32_t, 4>& b) { | |||||
| return Vector<int32_t, 4>(_mm_cmplt_epi32(a.v, b.v)) ^ Vector<int32_t, 4>::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<int32_t, 4> operator!=(const Vector<int32_t, 4>& a, const Vector<int32_t, 4>& b) { | |||||
| return Vector<int32_t, 4>(_mm_cmpeq_epi32(a.v, b.v)) ^ Vector<int32_t, 4>::mask(); | |||||
| } | |||||
| /** `+a` */ | |||||
| inline Vector<float, 4> operator+(const Vector<float, 4>& a) { | |||||
| return a; | |||||
| } | |||||
| inline Vector<int32_t, 4> operator+(const Vector<int32_t, 4>& a) { | |||||
| return a; | |||||
| } | |||||
| /** `-a` */ | |||||
| inline Vector<float, 4> operator-(const Vector<float, 4>& a) { | |||||
| return 0.f - a; | |||||
| } | |||||
| inline Vector<int32_t, 4> operator-(const Vector<int32_t, 4>& a) { | |||||
| return 0 - a; | |||||
| } | |||||
| /** `++a` */ | |||||
| inline Vector<float, 4>& operator++(Vector<float, 4>& a) { | |||||
| return a += 1.f; | |||||
| } | |||||
| inline Vector<int32_t, 4>& operator++(Vector<int32_t, 4>& a) { | |||||
| return a += 1; | |||||
| } | |||||
| /** `--a` */ | |||||
| inline Vector<float, 4>& operator--(Vector<float, 4>& a) { | |||||
| return a -= 1.f; | |||||
| } | |||||
| inline Vector<int32_t, 4>& operator--(Vector<int32_t, 4>& a) { | |||||
| return a -= 1; | |||||
| } | |||||
| /** `a++` */ | |||||
| inline Vector<float, 4> operator++(Vector<float, 4>& a, int) { | |||||
| Vector<float, 4> b = a; | |||||
| ++a; | |||||
| return b; | |||||
| } | |||||
| inline Vector<int32_t, 4> operator++(Vector<int32_t, 4>& a, int) { | |||||
| Vector<int32_t, 4> b = a; | |||||
| ++a; | |||||
| return b; | |||||
| } | |||||
| /** `a--` */ | |||||
| inline Vector<float, 4> operator--(Vector<float, 4>& a, int) { | |||||
| Vector<float, 4> b = a; | |||||
| --a; | |||||
| return b; | |||||
| } | |||||
| inline Vector<int32_t, 4> operator--(Vector<int32_t, 4>& a, int) { | |||||
| Vector<int32_t, 4> b = a; | |||||
| --a; | |||||
| return b; | |||||
| } | |||||
| /** `~a` */ | |||||
| inline Vector<float, 4> operator~(const Vector<float, 4>& a) { | |||||
| return a ^ Vector<float, 4>::mask(); | |||||
| } | |||||
| inline Vector<int32_t, 4> operator~(const Vector<int32_t, 4>& a) { | |||||
| return a ^ Vector<int32_t, 4>::mask(); | |||||
| } | |||||
| /** `a << b` */ | |||||
| inline Vector<int32_t, 4> operator<<(const Vector<int32_t, 4>& a, const int& b) { | |||||
| return Vector<int32_t, 4>(_mm_slli_epi32(a.v, b)); | |||||
| } | |||||
| /** `a >> b` */ | |||||
| inline Vector<int32_t, 4> operator>>(const Vector<int32_t, 4>& a, const int& b) { | |||||
| return Vector<int32_t, 4>(_mm_srli_epi32(a.v, b)); | |||||
| } | |||||
| // Typedefs | |||||
| using float_4 = Vector<float, 4>; | |||||
| using int32_4 = Vector<int32_t, 4>; | |||||
| } // namespace simd | |||||
| } // namespace rack | |||||
| @@ -1,19 +1,124 @@ | |||||
| cmake_minimum_required(VERSION 3.15) | cmake_minimum_required(VERSION 3.15) | ||||
| project(Cardinal VERSION 0.0.0) | |||||
| project(Cardinal VERSION 22.03) | |||||
| add_subdirectory(JUCE) | 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 | # FX variant | ||||
| juce_add_plugin(CardinalFX | 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 | 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_MANUFACTURER_CODE Dstr | ||||
| PLUGIN_CODE dCnF | |||||
| FORMATS VST3 AU | |||||
| PRODUCT_NAME "CardinalFX") | PRODUCT_NAME "CardinalFX") | ||||
| target_sources(CardinalFX | target_sources(CardinalFX | ||||
| @@ -22,26 +127,152 @@ target_sources(CardinalFX | |||||
| target_include_directories(CardinalFX | target_include_directories(CardinalFX | ||||
| PRIVATE | PRIVATE | ||||
| . | |||||
| ../dpf/distrho) | |||||
| ../dpf/distrho | |||||
| ../src/CardinalFX) | |||||
| target_compile_definitions(CardinalFX | target_compile_definitions(CardinalFX | ||||
| PUBLIC | 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_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) | 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 | target_link_libraries(CardinalFX | ||||
| PRIVATE | PRIVATE | ||||
| juce::juce_audio_utils | 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 | PUBLIC | ||||
| juce::juce_recommended_config_flags | juce::juce_recommended_config_flags | ||||
| juce::juce_recommended_lto_flags | juce::juce_recommended_lto_flags | ||||
| juce::juce_recommended_warning_flags) | juce::juce_recommended_warning_flags) | ||||
| # Synth variant | # 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) | |||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
| * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
| * modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
| @@ -17,46 +17,62 @@ | |||||
| #include <juce_audio_processors/juce_audio_processors.h> | #include <juce_audio_processors/juce_audio_processors.h> | ||||
| #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/DistrhoPluginInternal.hpp" | ||||
| #include "src/DistrhoUIInternal.hpp" | |||||
| START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
| // ----------------------------------------------------------------------------------------------------------- | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| class ParameterForDPF : public juce::AudioProcessorParameter | |||||
| class ParameterFromDPF : public juce::AudioProcessorParameter | |||||
| { | { | ||||
| PluginExporter& plugin; | PluginExporter& plugin; | ||||
| const ParameterEnumerationValues& enumValues; | |||||
| const ParameterRanges& ranges; | |||||
| const uint32_t hints; | |||||
| const uint index; | const uint index; | ||||
| bool* const updatedPtr; | |||||
| mutable juce::StringArray dpfValueStrings; | |||||
| public: | public: | ||||
| ParameterForDPF(PluginExporter& plugin_, const uint index_) | |||||
| ParameterFromDPF(PluginExporter& plugin_, const uint index_, bool* const updatedPtr_) | |||||
| : plugin(plugin_), | : 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: | protected: | ||||
| float getValue() const override | float getValue() const override | ||||
| { | { | ||||
| return plugin.getParameterRanges(index).getNormalizedValue(plugin.getParameterValue(index)); | |||||
| return ranges.getNormalizedValue(plugin.getParameterValue(index)); | |||||
| } | } | ||||
| void setValue(const float newValue) override | 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 | 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<size_t>(maximumStringLength)); | |||||
| } | } | ||||
| juce::String getLabel() const override | juce::String getLabel() const override | ||||
| @@ -64,40 +80,219 @@ protected: | |||||
| return plugin.getParameterUnit(index).buffer(); | 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; | 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<size_t>(maximumStringLength)); | |||||
| } | |||||
| } | |||||
| } | |||||
| juce::String text; | |||||
| if (hints & kParameterIsInteger) | |||||
| text = juce::String(static_cast<int>(value)); | |||||
| else | |||||
| text = juce::String(value); | |||||
| if (maximumStringLength <= 0) | |||||
| return text; | |||||
| return juce::String(text.toRawUTF8(), static_cast<size_t>(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<int>(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<int>(ranges.min))); | |||||
| dpfValueStrings.add(juce::String(static_cast<int>(ranges.max))); | |||||
| } | |||||
| else | |||||
| { | |||||
| dpfValueStrings.add(juce::String(ranges.min)); | |||||
| dpfValueStrings.add(juce::String(ranges.max)); | |||||
| } | |||||
| } | |||||
| else if (hints & kParameterIsInteger) | |||||
| { | |||||
| const int imin = static_cast<int>(ranges.min); | |||||
| const int imax = static_cast<int>(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: | public: | ||||
| CardinalWrapperProcessor() | CardinalWrapperProcessor() | ||||
| : plugin(this, writeMidiCb, requestParameterValueChangeCb) | |||||
| : plugin(this, writeMidiFunc, nullRequestParameterValueChangeFunc, nullUpdateStateValueFunc), | |||||
| parameterCount(plugin.getParameterCount()), | |||||
| bypassParameter(nullptr), | |||||
| currentMidiMessages(nullptr), | |||||
| updatedParameters(nullptr) | |||||
| { | { | ||||
| for (uint i=0; i<plugin.getParameterCount(); ++i) | |||||
| addParameter(new ParameterForDPF(plugin, i)); | |||||
| if (const double sampleRate = getSampleRate()) | |||||
| if (sampleRate > 0.0) | |||||
| plugin.setSampleRate(sampleRate); | |||||
| if (const int samplesPerBlock = getBlockSize()) | |||||
| if (samplesPerBlock > 0) | |||||
| plugin.setBufferSize(static_cast<uint32_t>(samplesPerBlock)); | |||||
| if (parameterCount != 0) | |||||
| { | |||||
| updatedParameters = new bool[parameterCount]; | |||||
| std::memset(updatedParameters, 0, sizeof(bool)*parameterCount); | |||||
| for (uint i=0; i<parameterCount; ++i) | |||||
| { | |||||
| ParameterFromDPF* const param = new ParameterFromDPF(plugin, i, updatedParameters + i); | |||||
| addParameter(param); | |||||
| if (plugin.getParameterDesignation(i) == kParameterDesignationBypass) | |||||
| bypassParameter = param; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| ~CardinalWrapperProcessor() override | ~CardinalWrapperProcessor() override | ||||
| { | { | ||||
| delete[] updatedParameters; | |||||
| } | } | ||||
| protected: | |||||
| const juce::String getName() const override | const juce::String getName() const override | ||||
| { | { | ||||
| return plugin.getName(); | return plugin.getName(); | ||||
| @@ -108,11 +303,13 @@ public: | |||||
| return juce::StringArray(plugin.getLabel()); | return juce::StringArray(plugin.getLabel()); | ||||
| } | } | ||||
| void prepareToPlay(double sampleRate, int samplesPerBlock) override | |||||
| void prepareToPlay(const double sampleRate, const int samplesPerBlock) override | |||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(samplesPerBlock > 0,); | |||||
| plugin.deactivateIfNeeded(); | plugin.deactivateIfNeeded(); | ||||
| plugin.setSampleRate(sampleRate); | plugin.setSampleRate(sampleRate); | ||||
| plugin.setBufferSize(samplesPerBlock); | |||||
| plugin.setBufferSize(static_cast<uint32_t>(samplesPerBlock)); | |||||
| plugin.activate(); | plugin.activate(); | ||||
| } | } | ||||
| @@ -123,13 +320,100 @@ public: | |||||
| void processBlock(juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages) override | void processBlock(juce::AudioBuffer<float>& 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<int>(MidiEvent::kDataSize)) | |||||
| continue; | |||||
| MidiEvent& midiEvent(midiEvents[midiEventCount++]); | |||||
| midiEvent.frame = static_cast<uint32_t>(midiMessage.samplePosition); | |||||
| midiEvent.size = (static_cast<uint8_t>(midiMessage.numBytes)); | |||||
| std::memcpy(midiEvent.data, midiMessage.data, midiEvent.size); | |||||
| if (midiEventCount == kMaxMidiEvents) | |||||
| break; | |||||
| } | |||||
| midiMessages.clear(); | midiMessages.clear(); | ||||
| // AudioPlayHead* getPlayHead() | |||||
| const juce::ScopedValueSetter<juce::MidiBuffer*> 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<uint64_t>(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<int32_t>(ppqPos) / ppqPerBar + 1; | |||||
| timePosition.bbt.beat = static_cast<int32_t>(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<uint32_t>(numSamples), midiEvents, midiEventCount); | |||||
| } | } | ||||
| // fix compiler warning | |||||
| void processBlock(juce::AudioBuffer<double>&, juce::MidiBuffer&) override {} | |||||
| double getTailLengthSeconds() const override | double getTailLengthSeconds() const override | ||||
| { | { | ||||
| return true; | |||||
| return 0.0; | |||||
| } | } | ||||
| bool acceptsMidi() const override | bool acceptsMidi() const override | ||||
| @@ -142,6 +426,11 @@ public: | |||||
| return true; | return true; | ||||
| } | } | ||||
| juce::AudioProcessorParameter* getBypassParameter() const override | |||||
| { | |||||
| return bypassParameter; | |||||
| } | |||||
| juce::AudioProcessorEditor* createEditor() override; | juce::AudioProcessorEditor* createEditor() override; | ||||
| bool hasEditor() const override | bool hasEditor() const override | ||||
| @@ -151,7 +440,7 @@ public: | |||||
| int getNumPrograms() override | int getNumPrograms() override | ||||
| { | { | ||||
| return 0; | |||||
| return 1; | |||||
| } | } | ||||
| int getCurrentProgram() override | int getCurrentProgram() override | ||||
| @@ -165,7 +454,7 @@ public: | |||||
| const juce::String getProgramName(int) override | const juce::String getProgramName(int) override | ||||
| { | { | ||||
| return {}; | |||||
| return "Default"; | |||||
| } | } | ||||
| void changeProgramName(int, const juce::String&) override | void changeProgramName(int, const juce::String&) override | ||||
| @@ -174,37 +463,219 @@ public: | |||||
| void getStateInformation(juce::MemoryBlock& destData) override | void getStateInformation(juce::MemoryBlock& destData) override | ||||
| { | { | ||||
| juce::XmlElement xmlState("CardinalState"); | |||||
| for (uint32_t i=0; i<parameterCount; ++i) | |||||
| xmlState.setAttribute(plugin.getParameterSymbol(i).buffer(), plugin.getParameterValue(i)); | |||||
| for (uint32_t i=0, stateCount=plugin.getStateCount(); i<stateCount; ++i) | |||||
| { | |||||
| const String& key(plugin.getStateKey(i)); | |||||
| xmlState.setAttribute(key.buffer(), plugin.getStateValue(key).buffer()); | |||||
| } | |||||
| copyXmlToBinary(xmlState, destData); | |||||
| } | |||||
| void setStateInformation(const void* const data, const int sizeInBytes) override | |||||
| { | |||||
| std::unique_ptr<juce::XmlElement> xmlState(getXmlFromBinary(data, sizeInBytes)); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(xmlState.get() != nullptr,); | |||||
| const juce::Array<juce::AudioProcessorParameter*>& parameters(getParameters()); | |||||
| for (uint32_t i=0; i<parameterCount; ++i) | |||||
| { | |||||
| const double value = xmlState->getDoubleAttribute(plugin.getParameterSymbol(i).buffer(), | |||||
| plugin.getParameterDefault(i)); | |||||
| const float normalizedValue = plugin.getParameterRanges(i).getFixedAndNormalizedValue(value); | |||||
| parameters.getUnchecked(static_cast<int>(i))->setValueNotifyingHost(normalizedValue); | |||||
| } | |||||
| for (uint32_t i=0, stateCount=plugin.getStateCount(); i<stateCount; ++i) | |||||
| { | |||||
| const String& key(plugin.getStateKey(i)); | |||||
| const juce::String value = xmlState->getStringAttribute(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<CardinalWrapperProcessor*>(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<int>(midiEvent.size), | |||||
| static_cast<int>(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: | 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 | ~CardinalWrapperEditor() override | ||||
| {} | |||||
| { | |||||
| stopTimer(); | |||||
| delete ui; | |||||
| } | |||||
| protected: | |||||
| void timerCallback() override | |||||
| { | |||||
| if (ui == nullptr) | |||||
| return; | |||||
| for (uint32_t i=0; i<cardinalProcessor.parameterCount; ++i) | |||||
| { | |||||
| if (cardinalProcessor.updatedParameters[i]) | |||||
| { | |||||
| cardinalProcessor.updatedParameters[i] = false; | |||||
| ui->parameterChanged(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<CardinalWrapperEditor*>(ptr); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(editor != nullptr,); | |||||
| CardinalWrapperProcessor& cardinalProcessor(editor->cardinalProcessor); | |||||
| if (started) | |||||
| cardinalProcessor.getParameters().getUnchecked(static_cast<int>(index))->beginChangeGesture(); | |||||
| else | |||||
| cardinalProcessor.getParameters().getUnchecked(static_cast<int>(index))->endChangeGesture(); | |||||
| } | |||||
| static void setParamFunc(void* const ptr, const uint32_t index, const float value) | |||||
| { | |||||
| CardinalWrapperEditor* const editor = static_cast<CardinalWrapperEditor*>(ptr); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(editor != nullptr,); | |||||
| CardinalWrapperProcessor& cardinalProcessor(editor->cardinalProcessor); | |||||
| const juce::Array<juce::AudioProcessorParameter*>& parameters(cardinalProcessor.getParameters()); | |||||
| juce::AudioProcessorParameter* const parameter = parameters.getUnchecked(static_cast<int>(index)); | |||||
| static_cast<ParameterFromDPF*>(parameter)->setValueNotifyingHostFromDPF(value); | |||||
| } | |||||
| static void setStateFunc(void* const ptr, const char* const key, const char* const value) | |||||
| { | |||||
| CardinalWrapperEditor* const editor = static_cast<CardinalWrapperEditor*>(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<CardinalWrapperEditor*>(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<int>(width), static_cast<int>(height)); | |||||
| } | |||||
| }; | }; | ||||
| // ----------------------------------------------------------------------------------------------------------- | |||||
| juce::AudioProcessorEditor* CardinalWrapperProcessor::createEditor() | |||||
| { | |||||
| return new CardinalWrapperEditor(*this); | |||||
| } | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | END_NAMESPACE_DISTRHO | ||||
| // ----------------------------------------------------------------------------------------------------------- | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| juce::AudioProcessor* createPluginFilter() | juce::AudioProcessor* createPluginFilter() | ||||
| { | { | ||||
| // set valid but dummy values | |||||
| d_nextBufferSize = 512; | |||||
| d_nextSampleRate = 48000.0; | |||||
| return new DISTRHO_NAMESPACE::CardinalWrapperProcessor; | return new DISTRHO_NAMESPACE::CardinalWrapperProcessor; | ||||
| } | } | ||||
| // ----------------------------------------------------------------------------------------------------------- | |||||
| #define DISTRHO_IS_STANDALONE 0 | |||||
| #include "src/DistrhoPlugin.cpp" | |||||
| #include "src/DistrhoUtils.cpp" | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| @@ -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": "<?xml version='1.0' encoding='UTF-8'?>\n<!DOCTYPE CARLA-PROJECT>\n<CARLA-PROJECT VERSION='2.4'>\n <EngineSettings>\n <ForceStereo>false</ForceStereo>\n <PreferPluginBridges>false</PreferPluginBridges>\n <PreferUiBridges>false</PreferUiBridges>\n <UIsAlwaysOnTop>true</UIsAlwaysOnTop>\n <MaxParameters>200</MaxParameters>\n <UIBridgesTimeout>4000</UIBridgesTimeout>\n <LADSPA_PATH></LADSPA_PATH>\n <DSSI_PATH></DSSI_PATH>\n <LV2_PATH></LV2_PATH>\n <VST2_PATH></VST2_PATH>\n <VST3_PATH></VST3_PATH>\n <SF2_PATH></SF2_PATH>\n <SFZ_PATH></SFZ_PATH>\n <JSFX_PATH></JSFX_PATH>\n </EngineSettings>\n\n <Patchbay>\n </Patchbay>\n</CARLA-PROJECT>\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" | |||||
| } | |||||
| ] | |||||
| } | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit 4ace0a1789c577ee4eb12dc03da5271f80598d62 | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit 9d41fe882ab5029100b55c98ba7f10172d452795 | |||||
| @@ -1 +1 @@ | |||||
| Subproject commit 35b89c93152ac2194eecffbd4aa39e71caa90cc0 | |||||
| Subproject commit 21a031870db2068a98d9690eaffc24bbbfc99c2e | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit 890448f087e3ab47eac391f9bcfe03f7bbd2123e | |||||
| @@ -1 +1 @@ | |||||
| Subproject commit 0a6c390eedf98884393f82cb066038a78a316ea5 | |||||
| Subproject commit 9d35b745af8569d6a9d6bc5c3f2c3e64c852d8e0 | |||||
| @@ -1 +1 @@ | |||||
| Subproject commit ec406ce181f340bce8e475cb508c4db0db02fdc6 | |||||
| Subproject commit 7e0b020000225e3d2aecba3f09054595339fe540 | |||||
| @@ -1 +1 @@ | |||||
| Subproject commit e55fcd2e1d7c0fef69d4919baac6f791172c89ca | |||||
| Subproject commit f771bf270393b8587516329614ba76e2894355b7 | |||||
| @@ -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(); | |||||
| } | |||||
| @@ -1 +1 @@ | |||||
| Subproject commit 8e982f462c4117f84794cbf6a13740992ff17d92 | |||||
| Subproject commit a86e7d7b18e0c7cb6e857df36263b0e85bf85566 | |||||
| @@ -99,7 +99,7 @@ struct CarlaInternalPluginModule : Module, Thread { | |||||
| float dataOut[NUM_OUTPUTS][BUFFER_SIZE]; | float dataOut[NUM_OUTPUTS][BUFFER_SIZE]; | ||||
| float* dataOutPtr[NUM_OUTPUTS]; | float* dataOutPtr[NUM_OUTPUTS]; | ||||
| unsigned audioDataFill = 0; | unsigned audioDataFill = 0; | ||||
| int64_t lastBlockFrame = -1; | |||||
| uint32_t lastProcessCounter = 0; | |||||
| bool fileChanged = false; | bool fileChanged = false; | ||||
| std::string currentFile; | std::string currentFile; | ||||
| @@ -300,12 +300,12 @@ struct CarlaInternalPluginModule : Module, Thread { | |||||
| if (audioDataFill == BUFFER_SIZE) | 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 | // Update time position if running a new audio block | ||||
| if (lastBlockFrame != blockFrame) | |||||
| if (lastProcessCounter != processCounter) | |||||
| { | { | ||||
| lastBlockFrame = blockFrame; | |||||
| lastProcessCounter = processCounter; | |||||
| fCarlaTimeInfo.playing = pcontext->playing; | fCarlaTimeInfo.playing = pcontext->playing; | ||||
| fCarlaTimeInfo.frame = pcontext->frame; | fCarlaTimeInfo.frame = pcontext->frame; | ||||
| } | } | ||||
| @@ -95,10 +95,15 @@ struct CarlaModule : Module { | |||||
| float* dataInPtr[NUM_INPUTS]; | float* dataInPtr[NUM_INPUTS]; | ||||
| float* dataOutPtr[NUM_OUTPUTS]; | float* dataOutPtr[NUM_OUTPUTS]; | ||||
| unsigned audioDataFill = 0; | unsigned audioDataFill = 0; | ||||
| int64_t lastBlockFrame = -1; | |||||
| uint32_t lastProcessCounter = 0; | |||||
| CardinalExpanderFromCarlaMIDIToCV* midiOutExpander = nullptr; | CardinalExpanderFromCarlaMIDIToCV* midiOutExpander = nullptr; | ||||
| std::string patchStorage; | std::string patchStorage; | ||||
| #ifdef CARLA_OS_WIN | |||||
| // must keep string pointer valid | |||||
| std::string winResourceDir; | |||||
| #endif | |||||
| CarlaModule() | CarlaModule() | ||||
| : pcontext(static_cast<CardinalPluginContext*>(APP)) | : pcontext(static_cast<CardinalPluginContext*>(APP)) | ||||
| { | { | ||||
| @@ -138,10 +143,14 @@ struct CarlaModule : Module { | |||||
| binaryDir = "/Applications/Carla.app/Contents/MacOS"; | binaryDir = "/Applications/Carla.app/Contents/MacOS"; | ||||
| resourceDir = "/Applications/Carla.app/Contents/MacOS/resources"; | 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 | #else | ||||
| if (system::exists("/usr/local/lib/carla")) | if (system::exists("/usr/local/lib/carla")) | ||||
| @@ -318,12 +327,12 @@ struct CarlaModule : Module { | |||||
| if (audioDataFill == BUFFER_SIZE) | 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 | // Update time position if running a new audio block | ||||
| if (lastBlockFrame != blockFrame) | |||||
| if (lastProcessCounter != processCounter) | |||||
| { | { | ||||
| lastBlockFrame = blockFrame; | |||||
| lastProcessCounter = processCounter; | |||||
| fCarlaTimeInfo.playing = pcontext->playing; | fCarlaTimeInfo.playing = pcontext->playing; | ||||
| fCarlaTimeInfo.frame = pcontext->frame; | fCarlaTimeInfo.frame = pcontext->frame; | ||||
| fCarlaTimeInfo.bbt.valid = pcontext->bbtValid; | fCarlaTimeInfo.bbt.valid = pcontext->bbtValid; | ||||
| @@ -29,18 +29,16 @@ struct HostAudio : TerminalModule { | |||||
| const int numParams; | const int numParams; | ||||
| const int numInputs; | const int numInputs; | ||||
| const int numOutputs; | 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 | // for rack core audio module compatibility | ||||
| dsp::RCFilter dcFilters[numIO]; | dsp::RCFilter dcFilters[numIO]; | ||||
| bool dcFilterEnabled = (numIO == 2); | bool dcFilterEnabled = (numIO == 2); | ||||
| // for stereo meter | |||||
| volatile bool resetMeters = true; | |||||
| float gainMeterL = 0.0f; | |||||
| float gainMeterR = 0.0f; | |||||
| HostAudio() | HostAudio() | ||||
| : pcontext(static_cast<CardinalPluginContext*>(APP)), | : pcontext(static_cast<CardinalPluginContext*>(APP)), | ||||
| numParams(numIO == 2 ? 1 : 0), | numParams(numIO == 2 ? 1 : 0), | ||||
| @@ -63,35 +61,39 @@ struct HostAudio : TerminalModule { | |||||
| void onReset() override | void onReset() override | ||||
| { | { | ||||
| dcFilterEnabled = (numIO == 2); | dcFilterEnabled = (numIO == 2); | ||||
| resetMeters = true; | |||||
| } | } | ||||
| void onSampleRateChange(const SampleRateChangeEvent& e) override | void onSampleRateChange(const SampleRateChangeEvent& e) override | ||||
| { | { | ||||
| resetMeters = true; | |||||
| for (int i=0; i<numIO; ++i) | for (int i=0; i<numIO; ++i) | ||||
| dcFilters[i].setCutoffFreq(10.f * e.sampleTime); | dcFilters[i].setCutoffFreq(10.f * e.sampleTime); | ||||
| } | } | ||||
| void processTerminalInput(const ProcessArgs&) override | void processTerminalInput(const ProcessArgs&) override | ||||
| { | { | ||||
| const int blockFrames = pcontext->engine->getBlockFrames(); | |||||
| const int64_t blockFrame = pcontext->engine->getBlockFrame(); | |||||
| const uint32_t bufferSize = pcontext->bufferSize; | |||||
| const uint32_t processCounter = pcontext->processCounter; | |||||
| // only checked on input | // only checked on input | ||||
| if (lastBlockFrame != blockFrame) | |||||
| if (lastProcessCounter != processCounter) | |||||
| { | { | ||||
| bypassed = isBypassed(); | |||||
| dataFrame = 0; | dataFrame = 0; | ||||
| lastBlockFrame = blockFrame; | |||||
| lastProcessCounter = processCounter; | |||||
| if (numIO == 2) | |||||
| { | |||||
| in1connected = inputs[0].isConnected(); | |||||
| in2connected = inputs[1].isConnected(); | |||||
| } | |||||
| } | } | ||||
| // only incremented on output | // 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 | // from host into cardinal, shows as output plug | ||||
| if (isBypassed()) | |||||
| if (bypassed) | |||||
| { | { | ||||
| for (int i=0; i<numOutputs; ++i) | for (int i=0; i<numOutputs; ++i) | ||||
| outputs[i].setVoltage(0.0f); | outputs[i].setVoltage(0.0f); | ||||
| @@ -103,97 +105,210 @@ struct HostAudio : TerminalModule { | |||||
| } | } | ||||
| } | } | ||||
| json_t* dataToJson() override | |||||
| { | |||||
| json_t* const rootJ = json_object(); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(rootJ != nullptr, nullptr); | |||||
| json_object_set_new(rootJ, "dcFilter", json_boolean(dcFilterEnabled)); | |||||
| return rootJ; | |||||
| } | |||||
| void dataFromJson(json_t* const rootJ) override | |||||
| { | |||||
| json_t* const dcFilterJ = json_object_get(rootJ, "dcFilter"); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(dcFilterJ != nullptr,); | |||||
| dcFilterEnabled = json_boolean_value(dcFilterJ); | |||||
| } | |||||
| }; | |||||
| struct HostAudio2 : HostAudio<2> { | |||||
| #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 | 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 | // 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; | return; | ||||
| float** const dataOuts = pcontext->dataOuts; | 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<numInputs; ++i) | |||||
| valueL = clamp(valueL * gain, -1.0f, 1.0f); | |||||
| dataOuts[0][k] += valueL; | |||||
| } | |||||
| else | |||||
| { | { | ||||
| float v = inputs[i].getVoltageSum() * 0.1f; | |||||
| valueL = 0.0f; | |||||
| } | |||||
| if (in2connected) | |||||
| { | |||||
| valueR = inputs[1].getVoltageSum() * 0.1f; | |||||
| // Apply DC filter | |||||
| if (dcFilterEnabled) | if (dcFilterEnabled) | ||||
| { | { | ||||
| dcFilters[i].process(v); | |||||
| v = dcFilters[i].highpass(); | |||||
| dcFilters[1].process(valueR); | |||||
| valueR = dcFilters[1].highpass(); | |||||
| } | } | ||||
| dataOuts[i][k] += clamp(v * gain, -1.0f, 1.0f); | |||||
| valueR = clamp(valueR * gain, -1.0f, 1.0f); | |||||
| dataOuts[1][k] += valueR; | |||||
| } | } | ||||
| if (numInputs == 2) | |||||
| else if (in1connected) | |||||
| { | { | ||||
| const bool connected = inputs[1].isConnected(); | |||||
| valueR = valueL; | |||||
| dataOuts[1][k] += valueL; | |||||
| } | |||||
| #ifndef HEADLESS | |||||
| else | |||||
| { | |||||
| valueR = 0.0f; | |||||
| } | |||||
| if (! connected) | |||||
| dataOuts[1][k] += valueL; | |||||
| const uint32_t j = internalDataFrame++; | |||||
| internalDataBuffer[0][j] = valueL; | |||||
| internalDataBuffer[1][j] = valueR; | |||||
| if (dataFrame == blockFrames) | |||||
| { | |||||
| if (resetMeters) | |||||
| gainMeterL = gainMeterR = 0.0f; | |||||
| if (internalDataFrame == 128) | |||||
| { | |||||
| internalDataFrame = 0; | |||||
| gainMeterL = std::max(gainMeterL, d_findMaxNormalizedFloat(dataOuts[0], blockFrames)); | |||||
| if (resetMeters) | |||||
| gainMeterL = gainMeterR = 0.0f; | |||||
| if (connected) | |||||
| gainMeterR = std::max(gainMeterR, d_findMaxNormalizedFloat(dataOuts[1], blockFrames)); | |||||
| else | |||||
| gainMeterR = gainMeterL; | |||||
| gainMeterL = std::max(gainMeterL, d_findMaxNormalizedFloat(internalDataBuffer[0], 128)); | |||||
| resetMeters = false; | |||||
| } | |||||
| if (in2connected) | |||||
| gainMeterR = std::max(gainMeterR, d_findMaxNormalizedFloat(internalDataBuffer[1], 128)); | |||||
| else | |||||
| gainMeterR = gainMeterL; | |||||
| resetMeters = false; | |||||
| } | } | ||||
| #endif | |||||
| } | } | ||||
| }; | |||||
| json_t* dataToJson() override | |||||
| struct HostAudio8 : HostAudio<8> { | |||||
| // 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<numInputs; ++i) | |||||
| { | |||||
| float v = inputs[i].getVoltageSum() * 0.1f; | |||||
| if (dcFilterEnabled) | |||||
| { | |||||
| dcFilters[i].process(v); | |||||
| v = dcFilters[i].highpass(); | |||||
| } | |||||
| dataOuts[i][k] += clamp(v, -1.0f, 1.0f); | |||||
| } | |||||
| } | } | ||||
| void dataFromJson(json_t* const rootJ) override | |||||
| }; | |||||
| #ifndef HEADLESS | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| template<int numIO> | |||||
| struct HostAudioWidget : ModuleWidgetWith8HP { | |||||
| HostAudio<numIO>* const module; | |||||
| HostAudioWidget(HostAudio<numIO>* 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; i<numIO; ++i) | |||||
| { | |||||
| createAndAddInput(i); | |||||
| createAndAddOutput(i); | |||||
| } | |||||
| } | |||||
| void appendContextMenu(Menu* const menu) override { | |||||
| menu->addChild(new MenuSeparator); | |||||
| menu->addChild(createBoolPtrMenuItem("DC blocker", "", &module->dcFilterEnabled)); | |||||
| } | } | ||||
| }; | }; | ||||
| template<int numIO> | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| struct HostAudioNanoMeter : NanoMeter { | struct HostAudioNanoMeter : NanoMeter { | ||||
| HostAudio<numIO>* const module; | |||||
| HostAudio2* const module; | |||||
| HostAudioNanoMeter(HostAudio<numIO>* const m) | |||||
| HostAudioNanoMeter(HostAudio2* const m) | |||||
| : module(m) | : module(m) | ||||
| { | { | ||||
| hasGainKnob = true; | hasGainKnob = true; | ||||
| @@ -211,69 +326,81 @@ struct HostAudioNanoMeter : NanoMeter { | |||||
| } | } | ||||
| }; | }; | ||||
| template<int numIO> | |||||
| struct HostAudioWidget : ModuleWidgetWith8HP { | |||||
| HostAudio<numIO>* const module; | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| HostAudioWidget(HostAudio<numIO>* 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<NanoKnob>(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<numIO; ++i) | |||||
| { | |||||
| createAndAddInput(i); | |||||
| createAndAddOutput(i); | |||||
| } | |||||
| drawTextLine(args.vg, 0, "Left/M"); | |||||
| drawTextLine(args.vg, 1, "Right"); | |||||
| if (numIO == 2) | |||||
| { | |||||
| // FIXME | |||||
| const float middleX = box.size.x * 0.5f; | |||||
| addParam(createParamCentered<NanoKnob>(Vec(middleX, 310.0f), m, 0)); | |||||
| HostAudioNanoMeter<numIO>* const meter = new HostAudioNanoMeter<numIO>(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 | void draw(const DrawArgs& args) override | ||||
| { | { | ||||
| drawBackground(args.vg); | drawBackground(args.vg); | ||||
| drawOutputJacksArea(args.vg, numIO); | |||||
| drawOutputJacksArea(args.vg, 8); | |||||
| setupTextLines(args.vg); | 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<numIO; ++i) | |||||
| { | |||||
| char text[] = {'A','u','d','i','o',' ',static_cast<char>('0'+i+1),'\0'}; | |||||
| drawTextLine(args.vg, i, text); | |||||
| } | |||||
| char text[] = {'A','u','d','i','o',' ',static_cast<char>('0'+i+1),'\0'}; | |||||
| drawTextLine(args.vg, i, text); | |||||
| } | } | ||||
| ModuleWidgetWith8HP::draw(args); | 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<PJ301MPort>({}, module, i)); | |||||
| addOutput(createOutput<PJ301MPort>({}, module, i)); | |||||
| } | |||||
| } | |||||
| }; | |||||
| struct HostAudioWidget8 : ModuleWidget { | |||||
| HostAudioWidget8(HostAudio8* const module) { | |||||
| setModule(module); | |||||
| for (uint i=0; i<8; ++i) { | |||||
| addInput(createInput<PJ301MPort>({}, module, i)); | |||||
| addOutput(createOutput<PJ301MPort>({}, module, i)); | |||||
| } | |||||
| } | } | ||||
| }; | }; | ||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| #endif | |||||
| Model* modelHostAudio2 = createModel<HostAudio<2>, HostAudioWidget<2>>("HostAudio2"); | |||||
| Model* modelHostAudio8 = createModel<HostAudio<8>, HostAudioWidget<8>>("HostAudio8"); | |||||
| Model* modelHostAudio2 = createModel<HostAudio2, HostAudioWidget2>("HostAudio2"); | |||||
| Model* modelHostAudio8 = createModel<HostAudio8, HostAudioWidget8>("HostAudio8"); | |||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -27,7 +27,7 @@ USE_NAMESPACE_DISTRHO; | |||||
| struct HostCV : TerminalModule { | struct HostCV : TerminalModule { | ||||
| CardinalPluginContext* const pcontext; | CardinalPluginContext* const pcontext; | ||||
| int dataFrame = 0; | int dataFrame = 0; | ||||
| int64_t lastBlockFrame = -1; | |||||
| uint32_t lastProcessCounter = 0; | |||||
| enum ParamIds { | enum ParamIds { | ||||
| BIPOLAR_INPUTS_1_5, | BIPOLAR_INPUTS_1_5, | ||||
| @@ -64,18 +64,19 @@ struct HostCV : TerminalModule { | |||||
| if (pcontext->variant != kCardinalVariantMain) | if (pcontext->variant != kCardinalVariantMain) | ||||
| return; | return; | ||||
| const int64_t blockFrame = pcontext->engine->getBlockFrame(); | |||||
| const uint32_t bufferSize = pcontext->bufferSize; | |||||
| const uint32_t processCounter = pcontext->processCounter; | |||||
| // only checked on input | // only checked on input | ||||
| if (lastBlockFrame != blockFrame) | |||||
| if (lastProcessCounter != processCounter) | |||||
| { | { | ||||
| dataFrame = 0; | dataFrame = 0; | ||||
| lastBlockFrame = blockFrame; | |||||
| lastProcessCounter = processCounter; | |||||
| } | } | ||||
| // only incremented on output | // 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()) | if (isBypassed()) | ||||
| { | { | ||||
| @@ -102,9 +103,11 @@ struct HostCV : TerminalModule { | |||||
| if (pcontext->variant != kCardinalVariantMain) | if (pcontext->variant != kCardinalVariantMain) | ||||
| return; | return; | ||||
| const uint32_t bufferSize = pcontext->bufferSize; | |||||
| // only incremented on output | // 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()) | if (isBypassed()) | ||||
| return; | return; | ||||
| @@ -124,6 +127,7 @@ struct HostCV : TerminalModule { | |||||
| } | } | ||||
| }; | }; | ||||
| #ifndef HEADLESS | |||||
| struct HostCVWidget : ModuleWidgetWith8HP { | struct HostCVWidget : ModuleWidgetWith8HP { | ||||
| HostCVWidget(HostCV* const module) | 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<HostCV::NUM_INPUTS; ++i) | |||||
| addInput(createInput<PJ301MPort>({}, module, i)); | |||||
| for (uint i=0; i<HostCV::NUM_OUTPUTS; ++i) | |||||
| addOutput(createOutput<PJ301MPort>({}, module, i)); | |||||
| } | |||||
| }; | |||||
| #endif | |||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -62,13 +62,13 @@ struct HostMIDICC : TerminalModule { | |||||
| const MidiEvent* midiEvents; | const MidiEvent* midiEvents; | ||||
| uint32_t midiEventsLeft; | uint32_t midiEventsLeft; | ||||
| uint32_t midiEventFrame; | uint32_t midiEventFrame; | ||||
| int64_t lastBlockFrame; | |||||
| uint32_t lastProcessCounter; | |||||
| uint8_t channel; | uint8_t channel; | ||||
| uint8_t chPressure[16]; | uint8_t chPressure[16]; | ||||
| uint16_t pitchbend[16]; | uint16_t pitchbend[16]; | ||||
| // stuff from Rack | |||||
| // adapted from Rack | |||||
| /** [cc][channel] */ | /** [cc][channel] */ | ||||
| uint8_t ccValues[128][16]; | uint8_t ccValues[128][16]; | ||||
| /** When LSB is enabled for CC 0-31, the MSB is stored here until the LSB is received. | /** 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) | MidiInput(CardinalPluginContext* const pc) | ||||
| : pcontext(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(); | reset(); | ||||
| } | } | ||||
| @@ -98,40 +99,33 @@ struct HostMIDICC : TerminalModule { | |||||
| midiEvents = nullptr; | midiEvents = nullptr; | ||||
| midiEventsLeft = 0; | midiEventsLeft = 0; | ||||
| midiEventFrame = 0; | midiEventFrame = 0; | ||||
| lastBlockFrame = -1; | |||||
| lastProcessCounter = 0; | |||||
| channel = 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; | pitchbend[c] = 8192; | ||||
| } | |||||
| learningId = -1; | learningId = -1; | ||||
| smooth = true; | smooth = true; | ||||
| mpeMode = false; | mpeMode = false; | ||||
| lsbMode = false; | lsbMode = false; | ||||
| } | } | ||||
| bool process(const ProcessArgs& args, std::vector<rack::engine::Output>& outputs, int learnedCcs[16], | |||||
| bool process(const ProcessArgs& args, std::vector<rack::engine::Output>& outputs, int8_t learnedCcs[16], | |||||
| const bool isBypassed) | const bool isBypassed) | ||||
| { | { | ||||
| // Cardinal specific | // 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; | midiEvents = pcontext->midiEvents; | ||||
| midiEventsLeft = pcontext->midiEventCount; | midiEventsLeft = pcontext->midiEventCount; | ||||
| midiEventFrame = 0; | midiEventFrame = 0; | ||||
| @@ -166,27 +160,38 @@ struct HostMIDICC : TerminalModule { | |||||
| const uint8_t status = data[0] & 0xF0; | const uint8_t status = data[0] & 0xF0; | ||||
| const uint8_t chan = data[0] & 0x0F; | const uint8_t chan = data[0] & 0x0F; | ||||
| /**/ if (status == 0xD0) | |||||
| if (status == 0xD0) | |||||
| { | { | ||||
| chPressure[chan] = data[1]; | chPressure[chan] = data[1]; | ||||
| continue; | |||||
| } | } | ||||
| else if (status == 0xE0) | |||||
| if (status == 0xE0) | |||||
| { | { | ||||
| pitchbend[chan] = (data[2] << 7) | data[1]; | pitchbend[chan] = (data[2] << 7) | data[1]; | ||||
| continue; | |||||
| } | } | ||||
| else if (status != 0xB0) | |||||
| if (status != 0xB0) | |||||
| { | { | ||||
| continue; | continue; | ||||
| } | } | ||||
| // adapted from Rack | |||||
| // adapted from Rack `processCC` | |||||
| const uint8_t c = mpeMode ? chan : 0; | 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]; | const uint8_t value = data[2]; | ||||
| // Learn | // Learn | ||||
| if (learningId >= 0 && ccValues[cc][c] != value) | 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; | learnedCcs[learningId] = cc; | ||||
| learningId = -1; | learningId = -1; | ||||
| } | } | ||||
| @@ -196,7 +201,7 @@ struct HostMIDICC : TerminalModule { | |||||
| // Don't set MSB yet. Wait for LSB to be received. | // Don't set MSB yet. Wait for LSB to be received. | ||||
| msbValues[cc][c] = value; | msbValues[cc][c] = value; | ||||
| } | } | ||||
| else if (lsbMode && 32 <= cc && cc < 64) | |||||
| else if (lsbMode && cc >= 32 && cc < 64) | |||||
| { | { | ||||
| // Apply MSB when LSB is received | // Apply MSB when LSB is received | ||||
| ccValues[cc - 32][c] = msbValues[cc - 32][c]; | ccValues[cc - 32][c] = msbValues[cc - 32][c]; | ||||
| @@ -213,15 +218,21 @@ struct HostMIDICC : TerminalModule { | |||||
| // Rack stuff | // Rack stuff | ||||
| const int channels = mpeMode ? 16 : 1; | 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; | 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; | int16_t cellValue = int16_t(ccValues[cc][c]) * 128; | ||||
| if (lsbMode && cc < 32) | if (lsbMode && cc < 32) | ||||
| @@ -231,18 +242,18 @@ struct HostMIDICC : TerminalModule { | |||||
| const float value = static_cast<float>(cellValue) / (128.0f * 127.0f); | const float value = static_cast<float>(cellValue) / (128.0f * 127.0f); | ||||
| // Detect behavior from MIDI buttons. | // 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 | // Smooth value with filter | ||||
| valueFilters[i][c].process(args.sampleTime, value); | |||||
| valueFilters[id][c].process(args.sampleTime, value); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| // Jump value | // 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); | 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<float>(chPressure[c]) / 128.0f; | const float value = static_cast<float>(chPressure[c]) / 128.0f; | ||||
| @@ -274,7 +285,7 @@ struct HostMIDICC : TerminalModule { | |||||
| { | { | ||||
| outputs[CC_OUTPUT_PITCHBEND].setChannels(channels); | 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<float>(pitchbend[c]) / 16384.0f; | const float value = static_cast<float>(pitchbend[c]) / 16384.0f; | ||||
| @@ -294,7 +305,7 @@ struct HostMIDICC : TerminalModule { | |||||
| } | } | ||||
| } | } | ||||
| return blockFrameChanged; | |||||
| return processCounterChanged; | |||||
| } | } | ||||
| } midiInput; | } midiInput; | ||||
| @@ -365,7 +376,7 @@ struct HostMIDICC : TerminalModule { | |||||
| } midiOutput; | } midiOutput; | ||||
| int learnedCcs[16]; | |||||
| int8_t learnedCcs[16]; | |||||
| HostMIDICC() | HostMIDICC() | ||||
| : pcontext(static_cast<CardinalPluginContext*>(APP)), | : pcontext(static_cast<CardinalPluginContext*>(APP)), | ||||
| @@ -377,14 +388,14 @@ struct HostMIDICC : TerminalModule { | |||||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | 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_CH_PRESSURE, "Channel pressure"); | ||||
| configInput(CC_INPUT_PITCHBEND, "Pitchbend"); | 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_CH_PRESSURE, "Channel pressure"); | ||||
| configOutput(CC_OUTPUT_PITCHBEND, "Pitchbend"); | configOutput(CC_OUTPUT_PITCHBEND, "Pitchbend"); | ||||
| @@ -394,9 +405,8 @@ struct HostMIDICC : TerminalModule { | |||||
| void onReset() override | 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(); | midiInput.reset(); | ||||
| midiOutput.reset(); | midiOutput.reset(); | ||||
| } | } | ||||
| @@ -414,11 +424,13 @@ struct HostMIDICC : TerminalModule { | |||||
| if (isBypassed()) | if (isBypassed()) | ||||
| return; | 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* dataToJson() override | ||||
| { | { | ||||
| json_t* const rootJ = json_object(); | json_t* const rootJ = json_object(); | ||||
| @@ -442,8 +468,8 @@ struct HostMIDICC : TerminalModule { | |||||
| // input and output | // input and output | ||||
| if (json_t* const ccsJ = json_array()) | 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); | json_object_set_new(rootJ, "ccs", ccsJ); | ||||
| } | } | ||||
| @@ -473,12 +499,12 @@ struct HostMIDICC : TerminalModule { | |||||
| // input and output | // input and output | ||||
| if (json_t* const ccsJ = json_object_get(rootJ, "ccs")) | 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 | else | ||||
| learnedCcs[i] = i + 1; | |||||
| learnedCcs[id] = -1; | |||||
| } | } | ||||
| } | } | ||||
| @@ -524,7 +550,7 @@ struct HostMIDICC : TerminalModule { | |||||
| struct CardinalCcChoice : CardinalLedDisplayChoice { | struct CardinalCcChoice : CardinalLedDisplayChoice { | ||||
| HostMIDICC* const module; | HostMIDICC* const module; | ||||
| const int id; | const int id; | ||||
| int focusCc = -1; | |||||
| int8_t focusCc = -1; | |||||
| CardinalCcChoice(HostMIDICC* const m, const int i) | CardinalCcChoice(HostMIDICC* const m, const int i) | ||||
| : CardinalLedDisplayChoice(), | : CardinalLedDisplayChoice(), | ||||
| @@ -540,7 +566,7 @@ struct CardinalCcChoice : CardinalLedDisplayChoice { | |||||
| void step() override | void step() override | ||||
| { | { | ||||
| int cc; | |||||
| int8_t cc; | |||||
| if (module == nullptr) | if (module == nullptr) | ||||
| { | { | ||||
| @@ -583,8 +609,8 @@ struct CardinalCcChoice : CardinalLedDisplayChoice { | |||||
| if (module->midiInput.learningId == id) | 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; | module->midiInput.learningId = -1; | ||||
| } | } | ||||
| } | } | ||||
| @@ -600,7 +626,7 @@ struct CardinalCcChoice : CardinalLedDisplayChoice { | |||||
| focusCc = focusCc * 10 + (c - '0'); | focusCc = focusCc * 10 + (c - '0'); | ||||
| } | } | ||||
| if (focusCc >= 128) | |||||
| if (focusCc < 0) | |||||
| focusCc = -1; | focusCc = -1; | ||||
| e.consume(this); | e.consume(this); | ||||
| @@ -58,7 +58,7 @@ struct HostMIDIGate : TerminalModule { | |||||
| const MidiEvent* midiEvents; | const MidiEvent* midiEvents; | ||||
| uint32_t midiEventsLeft; | uint32_t midiEventsLeft; | ||||
| uint32_t midiEventFrame; | uint32_t midiEventFrame; | ||||
| int64_t lastBlockFrame; | |||||
| uint32_t lastProcessCounter; | |||||
| uint8_t channel; | uint8_t channel; | ||||
| // stuff from Rack | // stuff from Rack | ||||
| @@ -84,7 +84,7 @@ struct HostMIDIGate : TerminalModule { | |||||
| midiEvents = nullptr; | midiEvents = nullptr; | ||||
| midiEventsLeft = 0; | midiEventsLeft = 0; | ||||
| midiEventFrame = 0; | midiEventFrame = 0; | ||||
| lastBlockFrame = -1; | |||||
| lastProcessCounter = 0; | |||||
| channel = 0; | channel = 0; | ||||
| learningId = -1; | learningId = -1; | ||||
| mpeMode = false; | mpeMode = false; | ||||
| @@ -104,16 +104,15 @@ struct HostMIDIGate : TerminalModule { | |||||
| } | } | ||||
| bool process(const ProcessArgs& args, std::vector<rack::engine::Output>& outputs, | bool process(const ProcessArgs& args, std::vector<rack::engine::Output>& outputs, | ||||
| const bool velocityMode, uint8_t learnedNotes[18], const bool isBypassed) | |||||
| const bool velocityMode, int8_t learnedNotes[18], const bool isBypassed) | |||||
| { | { | ||||
| // Cardinal specific | // 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; | midiEvents = pcontext->midiEvents; | ||||
| midiEventsLeft = pcontext->midiEventCount; | midiEventsLeft = pcontext->midiEventCount; | ||||
| midiEventFrame = 0; | midiEventFrame = 0; | ||||
| @@ -122,7 +121,7 @@ struct HostMIDIGate : TerminalModule { | |||||
| if (isBypassed) | if (isBypassed) | ||||
| { | { | ||||
| ++midiEventFrame; | ++midiEventFrame; | ||||
| return blockFrameChanged; | |||||
| return processCounterChanged; | |||||
| } | } | ||||
| while (midiEventsLeft != 0) | while (midiEventsLeft != 0) | ||||
| @@ -153,17 +152,30 @@ struct HostMIDIGate : TerminalModule { | |||||
| if (data[2] > 0) | if (data[2] > 0) | ||||
| { | { | ||||
| const int c = mpeMode ? (data[0] & 0x0F) : 0; | const int c = mpeMode ? (data[0] & 0x0F) : 0; | ||||
| const int8_t note = data[1]; | |||||
| // Learn | // 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; | learningId = -1; | ||||
| } | } | ||||
| // Find id | // 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; | break; | ||||
| @@ -172,11 +184,12 @@ struct HostMIDIGate : TerminalModule { | |||||
| // note off | // note off | ||||
| case 0x80: | case 0x80: | ||||
| const int c = mpeMode ? (data[0] & 0x0F) : 0; | const int c = mpeMode ? (data[0] & 0x0F) : 0; | ||||
| const int8_t note = data[1]; | |||||
| // Find id | // 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; | break; | ||||
| } | } | ||||
| @@ -206,7 +219,7 @@ struct HostMIDIGate : TerminalModule { | |||||
| } | } | ||||
| } | } | ||||
| return blockFrameChanged; | |||||
| return processCounterChanged; | |||||
| } | } | ||||
| } midiInput; | } midiInput; | ||||
| @@ -217,7 +230,7 @@ struct HostMIDIGate : TerminalModule { | |||||
| uint8_t channel = 0; | uint8_t channel = 0; | ||||
| // base class vars | // base class vars | ||||
| int vels[128]; | |||||
| uint8_t vels[128]; | |||||
| bool lastGates[128]; | bool lastGates[128]; | ||||
| int64_t frame = 0; | int64_t frame = 0; | ||||
| @@ -230,7 +243,7 @@ struct HostMIDIGate : TerminalModule { | |||||
| void reset() | void reset() | ||||
| { | { | ||||
| // base class vars | // base class vars | ||||
| for (int note = 0; note < 128; ++note) | |||||
| for (uint8_t note = 0; note < 128; ++note) | |||||
| { | { | ||||
| vels[note] = 100; | vels[note] = 100; | ||||
| lastGates[note] = false; | lastGates[note] = false; | ||||
| @@ -245,7 +258,7 @@ struct HostMIDIGate : TerminalModule { | |||||
| // TODO send all notes off CC | // TODO send all notes off CC | ||||
| // Send all note off commands | // Send all note off commands | ||||
| for (int note = 0; note < 128; note++) | |||||
| for (uint8_t note = 0; note < 128; note++) | |||||
| { | { | ||||
| // Note off | // Note off | ||||
| midi::Message m; | 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; | vels[note] = vel; | ||||
| } | } | ||||
| void setGate(bool gate, int note) | |||||
| void setGate(uint8_t note, bool gate) | |||||
| { | { | ||||
| if (gate && !lastGates[note]) | if (gate && !lastGates[note]) | ||||
| { | { | ||||
| @@ -296,7 +309,8 @@ struct HostMIDIGate : TerminalModule { | |||||
| } midiOutput; | } midiOutput; | ||||
| bool velocityMode = false; | bool velocityMode = false; | ||||
| uint8_t learnedNotes[18] = {}; | |||||
| int8_t learnedNotes[18] = {}; | |||||
| dsp::SchmittTrigger cellTriggers[18]; | |||||
| HostMIDIGate() | HostMIDIGate() | ||||
| : pcontext(static_cast<CardinalPluginContext*>(APP)), | : pcontext(static_cast<CardinalPluginContext*>(APP)), | ||||
| @@ -308,19 +322,19 @@ struct HostMIDIGate : TerminalModule { | |||||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | 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(); | onReset(); | ||||
| } | } | ||||
| void onReset() override | 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; | velocityMode = false; | ||||
| @@ -341,24 +355,39 @@ struct HostMIDIGate : TerminalModule { | |||||
| if (isBypassed()) | if (isBypassed()) | ||||
| return; | 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) | 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 | 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 | json_t* dataToJson() override | ||||
| @@ -369,8 +398,8 @@ struct HostMIDIGate : TerminalModule { | |||||
| // input and output | // input and output | ||||
| if (json_t* const notesJ = json_array()) | 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, "notes", notesJ); | ||||
| } | } | ||||
| json_object_set_new(rootJ, "velocity", json_boolean(velocityMode)); | json_object_set_new(rootJ, "velocity", json_boolean(velocityMode)); | ||||
| @@ -390,12 +419,12 @@ struct HostMIDIGate : TerminalModule { | |||||
| // input and output | // input and output | ||||
| if (json_t* const notesJ = json_object_get(rootJ, "notes")) | 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 | else | ||||
| learnedNotes[i] = -1; | |||||
| learnedNotes[id] = -1; | |||||
| } | } | ||||
| } | } | ||||
| @@ -430,7 +459,7 @@ struct HostMIDIGate : TerminalModule { | |||||
| struct CardinalNoteChoice : CardinalLedDisplayChoice { | struct CardinalNoteChoice : CardinalLedDisplayChoice { | ||||
| HostMIDIGate* const module; | HostMIDIGate* const module; | ||||
| const int id; | const int id; | ||||
| int focusNote = -1; | |||||
| int8_t focusNote = -1; | |||||
| CardinalNoteChoice(HostMIDIGate* const m, const int i) | CardinalNoteChoice(HostMIDIGate* const m, const int i) | ||||
| : CardinalLedDisplayChoice(), | : CardinalLedDisplayChoice(), | ||||
| @@ -439,7 +468,7 @@ struct CardinalNoteChoice : CardinalLedDisplayChoice { | |||||
| void step() override | void step() override | ||||
| { | { | ||||
| int note; | |||||
| int8_t note; | |||||
| if (module == nullptr) | if (module == nullptr) | ||||
| { | { | ||||
| @@ -489,8 +518,8 @@ struct CardinalNoteChoice : CardinalLedDisplayChoice { | |||||
| if (module->midiInput.learningId == id) | 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; | module->midiInput.learningId = -1; | ||||
| } | } | ||||
| } | } | ||||
| @@ -518,7 +547,7 @@ struct CardinalNoteChoice : CardinalLedDisplayChoice { | |||||
| } | } | ||||
| } | } | ||||
| if (focusNote >= 128) | |||||
| if (focusNote < 0) | |||||
| focusNote = -1; | focusNote = -1; | ||||
| e.consume(this); | e.consume(this); | ||||
| @@ -55,7 +55,7 @@ struct HostMIDIMap : TerminalModule { | |||||
| const MidiEvent* midiEvents; | const MidiEvent* midiEvents; | ||||
| uint32_t midiEventsLeft; | uint32_t midiEventsLeft; | ||||
| uint32_t midiEventFrame; | uint32_t midiEventFrame; | ||||
| int64_t lastBlockFrame; | |||||
| uint32_t lastProcessCounter; | |||||
| int nextLearningId; | int nextLearningId; | ||||
| uint8_t channel; | uint8_t channel; | ||||
| @@ -117,7 +117,7 @@ struct HostMIDIMap : TerminalModule { | |||||
| midiEvents = nullptr; | midiEvents = nullptr; | ||||
| midiEventsLeft = 0; | midiEventsLeft = 0; | ||||
| midiEventFrame = 0; | midiEventFrame = 0; | ||||
| lastBlockFrame = -1; | |||||
| lastProcessCounter = 0; | |||||
| nextLearningId = -1; | nextLearningId = -1; | ||||
| channel = 0; | channel = 0; | ||||
| @@ -134,13 +134,12 @@ struct HostMIDIMap : TerminalModule { | |||||
| void processTerminalInput(const ProcessArgs& args) override | void processTerminalInput(const ProcessArgs& args) override | ||||
| { | { | ||||
| // Cardinal specific | // 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; | midiEvents = pcontext->midiEvents; | ||||
| midiEventsLeft = pcontext->midiEventCount; | midiEventsLeft = pcontext->midiEventCount; | ||||
| midiEventFrame = 0; | midiEventFrame = 0; | ||||
| @@ -81,11 +81,13 @@ struct HostMIDI : TerminalModule { | |||||
| const MidiEvent* midiEvents; | const MidiEvent* midiEvents; | ||||
| uint32_t midiEventsLeft; | uint32_t midiEventsLeft; | ||||
| uint32_t midiEventFrame; | uint32_t midiEventFrame; | ||||
| int64_t lastBlockFrame; | |||||
| uint32_t lastProcessCounter; | |||||
| bool wasPlaying; | bool wasPlaying; | ||||
| uint8_t channel; | uint8_t channel; | ||||
| // stuff from Rack | // stuff from Rack | ||||
| /** Number of semitones to bend up/down by pitch wheel */ | |||||
| float pwRange; | |||||
| bool smooth; | bool smooth; | ||||
| int channels; | int channels; | ||||
| enum PolyMode { | enum PolyMode { | ||||
| @@ -120,6 +122,7 @@ struct HostMIDI : TerminalModule { | |||||
| dsp::PulseGenerator startPulse; | dsp::PulseGenerator startPulse; | ||||
| dsp::PulseGenerator stopPulse; | dsp::PulseGenerator stopPulse; | ||||
| dsp::PulseGenerator continuePulse; | dsp::PulseGenerator continuePulse; | ||||
| dsp::PulseGenerator retriggerPulses[16]; | |||||
| MidiInput(CardinalPluginContext* const pc) | MidiInput(CardinalPluginContext* const pc) | ||||
| : pcontext(pc) | : pcontext(pc) | ||||
| @@ -138,12 +141,13 @@ struct HostMIDI : TerminalModule { | |||||
| midiEvents = nullptr; | midiEvents = nullptr; | ||||
| midiEventsLeft = 0; | midiEventsLeft = 0; | ||||
| midiEventFrame = 0; | midiEventFrame = 0; | ||||
| lastBlockFrame = -1; | |||||
| lastProcessCounter = 0; | |||||
| wasPlaying = false; | wasPlaying = false; | ||||
| channel = 0; | channel = 0; | ||||
| smooth = true; | |||||
| smooth = false; | |||||
| channels = 1; | channels = 1; | ||||
| polyMode = ROTATE_MODE; | polyMode = ROTATE_MODE; | ||||
| pwRange = 0; | |||||
| panic(); | panic(); | ||||
| } | } | ||||
| @@ -168,12 +172,12 @@ struct HostMIDI : TerminalModule { | |||||
| bool process(const ProcessArgs& args, std::vector<rack::engine::Output>& outputs, const bool isBypassed) | bool process(const ProcessArgs& args, std::vector<rack::engine::Output>& outputs, const bool isBypassed) | ||||
| { | { | ||||
| // Cardinal specific | // 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; | midiEvents = pcontext->midiEvents; | ||||
| midiEventsLeft = pcontext->midiEventCount; | midiEventsLeft = pcontext->midiEventCount; | ||||
| @@ -246,30 +250,20 @@ struct HostMIDI : TerminalModule { | |||||
| ++midiEventFrame; | ++midiEventFrame; | ||||
| // Rack stuff | // 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 | // Set pitch and mod wheel | ||||
| const int wheelChannels = (polyMode == MPE_MODE) ? 16 : 1; | const int wheelChannels = (polyMode == MPE_MODE) ? 16 : 1; | ||||
| float pwValues[16] = {}; | |||||
| outputs[PITCHBEND_OUTPUT].setChannels(wheelChannels); | outputs[PITCHBEND_OUTPUT].setChannels(wheelChannels); | ||||
| outputs[MODWHEEL_OUTPUT].setChannels(wheelChannels); | outputs[MODWHEEL_OUTPUT].setChannels(wheelChannels); | ||||
| for (int c = 0; c < wheelChannels; c++) { | 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); | pw = clamp(pw, -1.f, 1.f); | ||||
| if (smooth) | if (smooth) | ||||
| pw = pwFilters[c].process(args.sampleTime, pw); | pw = pwFilters[c].process(args.sampleTime, pw); | ||||
| else | else | ||||
| pwFilters[c].out = pw; | 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; | float mod = mods[c] / 127.f; | ||||
| mod = clamp(mod, 0.f, 1.f); | mod = clamp(mod, 0.f, 1.f); | ||||
| @@ -277,14 +271,31 @@ struct HostMIDI : TerminalModule { | |||||
| mod = modFilters[c].process(args.sampleTime, mod); | mod = modFilters[c].process(args.sampleTime, mod); | ||||
| else | else | ||||
| modFilters[c].out = mod; | 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[START_OUTPUT].setVoltage(startPulse.process(args.sampleTime) ? 10.f : 0.f); | ||||
| outputs[STOP_OUTPUT].setVoltage(stopPulse.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); | outputs[CONTINUE_OUTPUT].setVoltage(continuePulse.process(args.sampleTime) ? 10.f : 0.f); | ||||
| return blockFrameChanged; | |||||
| return processCounterChanged; | |||||
| } | } | ||||
| void processMessage(const midi::Message& msg) | void processMessage(const midi::Message& msg) | ||||
| @@ -452,6 +463,7 @@ struct HostMIDI : TerminalModule { | |||||
| // Set note | // Set note | ||||
| notes[*channel] = note; | notes[*channel] = note; | ||||
| gates[*channel] = true; | gates[*channel] = true; | ||||
| retriggerPulses[*channel].trigger(1e-3); | |||||
| } | } | ||||
| void releaseNote(uint8_t note) { | void releaseNote(uint8_t note) { | ||||
| @@ -533,6 +545,18 @@ struct HostMIDI : TerminalModule { | |||||
| CardinalPluginContext* const pcontext; | CardinalPluginContext* const pcontext; | ||||
| uint8_t channel = 0; | 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) | MidiOutput(CardinalPluginContext* const pc) | ||||
| : pcontext(pc) {} | : pcontext(pc) {} | ||||
| @@ -587,9 +611,21 @@ struct HostMIDI : TerminalModule { | |||||
| void processTerminalInput(const ProcessArgs& args) override | void processTerminalInput(const ProcessArgs& args) override | ||||
| { | { | ||||
| if (midiInput.process(args, outputs, isBypassed())) | if (midiInput.process(args, outputs, isBypassed())) | ||||
| { | |||||
| midiOutput.frame = 0; | 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 | else | ||||
| { | |||||
| ++midiOutput.frame; | ++midiOutput.frame; | ||||
| } | |||||
| } | } | ||||
| void processTerminalOutput(const ProcessArgs&) override | void processTerminalOutput(const ProcessArgs&) override | ||||
| @@ -597,37 +633,67 @@ struct HostMIDI : TerminalModule { | |||||
| if (isBypassed()) | if (isBypassed()) | ||||
| return; | return; | ||||
| auto connected = midiOutput.connected; | |||||
| for (int c = 0; c < inputs[PITCH_INPUT].getChannels(); ++c) | 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<int>(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<int>(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); | 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<int>(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<int>((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<int>(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); | 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); | 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); | midiOutput.setContinue(cont); | ||||
| } | } | ||||
| @@ -636,6 +702,7 @@ struct HostMIDI : TerminalModule { | |||||
| json_t* const rootJ = json_object(); | json_t* const rootJ = json_object(); | ||||
| DISTRHO_SAFE_ASSERT_RETURN(rootJ != nullptr, nullptr); | 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, "smooth", json_boolean(midiInput.smooth)); | ||||
| json_object_set_new(rootJ, "channels", json_integer(midiInput.channels)); | json_object_set_new(rootJ, "channels", json_integer(midiInput.channels)); | ||||
| json_object_set_new(rootJ, "polyMode", json_integer(midiInput.polyMode)); | json_object_set_new(rootJ, "polyMode", json_integer(midiInput.polyMode)); | ||||
| @@ -655,6 +722,12 @@ struct HostMIDI : TerminalModule { | |||||
| void dataFromJson(json_t* const rootJ) override | 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")) | if (json_t* const smoothJ = json_object_get(rootJ, "smooth")) | ||||
| midiInput.smooth = json_boolean_value(smoothJ); | midiInput.smooth = json_boolean_value(smoothJ); | ||||
| @@ -680,6 +753,7 @@ struct HostMIDI : TerminalModule { | |||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| #ifndef HEADLESS | |||||
| struct HostMIDIWidget : ModuleWidgetWith9HP { | struct HostMIDIWidget : ModuleWidgetWith9HP { | ||||
| HostMIDI* const module; | HostMIDI* const module; | ||||
| @@ -710,12 +784,13 @@ struct HostMIDIWidget : ModuleWidgetWith9HP { | |||||
| createAndAddOutput(6, HostMIDI::START_OUTPUT); | createAndAddOutput(6, HostMIDI::START_OUTPUT); | ||||
| createAndAddOutput(7, HostMIDI::STOP_OUTPUT); | createAndAddOutput(7, HostMIDI::STOP_OUTPUT); | ||||
| createAndAddOutput(8, HostMIDI::CONTINUE_OUTPUT); | createAndAddOutput(8, HostMIDI::CONTINUE_OUTPUT); | ||||
| createAndAddOutput(9, HostMIDI::RETRIGGER_OUTPUT); | |||||
| } | } | ||||
| void draw(const DrawArgs& args) override | void draw(const DrawArgs& args) override | ||||
| { | { | ||||
| drawBackground(args.vg); | drawBackground(args.vg); | ||||
| drawOutputJacksArea(args.vg, 9); | |||||
| drawOutputJacksArea(args.vg, 10); | |||||
| setupTextLines(args.vg); | setupTextLines(args.vg); | ||||
| drawTextLine(args.vg, 0, "V/Oct"); | drawTextLine(args.vg, 0, "V/Oct"); | ||||
| @@ -727,6 +802,7 @@ struct HostMIDIWidget : ModuleWidgetWith9HP { | |||||
| drawTextLine(args.vg, 6, "Start"); | drawTextLine(args.vg, 6, "Start"); | ||||
| drawTextLine(args.vg, 7, "Stop"); | drawTextLine(args.vg, 7, "Stop"); | ||||
| drawTextLine(args.vg, 8, "Cont"); | drawTextLine(args.vg, 8, "Cont"); | ||||
| drawTextLine(args.vg, 9, "Retrigger"); | |||||
| ModuleWidgetWith9HP::draw(args); | ModuleWidgetWith9HP::draw(args); | ||||
| } | } | ||||
| @@ -738,6 +814,16 @@ struct HostMIDIWidget : ModuleWidgetWith9HP { | |||||
| menu->addChild(createBoolPtrMenuItem("Smooth pitch/mod wheel", "", &module->midiInput.smooth)); | menu->addChild(createBoolPtrMenuItem("Smooth pitch/mod wheel", "", &module->midiInput.smooth)); | ||||
| static const std::vector<float> 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 { | struct InputChannelItem : MenuItem { | ||||
| HostMIDI* module; | HostMIDI* module; | ||||
| Menu* createChildMenu() override { | Menu* createChildMenu() override { | ||||
| @@ -758,24 +844,14 @@ struct HostMIDIWidget : ModuleWidgetWith9HP { | |||||
| inputChannelItem->module = module; | inputChannelItem->module = module; | ||||
| menu->addChild(inputChannelItem); | 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", { | menu->addChild(createIndexPtrSubmenuItem("Polyphony mode", { | ||||
| "Rotate", | "Rotate", | ||||
| @@ -814,6 +890,17 @@ struct HostMIDIWidget : ModuleWidgetWith9HP { | |||||
| )); | )); | ||||
| } | } | ||||
| }; | }; | ||||
| #else | |||||
| struct HostMIDIWidget : ModuleWidget { | |||||
| HostMIDIWidget(HostMIDI* const module) { | |||||
| setModule(module); | |||||
| for (uint i=0; i<HostMIDI::NUM_INPUTS; ++i) | |||||
| addInput(createInput<PJ301MPort>({}, module, i)); | |||||
| for (uint i=0; i<HostMIDI::NUM_OUTPUTS; ++i) | |||||
| addOutput(createOutput<PJ301MPort>({}, module, i)); | |||||
| } | |||||
| }; | |||||
| #endif | |||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -20,8 +20,6 @@ | |||||
| // ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
| USE_NAMESPACE_DISTRHO; | |||||
| struct HostParameters : TerminalModule { | struct HostParameters : TerminalModule { | ||||
| enum ParamIds { | enum ParamIds { | ||||
| NUM_PARAMS | NUM_PARAMS | ||||
| @@ -91,6 +89,8 @@ struct HostParameters : TerminalModule { | |||||
| } | } | ||||
| }; | }; | ||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| #ifndef HEADLESS | #ifndef HEADLESS | ||||
| struct CardinalParameterPJ301MPort : PJ301MPort { | struct CardinalParameterPJ301MPort : PJ301MPort { | ||||
| void onDragStart(const DragStartEvent& e) override { | void onDragStart(const DragStartEvent& e) override { | ||||
| @@ -159,11 +159,14 @@ struct HostParametersWidget : ModuleWidgetWith9HP { | |||||
| struct HostParametersWidget : ModuleWidget { | struct HostParametersWidget : ModuleWidget { | ||||
| HostParametersWidget(HostParameters* const module) { | HostParametersWidget(HostParameters* const module) { | ||||
| setModule(module); | setModule(module); | ||||
| for (int i=0; i<24; ++i) | |||||
| for (uint i=0; i<HostParameters::NUM_OUTPUTS; ++i) | |||||
| addOutput(createOutput<PJ301MPort>({}, module, i)); | addOutput(createOutput<PJ301MPort>({}, module, i)); | ||||
| } | } | ||||
| }; | }; | ||||
| #endif | #endif | ||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| Model* modelHostParameters = createModel<HostParameters, HostParametersWidget>("HostParameters"); | Model* modelHostParameters = createModel<HostParameters, HostParametersWidget>("HostParameters"); | ||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| @@ -17,6 +17,8 @@ | |||||
| #include "plugincontext.hpp" | #include "plugincontext.hpp" | ||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| struct HostTime : TerminalModule { | struct HostTime : TerminalModule { | ||||
| enum ParamIds { | enum ParamIds { | ||||
| NUM_PARAMS | NUM_PARAMS | ||||
| @@ -39,7 +41,7 @@ struct HostTime : TerminalModule { | |||||
| rack::dsp::PulseGenerator pulseReset, pulseBar, pulseBeat, pulseClock; | rack::dsp::PulseGenerator pulseReset, pulseBar, pulseBeat, pulseClock; | ||||
| float sampleTime = 0.0f; | float sampleTime = 0.0f; | ||||
| int64_t lastBlockFrame = -1; | |||||
| uint32_t lastProcessCounter = 0; | |||||
| // cached time values | // cached time values | ||||
| struct { | struct { | ||||
| bool reset = true; | bool reset = true; | ||||
| @@ -61,15 +63,15 @@ struct HostTime : TerminalModule { | |||||
| void processTerminalInput(const ProcessArgs& args) override | void processTerminalInput(const ProcessArgs& args) override | ||||
| { | { | ||||
| const int64_t blockFrame = pcontext->engine->getBlockFrame(); | |||||
| const uint32_t processCounter = pcontext->processCounter; | |||||
| // local variables for faster access | // local variables for faster access | ||||
| double tick, tickClock; | double tick, tickClock; | ||||
| // Update time position if running a new audio block | // Update time position if running a new audio block | ||||
| if (lastBlockFrame != blockFrame) | |||||
| if (lastProcessCounter != processCounter) | |||||
| { | { | ||||
| lastBlockFrame = blockFrame; | |||||
| lastProcessCounter = processCounter; | |||||
| timeInfo.reset = pcontext->reset; | timeInfo.reset = pcontext->reset; | ||||
| timeInfo.bar = pcontext->bar; | timeInfo.bar = pcontext->bar; | ||||
| timeInfo.beat = pcontext->beat; | 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 hasReset = pulseReset.process(args.sampleTime); | ||||
| const bool hasBar = pulseBar.process(args.sampleTime); | const bool hasBar = pulseBar.process(args.sampleTime); | ||||
| const bool hasBeat = pulseBeat.process(args.sampleTime); | const bool hasBeat = pulseBeat.process(args.sampleTime); | ||||
| @@ -138,13 +147,6 @@ struct HostTime : TerminalModule { | |||||
| ? ((float) (timeInfo.beat - 1) + beatPhase) / pcontext->beatsPerBar | ? ((float) (timeInfo.beat - 1) + beatPhase) / pcontext->beatsPerBar | ||||
| : 0.0f; | : 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[kHostTimeRolling].setBrightness(playing ? 1.0f : 0.0f); | ||||
| lights[kHostTimeReset].setBrightnessSmooth(hasReset ? 1.0f : 0.0f, args.sampleTime * 0.5f); | lights[kHostTimeReset].setBrightnessSmooth(hasReset ? 1.0f : 0.0f, args.sampleTime * 0.5f); | ||||
| lights[kHostTimeBar].setBrightnessSmooth(hasBar ? 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 { | struct HostTimeWidget : ModuleWidget { | ||||
| static constexpr const float startX = 10.0f; | static constexpr const float startX = 10.0f; | ||||
| static constexpr const float startY_top = 71.0f; | static constexpr const float startY_top = 71.0f; | ||||
| @@ -285,5 +290,18 @@ struct HostTimeWidget : ModuleWidget { | |||||
| ModuleWidget::drawLayer(args, layer); | ModuleWidget::drawLayer(args, layer); | ||||
| } | } | ||||
| }; | }; | ||||
| #else | |||||
| struct HostTimeWidget : ModuleWidget { | |||||
| HostTimeWidget(HostTime* const module) { | |||||
| setModule(module); | |||||
| for (uint i=0; i<HostTime::kHostTimeCount; ++i) | |||||
| addOutput(createOutput<PJ301MPort>({}, module, i)); | |||||
| } | |||||
| }; | |||||
| #endif | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| Model* modelHostTime = createModel<HostTime, HostTimeWidget>("HostTime"); | Model* modelHostTime = createModel<HostTime, HostTimeWidget>("HostTime"); | ||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| @@ -97,12 +97,14 @@ static void projectLoadedFromDSP(void* ui); | |||||
| static Mutex sPluginInfoLoadMutex; | static Mutex sPluginInfoLoadMutex; | ||||
| /* | |||||
| #ifndef HEADLESS | #ifndef HEADLESS | ||||
| struct JuceInitializer { | struct JuceInitializer { | ||||
| JuceInitializer() { carla_juce_init(); } | JuceInitializer() { carla_juce_init(); } | ||||
| ~JuceInitializer() { carla_juce_cleanup(); } | ~JuceInitializer() { carla_juce_cleanup(); } | ||||
| }; | }; | ||||
| #endif | #endif | ||||
| */ | |||||
| struct IldaeilModule : Module { | struct IldaeilModule : Module { | ||||
| enum ParamIds { | enum ParamIds { | ||||
| @@ -122,9 +124,11 @@ struct IldaeilModule : Module { | |||||
| NUM_LIGHTS | NUM_LIGHTS | ||||
| }; | }; | ||||
| /* | |||||
| #ifndef HEADLESS | #ifndef HEADLESS | ||||
| SharedResourcePointer<JuceInitializer> juceInitializer; | SharedResourcePointer<JuceInitializer> juceInitializer; | ||||
| #endif | #endif | ||||
| */ | |||||
| const CardinalPluginContext* const pcontext; | const CardinalPluginContext* const pcontext; | ||||
| @@ -144,7 +148,7 @@ struct IldaeilModule : Module { | |||||
| float audioDataOut1[BUFFER_SIZE]; | float audioDataOut1[BUFFER_SIZE]; | ||||
| float audioDataOut2[BUFFER_SIZE]; | float audioDataOut2[BUFFER_SIZE]; | ||||
| unsigned audioDataFill = 0; | unsigned audioDataFill = 0; | ||||
| int64_t lastBlockFrame = -1; | |||||
| uint32_t lastProcessCounter = 0; | |||||
| CardinalExpanderFromCarlaMIDIToCV* midiOutExpander = nullptr; | CardinalExpanderFromCarlaMIDIToCV* midiOutExpander = nullptr; | ||||
| volatile bool resetMeterIn = true; | 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_BINARIES, 0, "/Applications/Carla.app/Contents/MacOS"); | ||||
| carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PATH_RESOURCES, 0, "/Applications/Carla.app/Contents/MacOS/resources"); | 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 | #else | ||||
| if (system::exists("/usr/local/lib/carla")) | if (system::exists("/usr/local/lib/carla")) | ||||
| @@ -351,12 +359,12 @@ struct IldaeilModule : Module { | |||||
| if (audioDataFill == BUFFER_SIZE) | 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 | // Update time position if running a new audio block | ||||
| if (lastBlockFrame != blockFrame) | |||||
| if (lastProcessCounter != processCounter) | |||||
| { | { | ||||
| lastBlockFrame = blockFrame; | |||||
| lastProcessCounter = processCounter; | |||||
| fCarlaTimeInfo.playing = pcontext->playing; | fCarlaTimeInfo.playing = pcontext->playing; | ||||
| fCarlaTimeInfo.frame = pcontext->frame; | fCarlaTimeInfo.frame = pcontext->frame; | ||||
| fCarlaTimeInfo.bbt.valid = pcontext->bbtValid; | fCarlaTimeInfo.bbt.valid = pcontext->bbtValid; | ||||
| @@ -973,7 +981,9 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Thread { | |||||
| const CarlaHostHandle handle = module->fCarlaHostHandle; | const CarlaHostHandle handle = module->fCarlaHostHandle; | ||||
| DISTRHO_SAFE_ASSERT_RETURN(handle != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(handle != nullptr,); | ||||
| /* | |||||
| carla_juce_idle(); | carla_juce_idle(); | ||||
| */ | |||||
| if (fileBrowserHandle != nullptr && fileBrowserIdle(fileBrowserHandle)) | if (fileBrowserHandle != nullptr && fileBrowserIdle(fileBrowserHandle)) | ||||
| { | { | ||||
| @@ -25,6 +25,7 @@ | |||||
| using namespace rack; | using namespace rack; | ||||
| #ifndef HEADLESS | |||||
| struct CardinalLedDisplayChoice : LedDisplayChoice { | struct CardinalLedDisplayChoice : LedDisplayChoice { | ||||
| bool alignTextCenter = true; | bool alignTextCenter = true; | ||||
| @@ -403,3 +404,4 @@ struct OpenGlWidgetWithBrowserPreview : OpenGlWidget { | |||||
| virtual void drawFramebufferForBrowserPreview() = 0; | virtual void drawFramebufferForBrowserPreview() = 0; | ||||
| }; | }; | ||||
| #endif | |||||
| @@ -51,11 +51,11 @@ struct MidiEvent { | |||||
| }; | }; | ||||
| struct CardinalPluginContext : rack::Context { | struct CardinalPluginContext : rack::Context { | ||||
| uint32_t bufferSize; | |||||
| uint32_t bufferSize, processCounter; | |||||
| double sampleRate; | double sampleRate; | ||||
| float parameters[kModuleParameters]; | float parameters[kModuleParameters]; | ||||
| CardinalVariant variant; | CardinalVariant variant; | ||||
| bool playing, reset, bbtValid; | |||||
| bool bypassed, playing, reset, bbtValid; | |||||
| int32_t bar, beat, beatsPerBar, beatType; | int32_t bar, beat, beatsPerBar, beatType; | ||||
| uint64_t frame; | uint64_t frame; | ||||
| double barStartTick, beatsPerMinute; | double barStartTick, beatsPerMinute; | ||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit bf6f969c5f7fff6a419a54197fb4318671281ad5 | |||||
| @@ -1 +1 @@ | |||||
| Subproject commit 80f61cd0171bb7d988c9ec3a144e0566d62c767c | |||||
| Subproject commit 52f89b94a25828f9debf8bca4d58854fb1e70228 | |||||
| @@ -1 +1 @@ | |||||
| Subproject commit df096a635fe8d3ea86a1e6451a55e45ccee5b83d | |||||
| Subproject commit 95496e8a955407889bbab94cf404cf356802bb76 | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit 48bf3c84ebafc9effe7e565d8cdbf8a46b9d503c | |||||
| @@ -1 +1 @@ | |||||
| Subproject commit 54fed7f78bbaac1f1d6275aa737acc39aebc6e72 | |||||
| Subproject commit 2c535bc38d61fd4d776aad7307c1dfbbed062b66 | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit 636351059f2eec629f3b8a537451dd3d0eb01c30 | |||||
| @@ -1 +1 @@ | |||||
| Subproject commit 40a197698496030a30ead69658b1484eca2ae299 | |||||
| Subproject commit b0d8a6fcdb28d2e56d6b024326a7378a2c8ee45d | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit e5cf81f1c356fdc98fd08584146cda8af7e16b1f | |||||
| @@ -1 +1 @@ | |||||
| Subproject commit 368cbd6ee17398c7329b263dde0409bf7a57ce3b | |||||
| Subproject commit 2bd5691c8f12e21e1e6db33e42fe2fe3db7726a3 | |||||
| @@ -1 +1 @@ | |||||
| Subproject commit 68f04a5a8a1a656e7a3aa7e217524f0feb91167e | |||||
| Subproject commit f7399c473735c0a5bec95bb40953e781f9a47ca4 | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit 69d8d66521175cd561d53e65728d460b398950c9 | |||||
| @@ -1 +1 @@ | |||||
| Subproject commit 1c32b02bd11a549d28da0620719541ac6f966652 | |||||
| Subproject commit b21cbe8ee25ddf2a927e0b4ec9f2c97c115857af | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit 788ceb73cfabddaff7245b0df072b0e22a19b360 | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit abe3c24d40b11d31f9f38b2125eff9280c77ad1b | |||||
| @@ -222,6 +222,15 @@ PLUGIN_FILES += $(wildcard Cardinal/src/DearImGui/*.cpp) | |||||
| PLUGIN_FILES += $(wildcard Cardinal/src/DearImGuiColorTextEditor/*.cpp) | PLUGIN_FILES += $(wildcard Cardinal/src/DearImGuiColorTextEditor/*.cpp) | ||||
| endif | 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) | ifneq ($(NOPLUGINS),true) | ||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # 21kHz | # 21kHz | ||||
| @@ -231,7 +240,20 @@ PLUGIN_FILES += $(filter-out 21kHz/src/21kHz.cpp,$(wildcard 21kHz/src/*.cpp)) | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # 8Mode | # 8Mode | ||||
| PLUGIN_FILES += $(wildcard 8Mode/src/*.cpp) | |||||
| PLUGIN_FILES += $(filter-out 8Mode/src/8mode.cpp,$(wildcard 8Mode/src/*.cpp)) | |||||
| # -------------------------------------------------------------- | |||||
| # AlgoritmArte | |||||
| PLUGIN_FILES += $(filter-out Algoritmarte/src/plugin.cpp,$(wildcard Algoritmarte/src/*.cpp)) | |||||
| # -------------------------------------------------------------- | |||||
| # Aaron Static | |||||
| PLUGIN_FILES += $(wildcard AaronStatic/src/*.cpp) | |||||
| # modules/types which are present in other plugins | |||||
| AARONSTATIC_CUSTOM = RefreshCounter | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # AmalgamatedHarmonics | # AmalgamatedHarmonics | ||||
| @@ -248,6 +270,24 @@ AMALGAMATEDHARMONICS_CUSTOM += bogaudio | |||||
| PLUGIN_FILES += $(wildcard AnimatedCircuits/src/Folding/*.cpp) | PLUGIN_FILES += $(wildcard AnimatedCircuits/src/Folding/*.cpp) | ||||
| PLUGIN_FILES += $(wildcard AnimatedCircuits/src/LFold/*.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 | # Aria | ||||
| @@ -378,7 +418,7 @@ AUTINN_CUSTOM = Chord Vibrato | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # Axioma | # Axioma | ||||
| PLUGIN_FILES += $(wildcard Axioma/src/*.cpp) | |||||
| PLUGIN_FILES += $(filter-out Axioma/src/plugin.cpp,$(wildcard Axioma/src/*.cpp)) | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # BaconPlugs | # BaconPlugs | ||||
| @@ -391,6 +431,7 @@ PLUGIN_FILES += $(wildcard BaconPlugs/libs/open303-code/Source/DSPCode/*.cpp) | |||||
| # Befaco | # Befaco | ||||
| PLUGIN_FILES += $(filter-out Befaco/src/plugin.cpp,$(wildcard Befaco/src/*.cpp)) | 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 | PLUGIN_BINARIES += Befaco/src/SpringReverbIR.pcm | ||||
| # modules/types which are present in other plugins | # modules/types which are present in other plugins | ||||
| @@ -405,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/freeverb/*.cpp) | ||||
| PLUGIN_FILES += $(wildcard Bidoo/src/dep/lodepng/*.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 += $(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 | # 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 | BIDOO_CUSTOM_PER_FILE = channel channel filterType | ||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| @@ -424,11 +466,18 @@ BOGAUDIO_CUSTOM_PER_FILE = ARQuantity AttackMenuItem ReleaseMenuItem | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # ChowDSP | # 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/src/*/*/*.cpp) | ||||
| PLUGIN_FILES += $(wildcard ChowDSP/lib/r8lib/*.cpp) | PLUGIN_FILES += $(wildcard ChowDSP/lib/r8lib/*.cpp) | ||||
| # -------------------------------------------------------------- | |||||
| # CatroModulo | |||||
| PLUGIN_FILES += $(filter-out CatroModulo/src/CatroModulo.cpp,$(wildcard CatroModulo/src/*.cpp)) | |||||
| # modules/types which are present in other plugins | |||||
| CATROMODULO_CUSTOM = LowFrequencyOscillator NumDisplayWidget | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # cf | # cf | ||||
| @@ -449,6 +498,7 @@ PLUGIN_FILES += $(wildcard DrumKit/src/model/*.cpp) | |||||
| PLUGIN_FILES += $(wildcard DrumKit/deps/*.cpp) | PLUGIN_FILES += $(wildcard DrumKit/deps/*.cpp) | ||||
| PLUGIN_FILES += $(wildcard DrumKit/deps/SynthDevKit/src/*.cpp) | PLUGIN_FILES += $(wildcard DrumKit/deps/SynthDevKit/src/*.cpp) | ||||
| # modules/types which are present in other plugins | |||||
| DRUMKIT_CUSTOM = ADSR Envelope LowFrequencyOscillator | DRUMKIT_CUSTOM = ADSR Envelope LowFrequencyOscillator | ||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| @@ -471,35 +521,36 @@ PLUGIN_FILES += $(filter-out Extratone/src/plugin.cpp,$(wildcard Extratone/src/* | |||||
| PLUGIN_FILES += $(filter-out FehlerFabrik/src/plugin.cpp,$(wildcard FehlerFabrik/src/*.cpp)) | PLUGIN_FILES += $(filter-out FehlerFabrik/src/plugin.cpp,$(wildcard FehlerFabrik/src/*.cpp)) | ||||
| # modules/types which are present in other plugins | |||||
| FEHLERFABRIK_CUSTOM = Operator Sequencer SlewLimiter | 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 | |||||
| # GlueTheGiant | |||||
| # modules/types which are present in other plugins | |||||
| FUNDAMENTAL_CUSTOM = $(DRWAV) | |||||
| endif | |||||
| PLUGIN_FILES += $(filter-out GlueTheGiant/src/plugin.cpp,$(wildcard GlueTheGiant/src/*.cpp)) | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # GlueTheGiant | |||||
| # GoodSheperd | |||||
| PLUGIN_FILES += $(filter-out GlueTheGiant/src/plugin.cpp,$(wildcard GlueTheGiant/src/*.cpp)) | |||||
| PLUGIN_FILES += $(filter-out GoodSheperd/src/plugin.cpp,$(wildcard GoodSheperd/src/*.cpp)) | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # GrandeModular | # GrandeModular | ||||
| PLUGIN_FILES += $(filter-out GrandeModular/src/plugin.cpp,$(wildcard GrandeModular/src/*.cpp)) | PLUGIN_FILES += $(filter-out GrandeModular/src/plugin.cpp,$(wildcard GrandeModular/src/*.cpp)) | ||||
| # -------------------------------------------------------------- | |||||
| # Hampton Harmonics | |||||
| PLUGIN_FILES += $(filter-out HamptonHarmonics/src/plugin.cpp,$(wildcard HamptonHarmonics/src/*.cpp)) | |||||
| # modules/types which are present in other plugins | |||||
| HAMPTONHARMONICS_CUSTOM = Arp Progress | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # HetrickCV | # 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/src/DSP/*.cpp) | ||||
| PLUGIN_FILES += $(wildcard HetrickCV/Gamma/src/arr.cpp) | PLUGIN_FILES += $(wildcard HetrickCV/Gamma/src/arr.cpp) | ||||
| PLUGIN_FILES += $(wildcard HetrickCV/Gamma/src/Domain.cpp) | PLUGIN_FILES += $(wildcard HetrickCV/Gamma/src/Domain.cpp) | ||||
| @@ -551,6 +602,14 @@ endif | |||||
| # modules/types which are present in other plugins | # modules/types which are present in other plugins | ||||
| JW_CUSTOM = PlayHead Quantizer | JW_CUSTOM = PlayHead Quantizer | ||||
| # -------------------------------------------------------------- | |||||
| # kocmoc | |||||
| 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 | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # LifeFormModular | # LifeFormModular | ||||
| @@ -559,6 +618,14 @@ PLUGIN_FILES += $(filter-out LifeFormModular/src/plugin.cpp,$(wildcard LifeFormM | |||||
| # modules/types which are present in other plugins | # modules/types which are present in other plugins | ||||
| LIFEFORMMODULAR_CUSTOM = IO MS __ct_base __ct_comp | LIFEFORMMODULAR_CUSTOM = IO MS __ct_base __ct_comp | ||||
| # -------------------------------------------------------------- | |||||
| # Lilac Loop | |||||
| PLUGIN_FILES += $(filter-out LilacLoop/src/plugin.cpp,$(wildcard LilacLoop/src/*.cpp)) | |||||
| # modules/types which are present in other plugins | |||||
| LILACLOOP_CUSTOM = AudioFile Mode | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # LittleUtils | # LittleUtils | ||||
| @@ -596,6 +663,15 @@ PLUGIN_FILES += $(wildcard MindMeldModular/src/Utilities/*.cpp) | |||||
| # modules/types which are present in other plugins | # modules/types which are present in other plugins | ||||
| MINDMELD_CUSTOM = printNote | MINDMELD_CUSTOM = printNote | ||||
| # -------------------------------------------------------------- | |||||
| # ML_modules | |||||
| 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 | |||||
| ML_CUSTOM = Mode Quant Quantizer QuantizerWidget SH8 allpass comb revmodel | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # MockbaModular | # MockbaModular | ||||
| @@ -618,6 +694,53 @@ PLUGIN_FILES += $(wildcard mscHack/src/*.cpp) | |||||
| # modules/types which are present in other plugins | # modules/types which are present in other plugins | ||||
| MSCHACK_CUSTOM_PER_FILE = MAIN_SYNC_CLOCK FILTER_STRUCT FILTER_PARAM_STRUCT OSC_PARAM_STRUCT PHRASE_CHANGE_STRUCT | MSCHACK_CUSTOM_PER_FILE = MAIN_SYNC_CLOCK FILTER_STRUCT FILTER_PARAM_STRUCT OSC_PARAM_STRUCT PHRASE_CHANGE_STRUCT | ||||
| # -------------------------------------------------------------- | |||||
| # MSM | |||||
| PLUGIN_FILES += $(filter-out MSM/src/MSM.cpp,$(wildcard MSM/src/*.cpp)) | |||||
| # modules/types which are present in other plugins | |||||
| MSM_CUSTOM = ADSR BlankPanel Delay LFO LowFrequencyOscillator Mult Noise OP VCA VCO sawTable triTable | |||||
| # -------------------------------------------------------------- | |||||
| # Nonlinear Circuits | |||||
| PLUGIN_FILES += $(filter-out nonlinearcircuits/src/NLC.cpp,$(wildcard nonlinearcircuits/src/*.cpp)) | |||||
| # -------------------------------------------------------------- | |||||
| # Orbits | |||||
| 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 += $(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 | # Prism | ||||
| @@ -643,15 +766,21 @@ REPELZEN_CUSTOM = Blank Mixer Werner tanh_pade | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # sonusmodular | # sonusmodular | ||||
| PLUGIN_FILES += $(filter-out sonusmodular/src/sonusmodular,$(wildcard sonusmodular/src/*.cpp)) | |||||
| PLUGIN_FILES += $(filter-out sonusmodular/src/sonusmodular.cpp,$(wildcard sonusmodular/src/*.cpp)) | |||||
| # -------------------------------------------------------------- | |||||
| # stocaudio | |||||
| 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 | # ValleyAudio | ||||
| @@ -729,6 +858,15 @@ PLUGIN_BINARIES += ValleyAudio/src/XFADE.bin | |||||
| VALLEYAUDIO_CUSTOM = $(DRWAV) DigitalDisplay | VALLEYAUDIO_CUSTOM = $(DRWAV) DigitalDisplay | ||||
| VALLEYAUDIO_CUSTOM_PER_FILE = TempoKnob | 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 | # ZetaCarinaeModules | ||||
| @@ -762,7 +900,6 @@ BASE_FLAGS += -DARCH_LIN | |||||
| endif | endif | ||||
| BASE_FLAGS += -DBUILDING_PLUGIN_MODULES | BASE_FLAGS += -DBUILDING_PLUGIN_MODULES | ||||
| BASE_FLAGS += -fno-strict-aliasing | |||||
| BASE_FLAGS += -I../dpf/dgl/src/nanovg | BASE_FLAGS += -I../dpf/dgl/src/nanovg | ||||
| BASE_FLAGS += -I../dpf/distrho | BASE_FLAGS += -I../dpf/distrho | ||||
| @@ -832,8 +969,8 @@ BASE_FLAGS += -DHAVE_SNDFILE | |||||
| endif | endif | ||||
| BUILD_C_FLAGS += -std=gnu11 | BUILD_C_FLAGS += -std=gnu11 | ||||
| BUILD_C_FLAGS += -fno-finite-math-only | |||||
| BUILD_CXX_FLAGS += -fno-finite-math-only | |||||
| BUILD_C_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 | # Rack code is not tested for this flag, unset it | ||||
| BUILD_CXX_FLAGS += -U_GLIBCXX_ASSERTIONS -Wp,-U_GLIBCXX_ASSERTIONS | BUILD_CXX_FLAGS += -U_GLIBCXX_ASSERTIONS -Wp,-U_GLIBCXX_ASSERTIONS | ||||
| @@ -872,18 +1009,26 @@ else | |||||
| PLUGIN_LIST = $(subst /plugin.json,,$(wildcard */plugin.json)) | PLUGIN_LIST = $(subst /plugin.json,,$(wildcard */plugin.json)) | ||||
| endif | endif | ||||
| UNWANTED_FILES = HetrickCV/res/illustrator - deprecated/MyModule.svg | |||||
| UNWANTED_FILES = HetrickCV/res/illustrator - deprecated/MyModule.svg | |||||
| UNWANTED_FILES += $(wildcard Mog/res/*) | |||||
| UNWANTED_FILES += $(wildcard Mog/res/*/*) | |||||
| UNWANTED_FILES += $(wildcard nonlinearcircuits/res/*) | |||||
| RESOURCE_FILES = \ | RESOURCE_FILES = \ | ||||
| $(filter-out $(UNWANTED_FILES), \ | $(filter-out $(UNWANTED_FILES), \ | ||||
| $(wildcard */res/*.svg) \ | $(wildcard */res/*.svg) \ | ||||
| $(wildcard */res/*/*.svg) \ | $(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) \ | $(wildcard */res/*/*.ttf) \ | ||||
| $(wildcard */res/*/*/*.ttf)) | $(wildcard */res/*/*/*.ttf)) | ||||
| RESOURCE_FILES += $(wildcard */presets) | 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/Keypunch029.json | ||||
| RESOURCE_FILES += BaconPlugs/res/midi/chopin | RESOURCE_FILES += BaconPlugs/res/midi/chopin | ||||
| RESOURCE_FILES += BaconPlugs/res/midi/debussy | RESOURCE_FILES += BaconPlugs/res/midi/debussy | ||||
| @@ -895,6 +1040,13 @@ RESOURCE_FILES += MindMeldModular/res/ShapeMaster/CommunityPresets | |||||
| RESOURCE_FILES += MindMeldModular/res/ShapeMaster/CommunityShapes | RESOURCE_FILES += MindMeldModular/res/ShapeMaster/CommunityShapes | ||||
| RESOURCE_FILES += MindMeldModular/res/ShapeMaster/MindMeldPresets | RESOURCE_FILES += MindMeldModular/res/ShapeMaster/MindMeldPresets | ||||
| RESOURCE_FILES += MindMeldModular/res/ShapeMaster/MindMeldShapes | 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 | # MOD builds only have LV2 FX variant for now | ||||
| ifeq ($(MOD_BUILD),true) | ifeq ($(MOD_BUILD),true) | ||||
| @@ -914,10 +1066,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/CardinalFX.vst/Contents/Resources/%) | ||||
| VST2_RESOURCES += $(RESOURCE_FILES:%=../bin/CardinalSynth.vst/Contents/Resources/%) | VST2_RESOURCES += $(RESOURCE_FILES:%=../bin/CardinalSynth.vst/Contents/Resources/%) | ||||
| else | 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 | endif | ||||
| VST3_RESOURCES = $(PLUGIN_LIST:%=../bin/Cardinal.vst3/Contents/Resources/PluginManifests/%.json) | VST3_RESOURCES = $(PLUGIN_LIST:%=../bin/Cardinal.vst3/Contents/Resources/PluginManifests/%.json) | ||||
| @@ -1001,19 +1151,11 @@ ifeq ($(MACOS),true) | |||||
| -@mkdir -p "$(shell dirname $@)" | -@mkdir -p "$(shell dirname $@)" | ||||
| $(SILENT)ln -sf $(abspath $<) $@ | $(SILENT)ln -sf $(abspath $<) $@ | ||||
| else | 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 $@)" | -@mkdir -p "$(shell dirname $@)" | ||||
| $(SILENT)ln -sf $(abspath $<) $@ | $(SILENT)ln -sf $(abspath $<) $@ | ||||
| ../bin/CardinalSynth.vst/resources/PluginManifests/%.json: %/plugin.json | |||||
| ../bin/Cardinal.vst/resources/PluginManifests/%.json: %/plugin.json | |||||
| -@mkdir -p "$(shell dirname $@)" | -@mkdir -p "$(shell dirname $@)" | ||||
| $(SILENT)ln -sf $(abspath $<) $@ | $(SILENT)ln -sf $(abspath $<) $@ | ||||
| endif | endif | ||||
| @@ -1082,6 +1224,21 @@ $(BUILD_DIR)/8Mode/%.cpp.o: 8Mode/%.cpp | |||||
| $(foreach m,$(8MODE_CUSTOM),$(call custom_module_names,$(m),8Mode)) \ | $(foreach m,$(8MODE_CUSTOM),$(call custom_module_names,$(m),8Mode)) \ | ||||
| -DpluginInstance=pluginInstance__8Mode | -DpluginInstance=pluginInstance__8Mode | ||||
| $(BUILD_DIR)/AaronStatic/%.cpp.o: AaronStatic/%.cpp | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||||
| @echo "Compiling $<" | |||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ | |||||
| $(foreach m,$(AARONSTATIC_CUSTOM),$(call custom_module_names,$(m),AaronStatic)) \ | |||||
| -DpluginInstance=pluginInstance__AaronStatic \ | |||||
| -Dinit=init__AaronStatic | |||||
| $(BUILD_DIR)/Algoritmarte/%.cpp.o: Algoritmarte/%.cpp | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||||
| @echo "Compiling $<" | |||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ | |||||
| $(foreach m,$(ALGORITMARTE_CUSTOM),$(call custom_module_names,$(m),Algoritmarte)) \ | |||||
| -DpluginInstance=pluginInstance__Algoritmarte | |||||
| $(BUILD_DIR)/AmalgamatedHarmonics/%.cpp.o: AmalgamatedHarmonics/%.cpp | $(BUILD_DIR)/AmalgamatedHarmonics/%.cpp.o: AmalgamatedHarmonics/%.cpp | ||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| @@ -1096,6 +1253,17 @@ $(BUILD_DIR)/AnimatedCircuits/%.cpp.o: AnimatedCircuits/%.cpp | |||||
| $(foreach m,$(ANIMATEDCIRCUITS_CUSTOM),$(call custom_module_names,$(m),AnimatedCircuits)) \ | $(foreach m,$(ANIMATEDCIRCUITS_CUSTOM),$(call custom_module_names,$(m),AnimatedCircuits)) \ | ||||
| -DpluginInstance=pluginInstance__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 | $(BUILD_DIR)/AriaModules/%.cpp.o: AriaModules/%.cpp | ||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| @@ -1150,7 +1318,7 @@ $(BUILD_DIR)/Befaco/%.cpp.o: Befaco/%.cpp | |||||
| $(foreach m,$(BEFACO_CUSTOM),$(call custom_module_names,$(m),Befaco)) \ | $(foreach m,$(BEFACO_CUSTOM),$(call custom_module_names,$(m),Befaco)) \ | ||||
| -DpluginInstance=pluginInstance__Befaco | -DpluginInstance=pluginInstance__Befaco | ||||
| $(BUILD_DIR)/Bidoo/%.cpp.o: Bidoo/%.cpp | |||||
| $(BUILD_DIR)/Bidoo%.cpp.o: Bidoo%.cpp | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ | $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ | ||||
| @@ -1187,6 +1355,13 @@ $(BUILD_DIR)/BogaudioModules/%.cpp.o: BogaudioModules/%.cpp | |||||
| -IBogaudioModules/lib \ | -IBogaudioModules/lib \ | ||||
| -IBogaudioModules/src/dsp | -IBogaudioModules/src/dsp | ||||
| $(BUILD_DIR)/CatroModulo/src/%.cpp.o: CatroModulo/src/%.cpp | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||||
| @echo "Compiling $<" | |||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ | |||||
| $(foreach m,$(CATROMODULO_CUSTOM),$(call custom_module_names,$(m),CatroModulo)) \ | |||||
| -DpluginInstance=pluginInstance__CatroModulo | |||||
| $(BUILD_DIR)/cf/src/%.cpp.o: cf/src/%.cpp | $(BUILD_DIR)/cf/src/%.cpp.o: cf/src/%.cpp | ||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| @@ -1282,6 +1457,13 @@ $(BUILD_DIR)/GlueTheGiant/src/gtgComponents.cpp.o: GlueTheGiant/src/gtgComponent | |||||
| -DloadGtgPluginDefault=ignoredGlueTheGiant1 \ | -DloadGtgPluginDefault=ignoredGlueTheGiant1 \ | ||||
| -DsaveGtgPluginDefault=ignoredGlueTheGiant2 | -DsaveGtgPluginDefault=ignoredGlueTheGiant2 | ||||
| $(BUILD_DIR)/GoodSheperd/%.cpp.o: GoodSheperd/%.cpp | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||||
| @echo "Compiling $<" | |||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ | |||||
| $(foreach m,$(GOODSHEPERD_CUSTOM),$(call custom_module_names,$(m),GoodSheperd)) \ | |||||
| -DpluginInstance=pluginInstance__GoodSheperd | |||||
| $(BUILD_DIR)/GrandeModular/%.cpp.o: GrandeModular/%.cpp | $(BUILD_DIR)/GrandeModular/%.cpp.o: GrandeModular/%.cpp | ||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| @@ -1289,8 +1471,16 @@ $(BUILD_DIR)/GrandeModular/%.cpp.o: GrandeModular/%.cpp | |||||
| $(foreach m,$(GRANDEMODULAR_CUSTOM),$(call custom_module_names,$(m),GrandeModular)) \ | $(foreach m,$(GRANDEMODULAR_CUSTOM),$(call custom_module_names,$(m),GrandeModular)) \ | ||||
| -DpluginInstance=pluginInstance__GrandeModular \ | -DpluginInstance=pluginInstance__GrandeModular \ | ||||
| -Wno-missing-braces \ | -Wno-missing-braces \ | ||||
| -Wno-narrowing \ | |||||
| -Wno-self-assign | -Wno-self-assign | ||||
| $(BUILD_DIR)/HamptonHarmonics/%.cpp.o: HamptonHarmonics/%.cpp | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||||
| @echo "Compiling $<" | |||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ | |||||
| $(foreach m,$(HAMPTONHARMONICS_CUSTOM),$(call custom_module_names,$(m),HamptonHarmonics)) \ | |||||
| -DpluginInstance=pluginInstance__HamptonHarmonics | |||||
| $(BUILD_DIR)/HetrickCV/%.cpp.o: HetrickCV/%.cpp | $(BUILD_DIR)/HetrickCV/%.cpp.o: HetrickCV/%.cpp | ||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| @@ -1360,6 +1550,13 @@ $(BUILD_DIR)/JW-Modules/%.cpp.o: JW-Modules/%.cpp | |||||
| -Wno-unused-but-set-variable \ | -Wno-unused-but-set-variable \ | ||||
| -Wno-unused-result | -Wno-unused-result | ||||
| $(BUILD_DIR)/kocmoc/%.cpp.o: kocmoc/%.cpp | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||||
| @echo "Compiling $<" | |||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ | |||||
| $(foreach m,$(KOCMOC_CUSTOM),$(call custom_module_names,$(m),kocmoc)) \ | |||||
| -DpluginInstance=pluginInstance__kocmoc | |||||
| $(BUILD_DIR)/LifeFormModular/%.cpp.o: LifeFormModular/%.cpp | $(BUILD_DIR)/LifeFormModular/%.cpp.o: LifeFormModular/%.cpp | ||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| @@ -1367,6 +1564,14 @@ $(BUILD_DIR)/LifeFormModular/%.cpp.o: LifeFormModular/%.cpp | |||||
| $(foreach m,$(LIFEFORMMODULAR_CUSTOM),$(call custom_module_names,$(m),LifeFormModular)) \ | $(foreach m,$(LIFEFORMMODULAR_CUSTOM),$(call custom_module_names,$(m),LifeFormModular)) \ | ||||
| -DpluginInstance=pluginInstance__LifeFormModular | -DpluginInstance=pluginInstance__LifeFormModular | ||||
| $(BUILD_DIR)/LilacLoop/%.cpp.o: LilacLoop/%.cpp | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||||
| @echo "Compiling $<" | |||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ | |||||
| $(foreach m,$(LILACLOOP_CUSTOM),$(call custom_module_names,$(m),LilacLoop)) \ | |||||
| -DpluginInstance=pluginInstance__LilacLoop \ | |||||
| -DSKIP_MINGW_FORMAT | |||||
| $(BUILD_DIR)/LittleUtils/%.cpp.o: LittleUtils/%.cpp | $(BUILD_DIR)/LittleUtils/%.cpp.o: LittleUtils/%.cpp | ||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| @@ -1388,7 +1593,7 @@ $(BUILD_DIR)/LyraeModules/%.cpp.o: LyraeModules/%.cpp | |||||
| $(foreach m,$(LYRAE_CUSTOM),$(call custom_module_names,$(m),Lyrae)) \ | $(foreach m,$(LYRAE_CUSTOM),$(call custom_module_names,$(m),Lyrae)) \ | ||||
| -DpluginInstance=pluginInstance__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)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ | $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ | ||||
| @@ -1403,6 +1608,13 @@ $(BUILD_DIR)/MindMeldModular/%.cpp.o: MindMeldModular/%.cpp | |||||
| $(foreach m,$(MINDMELD_CUSTOM),$(call custom_module_names,$(m),MindMeld)) \ | $(foreach m,$(MINDMELD_CUSTOM),$(call custom_module_names,$(m),MindMeld)) \ | ||||
| -DpluginInstance=pluginInstance__MindMeld | -DpluginInstance=pluginInstance__MindMeld | ||||
| $(BUILD_DIR)/ML_modules/%.cpp.o: ML_modules/%.cpp | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||||
| @echo "Compiling $<" | |||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ | |||||
| $(foreach m,$(ML_CUSTOM),$(call custom_module_names,$(m),ML)) \ | |||||
| -DpluginInstance=pluginInstance__ML | |||||
| $(BUILD_DIR)/MockbaModular/%.cpp.o: MockbaModular/%.cpp | $(BUILD_DIR)/MockbaModular/%.cpp.o: MockbaModular/%.cpp | ||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| @@ -1430,6 +1642,54 @@ $(BUILD_DIR)/mscHack/%.cpp.o: mscHack/%.cpp | |||||
| -Wno-non-c-typedef-for-linkage \ | -Wno-non-c-typedef-for-linkage \ | ||||
| -Wno-unused-but-set-variable | -Wno-unused-but-set-variable | ||||
| $(BUILD_DIR)/MSM/%.cpp.o: MSM/%.cpp | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||||
| @echo "Compiling $<" | |||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ | |||||
| $(foreach m,$(MSM_CUSTOM),$(call custom_module_names,$(m),MSM)) \ | |||||
| -DpluginInstance=pluginInstance__MSM \ | |||||
| -DDARKTHEME | |||||
| $(BUILD_DIR)/nonlinearcircuits/%.cpp.o: nonlinearcircuits/%.cpp | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||||
| @echo "Compiling $<" | |||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ | |||||
| $(foreach m,$(NONLINEARCIRCUITS_CUSTOM),$(call custom_module_names,$(m),nonlinearcircuits)) \ | |||||
| -DpluginInstance=pluginInstance__nonlinearcircuits | |||||
| $(BUILD_DIR)/Orbits/%.cpp.o: Orbits/%.cpp | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||||
| @echo "Compiling $<" | |||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ | |||||
| $(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 $<" | |||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ | |||||
| $(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 | $(BUILD_DIR)/Prism/%.cpp.o: Prism/%.cpp | ||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| @@ -1461,14 +1721,19 @@ $(BUILD_DIR)/sonusmodular/%.cpp.o: sonusmodular/%.cpp | |||||
| $(foreach m,$(SONUSMODULAR_CUSTOM),$(call custom_module_names,$(m),sonusmodular)) \ | $(foreach m,$(SONUSMODULAR_CUSTOM),$(call custom_module_names,$(m),sonusmodular)) \ | ||||
| -DpluginInstance=pluginInstance__sonusmodular | -DpluginInstance=pluginInstance__sonusmodular | ||||
| $(BUILD_DIR)/substation-%.cpp.o: substation-%.cpp | |||||
| $(BUILD_DIR)/stocaudio/%.cpp.o: stocaudio/%.cpp | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||||
| @echo "Compiling $<" | |||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ | |||||
| $(foreach m,$(STOCAUDIO_CUSTOM),$(call custom_module_names,$(m),stocaudio)) \ | |||||
| -DpluginInstance=pluginInstance__stocaudio | |||||
| $(BUILD_DIR)/unless_modules/%.cpp.o: unless_modules/%.cpp | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ \ | $(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 | $(BUILD_DIR)/ValleyAudio/%.cpp.o: ValleyAudio/%.cpp | ||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @@ -1481,6 +1746,15 @@ $(BUILD_DIR)/ValleyAudio/%.cpp.o: ValleyAudio/%.cpp | |||||
| -Wno-sign-compare \ | -Wno-sign-compare \ | ||||
| -Wno-unused-but-set-variable | -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 | $(BUILD_DIR)/ZetaCarinaeModules/%.cpp.o: ZetaCarinaeModules/%.cpp | ||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| @@ -1 +1 @@ | |||||
| Subproject commit 621a29f3f1b521582fd11ca7f17635d19faa340c | |||||
| Subproject commit a721e381fa1d72d738c9c2daae08c740107e3d5e | |||||
| @@ -1 +1 @@ | |||||
| Subproject commit 01c4fac9f2e91f60125d36767224f457b2057fb7 | |||||
| Subproject commit 00a7e3b01f56da5cfc86720ae6951ecdf8953ee5 | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit ff0c007feb9ed1de57ea246f86e8b2b68572f5e6 | |||||
| @@ -0,0 +1 @@ | |||||
| ../ArableInstruments/parasites | |||||
| @@ -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" | |||||
| ] | |||||
| } | |||||
| ] | |||||
| } | |||||
| @@ -0,0 +1 @@ | |||||
| ../../ArableInstruments/res/CKSS_rot_0.svg | |||||
| @@ -0,0 +1 @@ | |||||
| ../../ArableInstruments/res/CKSS_rot_1.svg | |||||
| @@ -0,0 +1 @@ | |||||
| ../../ArableInstruments/res/Neil.png | |||||
| @@ -0,0 +1 @@ | |||||
| ../../ArableInstruments/res/Neil.svg | |||||
| @@ -0,0 +1 @@ | |||||
| ../../ArableInstruments/src/ArableInstruments.hpp | |||||
| @@ -0,0 +1 @@ | |||||
| ../../ArableInstruments/src/Clouds.cpp | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit d03e8b486deba4740bc7f15ae95a08d823a7d00a | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit ea6ab0c6887102ebbf6e3534e0e891b867b130cc | |||||
| @@ -1 +1 @@ | |||||
| Subproject commit 453da225742f3829ba037770245333a28751fbb8 | |||||
| Subproject commit 8a9cc034d905079f156ed6c64efaeb4baf81490f | |||||
| @@ -1 +1 @@ | |||||
| Subproject commit c05209a6ad74e8b99703a033842797f06515f865 | |||||
| Subproject commit 98698dc28e6ed7aec56e4ab8280171a160d673ef | |||||
| @@ -1 +1 @@ | |||||
| Subproject commit 31c4229eb328f6aaa4024f76c595b55213cdf1cf | |||||
| Subproject commit 1b77e3c3ba12734bbd29a4aa59dd408e679b5cf7 | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit f2a8c19f8aa81769e13d085d69a44de5afaacfaa | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit 57eb090f233c21b2edee541ea17d800f22045d91 | |||||
| @@ -1 +1 @@ | |||||
| Subproject commit 185e07ea94086a04b3daacb4bf94c0fbd3544725 | |||||
| Subproject commit f812cc56b7fe9e41bb13da99ef23f014015c86c1 | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit ed5c85b0d9391c37f4ec4d9de4ef8aa30d94bcd6 | |||||
| @@ -1 +0,0 @@ | |||||
| Subproject commit cbc09d4db02d038493689c192d63b746d453d18f | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit 3f895c7663e3e54c4e30c406c56d420ea407133e | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit 03f4fc5cebb5d8eb152ac59d3a51ce0ec87a2740 | |||||
| @@ -29,6 +29,7 @@ | |||||
| #include "AsyncDialog.hpp" | #include "AsyncDialog.hpp" | ||||
| #include "PluginContext.hpp" | #include "PluginContext.hpp" | ||||
| #include "DistrhoPluginUtils.hpp" | |||||
| #include <asset.hpp> | #include <asset.hpp> | ||||
| #include <context.hpp> | #include <context.hpp> | ||||
| @@ -43,18 +44,50 @@ | |||||
| # undef DEBUG | # undef DEBUG | ||||
| #endif | #endif | ||||
| // for finding home dir | |||||
| #ifndef ARCH_WIN | |||||
| // for finding special paths | |||||
| #ifdef ARCH_WIN | |||||
| # include <shlobj.h> | |||||
| #else | |||||
| # include <pwd.h> | # include <pwd.h> | ||||
| # include <unistd.h> | # include <unistd.h> | ||||
| #endif | #endif | ||||
| const std::string CARDINAL_VERSION = "22.02"; | |||||
| const std::string CARDINAL_VERSION = "22.04"; | |||||
| namespace rack { | namespace rack { | ||||
| namespace settings { | namespace settings { | ||||
| int rateLimit = 0; | 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 | namespace patchUtils | ||||
| @@ -74,19 +107,11 @@ static void promptClear(const char* const message, const std::function<void()> a | |||||
| static std::string homeDir() | static std::string homeDir() | ||||
| { | { | ||||
| # ifdef ARCH_WIN | # 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 | # else | ||||
| if (const char* const home = getenv("HOME")) | if (const char* const home = getenv("HOME")) | ||||
| return home; | return home; | ||||
| else if (struct passwd* const pwd = getpwuid(getuid())) | |||||
| if (struct passwd* const pwd = getpwuid(getuid())) | |||||
| return pwd->pw_dir; | return pwd->pw_dir; | ||||
| # endif | # endif | ||||
| return {}; | return {}; | ||||
| @@ -112,6 +137,7 @@ void loadDialog() | |||||
| FileBrowserOptions opts; | FileBrowserOptions opts; | ||||
| opts.startDir = dir.c_str(); | opts.startDir = dir.c_str(); | ||||
| opts.saving = ui->saving = false; | opts.saving = ui->saving = false; | ||||
| opts.title = "Open patch"; | |||||
| ui->openFileBrowser(opts); | ui->openFileBrowser(opts); | ||||
| }); | }); | ||||
| #endif | #endif | ||||
| @@ -208,6 +234,7 @@ static void saveAsDialog(const bool uncompressed) | |||||
| FileBrowserOptions opts; | FileBrowserOptions opts; | ||||
| opts.startDir = dir.c_str(); | opts.startDir = dir.c_str(); | ||||
| opts.saving = ui->saving = true; | opts.saving = ui->saving = true; | ||||
| opts.title = "Save patch"; | |||||
| ui->savingUncompressed = uncompressed; | ui->savingUncompressed = uncompressed; | ||||
| ui->openFileBrowser(opts); | ui->openFileBrowser(opts); | ||||
| } | } | ||||
| @@ -41,6 +41,16 @@ namespace window { | |||||
| void generateScreenshot(); | void generateScreenshot(); | ||||
| } | } | ||||
| bool isStandalone(); | |||||
| #ifdef ARCH_WIN | |||||
| enum SpecialPath { | |||||
| kSpecialPathUserProfile, | |||||
| kSpecialPathCommonProgramFiles, | |||||
| }; | |||||
| std::string getSpecialPath(SpecialPath type); | |||||
| #endif | |||||
| } // namespace rack | } // namespace rack | ||||
| namespace patchUtils { | namespace patchUtils { | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
| * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
| * modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
| @@ -37,6 +37,7 @@ | |||||
| #include <asset.hpp> | #include <asset.hpp> | ||||
| #include <context.hpp> | #include <context.hpp> | ||||
| #include <helpers.hpp> | #include <helpers.hpp> | ||||
| #include <settings.hpp> | |||||
| #include <system.hpp> | #include <system.hpp> | ||||
| namespace rack { | namespace rack { | ||||
| @@ -54,7 +55,6 @@ struct ModuleWidget::Internal { | |||||
| math::Vec dragOffset; | math::Vec dragOffset; | ||||
| math::Vec dragRackPos; | math::Vec dragRackPos; | ||||
| bool dragEnabled; | bool dragEnabled; | ||||
| math::Vec oldPos; | |||||
| widget::Widget* panel; | widget::Widget* panel; | ||||
| }; | }; | ||||
| @@ -300,36 +300,65 @@ static void CardinalModuleWidget__saveSelectionDialog(RackWidget* const w) | |||||
| void CardinalModuleWidget::onButton(const ButtonEvent& e) | void CardinalModuleWidget::onButton(const ButtonEvent& e) | ||||
| { | { | ||||
| bool selected = APP->scene->rack->isSelected(this); | |||||
| const bool selected = APP->scene->rack->isSelected(this); | |||||
| if (selected) { | 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; | 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); | |||||
| } | } | ||||
| } | } | ||||
| @@ -49,12 +49,22 @@ | |||||
| #include "extra/Base64.hpp" | #include "extra/Base64.hpp" | ||||
| #include "extra/SharedResourcePointer.hpp" | #include "extra/SharedResourcePointer.hpp" | ||||
| static const constexpr uint kCardinalStateBaseCount = 3; // patch, screenshot, comment | |||||
| #ifndef HEADLESS | #ifndef HEADLESS | ||||
| # include "WindowParameters.hpp" | # include "WindowParameters.hpp" | ||||
| static const constexpr uint kCardinalStateCount = 4; // patch, screenshot, comment, windowSize | |||||
| static const constexpr uint kCardinalStateCount = kCardinalStateBaseCount + 2; // moduleInfos, windowSize | |||||
| #else | #else | ||||
| # define kWindowParameterCount 0 | # 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 | #endif | ||||
| namespace rack { | namespace rack { | ||||
| @@ -134,11 +144,11 @@ struct Initializer | |||||
| { | { | ||||
| asset::bundlePath = system::join(resourcePath, "PluginManifests"); | asset::bundlePath = system::join(resourcePath, "PluginManifests"); | ||||
| asset::systemDir = resourcePath; | 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 | #ifdef CARDINAL_PLUGIN_SOURCE_DIR | ||||
| // Make system dir point to source code location as fallback | // Make system dir point to source code location as fallback | ||||
| @@ -146,16 +156,27 @@ struct Initializer | |||||
| if (system::exists(system::join(asset::systemDir, "res"))) | 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 | // If source code dir does not exist use install target prefix as system dir | ||||
| else | else | ||||
| #endif | #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"; | 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) | void CardinalPluginContext::writeMidiMessage(const rack::midi::Message& message, const uint8_t channel) | ||||
| { | { | ||||
| if (bypassed) | |||||
| return; | |||||
| const size_t size = message.bytes.size(); | const size_t size = message.bytes.size(); | ||||
| DISTRHO_SAFE_ASSERT_RETURN(size > 0,); | DISTRHO_SAFE_ASSERT_RETURN(size > 0,); | ||||
| DISTRHO_SAFE_ASSERT_RETURN(message.frame >= 0,); | DISTRHO_SAFE_ASSERT_RETURN(message.frame >= 0,); | ||||
| @@ -425,9 +449,18 @@ class CardinalPlugin : public CardinalBasePlugin | |||||
| std::string fAutosavePath; | std::string fAutosavePath; | ||||
| uint64_t fPreviousFrame; | 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 | #ifndef HEADLESS | ||||
| // real values, not VCV interpreted ones | // real values, not VCV interpreted ones | ||||
| @@ -441,7 +474,8 @@ public: | |||||
| #if DISTRHO_PLUGIN_NUM_INPUTS != 0 | #if DISTRHO_PLUGIN_NUM_INPUTS != 0 | ||||
| fAudioBufferCopy(nullptr), | fAudioBufferCopy(nullptr), | ||||
| #endif | #endif | ||||
| fPreviousFrame(0) | |||||
| fPreviousFrame(0), | |||||
| fWasBypassed(false) | |||||
| { | { | ||||
| #ifndef HEADLESS | #ifndef HEADLESS | ||||
| fWindowParameters[kWindowParameterShowTooltips] = 1.0f; | fWindowParameters[kWindowParameterShowTooltips] = 1.0f; | ||||
| @@ -454,6 +488,9 @@ public: | |||||
| fWindowParameters[kWindowParameterWheelSensitivity] = 1.0f; | fWindowParameters[kWindowParameterWheelSensitivity] = 1.0f; | ||||
| fWindowParameters[kWindowParameterLockModulePositions] = 0.0f; | fWindowParameters[kWindowParameterLockModulePositions] = 0.0f; | ||||
| fWindowParameters[kWindowParameterUpdateRateLimit] = 0.0f; | fWindowParameters[kWindowParameterUpdateRateLimit] = 0.0f; | ||||
| fWindowParameters[kWindowParameterBrowserSort] = 3.0f; | |||||
| fWindowParameters[kWindowParameterBrowserZoom] = 50.0f; | |||||
| fWindowParameters[kWindowParameterInvertZoom] = 0.0f; | |||||
| #endif | #endif | ||||
| // create unique temporary path for this instance | // create unique temporary path for this instance | ||||
| @@ -475,6 +512,16 @@ public: | |||||
| } | } | ||||
| } DISTRHO_SAFE_EXCEPTION("create unique temporary path"); | } 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(); | const float sampleRate = getSampleRate(); | ||||
| rack::settings::sampleRate = sampleRate; | rack::settings::sampleRate = sampleRate; | ||||
| @@ -564,7 +611,7 @@ protected: | |||||
| uint32_t getVersion() const override | uint32_t getVersion() const override | ||||
| { | { | ||||
| return d_version(0, 22, 2); | |||||
| return d_version(0, 22, 4); | |||||
| } | } | ||||
| int64_t getUniqueId() const override | int64_t getUniqueId() const override | ||||
| @@ -721,6 +768,63 @@ protected: | |||||
| parameter.enumValues.values[2].label = "4x"; | parameter.enumValues.values[2].label = "4x"; | ||||
| parameter.enumValues.values[2].value = 2.0f; | parameter.enumValues.values[2].value = 2.0f; | ||||
| break; | 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 | #endif | ||||
| } | } | ||||
| @@ -745,6 +849,11 @@ protected: | |||||
| state.label = "Comment"; | state.label = "Comment"; | ||||
| break; | break; | ||||
| case 3: | case 3: | ||||
| state.hints = kStateIsOnlyForUI; | |||||
| state.key = "moduleInfos"; | |||||
| state.label = "moduleInfos"; | |||||
| break; | |||||
| case 4: | |||||
| state.hints = kStateIsOnlyForUI; | state.hints = kStateIsOnlyForUI; | ||||
| state.key = "windowSize"; | state.key = "windowSize"; | ||||
| state.label = "Window size"; | state.label = "Window size"; | ||||
| @@ -763,7 +872,7 @@ protected: | |||||
| // bypass | // bypass | ||||
| if (index == kModuleParameters) | if (index == kModuleParameters) | ||||
| return 0.0f; | |||||
| return context->bypassed ? 1.0f : 0.0f; | |||||
| #ifndef HEADLESS | #ifndef HEADLESS | ||||
| // window related parameters | // window related parameters | ||||
| @@ -787,7 +896,10 @@ protected: | |||||
| // bypass | // bypass | ||||
| if (index == kModuleParameters) | if (index == kModuleParameters) | ||||
| { | |||||
| context->bypassed = value > 0.5f; | |||||
| return; | return; | ||||
| } | |||||
| #ifndef HEADLESS | #ifndef HEADLESS | ||||
| // window related parameters | // window related parameters | ||||
| @@ -804,14 +916,57 @@ protected: | |||||
| String getState(const char* const key) const override | String getState(const char* const key) const override | ||||
| { | { | ||||
| #ifndef HEADLESS | #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) | if (std::strcmp(key, "windowSize") == 0) | ||||
| return fWindowSize; | |||||
| return fState.windowSize; | |||||
| #endif | #endif | ||||
| if (std::strcmp(key, "comment") == 0) | if (std::strcmp(key, "comment") == 0) | ||||
| return fStateComment; | |||||
| return fState.comment; | |||||
| if (std::strcmp(key, "screenshot") == 0) | if (std::strcmp(key, "screenshot") == 0) | ||||
| return fStateScreenshot; | |||||
| return fState.screenshot; | |||||
| if (std::strcmp(key, "patch") != 0) | if (std::strcmp(key, "patch") != 0) | ||||
| return String(); | return String(); | ||||
| @@ -839,22 +994,56 @@ protected: | |||||
| void setState(const char* const key, const char* const value) override | void setState(const char* const key, const char* const value) override | ||||
| { | { | ||||
| #ifndef HEADLESS | #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) | if (std::strcmp(key, "windowSize") == 0) | ||||
| { | { | ||||
| fWindowSize = value; | |||||
| fState.windowSize = value; | |||||
| return; | return; | ||||
| } | } | ||||
| #endif | #endif | ||||
| if (std::strcmp(key, "comment") == 0) | if (std::strcmp(key, "comment") == 0) | ||||
| { | { | ||||
| fStateComment = value; | |||||
| fState.comment = value; | |||||
| return; | return; | ||||
| } | } | ||||
| if (std::strcmp(key, "screenshot") == 0) | if (std::strcmp(key, "screenshot") == 0) | ||||
| { | { | ||||
| fStateScreenshot = value; | |||||
| fState.screenshot = value; | |||||
| #if defined(HAVE_LIBLO) && !defined(HEADLESS) | #if defined(HAVE_LIBLO) && !defined(HEADLESS) | ||||
| patchUtils::sendScreenshotToRemote(value); | patchUtils::sendScreenshotToRemote(value); | ||||
| #endif | #endif | ||||
| @@ -914,6 +1103,8 @@ protected: | |||||
| { | { | ||||
| rack::contextSet(context); | rack::contextSet(context); | ||||
| const bool bypassed = context->bypassed; | |||||
| { | { | ||||
| const TimePosition& timePos(getTimePosition()); | const TimePosition& timePos(getTimePosition()); | ||||
| @@ -967,10 +1158,29 @@ protected: | |||||
| for (int i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) | for (int i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) | ||||
| std::memset(outputs[i], 0, sizeof(float)*frames); | std::memset(outputs[i], 0, sizeof(float)*frames); | ||||
| context->midiEvents = 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); | context->engine->stepBlock(frames); | ||||
| fWasBypassed = bypassed; | |||||
| } | } | ||||
| void bufferSizeChanged(const uint32_t newBufferSize) override | void bufferSizeChanged(const uint32_t newBufferSize) override | ||||
| @@ -304,9 +304,7 @@ public: | |||||
| // hide "Browse VCV Library" button | // hide "Browse VCV Library" button | ||||
| rack::widget::Widget* const browser = context->scene->browser->children.back(); | rack::widget::Widget* const browser = context->scene->browser->children.back(); | ||||
| rack::widget::Widget* const headerLayout = browser->children.front(); | 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(); | rack::widget::Widget* const libraryButton = headerLayout->children.back(); | ||||
| favoriteButton->hide(); | |||||
| libraryButton->hide(); | libraryButton->hide(); | ||||
| // Report to user if something is wrong with the installation | // Report to user if something is wrong with the installation | ||||
| @@ -325,7 +323,15 @@ public: | |||||
| } | } | ||||
| if (! errorMessage.empty()) | if (! errorMessage.empty()) | ||||
| asyncDialog::create(errorMessage.c_str()); | |||||
| { | |||||
| static bool shown = false; | |||||
| if (! shown) | |||||
| { | |||||
| shown = true; | |||||
| asyncDialog::create(errorMessage.c_str()); | |||||
| } | |||||
| } | |||||
| context->window->step(); | context->window->step(); | ||||
| @@ -382,13 +388,11 @@ public: | |||||
| filebrowserhandle = nullptr; | filebrowserhandle = nullptr; | ||||
| } | } | ||||
| #ifndef DISTRHO_OS_MAC | |||||
| if (windowParameters.rateLimit != 0 && ++rateLimitStep % (windowParameters.rateLimit * 2)) | if (windowParameters.rateLimit != 0 && ++rateLimitStep % (windowParameters.rateLimit * 2)) | ||||
| return; | return; | ||||
| rateLimitStep = 0; | rateLimitStep = 0; | ||||
| repaint(); | repaint(); | ||||
| #endif | |||||
| } | } | ||||
| void WindowParametersChanged(const WindowParameterList param, float value) override | void WindowParametersChanged(const WindowParameterList param, float value) override | ||||
| @@ -447,6 +451,16 @@ public: | |||||
| windowParameters.rateLimit = static_cast<int>(value + 0.5f); | windowParameters.rateLimit = static_cast<int>(value + 0.5f); | ||||
| rateLimitStep = 0; | rateLimitStep = 0; | ||||
| break; | break; | ||||
| case kWindowParameterBrowserSort: | |||||
| windowParameters.browserSort = static_cast<int>(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: | default: | ||||
| return; | return; | ||||
| } | } | ||||
| @@ -512,6 +526,37 @@ protected: | |||||
| windowParameters.rateLimit = static_cast<int>(value + 0.5f); | windowParameters.rateLimit = static_cast<int>(value + 0.5f); | ||||
| rateLimitStep = 0; | rateLimitStep = 0; | ||||
| break; | break; | ||||
| case kWindowParameterBrowserSort: | |||||
| windowParameters.browserSort = static_cast<int>(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: | default: | ||||
| return; | return; | ||||
| } | } | ||||
| @@ -519,7 +564,7 @@ protected: | |||||
| WindowParametersSetValues(context->window, windowParameters); | 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) | if (std::strcmp(key, "windowSize") != 0) | ||||
| return; | return; | ||||
| @@ -36,7 +36,6 @@ ifeq ($(HAIKU),true) | |||||
| BASE_FLAGS += -I../include/haiku-compat | BASE_FLAGS += -I../include/haiku-compat | ||||
| endif | endif | ||||
| BASE_FLAGS += -fno-strict-aliasing | |||||
| BASE_FLAGS += -DPRIVATE= | BASE_FLAGS += -DPRIVATE= | ||||
| BASE_FLAGS += -I../dpf/dgl/src/nanovg | BASE_FLAGS += -I../dpf/dgl/src/nanovg | ||||
| BASE_FLAGS += -I../dpf/distrho | BASE_FLAGS += -I../dpf/distrho | ||||
| @@ -95,8 +94,8 @@ BASE_FLAGS += -I../include/mingw-std-threads | |||||
| endif | endif | ||||
| BUILD_C_FLAGS += -std=gnu11 | BUILD_C_FLAGS += -std=gnu11 | ||||
| BUILD_C_FLAGS += -fno-finite-math-only | |||||
| BUILD_CXX_FLAGS += -fno-finite-math-only | |||||
| BUILD_C_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 | # use our custom function to invert some colors | ||||
| BUILD_CXX_FLAGS += -DnsvgParseFromFile=nsvgParseFromFileCardinal | BUILD_CXX_FLAGS += -DnsvgParseFromFile=nsvgParseFromFileCardinal | ||||
| @@ -116,6 +115,7 @@ RACK_FILES += custom/network.cpp | |||||
| RACK_FILES += custom/osdialog.cpp | RACK_FILES += custom/osdialog.cpp | ||||
| RACK_FILES += override/blendish.c | RACK_FILES += override/blendish.c | ||||
| RACK_FILES += override/context.cpp | RACK_FILES += override/context.cpp | ||||
| RACK_FILES += override/minblep.cpp | |||||
| RACK_FILES += override/plugin.cpp | RACK_FILES += override/plugin.cpp | ||||
| RACK_FILES += override/Engine.cpp | RACK_FILES += override/Engine.cpp | ||||
| RACK_FILES += override/MenuBar.cpp | RACK_FILES += override/MenuBar.cpp | ||||
| @@ -145,6 +145,7 @@ IGNORED_FILES += Rack/src/app/MenuBar.cpp | |||||
| IGNORED_FILES += Rack/src/app/MidiDisplay.cpp | IGNORED_FILES += Rack/src/app/MidiDisplay.cpp | ||||
| IGNORED_FILES += Rack/src/app/Scene.cpp | IGNORED_FILES += Rack/src/app/Scene.cpp | ||||
| IGNORED_FILES += Rack/src/app/TipWindow.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/engine/Engine.cpp | ||||
| IGNORED_FILES += Rack/src/plugin/Model.cpp | IGNORED_FILES += Rack/src/plugin/Model.cpp | ||||
| IGNORED_FILES += Rack/src/window/Window.cpp | IGNORED_FILES += Rack/src/window/Window.cpp | ||||
| @@ -172,21 +173,43 @@ endif | |||||
| TARGET = rack.a | 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) | all: $(TARGET) | ||||
| ifeq ($(MOD_BUILD),true) | ifeq ($(MOD_BUILD),true) | ||||
| $(MAKE) -C CardinalFX lv2 | $(MAKE) -C CardinalFX lv2 | ||||
| else | else | ||||
| $(MAKE) -C Cardinal | $(MAKE) -C Cardinal | ||||
| $(MAKE) -C CardinalFX | |||||
| $(MAKE) -C CardinalSynth | |||||
| $(MAKE) -C CardinalFX $(CARDINAL_FX_ARGS) | |||||
| $(MAKE) -C CardinalSynth $(CARDINAL_SYNTH_ARGS) | |||||
| endif | 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: | clean: | ||||
| rm -f $(TARGET) | rm -f $(TARGET) | ||||
| rm -rf $(BUILD_DIR) | rm -rf $(BUILD_DIR) | ||||
| $(MAKE) clean -C Cardinal | $(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 | # Build commands | ||||
| @@ -85,6 +85,10 @@ FILES_UI = CardinalUI.cpp | |||||
| FILES_UI += Window.cpp | FILES_UI += Window.cpp | ||||
| endif | endif | ||||
| ifeq ($(WINDOWS),true) | |||||
| FILES_UI += distrho.rc | |||||
| endif | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # Extra libraries to link against | # Extra libraries to link against | ||||
| @@ -129,7 +133,6 @@ else | |||||
| BASE_FLAGS += -DARCH_LIN | BASE_FLAGS += -DARCH_LIN | ||||
| endif | endif | ||||
| BASE_FLAGS += -fno-strict-aliasing | |||||
| BASE_FLAGS += -DPRIVATE= | BASE_FLAGS += -DPRIVATE= | ||||
| BASE_FLAGS += -I.. | BASE_FLAGS += -I.. | ||||
| BASE_FLAGS += -I../../dpf/dgl/src/nanovg | BASE_FLAGS += -I../../dpf/dgl/src/nanovg | ||||
| @@ -170,8 +173,8 @@ BASE_FLAGS += -I../../include/mingw-std-threads | |||||
| endif | endif | ||||
| BUILD_C_FLAGS += -std=gnu11 | BUILD_C_FLAGS += -std=gnu11 | ||||
| BUILD_C_FLAGS += -fno-finite-math-only | |||||
| BUILD_CXX_FLAGS += -fno-finite-math-only | |||||
| BUILD_C_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 | # Rack code is not tested for this flag, unset it | ||||
| BUILD_CXX_FLAGS += -U_GLIBCXX_ASSERTIONS -Wp,-U_GLIBCXX_ASSERTIONS | BUILD_CXX_FLAGS += -U_GLIBCXX_ASSERTIONS -Wp,-U_GLIBCXX_ASSERTIONS | ||||
| @@ -207,7 +210,7 @@ ifeq ($(MACOS),true) | |||||
| LINK_FLAGS += -framework IOKit | LINK_FLAGS += -framework IOKit | ||||
| else ifeq ($(WINDOWS),true) | else ifeq ($(WINDOWS),true) | ||||
| # needed by VCVRack | # needed by VCVRack | ||||
| EXTRA_LIBS += -ldbghelp -lshlwapi | |||||
| EXTRA_LIBS += -ldbghelp -lshlwapi -Wl,--stack,0x100000 | |||||
| # needed by JW-Modules | # needed by JW-Modules | ||||
| EXTRA_LIBS += -lws2_32 -lwinmm | EXTRA_LIBS += -lws2_32 -lwinmm | ||||
| endif | endif | ||||
| @@ -236,6 +239,7 @@ endif | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # fallback path to resource files | # fallback path to resource files | ||||
| ifneq ($(CIBUILD),true) | |||||
| ifneq ($(SYSDEPS),true) | ifneq ($(SYSDEPS),true) | ||||
| ifeq ($(EXE_WRAPPER),wine) | ifeq ($(EXE_WRAPPER),wine) | ||||
| @@ -246,6 +250,7 @@ endif | |||||
| BUILD_CXX_FLAGS += -DCARDINAL_PLUGIN_SOURCE_DIR='"$(SOURCE_DIR)"' | BUILD_CXX_FLAGS += -DCARDINAL_PLUGIN_SOURCE_DIR='"$(SOURCE_DIR)"' | ||||
| endif | |||||
| endif | endif | ||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| @@ -257,13 +262,17 @@ BUILD_CXX_FLAGS += -DCARDINAL_PLUGIN_PREFIX='"$(PREFIX)"' | |||||
| # Enable all possible plugin types and setup resources | # Enable all possible plugin types and setup resources | ||||
| ifeq ($(CARDINAL_VARIANT),main) | ifeq ($(CARDINAL_VARIANT),main) | ||||
| ifneq ($(STATIC_BUILD),true) | |||||
| all: jack lv2 vst3 | all: jack lv2 vst3 | ||||
| else | else | ||||
| all: lv2 vst2 vst3 | |||||
| all: lv2 vst3 | |||||
| endif # STATIC_BUILD | |||||
| else | |||||
| all: lv2 vst2 vst3 static | |||||
| endif | endif | ||||
| CORE_RESOURCES = $(subst ../Rack/res/,,$(wildcard ../Rack/res/ComponentLibrary/*.svg ../Rack/res/fonts/*.ttf)) | CORE_RESOURCES = $(subst ../Rack/res/,,$(wildcard ../Rack/res/ComponentLibrary/*.svg ../Rack/res/fonts/*.ttf)) | ||||
| CORE_RESOURCES += template.vcv | |||||
| CORE_RESOURCES += $(subst ../,,$(wildcard ../template*.vcv)) | |||||
| LV2_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).lv2/resources/%) | LV2_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).lv2/resources/%) | ||||
| VST3_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst3/Contents/Resources/%) | VST3_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst3/Contents/Resources/%) | ||||
| @@ -285,7 +294,7 @@ ifneq ($(CARDINAL_VARIANT),main) | |||||
| ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
| VST2_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst/Contents/Resources/%) | VST2_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst/Contents/Resources/%) | ||||
| else | else | ||||
| VST2_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst/resources/%) | |||||
| VST2_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/Cardinal.vst/resources/%) | |||||
| endif | endif | ||||
| endif | endif | ||||
| @@ -294,8 +303,28 @@ vst2: $(VST2_RESOURCES) | |||||
| vst3: $(VST3_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 $@)" | -@mkdir -p "$(shell dirname $@)" | ||||
| $(SILENT)ln -sf $(abspath $<) $@ | $(SILENT)ln -sf $(abspath $<) $@ | ||||
| @@ -316,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 $@)) | (cd ../../docs/ && pandoc MODDEVICES.md -f markdown+implicit_figures -o $(abspath $@)) | ||||
| endif | endif | ||||
| $(TARGET_DIR)/$(NAME).vst/resources/%: ../Rack/res/% | |||||
| $(TARGET_DIR)/Cardinal.vst/resources/%: ../Rack/res/% | |||||
| -@mkdir -p "$(shell dirname $@)" | -@mkdir -p "$(shell dirname $@)" | ||||
| $(SILENT)ln -sf $(abspath $<) $@ | $(SILENT)ln -sf $(abspath $<) $@ | ||||
| @@ -48,11 +48,11 @@ enum CardinalVariant { | |||||
| // ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
| struct CardinalPluginContext : rack::Context { | struct CardinalPluginContext : rack::Context { | ||||
| uint32_t bufferSize; | |||||
| uint32_t bufferSize, processCounter; | |||||
| double sampleRate; | double sampleRate; | ||||
| float parameters[kModuleParameters]; | float parameters[kModuleParameters]; | ||||
| CardinalVariant variant; | CardinalVariant variant; | ||||
| bool playing, reset, bbtValid; | |||||
| bool bypassed, playing, reset, bbtValid; | |||||
| int32_t bar, beat, beatsPerBar, beatType; | int32_t bar, beat, beatsPerBar, beatType; | ||||
| uint64_t frame; | uint64_t frame; | ||||
| double barStartTick, beatsPerMinute; | double barStartTick, beatsPerMinute; | ||||
| @@ -69,6 +69,7 @@ struct CardinalPluginContext : rack::Context { | |||||
| CardinalPluginContext(Plugin* const p) | CardinalPluginContext(Plugin* const p) | ||||
| : bufferSize(p->getBufferSize()), | : bufferSize(p->getBufferSize()), | ||||
| processCounter(0), | |||||
| sampleRate(p->getSampleRate()), | sampleRate(p->getSampleRate()), | ||||
| #if CARDINAL_VARIANT_MAIN | #if CARDINAL_VARIANT_MAIN | ||||
| variant(kCardinalVariantMain), | variant(kCardinalVariantMain), | ||||
| @@ -79,6 +80,7 @@ struct CardinalPluginContext : rack::Context { | |||||
| #else | #else | ||||
| #error cardinal variant not set | #error cardinal variant not set | ||||
| #endif | #endif | ||||
| bypassed(false), | |||||
| playing(false), | playing(false), | ||||
| reset(false), | reset(false), | ||||
| bbtValid(false), | bbtValid(false), | ||||
| @@ -1 +1 @@ | |||||
| Subproject commit 0d003b96476af45102117c2bb958aeb59eb523cf | |||||
| Subproject commit 30665d62801c2ced7260a37a2d0214edfe6528a9 | |||||
| @@ -44,6 +44,9 @@ enum WindowParameterList { | |||||
| kWindowParameterWheelSensitivity, | kWindowParameterWheelSensitivity, | ||||
| kWindowParameterLockModulePositions, | kWindowParameterLockModulePositions, | ||||
| kWindowParameterUpdateRateLimit, | kWindowParameterUpdateRateLimit, | ||||
| kWindowParameterBrowserSort, | |||||
| kWindowParameterBrowserZoom, | |||||
| kWindowParameterInvertZoom, | |||||
| kWindowParameterCount, | kWindowParameterCount, | ||||
| }; | }; | ||||
| @@ -53,10 +56,13 @@ struct WindowParameters { | |||||
| float rackBrightness = 1.0f; | float rackBrightness = 1.0f; | ||||
| float haloBrightness = 0.25f; | float haloBrightness = 0.25f; | ||||
| float knobScrollSensitivity = 0.001f; | float knobScrollSensitivity = 0.001f; | ||||
| float browserZoom = -1.0f; | |||||
| int knobMode = 0; | int knobMode = 0; | ||||
| int browserSort = 3; | |||||
| bool tooltips = true; | bool tooltips = true; | ||||
| bool knobScroll = false; | bool knobScroll = false; | ||||
| bool lockModules = false; | bool lockModules = false; | ||||
| bool invertZoom = false; | |||||
| // cardinal specific | // cardinal specific | ||||
| int rateLimit = 0; | int rateLimit = 0; | ||||
| }; | }; | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
| * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
| * modify it under the terms of the GNU General Public License as | * 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) { | 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() { | Font::~Font() { | ||||
| // There is no NanoVG deleteFont() function yet, so do nothing | |||||
| } | } | ||||
| @@ -70,18 +64,10 @@ std::shared_ptr<Font> Font::load(const std::string& filename) { | |||||
| void Image::loadFile(const std::string& filename, NVGcontext* vg) { | 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() { | Image::~Image() { | ||||
| // TODO What if handle is invalid? | |||||
| if (handle >= 0) | |||||
| nvgDeleteImage(vg, handle); | |||||
| } | } | ||||
| @@ -90,115 +76,39 @@ std::shared_ptr<Image> 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<std::string, std::shared_ptr<Font>> fontCache; | |||||
| std::map<std::string, std::shared_ptr<Image>> imageCache; | |||||
| bool fbDirtyOnSubpixelChange = true; | |||||
| int fbCount = 0; | |||||
| }; | |||||
| Window::Window() { | 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) { | if (APP->scene) { | ||||
| widget::Widget::ContextDestroyEvent e; | widget::Widget::ContextDestroyEvent e; | ||||
| APP->scene->onContextDestroy(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() { | 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() { | void Window::run() { | ||||
| internal->frame = 0; | |||||
| } | } | ||||
| void Window::step() { | 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() { | void Window::activateContext() { | ||||
| // glfwMakeContextCurrent(win); | |||||
| } | } | ||||
| @@ -228,7 +138,7 @@ bool Window::isCursorLocked() { | |||||
| int Window::getMods() { | int Window::getMods() { | ||||
| return internal->mods; | |||||
| return 0; | |||||
| } | } | ||||
| @@ -242,73 +152,44 @@ bool Window::isFullScreen() { | |||||
| double Window::getMonitorRefreshRate() { | double Window::getMonitorRefreshRate() { | ||||
| return internal->monitorRefreshRate; | |||||
| return 60; | |||||
| } | } | ||||
| double Window::getFrameTime() { | double Window::getFrameTime() { | ||||
| return internal->frameTime; | |||||
| return 0; | |||||
| } | } | ||||
| double Window::getLastFrameDuration() { | double Window::getLastFrameDuration() { | ||||
| return internal->lastFrameDuration; | |||||
| return 0.0; | |||||
| } | } | ||||
| double Window::getFrameDurationRemaining() { | double Window::getFrameDurationRemaining() { | ||||
| double frameDurationDesired = internal->frameSwapInterval / internal->monitorRefreshRate; | |||||
| return frameDurationDesired - (system::getTime() - internal->frameTime); | |||||
| return 0.0; | |||||
| } | } | ||||
| std::shared_ptr<Font> Window::loadFont(const std::string& filename) { | std::shared_ptr<Font> 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> font; | |||||
| try { | |||||
| font = std::make_shared<Font>(); | |||||
| font->loadFile(filename, vg); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("%s", e.what()); | |||||
| font = NULL; | |||||
| } | |||||
| internal->fontCache[filename] = font; | |||||
| return font; | |||||
| return std::make_shared<Font>(); | |||||
| } | } | ||||
| std::shared_ptr<Image> Window::loadImage(const std::string& filename) { | std::shared_ptr<Image> 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> image; | |||||
| try { | |||||
| image = std::make_shared<Image>(); | |||||
| image->loadFile(filename, vg); | |||||
| } | |||||
| catch (Exception& e) { | |||||
| WARN("%s", e.what()); | |||||
| image = NULL; | |||||
| } | |||||
| internal->imageCache[filename] = image; | |||||
| return image; | |||||
| return std::make_shared<Image>(); | |||||
| } | } | ||||
| bool& Window::fbDirtyOnSubpixelChange() { | bool& Window::fbDirtyOnSubpixelChange() { | ||||
| return internal->fbDirtyOnSubpixelChange; | |||||
| static bool _fbDirtyOnSubpixelChange; | |||||
| return _fbDirtyOnSubpixelChange; | |||||
| } | } | ||||
| int& Window::fbCount() { | int& Window::fbCount() { | ||||
| return internal->fbCount; | |||||
| static int _fbCount; | |||||
| return _fbCount; | |||||
| } | } | ||||
| @@ -56,6 +56,21 @@ static const struct { | |||||
| { "/21kHz/res/Panels/D_Inf.svg", {}, -1 }, | { "/21kHz/res/Panels/D_Inf.svg", {}, -1 }, | ||||
| { "/21kHz/res/Panels/PalmLoop.svg", {}, -1 }, | { "/21kHz/res/Panels/PalmLoop.svg", {}, -1 }, | ||||
| { "/21kHz/res/Panels/TachyonEntangler.svg", {}, -1 }, | { "/21kHz/res/Panels/TachyonEntangler.svg", {}, -1 }, | ||||
| // MIT | |||||
| {"/AaronStatic/res/ChordCV.svg", {}, -1 }, | |||||
| {"/AaronStatic/res/DiatonicCV.svg", {}, -1 }, | |||||
| {"/AaronStatic/res/RandomNoteCV.svg", {}, -1 }, | |||||
| {"/AaronStatic/res/ScaleCV.svg", {}, -1 }, | |||||
| // GPL3.0-or-later | |||||
| { "/Algoritmarte/res/Clockkky.svg", {}, -1 }, | |||||
| { "/Algoritmarte/res/CyclicCA.svg", {}, -1 }, | |||||
| { "/Algoritmarte/res/HoldMeTight.svg", {}, -1 }, | |||||
| { "/Algoritmarte/res/MusiFrog.svg", {}, -1 }, | |||||
| { "/Algoritmarte/res/MusiMath.svg", {}, -1 }, | |||||
| { "/Algoritmarte/res/Planetz.svg", {}, -1 }, | |||||
| { "/Algoritmarte/res/Zefiro.svg", {}, -1 }, | |||||
| // Custom, runtime dark mode used with permission | |||||
| { "/ArableInstruments/res/Joni.svg", {}, -1 }, | |||||
| // Custom, runtime dark mode used with permission | // Custom, runtime dark mode used with permission | ||||
| { "/AudibleInstruments/res/Blinds.svg", {}, -1 }, | { "/AudibleInstruments/res/Blinds.svg", {}, -1 }, | ||||
| { "/AudibleInstruments/res/Braids.svg", {}, -1 }, | { "/AudibleInstruments/res/Braids.svg", {}, -1 }, | ||||
| @@ -125,6 +140,7 @@ static const struct { | |||||
| { "/Bidoo/res/VOID.svg", {}, -1 }, | { "/Bidoo/res/VOID.svg", {}, -1 }, | ||||
| { "/Bidoo/res/ZINC.svg", {}, -1 }, | { "/Bidoo/res/ZINC.svg", {}, -1 }, | ||||
| { "/Bidoo/res/ZOUMAI.svg", {}, -1 }, | { "/Bidoo/res/ZOUMAI.svg", {}, -1 }, | ||||
| { "/Bidoo/res/ZOUMAIExpander.svg", {}, -1 }, | |||||
| // BSD-3-Clause | // BSD-3-Clause | ||||
| { "/cf/res/ALGEBRA.svg", {}, -1 }, | { "/cf/res/ALGEBRA.svg", {}, -1 }, | ||||
| { "/cf/res/BUFFER.svg", {}, -1 }, | { "/cf/res/BUFFER.svg", {}, -1 }, | ||||
| @@ -234,6 +250,8 @@ static const struct { | |||||
| { "/JW-Modules/res/Trigs.svg", {}, -1 }, | { "/JW-Modules/res/Trigs.svg", {}, -1 }, | ||||
| { "/JW-Modules/res/WavHeadPanel.svg", {}, -1 }, | { "/JW-Modules/res/WavHeadPanel.svg", {}, -1 }, | ||||
| { "/JW-Modules/res/XYPad.svg", {}, -1 }, | { "/JW-Modules/res/XYPad.svg", {}, -1 }, | ||||
| // GPL3.0-or-later | |||||
| { "/LilacLoop/res/Looper.svg", {}, -1 }, | |||||
| // EUPL-1.2 | // EUPL-1.2 | ||||
| { "/LittleUtils/res/Bias_Semitone.svg", {}, -1 }, | { "/LittleUtils/res/Bias_Semitone.svg", {}, -1 }, | ||||
| { "/LittleUtils/res/ButtonModule.svg", {}, -1 }, | { "/LittleUtils/res/ButtonModule.svg", {}, -1 }, | ||||
| @@ -241,16 +259,75 @@ static const struct { | |||||
| { "/LittleUtils/res/PulseGenerator.svg", {}, -1 }, | { "/LittleUtils/res/PulseGenerator.svg", {}, -1 }, | ||||
| { "/LittleUtils/res/TeleportIn.svg", {}, -1 }, | { "/LittleUtils/res/TeleportIn.svg", {}, -1 }, | ||||
| { "/LittleUtils/res/TeleportOut.svg", {}, -1 }, | { "/LittleUtils/res/TeleportOut.svg", {}, -1 }, | ||||
| // GPL-3.0-or-later | |||||
| { "/kocmoc/res/DDLY.svg", {}, -1 }, | |||||
| { "/kocmoc/res/LADR.svg", {}, -1 }, | |||||
| { "/kocmoc/res/MUL.svg", {}, -1 }, | |||||
| { "/kocmoc/res/OP.svg", {}, -1 }, | |||||
| { "/kocmoc/res/PHASR.svg", {}, -1 }, | |||||
| { "/kocmoc/res/SKF.svg", {}, -1 }, | |||||
| { "/kocmoc/res/SVF.svg", {}, -1 }, | |||||
| { "/kocmoc/res/TRG.svg", {}, -1 }, | |||||
| // CC0-1.0 | |||||
| { "/nonlinearcircuits/res/NLC - 4seq.svg", {}, -1 }, | |||||
| { "/nonlinearcircuits/res/NLC - 8 BIT CIPHER.svg", {}, -1 }, | |||||
| { "/nonlinearcircuits/res/BOOLs2.svg", {}, -1 }, | |||||
| { "/nonlinearcircuits/res/NLC - DIVIDE & CONQUER.svg", {}, -1 }, | |||||
| { "/nonlinearcircuits/res/NLC - DIVINE CMOS.svg", {}, -1 }, | |||||
| { "/nonlinearcircuits/res/DoubleNeuronRef.svg", {}, -1 }, | |||||
| { "/nonlinearcircuits/res/NLC - GENiE.svg", {}, -1 }, | |||||
| { "/nonlinearcircuits/res/LetsSplosh.svg", {}, -1 }, | |||||
| { "/nonlinearcircuits/res/NLC - NEURON.svg", {}, -1 }, | |||||
| { "/nonlinearcircuits/res/NLC - NUMBERWANG.svg", {}, -1 }, | |||||
| { "/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(NSVGpaint& paint, const char* const svgFileToInvert = nullptr) | |||||
| static inline bool invertPaint(NSVGshape* const shape, NSVGpaint& paint, const char* const svgFileToInvert = nullptr) | |||||
| { | { | ||||
| // Special case for DrumKit background grandient | |||||
| if (paint.type == NSVG_PAINT_LINEAR_GRADIENT && svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/DrumKit/", 9) == 0) | |||||
| if (paint.type == NSVG_PAINT_LINEAR_GRADIENT && svgFileToInvert != nullptr) | |||||
| { | { | ||||
| paint.type = NSVG_PAINT_COLOR; | |||||
| paint.color = 0xff191919; | |||||
| return true; | |||||
| // Special case for DrumKit background gradient | |||||
| if (std::strncmp(svgFileToInvert, "/DrumKit/", 9) == 0) | |||||
| { | |||||
| paint.type = NSVG_PAINT_COLOR; | |||||
| paint.color = 0xff191919; | |||||
| return true; | |||||
| } | |||||
| // Special case for PathSet shifty gradient | |||||
| if (std::strncmp(svgFileToInvert, "/PathSet/", 9) == 0) | |||||
| { | |||||
| paint.gradient->stops[0].color = 0xff7c4919; // 50% darker than main blue | |||||
| paint.gradient->stops[1].color = 0xff5b3a1a; // 33.3% darker than main blue | |||||
| return false; | |||||
| } | |||||
| } | } | ||||
| if (paint.type == NSVG_PAINT_NONE) | if (paint.type == NSVG_PAINT_NONE) | ||||
| @@ -259,10 +336,25 @@ static inline bool invertPaint(NSVGpaint& paint, const char* const svgFileToInve | |||||
| return false; | return false; | ||||
| // Special case for Bidoo red color | // 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 | // Special case for JW-Modules colors | ||||
| @@ -303,6 +395,127 @@ static inline bool invertPaint(NSVGpaint& paint, const char* const svgFileToInve | |||||
| } | } | ||||
| } | } | ||||
| // Special case for Lilac | |||||
| if (svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/LilacLoop/", 11) == 0) | |||||
| { | |||||
| switch (paint.color) | |||||
| { | |||||
| // main bg (custom) | |||||
| case 0xffd5d5da: | |||||
| paint.color = 0xff242228; | |||||
| return true; | |||||
| // main color (do nothing) | |||||
| case 0xffbfb7d7: | |||||
| return false; | |||||
| // screws (hide) | |||||
| case 0xffc8c8cf: | |||||
| case 0xffbcbcbc: | |||||
| case 0xffb1b1bb: | |||||
| case 0xffacacac: | |||||
| case 0xff898991: | |||||
| case 0xff727272: | |||||
| paint.color = 0x00000000; | |||||
| return true; | |||||
| } | |||||
| } | |||||
| // Special case for Nonlinear Circuits | |||||
| if (svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/nonlinearcircuits/", 19) == 0) | |||||
| { | |||||
| switch (paint.color) | |||||
| { | |||||
| case 0xff9a7900: | |||||
| case 0xff96782c: | |||||
| case 0xff6a07ae: | |||||
| case 0xffcf8044: | |||||
| case 0xff2ac6ba: | |||||
| case 0xff5ba85c: | |||||
| case 0xffa97b00: | |||||
| case 0xff9f7a00: | |||||
| case 0xffff7300: | |||||
| case 0xffa47b00: | |||||
| case 0xffb09423: | |||||
| return false; | |||||
| case 0xffffffff: | |||||
| paint.color = 0x00000000; | |||||
| return true; | |||||
| } | |||||
| } | |||||
| // Special case for PathSet colors | |||||
| if (svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/PathSet/", 9) == 0) | |||||
| { | |||||
| switch (paint.color) | |||||
| { | |||||
| // main blue tone | |||||
| case 0xffdf7a1a: | |||||
| if (shape->opacity == 0.5f && std::strcmp(svgFileToInvert, "/PathSet/res/AstroVibe.svg") == 0) | |||||
| { | |||||
| shape->opacity = 0.2f; | |||||
| return true; | |||||
| } | |||||
| if (shape->opacity == 0.25f) | |||||
| shape->opacity = 0.75f; | |||||
| return false; | |||||
| // bottom logo stuff, set to full white | |||||
| case 0xff000000: | |||||
| if (shape->stroke.type != NSVG_PAINT_NONE) | |||||
| { | |||||
| paint.color = 0xffffffff; | |||||
| return true; | |||||
| } | |||||
| break; | |||||
| // pink step 2 (pink with 50% opacity on bg) | |||||
| case 0xffef73ea: | |||||
| paint.color = 0xff812d7d; | |||||
| return true; | |||||
| // pink step 3 (pink with 33.3% opacity on bg) | |||||
| case 0xfff49ff0: | |||||
| paint.color = 0xff4d234c; | |||||
| return true; | |||||
| // pink and orange | |||||
| case 0xffe941e2: | |||||
| case 0xff698efb: | |||||
| return false; | |||||
| // blue darker 1 (blue with 50% opacity on bg) | |||||
| case 0xffde944f: | |||||
| case 0xffe3b080: | |||||
| case 0xffe4cbb3: | |||||
| case 0xfff5c99f: | |||||
| case 0xfff6d1b0: | |||||
| paint.color = 0xff7c4919; | |||||
| return true; | |||||
| // blue darker 2 (blue with 33.3% opacity on bg) | |||||
| case 0xffe5d9cd: | |||||
| case 0xfff8dcc2: | |||||
| case 0xffe1a265: | |||||
| paint.color = 0xff5b3a1a; | |||||
| return true; | |||||
| // blue darker 3 (blue with 25% opacity on bg) | |||||
| case 0xffe5cbb3: | |||||
| paint.color = 0xff4b321a; | |||||
| return true; | |||||
| } | |||||
| } | |||||
| // 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) | switch (paint.color) | ||||
| { | { | ||||
| // scopes or other special things (do nothing) | // scopes or other special things (do nothing) | ||||
| @@ -329,6 +542,7 @@ static inline bool invertPaint(NSVGpaint& paint, const char* const svgFileToInve | |||||
| case 0xff0095fe: | case 0xff0095fe: | ||||
| case 0xff4d9a4d: | case 0xff4d9a4d: | ||||
| case 0xff4d4d9a: | case 0xff4d4d9a: | ||||
| case 0xff0187fc: | |||||
| return false; | return false; | ||||
| // pure black (convert to not quite pure white) | // pure black (convert to not quite pure white) | ||||
| case 0xff000000: | case 0xff000000: | ||||
| @@ -384,8 +598,8 @@ NSVGimage* nsvgParseFromFileCardinal(const char* const filename, const char* con | |||||
| if (ignore) | if (ignore) | ||||
| continue; | continue; | ||||
| if (invertPaint(shape->fill, svgFileToInvert)) | |||||
| invertPaint(shape->stroke, svgFileToInvert); | |||||
| if (invertPaint(shape, shape->fill, svgFileToInvert)) | |||||
| invertPaint(shape, shape->stroke, svgFileToInvert); | |||||
| } | } | ||||
| return handle; | return handle; | ||||
| @@ -479,7 +479,8 @@ struct ViewButton : MenuButton { | |||||
| menu->addChild(createBoolPtrMenuItem("Lock module positions", "", &settings::lockModules)); | menu->addChild(createBoolPtrMenuItem("Lock module positions", "", &settings::lockModules)); | ||||
| #ifndef DISTRHO_OS_MAC | |||||
| menu->addChild(createBoolPtrMenuItem("Invert zoom", "", &settings::invertZoom)); | |||||
| menu->addChild(new ui::MenuSeparator); | menu->addChild(new ui::MenuSeparator); | ||||
| static const std::vector<std::string> rateLimitLabels = { | static const std::vector<std::string> 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->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); | ||||
| menu->addChild(createMenuItem("Rack 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("Cardinal Project page", "", [=]() { | menu->addChild(createMenuItem("Cardinal Project page", "", [=]() { | ||||
| @@ -117,7 +117,7 @@ std::string Model::getManualUrl() { | |||||
| } | } | ||||
| void Model::appendContextMenu(ui::Menu* menu, bool) { | |||||
| void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) { | |||||
| // plugin | // plugin | ||||
| menu->addChild(createMenuItem("Plugin: " + plugin->name, "", [=]() { | menu->addChild(createMenuItem("Plugin: " + plugin->name, "", [=]() { | ||||
| system::openBrowser(plugin->pluginUrl); | system::openBrowser(plugin->pluginUrl); | ||||
| @@ -182,15 +182,28 @@ void Model::appendContextMenu(ui::Menu* menu, bool) { | |||||
| system::openBrowser(plugin->changelogUrl); | 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() { | 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; | |||||
| } | } | ||||
| @@ -46,6 +46,10 @@ | |||||
| # undef DEBUG | # undef DEBUG | ||||
| #endif | #endif | ||||
| #ifdef STATIC_BUILD | |||||
| # undef HAVE_LIBLO | |||||
| #endif | |||||
| #ifdef HAVE_LIBLO | #ifdef HAVE_LIBLO | ||||
| # include <lo/lo.h> | # include <lo/lo.h> | ||||
| #endif | #endif | ||||
| @@ -123,7 +127,7 @@ struct ResizeHandle : widget::OpaqueWidget { | |||||
| struct Scene::Internal { | struct Scene::Internal { | ||||
| ResizeHandle* resizeHandle; | |||||
| ResizeHandle* resizeHandle = nullptr; | |||||
| bool heldArrowKeys[4] = {}; | bool heldArrowKeys[4] = {}; | ||||
| @@ -169,6 +173,9 @@ Scene::Scene() { | |||||
| browser->hide(); | browser->hide(); | ||||
| addChild(browser); | addChild(browser); | ||||
| if (isStandalone()) | |||||
| return; | |||||
| internal->resizeHandle = new ResizeHandle; | internal->resizeHandle = new ResizeHandle; | ||||
| internal->resizeHandle->box.size = math::Vec(16, 16); | internal->resizeHandle->box.size = math::Vec(16, 16); | ||||
| addChild(internal->resizeHandle); | addChild(internal->resizeHandle); | ||||
| @@ -196,7 +203,8 @@ void Scene::step() { | |||||
| rackScroll->box.pos.y = menuBar->box.size.y; | 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 | // Resize owned descendants | ||||
| menuBar->box.size.x = box.size.x; | menuBar->box.size.x = box.size.x; | ||||
| @@ -718,6 +718,13 @@ void WindowParametersSave(rack::window::Window* const window) | |||||
| window->internal->callback->WindowParametersChanged(kWindowParameterWheelSensitivity, | window->internal->callback->WindowParametersChanged(kWindowParameterWheelSensitivity, | ||||
| rack::settings::knobScrollSensitivity); | 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) | if (window->internal->params.knobMode != rack::settings::knobMode) | ||||
| { | { | ||||
| 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, | window->internal->callback->WindowParametersChanged(kWindowParameterKnobMode, | ||||
| rack::settings::knobMode); | 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) | if (window->internal->params.tooltips != rack::settings::tooltips) | ||||
| { | { | ||||
| 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, | window->internal->callback->WindowParametersChanged(kWindowParameterLockModulePositions, | ||||
| rack::settings::lockModules); | 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) | if (window->internal->params.rateLimit != rack::settings::rateLimit) | ||||
| { | { | ||||
| 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::rackBrightness = window->internal->params.rackBrightness; | ||||
| rack::settings::haloBrightness = window->internal->params.haloBrightness; | rack::settings::haloBrightness = window->internal->params.haloBrightness; | ||||
| rack::settings::knobScrollSensitivity = window->internal->params.knobScrollSensitivity; | rack::settings::knobScrollSensitivity = window->internal->params.knobScrollSensitivity; | ||||
| rack::settings::browserZoom = window->internal->params.browserZoom; | |||||
| rack::settings::knobMode = static_cast<rack::settings::KnobMode>(window->internal->params.knobMode); | rack::settings::knobMode = static_cast<rack::settings::KnobMode>(window->internal->params.knobMode); | ||||
| rack::settings::browserSort = static_cast<rack::settings::BrowserSort>(window->internal->params.browserSort); | |||||
| rack::settings::tooltips = window->internal->params.tooltips; | rack::settings::tooltips = window->internal->params.tooltips; | ||||
| rack::settings::knobScroll = window->internal->params.knobScroll; | rack::settings::knobScroll = window->internal->params.knobScroll; | ||||
| rack::settings::lockModules = window->internal->params.lockModules; | rack::settings::lockModules = window->internal->params.lockModules; | ||||
| rack::settings::invertZoom = window->internal->params.invertZoom; | |||||
| rack::settings::rateLimit = window->internal->params.rateLimit; | rack::settings::rateLimit = window->internal->params.rateLimit; | ||||
| } | } | ||||