commit 3a3f76665be0d6d3501f04f31f3eb8f1b80a4cf8
parent 05c89fd873a165784e59d4ddd479965bf924ecd9
Author: 790 <790@users.noreply.github.com>
Date: Thu, 10 Mar 2022 14:38:24 +0000
merge cmakelist changes
Diffstat:
17 files changed, 622 insertions(+), 467 deletions(-)
diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml
@@ -10,7 +10,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
- os: [ ubuntu-latest, macos-latest, windows-latest ]
+ os: [ ubuntu-latest, macos-latest, windows-2019 ]
cmake_generator: [ default, Ninja ]
fail-fast: false
name: ${{ matrix.os }} build with ${{ matrix.cmake_generator }} cmake generator
@@ -28,7 +28,7 @@ jobs:
uses: seanmiddleditch/gha-setup-ninja@master
- name: Set up MSVC compiler
- if: matrix.os == 'windows-latest'
+ if: matrix.os == 'windows-2019'
uses: ilammy/msvc-dev-cmd@v1
- name: Configure CMake with ${{ matrix.cmake_generator }}
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -1,103 +1,84 @@
-cmake_minimum_required(VERSION 3.15)
-
-# build a fat binary that runs on both intel and the new Apple M1 chip
-set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "OS X Architectures")
-
-set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X deployment version")
-
-project(gearmulator VERSION 1.2.9)
-
-include(base.cmake)
-
-set(ASMJIT_STATIC TRUE)
-option(${PROJECT_NAME}_BUILD_JUCEPLUGIN "Build Juce plugin" on)
-add_subdirectory(source/dsp56300/source)
-add_subdirectory(source/synthLib)
-add_subdirectory(source/virusLib)
-add_subdirectory(source/libresample)
-
-if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/source/vstsdk2.4.2/public.sdk/source/vst2.x/audioeffect.h)
- set(JUCE_GLOBAL_VST2_SDK_PATH ${CMAKE_CURRENT_SOURCE_DIR}/source/vstsdk2.4.2/)
-endif()
-
-# ----------------- Juce based audio plugin
-
-set_property(GLOBAL PROPERTY USE_FOLDERS YES)
-if(${PROJECT_NAME}_BUILD_JUCEPLUGIN)
- set(JUCE_ENABLE_MODULE_SOURCE_GROUPS ON CACHE BOOL "" FORCE)
- add_subdirectory(source/JUCE)
- add_subdirectory(source/jucePlugin)
-
- if(MSVC OR APPLE)
- if(JUCE_GLOBAL_VST2_SDK_PATH)
- install(TARGETS jucePlugin_VST DESTINATION . COMPONENT VST2)
- endif()
- install(TARGETS jucePlugin_VST3 DESTINATION . COMPONENT VST3)
- if(APPLE)
- install(TARGETS jucePlugin_AU DESTINATION . COMPONENT AU)
- endif()
- elseif(UNIX)
- if(JUCE_GLOBAL_VST2_SDK_PATH)
- install(TARGETS jucePlugin_VST LIBRARY DESTINATION /usr/local/lib/lxvst/ COMPONENT VST2)
- endif()
- install(TARGETS jucePlugin_VST3 LIBRARY DESTINATION /usr/local/lib/vst3/ COMPONENT VST3)
- endif()
-
-# if(MSVC OR APPLE)
-# if(JUCE_GLOBAL_VST2_SDK_PATH)
-# install(TARGETS jucePlugin_Dark_VST DESTINATION . COMPONENT VST2_Dark)
-# endif()
-# install(TARGETS jucePlugin_Dark_VST3 DESTINATION . COMPONENT VST3_Dark)
-# if(APPLE)
-# install(TARGETS jucePlugin_Dark_AU DESTINATION . COMPONENT AU_Dark)
-# endif()
-# elseif(UNIX)
-# if(JUCE_GLOBAL_VST2_SDK_PATH)
-# install(TARGETS jucePlugin_Dark_VST LIBRARY DESTINATION /usr/local/lib/lxvst/ COMPONENT VST2_Dark)
-# endif()
-# install(TARGETS jucePlugin_Dark_VST3 LIBRARY DESTINATION /usr/local/lib/vst3/ COMPONENT VST3_Dark)
-# endif()
-endif()
-
-# ----------------- Test Console
-
-add_executable(virusTestConsole)
-target_sources(virusTestConsole PRIVATE source/virusTestConsole/virusTestConsole.cpp)
-target_link_libraries(virusTestConsole PUBLIC virusLib)
-
-if(UNIX AND NOT APPLE)
- target_link_libraries(virusTestConsole PUBLIC -static-libgcc -static-libstdc++)
-endif()
-
-install(TARGETS virusTestConsole DESTINATION . COMPONENT testConsole)
-
-if(MSVC)
- install(DIRECTORY deploy/win/ DESTINATION . COMPONENT testConsole)
-else()
- install(DIRECTORY deploy/linux/ DESTINATION . COMPONENT testConsole)
-endif()
-
-# ----------------- CPack
-
-get_cmake_property(CPACK_COMPONENTS_ALL COMPONENTS)
-list(REMOVE_ITEM CPACK_COMPONENTS_ALL "Unspecified")
-
-set(CPACK_COMPONENTS_GROUPING IGNORE)
-set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)
-
-set(CPACK_PACKAGE_CONTACT "The Usual Suspects")
-set(CPACK_PACKAGE_VENDOR "The Usual Suspects")
-set(CPACK_PACKAGE_NAME "DSP56300Emu")
-set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "DSP 56300 family emulator audio plugin")
-
-set(CPACK_DEB_COMPONENT_INSTALL ON)
-set(CPACK_DEBIAN_PACKAGE_MAINTAINER "The Usual Suspects")
-set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://dsp56300.wordpress.com")
-set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
-
-set(CPACK_RPM_COMPONENT_INSTALL ON)
-set(CPACK_RPM_PACKAGE_AUTOREQ "yes")
-set(CPACK_RPM_PACKAGE_URL ${CPACK_DEBIAN_PACKAGE_HOMEPAGE})
-set(CPACK_RPM_PACKAGE_DESCRIPTION ${CPACK_PACKAGE_DESCRIPTION_SUMMARY})
-
-include(CPack)
+cmake_minimum_required(VERSION 3.15)
+
+# build a fat binary that runs on both intel and the new Apple M1 chip
+set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "OS X Architectures")
+
+set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X deployment version")
+
+project(gearmulator VERSION 1.2.11)
+
+include(base.cmake)
+
+set(ASMJIT_STATIC TRUE)
+
+option(${PROJECT_NAME}_BUILD_JUCEPLUGIN "Build Juce plugin" on)
+
+add_subdirectory(source/dsp56300/source)
+add_subdirectory(source/synthLib)
+add_subdirectory(source/virusLib)
+add_subdirectory(source/libresample)
+
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/source/vstsdk2.4.2/public.sdk/source/vst2.x/audioeffect.h)
+ set(JUCE_GLOBAL_VST2_SDK_PATH ${CMAKE_CURRENT_SOURCE_DIR}/source/vstsdk2.4.2/)
+endif()
+
+# ----------------- Juce based audio plugin
+
+set_property(GLOBAL PROPERTY USE_FOLDERS YES)
+if(${PROJECT_NAME}_BUILD_JUCEPLUGIN)
+ set(JUCE_ENABLE_MODULE_SOURCE_GROUPS ON CACHE BOOL "" FORCE)
+ add_subdirectory(source/JUCE)
+ add_subdirectory(source/jucePlugin)
+endif()
+
+# ----------------- Test Console
+
+add_executable(virusTestConsole)
+target_sources(virusTestConsole PRIVATE source/virusTestConsole/virusTestConsole.cpp)
+target_link_libraries(virusTestConsole PUBLIC virusLib)
+
+if(UNIX AND NOT APPLE)
+ target_link_libraries(virusTestConsole PUBLIC -static-libgcc -static-libstdc++)
+endif()
+
+install(TARGETS virusTestConsole DESTINATION . COMPONENT testConsole)
+
+if(MSVC)
+ install(DIRECTORY deploy/win/ DESTINATION . COMPONENT testConsole)
+else()
+ install(DIRECTORY deploy/linux/ DESTINATION . COMPONENT testConsole)
+endif()
+
+# ----------------- CPack
+
+get_cmake_property(CPACK_COMPONENTS_ALL COMPONENTS)
+list(REMOVE_ITEM CPACK_COMPONENTS_ALL "Unspecified")
+
+message("CMAKE_SYSTEM_NAME: " ${CMAKE_SYSTEM_NAME})
+message("CMAKE_SYSTEM_PROCESSOR: " ${CMAKE_SYSTEM_PROCESSOR})
+
+if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+ set(CPACK_SYSTEM_NAME ${CMAKE_SYSTEM_NAME}_${CMAKE_SYSTEM_PROCESSOR})
+elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
+ set(CPACK_SYSTEM_NAME "MacOS")
+endif()
+
+set(CPACK_COMPONENTS_GROUPING IGNORE)
+set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)
+
+set(CPACK_PACKAGE_CONTACT "The Usual Suspects")
+set(CPACK_PACKAGE_VENDOR "The Usual Suspects")
+set(CPACK_PACKAGE_NAME "DSP56300Emu")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "DSP 56300 family emulator audio plugin")
+
+set(CPACK_DEB_COMPONENT_INSTALL ON)
+set(CPACK_DEBIAN_PACKAGE_MAINTAINER "The Usual Suspects")
+set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://dsp56300.wordpress.com")
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
+
+set(CPACK_RPM_COMPONENT_INSTALL ON)
+set(CPACK_RPM_PACKAGE_AUTOREQ "yes")
+set(CPACK_RPM_PACKAGE_URL ${CPACK_DEBIAN_PACKAGE_HOMEPAGE})
+set(CPACK_RPM_PACKAGE_DESCRIPTION ${CPACK_PACKAGE_DESCRIPTION_SUMMARY})
+
+include(CPack)
diff --git a/build_linux_console.sh b/build_linux_console.sh
@@ -1,3 +1,3 @@
-cmake . -B ./temp/cmake_linux_console -Dgearmulator_BUILD_JUCEPLUGIN=OFF
+cmake . -B ./temp/cmake_linux_console -Dgearmulator_BUILD_JUCEPLUGIN=OFF -DCMAKE_BUILD_TYPE=Release
cd ./temp/cmake_linux_console
-cmake --build . --config Release
-\ No newline at end of file
+cmake --build . --config Release -j 4
+\ No newline at end of file
diff --git a/source/jucePlugin/CMakeLists.txt b/source/jucePlugin/CMakeLists.txt
@@ -1,177 +1,205 @@
-
-cmake_minimum_required(VERSION 3.15)
-project(jucePlugin VERSION ${CMAKE_PROJECT_VERSION})
-
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_SOURCE_DIR}/version.h)
-
-if(JUCE_GLOBAL_VST2_SDK_PATH)
- set(VST "VST")
-else()
- set(VST "")
-endif()
-
-juce_add_plugin(jucePlugin
- # VERSION ... # Set this if the plugin version is different to the project version
- # ICON_BIG ... # ICON_* arguments specify a path to an image file to use as an icon for the Standalone
- # ICON_SMALL ...
- COMPANY_NAME "The Usual Suspects" # Specify the name of the plugin's author
- IS_SYNTH TRUE # Is this a synth or an effect?
- NEEDS_MIDI_INPUT TRUE # Does the plugin need midi input?
- NEEDS_MIDI_OUTPUT TRUE # Does the plugin need midi output?
- IS_MIDI_EFFECT FALSE # Is this plugin a MIDI effect?
- EDITOR_WANTS_KEYBOARD_FOCUS TRUE # Does the editor need keyboard focus?
- COPY_PLUGIN_AFTER_BUILD FALSE # Should the plugin be installed to a default location after building?
- PLUGIN_MANUFACTURER_CODE TusP # A four-character manufacturer id with at least one upper-case character
- PLUGIN_CODE TusV # A unique four-character plugin id with exactly one upper-case character
- # GarageBand 10.3 requires the first letter to be upper-case, and the remaining letters to be lower-case
- FORMATS AU VST3 ${VST} Standalone # The formats to build. Other valid formats are: AAX Unity VST AU AUv3
- PRODUCT_NAME "DSP56300Emu" # The name of the final executable, which can differ from the target name
-)
-
-set(SOURCES
- parameterDescriptions_C.json
- PluginProcessor.cpp
- PluginProcessor.h
- VirusController.cpp
- VirusController.h
- VirusParameter.cpp
- VirusParameter.h
- VirusParameterBinding.cpp
- VirusParameterBinding.h
- VirusParameterDescription.cpp
- VirusParameterDescription.h
- VirusParameterDescriptions.cpp
- VirusParameterDescriptions.h
- version.h
-)
-
-target_sources(jucePlugin
-PRIVATE
- ${SOURCES}
- PluginEditor.cpp
- PluginEditor.h
- ui/Virus_Buttons.cpp
- ui/Virus_LookAndFeel.cpp
- ui/VirusEditor.cpp
- ui/Virus_ArpEditor.cpp
- ui/Virus_FxEditor.cpp
- ui/Virus_LfoEditor.cpp
- ui/Virus_OscEditor.cpp
- ui/Virus_PatchBrowser.cpp
- ui/Virus_Parts.cpp
- ui/Virus_Buttons.h
- ui/Virus_LookAndFeel.h
- ui/VirusEditor.h
- ui/Virus_ArpEditor.h
- ui/Virus_FxEditor.h
- ui/Virus_LfoEditor.h
- ui/Virus_OscEditor.h
- ui/Virus_PatchBrowser.h
- ui/Virus_Parts.h
- ui/Ui_Utils.h
-
- ui2/Ui_Utils.h
- ui2/Virus_Buttons.cpp
- ui2/Virus_Buttons.h
- ui2/Virus_LookAndFeel.cpp
- ui2/Virus_LookAndFeel.h
- ui2/Virus_Panel1_OscEditor.cpp
- ui2/Virus_Panel1_OscEditor.h
- ui2/Virus_Panel2_LfoEditor.cpp
- ui2/Virus_Panel2_LfoEditor.h
- ui2/Virus_Panel3_FxEditor.cpp
- ui2/Virus_Panel3_FxEditor.h
- ui2/Virus_Panel4_ArpEditor.cpp
- ui2/Virus_Panel4_ArpEditor.h
- ui2/Virus_Panel5_PatchBrowser.cpp
- ui2/Virus_Panel5_PatchBrowser.h
- ui2/VirusEditor.cpp
- ui2/VirusEditor.h
-)
-
-# https://forum.juce.com/t/help-needed-using-binarydata-with-cmake-juce-6/40486
-# "This might be because the BinaryData files are generated during the build, so the IDE may not be able to find them until the build has been run once (and even then, some IDEs might need a bit of a nudge to re-index the binary directory…)"
-juce_add_binary_data(jucePlugin_BinaryData
- SOURCES
- "assets/bg_1377x800.png"
- "assets/panels/bg_arp_1018x620.png"
- "assets/panels/bg_fx_1018x620.png"
- "assets/panels/bg_lfo_1018x620.png"
- "assets/panels/bg_osc_1018x620.png"
- "assets/panels/bg_fxreverb_481x234.png"
- "assets/panels/bg_fxdelay_481x234.png"
- "assets/buttons/GLOBAL_btn_arp_settings_141x26.png"
- "assets/buttons/GLOBAL_btn_effects_141x26.png"
- "assets/buttons/GLOBAL_btn_lfo_matrix_141x26.png"
- "assets/buttons/GLOBAL_btn_osc_filter_141x26.png"
- "assets/buttons/GLOBAL_btn_patch_browser_141x26.png"
- "assets/buttons/env_pol_50x34.png"
- "assets/buttons/lfo_btn_23_19.png"
- "assets/buttons/link_vert_12x36.png"
- "assets/buttons/link_horizon_36x12.png"
- "assets/buttons/presets_btn_43_15.png"
- "assets/buttons/Handle_18x47.png"
- "assets/buttons/sync2_54x25.png"
- "assets/buttons/part_select_btn_36x36.png"
- "assets/buttons/arphold_btn_36x36.png"
- "assets/knobs/Gen_70x70_100.png"
- "assets/knobs/Gen_pol_70x70_100.png"
- "assets/knobs/GenBlue_70x70_100.png"
- "assets/knobs/GenRed_70x70_100.png"
- "assets/knobs/multi_18x18_100.png"
- "assets2/main_background.png"
- "assets2/panels/panel_1.png"
- "assets2/panels/panel_2.png"
- "assets2/panels/panel_3.png"
- "assets2/panels/panel_4.png"
- "assets2/panels/panel_5.png"
- "assets2/buttons/btn_main_1.png"
- "assets2/buttons/btn_main_2.png"
- "assets2/buttons/btn_main_3.png"
- "assets2/buttons/btn_main_4.png"
- "assets2/buttons/btn_main_5.png"
- "assets2/buttons/btn_1.png"
- "assets2/buttons/btn_2.png"
- "assets2/buttons/btn_3.png"
- "assets2/buttons/btn_4.png"
- "assets2/buttons/btn_left.png"
- "assets2/buttons/btn_right.png"
- "assets2/buttons/btn_down.png"
- "assets2/buttons/btn_menu.png"
- "assets2/buttons/btn_load_bank.png"
- "assets2/buttons/btn_save_preset.png"
- "assets2/combobox/cmb_1.png"
- "assets2/combobox/cmb_2.png"
- "assets2/knobs/knob_1_128.png"
- "assets2/knobs/knob_2_128.png"
- "assets2/font/Digital"
- "parameterDescriptions_C.json"
-)
-
-target_compile_definitions(jucePlugin
-PUBLIC
- # JUCE_WEB_BROWSER and JUCE_USE_CURL would be on by default, but you might not need them.
- JUCE_WEB_BROWSER=0 # If you remove this, add `NEEDS_WEB_BROWSER TRUE` to the `juce_add_plugin` call
- JUCE_USE_CURL=0 # If you remove this, add `NEEDS_CURL TRUE` to the `juce_add_plugin` call
- JUCE_VST3_CAN_REPLACE_VST2=0
- JUCE_WIN_PER_MONITOR_DPI_AWARE=0
-)
-
-target_link_libraries(jucePlugin
-PRIVATE
- jucePlugin_BinaryData
- juce::juce_audio_utils
- juce::juce_cryptography
-PUBLIC
- virusLib
- #juce::juce_recommended_config_flags
- #juce::juce_recommended_lto_flags
- #juce::juce_recommended_warning_flags
-)
-
-if(UNIX AND NOT APPLE)
- target_link_libraries(jucePlugin PUBLIC -static-libgcc -static-libstdc++)
-endif()
-
-
-
+
+cmake_minimum_required(VERSION 3.15)
+project(jucePlugin VERSION ${CMAKE_PROJECT_VERSION})
+
+option(${CMAKE_PROJECT_NAME}_BUILD_FX_PLUGIN "Build FX plugin variants" off)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_SOURCE_DIR}/version.h)
+
+if(JUCE_GLOBAL_VST2_SDK_PATH)
+ set(VST "VST")
+else()
+ set(VST "")
+endif()
+
+set(SOURCES
+ parameterDescriptions_C.json
+ PluginProcessor.cpp
+ PluginProcessor.h
+ VirusController.cpp
+ VirusController.h
+ VirusParameter.cpp
+ VirusParameter.h
+ VirusParameterBinding.cpp
+ VirusParameterBinding.h
+ VirusParameterDescription.cpp
+ VirusParameterDescription.h
+ VirusParameterDescriptions.cpp
+ VirusParameterDescriptions.h
+ version.h
+)
+
+macro(createJucePlugin targetName productName isSynth plugin4CC sourcesUI binaryDataProject componentName)
+
+ juce_add_plugin(${targetName}
+ # VERSION ... # Set this if the plugin version is different to the project version
+ # ICON_BIG ... # ICON_* arguments specify a path to an image file to use as an icon for the Standalone
+ # ICON_SMALL ...
+ COMPANY_NAME "The Usual Suspects" # Specify the name of the plugin's author
+ IS_SYNTH ${isSynth} # Is this a synth or an effect?
+ NEEDS_MIDI_INPUT TRUE # Does the plugin need midi input?
+ NEEDS_MIDI_OUTPUT TRUE # Does the plugin need midi output?
+ IS_MIDI_EFFECT FALSE # Is this plugin a MIDI effect?
+ EDITOR_WANTS_KEYBOARD_FOCUS TRUE # Does the editor need keyboard focus?
+ COPY_PLUGIN_AFTER_BUILD FALSE # Should the plugin be installed to a default location after building?
+ PLUGIN_MANUFACTURER_CODE TusP # A four-character manufacturer id with at least one upper-case character
+ PLUGIN_CODE ${plugin4CC} # A unique four-character plugin id with exactly one upper-case character
+ # GarageBand 10.3 requires the first letter to be upper-case, and the remaining letters to be lower-case
+ FORMATS AU VST3 ${VST} Standalone # The formats to build. Other valid formats are: AAX Unity VST AU AUv3
+ PRODUCT_NAME ${productName} # The name of the final executable, which can differ from the target name
+ )
+
+ target_sources(${targetName} PRIVATE ${SOURCES} ${sourcesUI})
+
+ target_compile_definitions(${targetName}
+ PUBLIC
+ # JUCE_WEB_BROWSER and JUCE_USE_CURL would be on by default, but you might not need them.
+ JUCE_WEB_BROWSER=0 # If you remove this, add `NEEDS_WEB_BROWSER TRUE` to the `juce_add_plugin` call
+ JUCE_USE_CURL=0 # If you remove this, add `NEEDS_CURL TRUE` to the `juce_add_plugin` call
+ JUCE_VST3_CAN_REPLACE_VST2=0
+ JUCE_WIN_PER_MONITOR_DPI_AWARE=0
+ )
+
+ target_link_libraries(${targetName}
+ PRIVATE
+ ${binaryDataProject}
+ juce::juce_audio_utils
+ juce::juce_cryptography
+ PUBLIC
+ virusLib
+ #juce::juce_recommended_config_flags
+ #juce::juce_recommended_lto_flags
+ #juce::juce_recommended_warning_flags
+ )
+
+ if(UNIX AND NOT APPLE)
+ target_link_libraries(${targetName} PUBLIC -static-libgcc -static-libstdc++)
+ endif()
+
+ if(MSVC OR APPLE)
+ if(JUCE_GLOBAL_VST2_SDK_PATH)
+ install(TARGETS ${targetName}_VST DESTINATION . COMPONENT VST2${componentName})
+ endif()
+ install(TARGETS ${targetName}_VST3 DESTINATION . COMPONENT VST3${componentName})
+ if(APPLE)
+ install(TARGETS ${targetName}_AU DESTINATION . COMPONENT AU${componentName})
+ endif()
+ elseif(UNIX)
+ if(JUCE_GLOBAL_VST2_SDK_PATH)
+ install(TARGETS ${targetName}_VST LIBRARY DESTINATION /usr/local/lib/lxvst/ COMPONENT VST2${componentName})
+ endif()
+ install(TARGETS ${targetName}_VST3 LIBRARY DESTINATION /usr/local/lib/vst3/ COMPONENT VST3${componentName})
+ endif()
+endmacro()
+
+macro(createJucePlugins postfix sourcesUI assets)
+ juce_add_binary_data(jucePlugin_BinaryData${postfix} SOURCES ${assets})
+
+ createJucePlugin(jucePlugin${postfix} "DSP56300Emu" TRUE "TusV" "${sourcesUI}" jucePlugin_BinaryData${postfix} "${postfix}")
+
+ if(${CMAKE_PROJECT_NAME}_BUILD_FX_PLUGIN)
+ createJucePlugin(jucePlugin${postfix}_FX "DSP56300EmuFX" FALSE "TusF" "${sourcesUI}" jucePlugin_BinaryData${postfix} "${postfix}_FX")
+ endif()
+endmacro()
+
+set(SOURCES_UI
+ PluginEditor.cpp
+ PluginEditor.h
+ ui/Virus_Buttons.cpp
+ ui/Virus_LookAndFeel.cpp
+ ui/VirusEditor.cpp
+ ui/Virus_ArpEditor.cpp
+ ui/Virus_FxEditor.cpp
+ ui/Virus_LfoEditor.cpp
+ ui/Virus_OscEditor.cpp
+ ui/Virus_PatchBrowser.cpp
+ ui/Virus_Parts.cpp
+ ui/Virus_Buttons.h
+ ui/Virus_LookAndFeel.h
+ ui/VirusEditor.h
+ ui/Virus_ArpEditor.h
+ ui/Virus_FxEditor.h
+ ui/Virus_LfoEditor.h
+ ui/Virus_OscEditor.h
+ ui/Virus_PatchBrowser.h
+ ui/Virus_Parts.h
+ ui/Ui_Utils.h
+
+ ui2/Ui_Utils.h
+ ui2/Virus_Buttons.cpp
+ ui2/Virus_Buttons.h
+ ui2/Virus_LookAndFeel.cpp
+ ui2/Virus_LookAndFeel.h
+ ui2/Virus_Panel1_OscEditor.cpp
+ ui2/Virus_Panel1_OscEditor.h
+ ui2/Virus_Panel2_LfoEditor.cpp
+ ui2/Virus_Panel2_LfoEditor.h
+ ui2/Virus_Panel3_FxEditor.cpp
+ ui2/Virus_Panel3_FxEditor.h
+ ui2/Virus_Panel4_ArpEditor.cpp
+ ui2/Virus_Panel4_ArpEditor.h
+ ui2/Virus_Panel5_PatchBrowser.cpp
+ ui2/Virus_Panel5_PatchBrowser.h
+ ui2/VirusEditor.cpp
+ ui2/VirusEditor.h
+)
+
+# https://forum.juce.com/t/help-needed-using-binarydata-with-cmake-juce-6/40486
+# "This might be because the BinaryData files are generated during the build, so the IDE may not be able to find them until the build has been run once (and even then, some IDEs might need a bit of a nudge to re-index the binary directory…)"
+SET(ASSETS
+ "assets/bg_1377x800.png"
+ "assets/panels/bg_arp_1018x620.png"
+ "assets/panels/bg_fx_1018x620.png"
+ "assets/panels/bg_lfo_1018x620.png"
+ "assets/panels/bg_osc_1018x620.png"
+ "assets/panels/bg_fxreverb_481x234.png"
+ "assets/panels/bg_fxdelay_481x234.png"
+ "assets/buttons/GLOBAL_btn_arp_settings_141x26.png"
+ "assets/buttons/GLOBAL_btn_effects_141x26.png"
+ "assets/buttons/GLOBAL_btn_lfo_matrix_141x26.png"
+ "assets/buttons/GLOBAL_btn_osc_filter_141x26.png"
+ "assets/buttons/GLOBAL_btn_patch_browser_141x26.png"
+ "assets/buttons/env_pol_50x34.png"
+ "assets/buttons/lfo_btn_23_19.png"
+ "assets/buttons/link_vert_12x36.png"
+ "assets/buttons/link_horizon_36x12.png"
+ "assets/buttons/presets_btn_43_15.png"
+ "assets/buttons/Handle_18x47.png"
+ "assets/buttons/sync2_54x25.png"
+ "assets/buttons/part_select_btn_36x36.png"
+ "assets/buttons/arphold_btn_36x36.png"
+ "assets/knobs/Gen_70x70_100.png"
+ "assets/knobs/Gen_pol_70x70_100.png"
+ "assets/knobs/GenBlue_70x70_100.png"
+ "assets/knobs/GenRed_70x70_100.png"
+ "assets/knobs/multi_18x18_100.png"
+ "assets2/main_background.png"
+ "assets2/panels/panel_1.png"
+ "assets2/panels/panel_2.png"
+ "assets2/panels/panel_3.png"
+ "assets2/panels/panel_4.png"
+ "assets2/panels/panel_5.png"
+ "assets2/buttons/btn_main_1.png"
+ "assets2/buttons/btn_main_2.png"
+ "assets2/buttons/btn_main_3.png"
+ "assets2/buttons/btn_main_4.png"
+ "assets2/buttons/btn_main_5.png"
+ "assets2/buttons/btn_1.png"
+ "assets2/buttons/btn_2.png"
+ "assets2/buttons/btn_3.png"
+ "assets2/buttons/btn_4.png"
+ "assets2/buttons/btn_left.png"
+ "assets2/buttons/btn_right.png"
+ "assets2/buttons/btn_down.png"
+ "assets2/buttons/btn_menu.png"
+ "assets2/buttons/btn_load_bank.png"
+ "assets2/buttons/btn_save_preset.png"
+ "assets2/combobox/cmb_1.png"
+ "assets2/combobox/cmb_2.png"
+ "assets2/knobs/knob_1_128.png"
+ "assets2/knobs/knob_2_128.png"
+ "assets2/font/Digital"
+ "parameterDescriptions_C.json"
+)
+
+createJucePlugins("" "${SOURCES_UI}" "${ASSETS}")
diff --git a/source/jucePlugin/VirusController.cpp b/source/jucePlugin/VirusController.cpp
@@ -26,16 +26,20 @@ namespace Virus
registerParams();
// add lambda to enforce updating patches when virus switch from/to multi/single.
- (findSynthParam(0, 0x72, 0x7a))->onValueChanged = [this] {
- const uint8_t prg = isMultiMode() ? 0x0 : virusLib::SINGLE;
- sendSysEx(constructMessage({MessageType::REQUEST_SINGLE, 0x0, prg}));
- sendSysEx(constructMessage({MessageType::REQUEST_MULTI, 0x0, prg}));
+ const auto& params = findSynthParam(0, 0x72, 0x7a);
+ for (const auto& parameter : params)
+ {
+ parameter->onValueChanged = [this] {
+ const uint8_t prg = isMultiMode() ? 0x0 : virusLib::SINGLE;
+ sendSysEx(constructMessage({ MessageType::REQUEST_SINGLE, 0x0, prg }));
+ sendSysEx(constructMessage({ MessageType::REQUEST_MULTI, 0x0, prg }));
- if (onMsgDone)
- {
- onMsgDone();
- }
- };
+ if (onMsgDone)
+ {
+ onMsgDone();
+ }
+ };
+ }
sendSysEx(constructMessage({MessageType::REQUEST_TOTAL}));
sendSysEx(constructMessage({MessageType::REQUEST_ARRANGEMENT}));
@@ -55,9 +59,14 @@ namespace Virus
// 16 parts * 3 pages * 128 params
// TODO: not register internal/unused params?
auto globalParams = std::make_unique<juce::AudioProcessorParameterGroup>("global", "Global", "|");
- for (uint8_t pt = 0; pt < 16; pt++)
+
+ std::map<ParamIndex, int> knownParameterIndices;
+
+ for (uint8_t part = 0; part < 16; part++)
{
- const auto partNumber = juce::String(pt + 1);
+ m_paramsByParamType[part].reserve(m_descriptions.getDescriptions().size());
+
+ const auto partNumber = juce::String(part + 1);
auto group =
std::make_unique<juce::AudioProcessorParameterGroup>("ch" + partNumber, "Ch " + partNumber, "|");
@@ -67,32 +76,76 @@ namespace Virus
const auto paramType = static_cast<ParameterType>(parameterDescIndex);
++parameterDescIndex;
- const ParamIndex idx = {static_cast<uint8_t>(desc.page), pt, desc.index};
+ const ParamIndex idx = {static_cast<uint8_t>(desc.page), part, desc.index};
+
+ int uid = 0;
+
+ auto itKnownParamIdx = knownParameterIndices.find(idx);
+
+ if(itKnownParamIdx == knownParameterIndices.end())
+ knownParameterIndices.insert(std::make_pair(idx, 0));
+ else
+ uid = ++itKnownParamIdx->second;
+
+ auto p = std::make_unique<Parameter>(*this, desc, part, uid);
- m_paramTypeToParamIndex.insert(std::make_pair(paramType, idx));
+ if(uid > 0)
+ {
+ const auto& existingParams = findSynthParam(idx);
+
+ for (auto& existingParam : existingParams)
+ existingParam->addLinkedParameter(p.get());
+ }
+
+ m_paramsByParamType[part].push_back(p.get());
- auto p = std::make_unique<Parameter>(*this, desc, pt);
- const bool isNonPartExclusive = (desc.classFlags & Parameter::Class::GLOBAL) ||
- (desc.classFlags & Parameter::Class::NON_PART_SENSITIVE);
+ const bool isNonPartExclusive = (desc.classFlags & Parameter::Class::GLOBAL) || (desc.classFlags & Parameter::Class::NON_PART_SENSITIVE);
if (isNonPartExclusive)
{
- if (pt != 0)
+ if (part != 0)
continue; // only register on first part!
}
if (p->getDescription().isPublic)
{
- // lifecycle managed by host
- m_synthParams.insert_or_assign(idx, p.get());
+ // lifecycle managed by Juce
+
+ auto itExisting = m_synthParams.find(idx);
+ if (itExisting != m_synthParams.end())
+ {
+ itExisting->second.push_back(p.get());
+ }
+ else
+ {
+ ParameterList params;
+ params.emplace_back(p.get());
+ m_synthParams.insert(std::make_pair(idx, std::move(params)));
+ }
+
if (isNonPartExclusive)
{
- jassert(pt == 0);
+ jassert(part == 0);
globalParams->addChild(std::move(p));
}
else
group->addChild(std::move(p));
}
else
- m_synthInternalParams.insert_or_assign(idx, std::move(p));
+ {
+ // lifecycle handled by us
+
+ auto itExisting = m_synthInternalParams.find(idx);
+ if (itExisting != m_synthInternalParams.end())
+ {
+ itExisting->second.push_back(p.get());
+ }
+ else
+ {
+ ParameterList params;
+ params.emplace_back(p.get());
+ m_synthInternalParams.insert(std::make_pair(idx, std::move(params)));
+ }
+ m_synthInternalParamList.emplace_back(std::move(p));
+ }
}
m_processor.addParameterGroup(std::move(group));
}
@@ -149,39 +202,41 @@ namespace Virus
}
}
- Parameter *Controller::findSynthParam(const uint8_t _part, const uint8_t _page, const uint8_t _paramIndex)
+ const Controller::ParameterList& Controller::findSynthParam(const uint8_t _part, const uint8_t _page, const uint8_t _paramIndex)
{
const ParamIndex paramIndex{ _page, _part, _paramIndex };
return findSynthParam(paramIndex);
}
- Parameter* Controller::findSynthParam(const ParamIndex& _paramIndex)
+ const Controller::ParameterList& Controller::findSynthParam(const ParamIndex& _paramIndex)
{
const auto it = m_synthParams.find(_paramIndex);
- if (it == m_synthParams.end())
- {
- const auto iti = m_synthInternalParams.find(_paramIndex);
+ if (it != m_synthParams.end())
+ return it->second;
- if (iti == m_synthInternalParams.end())
- return nullptr;
+ const auto iti = m_synthInternalParams.find(_paramIndex);
- return iti->second.get();
+ if (iti == m_synthInternalParams.end())
+ {
+ static ParameterList empty;
+ return empty;
}
- return it->second;
- }
- juce::Value *Controller::getParamValue(uint8_t ch, uint8_t bank, uint8_t paramIndex)
+ return iti->second;
+ }
+
+ juce::Value* Controller::getParamValue(uint8_t ch, uint8_t bank, uint8_t paramIndex)
{
- auto *param = findSynthParam(ch, static_cast<uint8_t>(virusLib::PAGE_A + bank), paramIndex);
- if (param == nullptr)
+ const auto& params = findSynthParam(ch, static_cast<uint8_t>(virusLib::PAGE_A + bank), paramIndex);
+ if (params.empty())
{
// unregistered param?
jassertfalse;
return nullptr;
}
- return ¶m->getValueObject();
+ return ¶ms.front()->getValueObject();
}
juce::Value* Controller::getParamValue(const ParameterType _param)
@@ -190,27 +245,20 @@ namespace Virus
return res ? &res->getValueObject() : nullptr;
}
- Parameter* Controller::getParameter(const ParameterType _param)
+ Parameter* Controller::getParameter(const ParameterType _param) const
{
- const auto it = m_paramTypeToParamIndex.find(_param);
- if (it == m_paramTypeToParamIndex.end())
- return nullptr;
-
- const auto& index = it->second;
-
- return findSynthParam(index);
+ return getParameter(_param, 0);
}
- Parameter *Controller::getParameter(const ParameterType _param, const uint8_t _part)
+ Parameter* Controller::getParameter(const ParameterType _param, const uint8_t _part) const
{
- const auto it = m_paramTypeToParamIndex.find(_param);
- if (it == m_paramTypeToParamIndex.end())
+ if (_part >= m_paramsByParamType.size())
return nullptr;
- const auto &index = it->second;
+ if (_param >= m_paramsByParamType[_part].size())
+ return nullptr;
- const ParamIndex paramIndex{index.page, _part, index.paramNum};
- return findSynthParam(paramIndex);
+ return m_paramsByParamType[_part][_param];
}
void Controller::parseParamChange(const SysEx &msg)
@@ -220,24 +268,32 @@ namespace Virus
const auto ch = msg[pos + 1];
const auto index = msg[pos + 2];
const auto value = msg[pos + 3];
- auto param = findSynthParam(ch, page, index);
- if (param == nullptr && ch != 0)
+
+ const auto& partParams = findSynthParam(ch, page, index);
+
+ if (partParams.empty() && ch != 0)
{
// ensure it's not global
- param = findSynthParam(0, page, index);
- if (param == nullptr)
+ const auto& globalParams = findSynthParam(0, page, index);
+ if (globalParams.empty())
{
jassertfalse;
return;
}
- auto flags = param->getDescription().classFlags;
- if (!(flags & Parameter::Class::GLOBAL) && !(flags & Parameter::Class::NON_PART_SENSITIVE))
+ for (const auto& param : globalParams)
{
- jassertfalse;
- return;
+ auto flags = param->getDescription().classFlags;
+ if (!(flags & Parameter::Class::GLOBAL) && !(flags & Parameter::Class::NON_PART_SENSITIVE))
+ {
+ jassertfalse;
+ return;
+ }
}
- }
- param->setValueFromSynth(value, true);
+ for (const auto& param : globalParams)
+ param->setValueFromSynth(value, true);
+ }
+ for (const auto& param : partParams)
+ param->setValueFromSynth(value, true);
// TODO:
/**
If a
@@ -361,11 +417,15 @@ namespace Virus
for (size_t i = 0; i < std::size(patch.data); i++)
{
const uint8_t page = virusLib::PAGE_A + static_cast<uint8_t>(i / pageSize);
- if (auto *p = findSynthParam(ch, page, i % pageSize))
+ const auto& params = findSynthParam(ch, page, i % pageSize);
+ if (!params.empty())
{
- if((p->getDescription().classFlags & Parameter::MULTI_OR_SINGLE) && isMultiMode())
- continue;
- p->setValueFromSynth(patch.data[i], true);
+ for (const auto& param : params)
+ {
+ if ((param->getDescription().classFlags & Parameter::MULTI_OR_SINGLE) && isMultiMode())
+ continue;
+ param->setValueFromSynth(patch.data[i], true);
+ }
}
}
if (onProgramChange)
@@ -400,13 +460,13 @@ namespace Virus
if (patch.bankNumber == 0) {
for (uint8_t pt = 0; pt < 16; pt++) {
for(int i = 0; i < 8; i++) {
- if (auto* p = findSynthParam(pt, virusLib::PAGE_C, virusLib::PART_MIDI_CHANNEL+i)) {
- p->setValueFromSynth(patch.data[virusLib::MD_PART_MIDI_CHANNEL + (i*16) + pt], true);
- }
+ const auto& params = findSynthParam(pt, virusLib::PAGE_C, virusLib::PART_MIDI_CHANNEL + i);
+ for (const auto& p : params)
+ p->setValueFromSynth(patch.data[virusLib::MD_PART_MIDI_CHANNEL + (i * 16) + pt], true);
}
- if (auto* p = findSynthParam(pt, virusLib::PAGE_B, virusLib::CLOCK_TEMPO)) {
+ const auto& params = findSynthParam(pt, virusLib::PAGE_B, virusLib::CLOCK_TEMPO);
+ for (const auto& p : params)
p->setValueFromSynth(patch.data[virusLib::MD_CLOCK_TEMPO], true);
- }
/* if (auto* p = findSynthParam(pt, virusLib::PAGE_A, virusLib::EFFECT_SEND)) {
p->setValueFromSynth(patch.data[virusLib::MD_PART_EFFECT_SEND], true);
}*/
@@ -443,8 +503,8 @@ namespace Virus
return;
DBG(juce::String::formatted("Set part: %d bank: %s param: %d value: %d", part, page == 0 ? "A" : "B", m.b, m.c));
- auto* p = findSynthParam(part, page, m.b);
- if(p)
+ const auto& params = findSynthParam(part, page, m.b);
+ for (const auto & p : params)
p->setValueFromSynth(m.c, true);
}
diff --git a/source/jucePlugin/VirusController.h b/source/jucePlugin/VirusController.h
@@ -39,10 +39,10 @@ namespace Virus
// ch - [0-15]
// bank - [0-2] (ABC)
// paramIndex - [0-127]
- juce::Value *getParamValue(uint8_t ch, uint8_t bank, uint8_t paramIndex);
- juce::Value *getParamValue(ParameterType _param);
- Parameter* getParameter(ParameterType _param);
- Parameter *getParameter(ParameterType _param, uint8_t _part);
+ juce::Value* getParamValue(uint8_t ch, uint8_t bank, uint8_t paramIndex);
+ juce::Value* getParamValue(ParameterType _param);
+ Parameter* getParameter(ParameterType _param) const;
+ Parameter *getParameter(ParameterType _param, uint8_t _part) const;
uint8_t getVirusModel() const;
// bank - 0-1 (AB)
juce::StringArray getSinglePresetNames(virusLib::BankNumber bank) const;
@@ -104,15 +104,18 @@ namespace Virus
}
};
- std::map<ParamIndex, std::unique_ptr<Parameter>> m_synthInternalParams;
- std::map<ParamIndex, Parameter *> m_synthParams; // exposed and managed by audio processor
- std::map<ParameterType, ParamIndex> m_paramTypeToParamIndex;
+ using ParameterList = std::vector<Parameter*>;
+
+ std::map<ParamIndex, ParameterList> m_synthInternalParams;
+ std::map<ParamIndex, ParameterList> m_synthParams; // exposed and managed by audio processor
+ std::array<ParameterList, 16> m_paramsByParamType;
+ std::vector<std::unique_ptr<Parameter>> m_synthInternalParamList;
void registerParams();
// tries to find synth param in both internal and host.
// @return found parameter or nullptr if none found.
- Parameter *findSynthParam(uint8_t _part, uint8_t _page, uint8_t _paramIndex);
- Parameter* findSynthParam(const ParamIndex& _paramIndex);
+ const ParameterList& findSynthParam(uint8_t _part, uint8_t _page, uint8_t _paramIndex);
+ const ParameterList& findSynthParam(const ParamIndex& _paramIndex);
// unchecked copy for patch data bytes
static inline uint8_t copyData(const SysEx &src, int startPos, std::array<uint8_t, kDataSizeInBytes>& dst);
diff --git a/source/jucePlugin/VirusParameter.cpp b/source/jucePlugin/VirusParameter.cpp
@@ -4,9 +4,9 @@
namespace Virus
{
- Parameter::Parameter(Controller &ctrl, const Description& desc, const uint8_t partNum) :
- juce::RangedAudioParameter(genId(desc, partNum), "Ch " + juce::String(partNum + 1) + " " + desc.name), m_ctrl(ctrl),
- m_desc(desc), m_partNum(partNum)
+ Parameter::Parameter(Controller &ctrl, const Description& desc, const uint8_t partNum, const int uniqueId) :
+ RangedAudioParameter(genId(desc, partNum, uniqueId), "Ch " + juce::String(partNum + 1) + " " + desc.name), m_ctrl(ctrl),
+ m_desc(desc), m_partNum(partNum), m_uniqueId(uniqueId)
{
m_range.start = static_cast<float>(m_desc.range.getStart());
m_range.end = static_cast<float>(m_desc.range.getEnd());
@@ -29,20 +29,93 @@ namespace Virus
onValueChanged();
}
+ void Parameter::setLinkedValue(const int _value)
+ {
+ const int newValue = juce::roundToInt(m_range.getRange().clipValue(static_cast<float>(_value)));
+
+ if (newValue == m_lastValue)
+ return;
+
+ m_lastValue = newValue;
+
+ if(getDescription().isPublic)
+ {
+ beginChangeGesture();
+ setValueNotifyingHost(convertTo0to1(static_cast<float>(newValue)));
+ endChangeGesture();
+ }
+ else
+ {
+ m_value.setValue(newValue);
+ }
+ }
+
+ void Parameter::setValue(float newValue)
+ {
+ if (m_changingLinkedValues)
+ return;
+
+ m_value.setValue(convertFrom0to1(newValue));
+
+ m_changingLinkedValues = true;
+
+ for (const auto& parameter : m_linkedParameters)
+ {
+ if(!parameter->m_changingLinkedValues)
+ parameter->setLinkedValue(m_value.getValue());
+ }
+
+ m_changingLinkedValues = false;
+ }
+
void Parameter::setValueFromSynth(int newValue, const bool notifyHost)
{
if (newValue == m_lastValue)
return;
+
m_lastValue = newValue;
- if (notifyHost)
+
+ if (notifyHost && getDescription().isPublic)
+ {
+ beginChangeGesture();
setValueNotifyingHost(convertTo0to1(static_cast<float>(newValue)));
+ endChangeGesture();
+ }
else
+ {
m_value.setValue(newValue);
+ }
+
+ if (m_changingLinkedValues)
+ return;
+
+ m_changingLinkedValues = true;
+
+ for (const auto& p : m_linkedParameters)
+ p->setLinkedValue(newValue);
+
+ m_changingLinkedValues = false;
}
- juce::String Parameter::genId(const Description &d, const int part)
+ juce::String Parameter::genId(const Description &d, const int part, const int uniqueId)
{
- return juce::String::formatted("%d_%d_%d", (int)d.page, part, d.index);
+ if(uniqueId > 0)
+ return juce::String::formatted("%d_%d_%d_%d", static_cast<int>(d.page), part, d.index, uniqueId);
+ return juce::String::formatted("%d_%d_%d", static_cast<int>(d.page), part, d.index);
}
+ void Parameter::addLinkedParameter(Parameter* _param)
+ {
+ if (_param == this)
+ return;
+
+ for (auto* p : m_linkedParameters)
+ {
+ _param->m_linkedParameters.insert(p);
+ p->m_linkedParameters.insert(_param);
+ }
+
+ m_linkedParameters.insert(_param);
+ _param->m_linkedParameters.insert(this);
+ }
} // namespace Virus
diff --git a/source/jucePlugin/VirusParameter.h b/source/jucePlugin/VirusParameter.h
@@ -1,5 +1,7 @@
#pragma once
+#include <set>
+
#include <juce_audio_processors/juce_audio_processors.h>
#include "VirusParameterDescription.h"
@@ -25,7 +27,7 @@ namespace Virus
VIRUS_C = 0x100,
};
- Parameter(Controller &, const Description& desc, uint8_t partNum = 0x40);
+ Parameter(Controller &, const Description& desc, uint8_t partNum, int uniqueId);
juce::Value &getValueObject() { return m_value; };
const juce::Value &getValueObject() const { return m_value; };
@@ -35,7 +37,7 @@ namespace Virus
const juce::NormalisableRange<float> &getNormalisableRange() const override { return m_range; }
float getValue() const override { return convertTo0to1(m_value.getValue()); }
- void setValue(float newValue) override { return m_value.setValue(convertFrom0to1(newValue)); };
+ void setValue(float newValue) override;
void setValueFromSynth(int newValue, bool notifyHost = true);
float getDefaultValue() const override {
// default value should probably be in description instead of hardcoded like this.
@@ -71,15 +73,23 @@ namespace Virus
// eg. multi/single value change requires triggering more logic.
std::function<void()> onValueChanged = {};
+ void addLinkedParameter(Parameter* _param);
+
+ int getUniqueId() const { return m_uniqueId; }
+
private:
- static juce::String genId(const Description &d, int part);
+ static juce::String genId(const Description &d, int part, int uniqueId);
void valueChanged(juce::Value &) override;
+ void setLinkedValue(int _value);
Controller &m_ctrl;
const Description m_desc;
juce::NormalisableRange<float> m_range;
- uint8_t m_partNum;
+ const uint8_t m_partNum;
+ const int m_uniqueId; // 0 for all unique parameters, > 0 if multiple Parameter instances reference a single synth parameter
int m_lastValue{-1};
juce::Value m_value;
+ std::set<Parameter*> m_linkedParameters;
+ bool m_changingLinkedValues = false;
};
} // namespace Virus
diff --git a/source/jucePlugin/VirusParameterBinding.cpp b/source/jucePlugin/VirusParameterBinding.cpp
@@ -83,14 +83,3 @@ void VirusParameterBinding::bind(juce::DrawableButton &_btn, Virus::ParameterTyp
}
_btn.getToggleStateValue().referTo(v->getValueObject());
}
-
-void VirusParameterBinding::bind(juce::Component &_btn, Virus::ParameterType _param)
-{
- const auto v = m_processor.getController().getParameter(_param, m_processor.getController().getCurrentPart());
- if (!v)
- {
- assert(false && "Failed to find parameter");
- return;
- }
-
-}
diff --git a/source/jucePlugin/VirusParameterBinding.h b/source/jucePlugin/VirusParameterBinding.h
@@ -35,7 +35,6 @@ public:
void bind(juce::ComboBox &_control, Virus::ParameterType _param);
void bind(juce::ComboBox &_control, Virus::ParameterType _param, uint8_t _part);
void bind(juce::DrawableButton &_control, Virus::ParameterType _param);
- void bind(juce::Component &_control, Virus::ParameterType _param);
AudioPluginAudioProcessor& m_processor;
juce::Array<Virus::Parameter*> m_bindings;
diff --git a/source/jucePlugin/VirusParameterDescription.h b/source/jucePlugin/VirusParameterDescription.h
@@ -121,8 +121,10 @@ namespace Virus
Param_DelayTime,
Param_DelayFeedback,
Param_DelayRateReverbDecayTime,
- Param_DelayDepthReverbRoomSize,
+ Param_DelayDepth,
+ Param_ReverbRoomSize,
Param_DelayLfoShape,
+ Param_ReverbDamping,
Param_DelayColor,
Param_KeybLocal,
Param_AllNotesOff,
diff --git a/source/jucePlugin/parameterDescriptions_C.json b/source/jucePlugin/parameterDescriptions_C.json
@@ -121,9 +121,10 @@
{"page":"A", "class":"SoundbankA|MultiOrSingle|NonPartSensitive", "index":114, "name":"Delay Time", "min":0, "max":127, "isPublic":true, "isDiscrete":false, "isBool":false},
{"page":"A", "class":"SoundbankA|MultiOrSingle|NonPartSensitive", "index":115, "name":"Delay Feedback", "min":0, "max":127, "isPublic":true, "isDiscrete":false, "isBool":false},
{"page":"A", "class":"SoundbankA|MultiOrSingle|NonPartSensitive", "index":116, "name":"Dly Rate / Rev Decay", "min":0, "max":127, "isPublic":true, "isDiscrete":false, "isBool":false},
- {"page":"A", "class":"SoundbankA|MultiOrSingle|NonPartSensitive", "index":117, "name":"Dly Depth / Rev Size", "min":0, "max":127, "toText":"reverbRoomSize", "isPublic":true, "isDiscrete":true, "isBool":false},
- {"page":"A", "class":"SoundbankA|MultiOrSingle|NonPartSensitive", "index":118, "name":"Delay Lfo Shape", "min":0, "max":127, "toText":"delayLfoShape", "isPublic":true, "isDiscrete":true, "isBool":false},
- // {"page":"A", "class":"SoundbankA|MultiOrSingle|NonPartSensitive", "index":118, "name":"Reverb Damping", "min":0, "max":127, "isPublic":true, "isDiscrete":false, "isBool":false},
+ {"page":"A", "class":"SoundbankA|MultiOrSingle|NonPartSensitive", "index":117, "name":"Dly Depth ", "min":0, "max":127, "isPublic":true, "isDiscrete":false, "isBool":false},
+ {"page":"A", "class":"SoundbankA|MultiOrSingle|NonPartSensitive", "index":117, "name":"Rev Size", "min":0, "max":3, "toText":"reverbRoomSize", "isPublic":true, "isDiscrete":true, "isBool":false},
+ {"page":"A", "class":"SoundbankA|MultiOrSingle|NonPartSensitive", "index":118, "name":"Delay Lfo Shape", "min":0, "max":5, "toText":"delayLfoShape", "isPublic":true, "isDiscrete":true, "isBool":false},
+ {"page":"A", "class":"SoundbankA|MultiOrSingle|NonPartSensitive", "index":118, "name":"Reverb Damping", "min":0, "max":127, "isPublic":true, "isDiscrete":false, "isBool":false},
{"page":"A", "class":"SoundbankA|MultiOrSingle|NonPartSensitive", "index":119, "name":"Delay Color", "min":0, "max":127, "toText":"signed", "isPublic":true, "isDiscrete":false, "isBool":false, "isBipolar":true},
{"page":"A", "class":"SoundbankA|MultiOrSingle|NonPartSensitive", "index":122, "name":"Keyb Local", "min":0, "max":1, "isPublic":false, "isDiscrete":false, "isBool":true},
{"page":"A", "class":"SoundbankA|MultiOrSingle|NonPartSensitive", "index":123, "name":"All Notes Off", "min":0, "max":127, "isPublic":false, "isDiscrete":false, "isBool":false},
@@ -148,8 +149,8 @@
{"page":"B", "class":"SoundbankB|MultiOrSingle|NonPartSensitive", "index":20, "name":"Delay Clock", "min":0, "max":16, "toText":"musicDivision", "isPublic":true, "isDiscrete":true, "isBool":false},
{"page":"B", "class":"SoundbankB", "index":21, "name":"Lfo3 Clock", "min":0, "max":21, "toText":"musicDivision", "isPublic":true, "isDiscrete":true, "isBool":false},
{"page":"B", "class":"SoundbankB", "index":25, "name":"Control Smooth Mode", "min":0, "max":3, "toText":"controlSmoothMode", "isPublic":true, "isDiscrete":true, "isBool":false},
- {"page":"B", "class":"SoundbankB", "index":26, "name":"Bender Range Up", "min":0, "max":127, "toText":"signed", "isPublic":true, "isDiscrete":true, "isBool":false, "isBipolar":"true"},
- {"page":"B", "class":"SoundbankB", "index":27, "name":"Bender Range Down", "min":0, "max":127, "toText":"signed", "isPublic":true, "isDiscrete":true, "isBool":false, "isBipolar":"true"},
+ {"page":"B", "class":"SoundbankB", "index":26, "name":"Bender Range Up", "min":0, "max":127, "toText":"signed", "isPublic":true, "isDiscrete":true, "isBool":false, "isBipolar":true},
+ {"page":"B", "class":"SoundbankB", "index":27, "name":"Bender Range Down", "min":0, "max":127, "toText":"signed", "isPublic":true, "isDiscrete":true, "isBool":false, "isBipolar":true},
{"page":"B", "class":"SoundbankB", "index":28, "name":"Bender Scale", "min":0, "max":1, "toText":"linExp", "isPublic":true, "isDiscrete":true, "isBool":false},
{"page":"B", "class":"SoundbankB", "index":30, "name":"Filter1 Env Polarity", "min":0, "max":1, "toText":"negPos", "isPublic":true, "isDiscrete":false, "isBool":true},
{"page":"B", "class":"SoundbankB", "index":31, "name":"Filter1 Env Polarity", "min":0, "max":1, "toText":"negPos", "isPublic":true, "isDiscrete":false, "isBool":true},
diff --git a/source/jucePlugin/ui/Virus_FxEditor.cpp b/source/jucePlugin/ui/Virus_FxEditor.cpp
@@ -221,7 +221,7 @@ FxEditor::Delay::Delay(VirusParameterBinding &_parameterBinding)
_parameterBinding.bind(m_time, Virus::Param_DelayTime, 0);
_parameterBinding.bind(m_rate, Virus::Param_DelayRateReverbDecayTime, 0);
- _parameterBinding.bind(m_depth, Virus::Param_DelayDepthReverbRoomSize, 0);
+ _parameterBinding.bind(m_depth, Virus::Param_DelayDepth, 0);
_parameterBinding.bind(m_color, Virus::Param_DelayColor, 0);
_parameterBinding.bind(m_feedback, Virus::Param_DelayFeedback, 0);
}
@@ -240,10 +240,10 @@ FxEditor::Reverb::Reverb(VirusParameterBinding &_parameterBinding)
m_reverbMode.setBounds(18, 116+2+22, comboBoxWidth, comboBoxHeight);
addAndMakeVisible(m_reverbMode);
- _parameterBinding.bind(m_reverbMode, Virus::Param_DelayDepthReverbRoomSize, 0);
+ _parameterBinding.bind(m_reverbMode, Virus::Param_ReverbRoomSize, 0);
_parameterBinding.bind(m_time, Virus::Param_DelayTime, 0);
_parameterBinding.bind(m_rate, Virus::Param_DelayRateReverbDecayTime, 0);
- _parameterBinding.bind(m_damping, Virus::Param_DelayLfoShape, 0);
+ _parameterBinding.bind(m_damping, Virus::Param_ReverbDamping, 0);
_parameterBinding.bind(m_color, Virus::Param_DelayColor, 0);
_parameterBinding.bind(m_feedback, Virus::Param_DelayFeedback, 0);
}
diff --git a/source/jucePlugin/ui2/Virus_Panel3_FxEditor.cpp b/source/jucePlugin/ui2/Virus_Panel3_FxEditor.cpp
@@ -180,12 +180,12 @@ namespace Trancy
m_reverbType.setBounds(467 + comboBoxXMargin - comboBox3Width / 2, 854 - comboBox3Height / 2, comboBox3Width,
comboBox3Height);
- _parameterBinding.bind(m_reverbDecayTime, Virus::Param_DelayRateReverbDecayTime);
- _parameterBinding.bind(m_reverbDaming, Virus::Param_DelayLfoShape);
- _parameterBinding.bind(m_reverbColoration, Virus::Param_DelayColor);
- _parameterBinding.bind(m_reverbPredelay, Virus::Param_DelayTime);
- _parameterBinding.bind(m_reverbFeedback, Virus::Param_DelayFeedback);
- _parameterBinding.bind(m_reverbType, Virus::Param_DelayDepthReverbRoomSize);
+ _parameterBinding.bind(m_reverbDecayTime, Virus::Param_DelayRateReverbDecayTime);
+ _parameterBinding.bind(m_reverbDaming, Virus::Param_DelayLfoShape);
+ _parameterBinding.bind(m_reverbColoration, Virus::Param_DelayColor);
+ _parameterBinding.bind(m_reverbPredelay, Virus::Param_DelayTime);
+ _parameterBinding.bind(m_reverbFeedback, Virus::Param_DelayFeedback);
+ _parameterBinding.bind(m_reverbType, Virus::Param_ReverbRoomSize);
// todo Need to check these parameters bindings for delay and reverb
// Delay
@@ -207,13 +207,13 @@ namespace Trancy
m_delayShape.setBounds(467 + comboBoxXMargin - comboBox3Width / 2, 653 - comboBox3Height / 2, comboBox3Width,
comboBox3Height);
- _parameterBinding.bind(m_delayTime, Virus::Param_DelayTime);
- _parameterBinding.bind(m_delayRate, Virus::Param_DelayRateReverbDecayTime);
- _parameterBinding.bind(m_delayFeedback, Virus::Param_DelayFeedback);
- _parameterBinding.bind(m_delayColoration, Virus::Param_DelayColor);
- _parameterBinding.bind(m_delayDepth, Virus::Param_DelayDepthReverbRoomSize);
- _parameterBinding.bind(m_delayClock, Virus::Param_DelayClock);
- _parameterBinding.bind(m_delayShape, Virus::Param_DelayLfoShape);
+ _parameterBinding.bind(m_delayTime, Virus::Param_DelayTime);
+ _parameterBinding.bind(m_delayRate, Virus::Param_DelayRateReverbDecayTime);
+ _parameterBinding.bind(m_delayFeedback, Virus::Param_DelayFeedback);
+ _parameterBinding.bind(m_delayColoration, Virus::Param_DelayColor);
+ _parameterBinding.bind(m_delayDepth, Virus::Param_DelayDepth);
+ _parameterBinding.bind(m_delayClock, Virus::Param_DelayClock);
+ _parameterBinding.bind(m_delayShape, Virus::Param_DelayLfoShape);
// Vocoder
for (auto *s : {&m_vocoderCenterFreq, &m_vocoderModOffset, &m_vocoderModQ, &m_vocoderModSpread, &m_vocoderCarrQ,
diff --git a/source/synthLib/plugin.cpp b/source/synthLib/plugin.cpp
@@ -5,6 +5,12 @@
#include "os.h"
+#if 0
+#define LOGMC(S) LOG(S)
+#else
+#define LOGMC(S) {}
+#endif
+
using namespace synthLib;
namespace synthLib
@@ -110,88 +116,87 @@ namespace synthLib
return m_device->setState(state, stateType);
}
+ void Plugin::insertMidiEvent(const SMidiEvent& _ev)
+ {
+ if(m_midiIn.empty() || m_midiIn.back().offset <= _ev.offset)
+ {
+ m_midiIn.push_back(_ev);
+ return;
+ }
+
+ for (auto it = m_midiIn.begin(); it != m_midiIn.end(); ++it)
+ {
+ if (it->offset > _ev.offset)
+ {
+ m_midiIn.insert(it, _ev);
+ return;
+ }
+ }
+
+ m_midiIn.push_back(_ev);
+ }
+
void Plugin::processMidiClock(float _bpm, float _ppqPos, bool _isPlaying, size_t _sampleCount)
{
if(_bpm < 1.0f)
return;
+ const double ppqPos = _ppqPos;
+
+ constexpr double clockTicksPerQuarter = 24.0;
+
if(_isPlaying && !m_isPlaying)
{
- const uint32_t beat = dsp56k::floor_int(_ppqPos);
-
- if(beat > m_lastKnownBeat)
- {
- // start
- m_isPlaying = true;
- m_needsStart = true;
- }
- m_lastKnownBeat = beat;
+ m_clockTickPos = (ppqPos - std::floor(ppqPos + 1.0)) * clockTicksPerQuarter;
+ LOGMC("Start at ppqPos=" << ppqPos << ", clock tick offset " << m_clockTickPos);
+ m_isPlaying = true;
+ m_needsStart = true;
}
else if(m_isPlaying && !_isPlaying)
{
+ LOGMC("Stop at ppqPos=" << ppqPos);
+
m_isPlaying = false;
SMidiEvent evStop;
evStop.a = M_STOP;
m_midiIn.insert(m_midiIn.begin(), evStop);
- m_clockTickPos = 0.0f;
+ m_clockTickPos = 0.0;
}
- if(m_isPlaying)
- {
- constexpr float clockTicksPerQuarter = 24.0f;
+ if(!m_isPlaying)
+ return;
- const float quartersPerSecond = _bpm / 60.0f;
- const float clockTicksPerSecond = clockTicksPerQuarter * quartersPerSecond;
- const float samplesPerClock = m_hostSamplerate / clockTicksPerSecond;
+ const double quartersPerSecond = _bpm / 60.0;
+ const double clockTicksPerSecond = clockTicksPerQuarter * quartersPerSecond;
- const auto clockTickPos = _ppqPos * clockTicksPerQuarter;
+ const double clocksPerSample = clockTicksPerSecond * m_hostSamplerateInv;
- if(m_clockTickPos <= 0.001f || clockTickPos < m_clockTickPos)
- m_clockTickPos = std::floor(clockTickPos);
+ for(uint32_t i=0; i<static_cast<uint32_t>(_sampleCount); ++i)
+ {
+ m_clockTickPos += clocksPerSample;
- const float offset = clockTickPos - m_clockTickPos;
+ if (m_clockTickPos < 0.0f)
+ continue;
- const float firstSamplePos = std::max((1.0f - offset) * samplesPerClock, 0.0f);
+ m_clockTickPos -= 1.0;
- const auto max = static_cast<float>(_sampleCount);
+ LOGMC("insert tick at " << i);
SMidiEvent evClock;
+ evClock.a = M_TIMINGCLOCK;
+ evClock.offset = i;
- const auto midiEventsEmpty = m_midiIn.empty();
-
- for(float pos = std::floor(firstSamplePos); pos < max; pos += samplesPerClock)
+ if(m_needsStart)
{
- const int insertPos = dsp56k::floor_int(pos);
-
- bool found = false;
-
- if(!midiEventsEmpty)
- {
- for(auto it = m_midiIn.begin(); it != m_midiIn.end(); ++it)
- {
- if(static_cast<int>(it->offset) > insertPos)
- {
- evClock.a = m_needsStart ? M_START : M_TIMINGCLOCK;
- evClock.offset = insertPos;
- m_midiIn.insert(it, evClock);
- found = true;
- break;
- }
- }
- }
-
- if(midiEventsEmpty || !found)
- {
- evClock.a = m_needsStart ? M_START : M_TIMINGCLOCK;
- evClock.offset = insertPos;
- m_midiIn.push_back(evClock);
- }
-
- m_clockTickPos += 1.0f;
+ evClock.a = M_START;
+ insertMidiEvent(evClock);
+ evClock.a = M_TIMINGCLOCK;
m_needsStart = false;
}
+
+ insertMidiEvent(evClock);
}
}
diff --git a/source/synthLib/plugin.h b/source/synthLib/plugin.h
@@ -33,6 +33,8 @@ namespace synthLib
bool getState(std::vector<uint8_t>& _state, StateType _type) const;
bool setState(const std::vector<uint8_t>& _state);
+ void insertMidiEvent(const SMidiEvent& _ev);
+
private:
void processMidiClock(float _bpm, float _ppqPos, bool _isPlaying, size_t _sampleCount);
float* getDummyBuffer(size_t _minimumSize);
@@ -64,7 +66,6 @@ namespace synthLib
// MIDI Clock
bool m_isPlaying = false;
bool m_needsStart = false;
- uint32_t m_lastKnownBeat = 0;
- float m_clockTickPos = 0.0f;
+ double m_clockTickPos = 0.0;
};
}
diff --git a/source/virusLib/microcontroller.cpp b/source/virusLib/microcontroller.cpp
@@ -560,11 +560,14 @@ bool Microcontroller::sendSysex(const std::vector<uint8_t>& _data, bool _cancelI
}
}
- // bounce back to UI
- SMidiEvent ev;
- ev.sysex = _data;
- ev.source = MidiEventSourceEditor; // don't send to output
- _responses.push_back(ev);
+ // bounce back to UI if not sent by editor
+ if(_source != MidiEventSourceEditor)
+ {
+ SMidiEvent ev;
+ ev.sysex = _data;
+ ev.source = MidiEventSourceEditor; // don't send to output
+ _responses.push_back(ev);
+ }
return send(page, part, param, value, _cancelIfFull);
}