├── .github └── workflows │ ├── bump_tag.yml │ ├── cmake_full_test.yml │ ├── cmake_release.yml │ ├── sync.yml │ └── sync_release.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── CMakeLists.txt ├── LICENSE.md ├── README.md ├── assets ├── font │ └── MiSansLatin-Medium.ttf ├── icon │ ├── shut-down-line.svg │ └── split-cells-horizontal.svg ├── logo.svg └── zlaudio.svg ├── cmake-includes ├── Assets.cmake ├── Benchmarks.cmake ├── CHANGELOG.md ├── GitHubENV.cmake ├── GitVersion.cmake ├── JUCEDefaults.cmake ├── PamplejuceIPP.cmake ├── PamplejuceMacOS.cmake ├── PamplejuceVersion.cmake ├── README.md ├── SharedCodeDefaults.cmake ├── Tests.cmake └── XcodePrettify.cmake ├── docs ├── compact_darkblue_flat.svg ├── logo.svg └── screenshot.png ├── licenses ├── Friz_LICENSE.txt ├── RemixIcon_License.txt └── pamplejuce_LICENSE.txt ├── modules └── .gitkeep ├── packaging ├── EULA ├── dmg.json └── installer.iss ├── renovate.json └── source ├── PluginEditor.cpp ├── PluginEditor.h ├── PluginProcessor.cpp ├── PluginProcessor.h ├── dsp ├── controller.cpp ├── controller.hpp ├── controller_attach.cpp ├── controller_attach.hpp ├── dsp.hpp ├── dsp_definitions.hpp ├── gain │ ├── auto_gain.cpp │ ├── auto_gain.hpp │ ├── gain.hpp │ ├── simple_gain.cpp │ └── simple_gain.hpp ├── meter │ ├── meter.hpp │ ├── single_meter.cpp │ └── single_meter.hpp ├── oversample │ ├── over_sampler.cpp │ └── over_sampler.hpp ├── splitter │ ├── iir_splitter.cpp │ ├── iir_splitter.hpp │ ├── lr_splitter.cpp │ ├── lr_splitter.hpp │ ├── ms_splitter.cpp │ ├── ms_splitter.hpp │ └── splitter.hpp └── waveshaper │ ├── warm_inflator.cpp │ ├── warm_inflator.hpp │ └── waveshaper.hpp ├── gui ├── button │ ├── button.hpp │ ├── click_button │ │ ├── click_button.cpp │ │ ├── click_button.hpp │ │ └── click_button_look_and_feel.hpp │ ├── compact_button │ │ ├── compact_button.cpp │ │ ├── compact_button.hpp │ │ └── compact_button_look_and_feel.hpp │ └── regular_button │ │ ├── regular_button.hpp │ │ └── regular_button_look_and_feel.hpp ├── calloutbox │ └── call_out_box_laf.hpp ├── combobox │ ├── combobox.hpp │ ├── compact_combobox │ │ ├── compact_combobox.cpp │ │ ├── compact_combobox.hpp │ │ └── compact_combobox_look_and_feel.hpp │ ├── left_right_combobox │ │ ├── left_right_button_look_and_feel.hpp │ │ ├── left_right_combobox.cpp │ │ ├── left_right_combobox.hpp │ │ └── left_right_combobox_look_and_feel.hpp │ └── regular_combobox │ │ ├── regular_combobox.hpp │ │ └── regular_combobox_look_and_feel.hpp ├── dragger2d │ ├── dragger2d.hpp │ ├── dragger_component.cpp │ ├── dragger_component.hpp │ ├── dragger_look_and_feel.hpp │ ├── dragger_parameter_attach.cpp │ └── dragger_parameter_attach.hpp ├── gui.hpp ├── interface_definitions.hpp ├── interface_definitons.cpp ├── label │ └── name_look_and_feel.hpp └── slider │ ├── compact_linear_slider │ ├── compact_linear_slider.cpp │ ├── compact_linear_slider.hpp │ └── compact_linear_slider_look_and_feel.hpp │ ├── linear_slider │ ├── linear_slider.hpp │ └── linear_slider_look_and_feel.hpp │ ├── rotary_slider │ ├── rotary_slider.hpp │ └── rotary_slider_look_and_feel.hpp │ ├── slider.hpp │ └── two_value_rotary_slider │ ├── first_rotary_slider_look_and_feel.hpp │ ├── second_rotary_slider_look_and_feel.hpp │ ├── two_value_ratary_slider.cpp │ └── two_value_rotary_slider.hpp ├── panel ├── control_panel.cpp ├── control_panel.h ├── logo_panel.cpp ├── logo_panel.h ├── main_panel.cpp ├── main_panel.h ├── meter_panel.cpp ├── meter_panel.h ├── meter_panel │ ├── meter_scale_panel.cpp │ ├── meter_scale_panel.hpp │ ├── single_meter_panel.cpp │ └── single_meter_panel.hpp ├── panel_definitions.h ├── top_panel.cpp └── top_panel.h └── state ├── dummy_processor.cpp ├── dummy_processor.h ├── property.cpp ├── property.h └── state_definitions.h /.github/workflows/bump_tag.yml: -------------------------------------------------------------------------------- 1 | name: Bump tag 2 | on: 3 | workflow_dispatch: 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-24.04 8 | permissions: 9 | contents: write 10 | steps: 11 | - uses: actions/checkout@v4 12 | with: 13 | fetch-depth: '0' 14 | 15 | - name: Bump version and push tag 16 | uses: anothrNick/github-tag-action@1.71.0 # Don't use @master or @v1 unless you're happy to test the latest version 17 | env: 18 | DEFAULT_BUMP: patch 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # if you don't want to set write permissions use a PAT token 20 | WITH_V: false 21 | -------------------------------------------------------------------------------- /.github/workflows/sync.yml: -------------------------------------------------------------------------------- 1 | name: Git sync 2 | on: 3 | workflow_dispatch: 4 | schedule: 5 | - cron: "0 0 * * 0" 6 | 7 | jobs: 8 | sync: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Sync to Gitee 12 | uses: abersheeran/sync-gitee-mirror@v1-beta 13 | with: 14 | repository: ${{ github.repository }} 15 | username: ${{ github.actor }} 16 | password: ${{ secrets.GITEE_PAT }} -------------------------------------------------------------------------------- /.github/workflows/sync_release.yml: -------------------------------------------------------------------------------- 1 | name: Release Sync 2 | on: 3 | workflow_dispatch: 4 | workflow_run: 5 | workflows: [Release] 6 | types: [completed] 7 | 8 | jobs: 9 | build: 10 | name: Release Sync 11 | if: ${{ github.event.workflow_run.conclusion == 'success' }} || ${{ github.event_name == 'workflow_dispatch' }} 12 | runs-on: ubuntu-24.04 13 | permissions: 14 | contents: write 15 | steps: 16 | - name: Checkout current repo 17 | uses: actions/checkout@v4 18 | with: 19 | submodules: false 20 | path: "current_repo" 21 | - name: Download release repo 22 | uses: actions/checkout@v4 23 | with: 24 | repository: "ZL-Audio/ZLRelease" 25 | fetch-depth: 0 26 | path: "release_repo" 27 | ssh-key: ${{ secrets.SSH_RELEASE_DEPLOY_KEY }} 28 | - name: Download current release assets (macOS) 29 | uses: robinraju/release-downloader@v1.11 30 | with: 31 | latest: true 32 | fileName: "*dmg" 33 | out-file-path: "current_release" 34 | - name: Download current release assets (macOS) 35 | uses: robinraju/release-downloader@v1.11 36 | with: 37 | latest: true 38 | fileName: "*exe" 39 | out-file-path: "current_release" 40 | - name: Remove old release assets 41 | run: | 42 | rm -rf "release_repo/${{ github.event.repository.name }}" 43 | mkdir -p "release_repo/${{ github.event.repository.name }}" 44 | ls "current_release/" 45 | - name: Move current release assets 46 | run: | 47 | mv -v "current_release"/* "release_repo/${{ github.event.repository.name }}/" 48 | mv -v "current_repo/CHANGELOG.md" "release_repo/${{ github.event.repository.name }}/README.md" 49 | - name: Commit release repo 50 | run: | 51 | cd "release_repo" 52 | git config user.name github-actions 53 | git config user.email github-actions@github.com 54 | git checkout --orphan newBranch 55 | git add -A 56 | git commit -m "release" 57 | git branch -D main 58 | git branch -m main 59 | git push -f origin main -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeLists.txt.user 2 | CMakeCache.txt 3 | CMakeFiles 4 | CMakeScripts 5 | Makefile 6 | cmake_install.cmake 7 | install_manifest.txt 8 | compile_commands.json 9 | CTestTestfile.cmake 10 | _deps 11 | **/.DS_Store 12 | VERSION 13 | 14 | # It's nice to have the Builds folder exist, to remind us where it is 15 | Builds/* 16 | !Builds/.gitkeep 17 | 18 | # This should never exist 19 | Install/* 20 | 21 | # Running CTest makes a bunch o junk 22 | Testing 23 | 24 | # IDE config 25 | .idea 26 | 27 | # clion cmake builds 28 | cmake-build-debug 29 | cmake-build-release 30 | cmake-build-relwithdebinfo 31 | packaging/Output/* -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "JUCE"] 2 | path = JUCE 3 | url = https://github.com/juce-framework/JUCE/ 4 | branch = master 5 | [submodule "modules/friz"] 6 | path = modules/friz 7 | url = https://github.com/ZL-Audio/animator 8 | branch = fix-warnings 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # ZLWarm 2 | 3 | LICENSE and CODE are available at [https://github.com/ZL-Audio/ZLWarm](https://github.com/ZL-Audio/ZLWarm) 4 | 5 | # Changelog 6 | 7 | ## 0.2.1 8 | 9 | - improve stability 10 | - adjust UI 11 | 12 | ## 0.2.0 13 | 14 | - improve stability and performance 15 | - redesign UI 16 | - add bypass button -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 |

5 | 6 | # ZLWarm 7 | ![pluginval]() 8 | 9 | ZLWarm is a distortion/saturation plugin. 10 | 11 | 12 | 13 | ## Usage 14 | 15 | See the wiki for details. 16 | 17 | ## Download 18 | 19 | See the releases for the latest version. 20 | 21 | **Please NOTICE**: 22 | - the installer has **NOT** been notarized/EV certificated on macOS/Windows 23 | - the plugin has **NOT** been fully tested on DAWs 24 | 25 | ## Build from Source 26 | 27 | 0. `git clone` this repo 28 | 29 | 1. [Download CMAKE](https://cmake.org/download/) if you do not have it. 30 | 31 | 2. Populate the latest JUCE by running `git submodule update --init` in your repository directory. 32 | 33 | 3. Follow the [JUCE CMake API](https://github.com/juce-framework/JUCE/blob/master/docs/CMake%20API.md) to build the source. 34 | 35 | ## License 36 | 37 | ZLWarm is licensed under GPLv3, as found in the [LICENSE.md](LICENSE.md) file. 38 | 39 | Copyright (c) 2023 - [zsliu98](https://github.com/zsliu98) 40 | 41 | JUCE framework from [JUCE](https://github.com/juce-framework/JUCE) 42 | 43 | JUCE template from [pamplejuce](https://github.com/sudara/pamplejuce) 44 | 45 | [Friz](https://github.com/bgporter/animator) by [bgporter](https://github.com/bgporter) 46 | 47 | [RemixIcon](https://github.com/Remix-Design/RemixIcon) by [Remix-Design](https://github.com/Remix-Design) 48 | 49 | Font from CMU Open Sans, Font Awesome and MiSans. -------------------------------------------------------------------------------- /assets/font/MiSansLatin-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZL-Audio/ZLWarm/48093f38c079551924679c5b86bd02d348885f3a/assets/font/MiSansLatin-Medium.ttf -------------------------------------------------------------------------------- /assets/icon/shut-down-line.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icon/split-cells-horizontal.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 10 | 12 | 19 | 20 | -------------------------------------------------------------------------------- /cmake-includes/Assets.cmake: -------------------------------------------------------------------------------- 1 | # HEADS UP: Pamplejuce assumes anything you stick in the assets folder you want to included in your binary! 2 | # This makes life easy, but will bloat your binary needlessly if you include unused files 3 | file(GLOB_RECURSE AssetFiles CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/assets/*") 4 | 5 | # Setup our binary data as a target called Assets 6 | juce_add_binary_data(Assets SOURCES ${AssetFiles}) 7 | 8 | # Required for Linux happiness: 9 | # See https://forum.juce.com/t/loading-pytorch-model-using-binarydata/39997/2 10 | set_target_properties(Assets PROPERTIES POSITION_INDEPENDENT_CODE TRUE) 11 | -------------------------------------------------------------------------------- /cmake-includes/Benchmarks.cmake: -------------------------------------------------------------------------------- 1 | file(GLOB_RECURSE BenchmarkFiles CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/benchmarks/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Benchmarks/*.h") 2 | 3 | # Organize the test source in the Tests/ folder in the IDE 4 | source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/benchmarks PREFIX "" FILES ${BenchmarkFiles}) 5 | 6 | add_executable(Benchmarks ${BenchmarkFiles}) 7 | target_compile_features(Benchmarks PRIVATE cxx_std_20) 8 | catch_discover_tests(Benchmarks) 9 | 10 | # Our benchmark executable also wants to know about our plugin code... 11 | target_include_directories(Benchmarks PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/source) 12 | 13 | # Copy over compile definitions from our plugin target so it has all the JUCEy goodness 14 | target_compile_definitions(Benchmarks PRIVATE $) 15 | 16 | # And give tests access to our shared code 17 | target_link_libraries(Benchmarks PRIVATE SharedCode Catch2::Catch2WithMain) 18 | 19 | # Make an Xcode Scheme for the test executable so we can run tests in the IDE 20 | set_target_properties(Benchmarks PROPERTIES XCODE_GENERATE_SCHEME ON) 21 | 22 | # When running Tests we have specific needs 23 | target_compile_definitions(Benchmarks PUBLIC 24 | JUCE_MODAL_LOOPS_PERMITTED=1 # let us run Message Manager in tests 25 | RUN_PAMPLEJUCE_TESTS=1 # also run tests in module .cpp files guarded by RUN_PAMPLEJUCE_TESTS 26 | ) 27 | -------------------------------------------------------------------------------- /cmake-includes/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2023-09-04 2 | 3 | * Added `SharedCodeDefaults.cmake` which handles setting C++20 and fast math on the `SharedCode` Target. 4 | * Modified CTest to report on failure 5 | 6 | ## 2023-09-04 7 | 8 | Initial commit. Added this CHANGELOG. 9 | -------------------------------------------------------------------------------- /cmake-includes/GitHubENV.cmake: -------------------------------------------------------------------------------- 1 | # Write some temp files to make GitHub Actions / packaging easy 2 | 3 | if ((DEFINED ENV{CI})) 4 | set (env_file "${PROJECT_SOURCE_DIR}/.env") 5 | message ("Writing ENV file for CI: ${env_file}") 6 | 7 | # the first call truncates, the rest append 8 | file(WRITE "${env_file}" "PROJECT_NAME=${PROJECT_NAME}\n") 9 | file(APPEND "${env_file}" "PRODUCT_NAME=${PRODUCT_NAME}\n") 10 | file(APPEND "${env_file}" "VERSION=${CURRENT_VERSION}\n") 11 | file(APPEND "${env_file}" "BUNDLE_ID=${BUNDLE_ID}\n") 12 | file(APPEND "${env_file}" "COMPANY_NAME=${COMPANY_NAME}\n") 13 | endif () 14 | -------------------------------------------------------------------------------- /cmake-includes/GitVersion.cmake: -------------------------------------------------------------------------------- 1 | # Read version from git tag and write it to VERSION file 2 | find_package(Git) 3 | 4 | if(GIT_EXECUTABLE) 5 | # Generate a git-describe version string from Git repository tags 6 | execute_process( 7 | COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=0 8 | OUTPUT_VARIABLE GIT_DESCRIBE_VERSION 9 | RESULT_VARIABLE GIT_DESCRIBE_ERROR_CODE 10 | OUTPUT_STRIP_TRAILING_WHITESPACE 11 | ) 12 | if(NOT GIT_DESCRIBE_ERROR_CODE) 13 | set(FOOBAR_VERSION ${GIT_DESCRIBE_VERSION}) 14 | endif() 15 | endif() 16 | 17 | if(NOT DEFINED FOOBAR_VERSION) 18 | set(FOOBAR_VERSION 0.0.0) 19 | message(WARNING "Failed to determine VERSION from Git tags. Using default version \"${FOOBAR_VERSION}\".") 20 | endif() 21 | 22 | string(REPLACE "v" "" FOOBAR_VERSION_WITHOUT_V "${FOOBAR_VERSION}") 23 | 24 | file(WRITE VERSION "${FOOBAR_VERSION_WITHOUT_V}") -------------------------------------------------------------------------------- /cmake-includes/JUCEDefaults.cmake: -------------------------------------------------------------------------------- 1 | # Adds all the module sources so they appear correctly in the IDE 2 | # Must be set before JUCE is added as a sub-dir (or any targets are made) 3 | # https://github.com/juce-framework/JUCE/commit/6b1b4cf7f6b1008db44411f2c8887d71a3348889 4 | set_property(GLOBAL PROPERTY USE_FOLDERS YES) 5 | 6 | # Creates a /Modules directory in the IDE with the JUCE Module code 7 | option(JUCE_ENABLE_MODULE_SOURCE_GROUPS "Show all module sources in IDE projects" ON) 8 | 9 | # Color our warnings and errors 10 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 11 | add_compile_options(-fdiagnostics-color=always) 12 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 13 | add_compile_options(-fcolor-diagnostics) 14 | endif () 15 | -------------------------------------------------------------------------------- /cmake-includes/PamplejuceIPP.cmake: -------------------------------------------------------------------------------- 1 | # When present, use Intel IPP for performance on Windows 2 | if (WIN32) # Can't use MSVC here, as it won't catch Clang on Windows 3 | find_package(IPP) 4 | if (IPP_FOUND) 5 | target_link_libraries(SharedCode INTERFACE IPP::ipps IPP::ippcore IPP::ippi IPP::ippcv) 6 | message("IPP LIBRARIES FOUND") 7 | target_compile_definitions(SharedCode INTERFACE PAMPLEJUCE_IPP=1) 8 | else () 9 | message("IPP LIBRARIES *NOT* FOUND") 10 | endif () 11 | endif () 12 | -------------------------------------------------------------------------------- /cmake-includes/PamplejuceMacOS.cmake: -------------------------------------------------------------------------------- 1 | 2 | # This must be set before the project() call 3 | # see: https://cmake.org/cmake/help/latest/variable/CMAKE_OSX_DEPLOYMENT_TARGET.html 4 | set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "Support macOS down to High Sierra") 5 | 6 | # Building universal binaries on macOS increases build time 7 | # This is set on CI but not during local dev 8 | if ((DEFINED ENV{CI}) AND (CMAKE_BUILD_TYPE STREQUAL "Release")) 9 | message("Building for Apple Silicon and x86_64") 10 | set(CMAKE_OSX_ARCHITECTURES arm64 x86_64) 11 | endif () 12 | 13 | # By default we don't want Xcode schemes to be made for modules, etc 14 | set(CMAKE_XCODE_GENERATE_SCHEME OFF) 15 | -------------------------------------------------------------------------------- /cmake-includes/PamplejuceVersion.cmake: -------------------------------------------------------------------------------- 1 | # Reads in our VERSION file and sticks in it CURRENT_VERSION variable 2 | # Be sure the file has no newlines! 3 | # This exposes CURRENT_VERSION to the build system 4 | # And it's later fed to JUCE so it shows up as VERSION in your IDE 5 | file(STRINGS VERSION CURRENT_VERSION) 6 | 7 | # Figure out the major version to append to our PROJECT_NAME 8 | string(REGEX MATCH "([0-9]+)" MAJOR_VERSION ${CURRENT_VERSION}) 9 | message(STATUS "Major version: ${MAJOR_VERSION}") 10 | -------------------------------------------------------------------------------- /cmake-includes/README.md: -------------------------------------------------------------------------------- 1 | # CMake Includes for Pamplejuce 2 | 3 | Hi there! 4 | 5 | ## What is this? 6 | 7 | It's most of the actual CMake functionality used by [Pamplejuce](https://github.com/sudara/pamplejuce), my template repository for plugins in the JUCE framework. 8 | 9 | ## Why is this its own git submodule? 10 | 11 | It's to help projects built by the template pull in the lastest changes. 12 | 13 | [Pamplejuce](https://github.com/sudara/pamplejuce) is a template repository. Unlike most "dependencies," when you hit "Create Template" you are literally copying and pasting the code. Which sorta sucks, as people can't get fixes or updates. 14 | 15 | ## Why would I want updates? 16 | 17 | For at least the gritty CMake details, there are fixes, improvements and additional functionality being added. 18 | 19 | In the best case, as a submodule, you can pull in the fixes and improvements. 20 | 21 | In the worst case, this seperate repo will help you see what exactly changed in Pamplejuce. 22 | 23 | ## Is it risky? 24 | 25 | It could be! 26 | 27 | As of 2023, Pamplejuce is still being changed around a bunch, with the goal of being a better and better ecosystem for developers. 28 | 29 | That means there could be breakage when you pull. 30 | 31 | ## What changed recently tho? 32 | 33 | See [CHANGELOG.md](CHANGELOG.md). 34 | -------------------------------------------------------------------------------- /cmake-includes/SharedCodeDefaults.cmake: -------------------------------------------------------------------------------- 1 | # fast math and better simd support in RELEASE and RELWITHDEBINFO 2 | if (MSVC) 3 | # https://learn.microsoft.com/en-us/cpp/build/reference/fp-specify-floating-point-behavior?view=msvc-170#fast 4 | target_compile_options(SharedCode INTERFACE $<$:/fp:fast>) 5 | else () 6 | # See the implications here: 7 | # https://stackoverflow.com/q/45685487 8 | target_compile_options(SharedCode INTERFACE $<$:-Ofast>) 9 | target_compile_options(SharedCode INTERFACE $<$:-Ofast>) 10 | endif () 11 | 12 | # Tell MSVC to properly report what c++ version is being used 13 | if (MSVC) 14 | target_compile_options(SharedCode INTERFACE /Zc:__cplusplus) 15 | endif () 16 | 17 | # C++20, please 18 | # Use cxx_std_23 for C++23 (as of CMake v 3.20) 19 | target_compile_features(SharedCode INTERFACE cxx_std_20) 20 | -------------------------------------------------------------------------------- /cmake-includes/Tests.cmake: -------------------------------------------------------------------------------- 1 | # Required for ctest (which is just an easier way to run in cross-platform CI) 2 | # include(CTest) could be used too, but adds additional targets we don't care about 3 | # See: https://github.com/catchorg/Catch2/issues/2026 4 | # You can also forgo ctest entirely and call ./Tests directly from the build dir 5 | enable_testing() 6 | 7 | # Go into detail when there's a CTest failure 8 | set(CTEST_OUTPUT_ON_FAILURE ON) 9 | set_property(GLOBAL PROPERTY CTEST_TARGETS_ADDED 1) 10 | 11 | # "GLOBS ARE BAD" is brittle and silly dev UX, sorry CMake! 12 | file(GLOB_RECURSE TestFiles CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/tests/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/tests/*.h") 13 | 14 | # Organize the test source in the Tests/ folder in Xcode 15 | source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/tests PREFIX "" FILES ${TestFiles}) 16 | 17 | # Use Catch2 v3 on the devel branch 18 | Include(FetchContent) 19 | FetchContent_Declare( 20 | Catch2 21 | GIT_REPOSITORY https://github.com/catchorg/Catch2.git 22 | GIT_PROGRESS TRUE 23 | GIT_SHALLOW TRUE 24 | GIT_TAG v3.4.0) 25 | FetchContent_MakeAvailable(Catch2) # find_package equivalent 26 | 27 | # Setup the test executable, again C++20 please 28 | add_executable(Tests ${TestFiles}) 29 | target_compile_features(Tests PRIVATE cxx_std_20) 30 | 31 | # Our test executable also wants to know about our plugin code... 32 | target_include_directories(Tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/source) 33 | 34 | # Copy over compile definitions from our plugin target so it has all the JUCEy goodness 35 | target_compile_definitions(Tests PRIVATE $) 36 | 37 | # And give tests access to our shared code 38 | target_link_libraries(Tests PRIVATE SharedCode Catch2::Catch2WithMain) 39 | 40 | # Make an Xcode Scheme for the test executable so we can run tests in the IDE 41 | set_target_properties(Tests PROPERTIES XCODE_GENERATE_SCHEME ON) 42 | 43 | # When running Tests we have specific needs 44 | target_compile_definitions(Tests PUBLIC 45 | JUCE_MODAL_LOOPS_PERMITTED=1 # let us run Message Manager in tests 46 | RUN_PAMPLEJUCE_TESTS=1 # also run tests in other module .cpp files guarded by RUN_PAMPLEJUCE_TESTS 47 | ) 48 | 49 | # Load and use the .cmake file provided by Catch2 50 | # https://github.com/catchorg/Catch2/blob/devel/docs/cmake-integration.md 51 | # We have to manually provide the source directory here for now 52 | include(${Catch2_SOURCE_DIR}/extras/Catch.cmake) 53 | catch_discover_tests(Tests) 54 | -------------------------------------------------------------------------------- /cmake-includes/XcodePrettify.cmake: -------------------------------------------------------------------------------- 1 | # No, we don't want our source buried in extra nested folders 2 | set_target_properties(SharedCode PROPERTIES FOLDER "") 3 | 4 | # The Xcode source tree should uhhh, still look like the source tree, yo 5 | source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/source PREFIX "" FILES ${SourceFiles}) 6 | 7 | # It tucks the Plugin varieties into a "Targets" folder and generate an Xcode Scheme manually 8 | # Xcode scheme generation is turned off globally to limit noise from other targets 9 | # The non-hacky way of doing this is via the global PREDEFINED_TARGETS_FOLDER property 10 | # However that doesn't seem to be working in Xcode 11 | # Not all plugin types (au, vst) available on each build type (win, macos, linux) 12 | foreach (target ${FORMATS} "All") 13 | if (TARGET ${PROJECT_NAME}_${target}) 14 | set_target_properties(${PROJECT_NAME}_${target} PROPERTIES 15 | # Tuck the actual plugin targets into a folder where they won't bother us 16 | FOLDER "Targets" 17 | # Let us build the target in Xcode 18 | XCODE_GENERATE_SCHEME ON) 19 | 20 | # Set the default executable that Xcode will open on build 21 | # Note: you must manually build the AudioPluginHost.xcodeproj in the JUCE subdir 22 | if ((NOT target STREQUAL "All") AND (NOT target STREQUAL "Standalone")) 23 | set_target_properties(${PROJECT_NAME}_${target} PROPERTIES 24 | XCODE_SCHEME_EXECUTABLE "${CMAKE_CURRENT_SOURCE_DIR}/JUCE/extras/AudioPluginHost/Builds/MacOSX/build/Debug/AudioPluginHost.app") 25 | endif () 26 | endif () 27 | endforeach () 28 | 29 | if (TARGET Assets) 30 | set_target_properties(Assets PROPERTIES FOLDER "Targets") 31 | endif () 32 | -------------------------------------------------------------------------------- /docs/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 10 | 12 | 19 | 20 | -------------------------------------------------------------------------------- /docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZL-Audio/ZLWarm/48093f38c079551924679c5b86bd02d348885f3a/docs/screenshot.png -------------------------------------------------------------------------------- /licenses/Friz_LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019-2023 Brett g Porter 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /licenses/pamplejuce_LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Sudara Williams 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /modules/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZL-Audio/ZLWarm/48093f38c079551924679c5b86bd02d348885f3a/modules/.gitkeep -------------------------------------------------------------------------------- /packaging/dmg.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "ZL Warm", 3 | "window": { 4 | "position": { 5 | "x": 100, 6 | "y": 100 7 | }, 8 | "size": { 9 | "width": 730, 10 | "height": 520 11 | } 12 | }, 13 | "format": "UDZO", 14 | "contents": [ 15 | { "x": 250, "y": 245, "type": "file", "path": "dmg/ZL Warm.component" }, 16 | { "x": 480, "y": 245, "type": "file", "path": "dmg/Your Mac's Component Folder" }, 17 | { "x": 250, "y": 405, "type": "file", "path": "dmg/ZL Warm.vst3" }, 18 | { "x": 480, "y": 405, "type": "file", "path": "dmg/Your Mac's VST3 Folder" } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packaging/installer.iss: -------------------------------------------------------------------------------- 1 | #define Version Trim(FileRead(FileOpen("..\VERSION"))) 2 | #define ProjectName GetEnv('PROJECT_NAME') 3 | #define ProductName GetEnv('PRODUCT_NAME') 4 | #define Publisher GetEnv('COMPANY_NAME') 5 | #define Year GetDateTimeString("yyyy","","") 6 | 7 | [Setup] 8 | ArchitecturesInstallIn64BitMode=x64 9 | ArchitecturesAllowed=x64 10 | AppName={#ProductName} 11 | OutputBaseFilename={#ProductName}-{#Version} 12 | AppCopyright=Copyright (C) {#Year} {#Publisher} 13 | AppPublisher={#Publisher} 14 | AppVersion={#Version} 15 | DefaultDirName="{commoncf64}\VST3\{#ProductName}.vst3" 16 | DisableDirPage=yes 17 | 18 | ; MAKE SURE YOU READ THE FOLLOWING! 19 | LicenseFile="EULA" 20 | UninstallFilesDir="{commonappdata}\{#ProductName}\uninstall" 21 | 22 | [UninstallDelete] 23 | Type: filesandordirs; Name: "{commoncf64}\VST3\{#ProductName}Data" 24 | 25 | ; MSVC adds a .ilk when building the plugin. Let's not include that. 26 | [Files] 27 | Source: "..\Builds\{#ProjectName}_artefacts\Release\VST3\{#ProductName}.vst3\*"; DestDir: "{commoncf64}\VST3\{#ProductName}.vst3\"; Excludes: *.ilk; Flags: ignoreversion recursesubdirs; 28 | 29 | [Run] 30 | Filename: "{cmd}"; \ 31 | WorkingDir: "{commoncf64}\VST3"; \ 32 | Parameters: "/C mklink /D ""{commoncf64}\VST3\{#ProductName}Data"" ""{commonappdata}\{#ProductName}"""; \ 33 | Flags: runascurrentuser; -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base" 5 | ], 6 | "git-submodules": { 7 | "enabled": true 8 | }, 9 | "schedule": "after 5am on Friday" 10 | } -------------------------------------------------------------------------------- /source/PluginEditor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2023 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #include "PluginEditor.h" 14 | #include 15 | 16 | //============================================================================== 17 | PluginEditor::PluginEditor(PluginProcessor &p) : 18 | AudioProcessorEditor(&p), processorRef(p), 19 | property(p.states), 20 | mainPanel(p) { 21 | 22 | for (auto &ID: IDs) { 23 | processorRef.states.addParameterListener(ID, this); 24 | } 25 | // set font 26 | auto sourceCodePro = juce::Typeface::createSystemTypefaceFor(BinaryData::MiSansLatinMedium_ttf, 27 | BinaryData::MiSansLatinMedium_ttfSize); 28 | juce::LookAndFeel::getDefaultLookAndFeel().setDefaultSansSerifTypeface(sourceCodePro); 29 | 30 | // add main panel 31 | addAndMakeVisible(mainPanel); 32 | 33 | // set size & size listener 34 | setResizeLimits(zlstate::windowW::minV, zlstate::windowH::minV, zlstate::windowW::maxV, zlstate::windowH::maxV); 35 | getConstrainer()->setFixedAspectRatio( 36 | static_cast(zlstate::windowW::defaultV) / static_cast(zlstate::windowH::defaultV)); 37 | setResizable(true, p.wrapperType != PluginProcessor::wrapperType_AudioUnitv3); 38 | lastUIWidth.referTo(p.states.getParameterAsValue(zlstate::windowW::ID)); 39 | lastUIHeight.referTo(p.states.getParameterAsValue(zlstate::windowH::ID)); 40 | setSize(lastUIWidth.getValue(), lastUIHeight.getValue()); 41 | lastUIWidth.addListener(this); 42 | lastUIHeight.addListener(this); 43 | } 44 | 45 | PluginEditor::~PluginEditor() { 46 | for (auto &ID: IDs) { 47 | processorRef.states.removeParameterListener(ID, this); 48 | } 49 | } 50 | 51 | //============================================================================== 52 | void PluginEditor::paint(juce::Graphics &g) { 53 | juce::ignoreUnused(g); 54 | } 55 | 56 | void PluginEditor::resized() { 57 | mainPanel.setBounds(getLocalBounds()); 58 | lastUIWidth = getWidth(); 59 | lastUIHeight = getHeight(); 60 | } 61 | 62 | void PluginEditor::valueChanged(juce::Value &) { 63 | setSize(lastUIWidth.getValue(), lastUIHeight.getValue()); 64 | } 65 | 66 | void PluginEditor::parameterChanged(const juce::String ¶meterID, float newValue) { 67 | juce::ignoreUnused(parameterID, newValue); 68 | triggerAsyncUpdate(); 69 | } 70 | 71 | void PluginEditor::handleAsyncUpdate() { 72 | property.saveAPVTS(processorRef.states); 73 | sendLookAndFeelChange(); 74 | } -------------------------------------------------------------------------------- /source/PluginEditor.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2023 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #pragma once 14 | 15 | #include "panel/main_panel.h" 16 | #include "state/state_definitions.h" 17 | #include "state/property.h" 18 | #include "PluginProcessor.h" 19 | 20 | //============================================================================== 21 | /** 22 | */ 23 | class PluginEditor : public juce::AudioProcessorEditor, 24 | private juce::Value::Listener, 25 | private juce::AudioProcessorValueTreeState::Listener, 26 | private juce::AsyncUpdater { 27 | public: 28 | explicit PluginEditor(PluginProcessor &); 29 | 30 | ~PluginEditor() override; 31 | 32 | //============================================================================== 33 | void paint(juce::Graphics &) override; 34 | 35 | void resized() override; 36 | 37 | private: 38 | PluginProcessor &processorRef; 39 | zlstate::Property property; 40 | MainPanel mainPanel; 41 | juce::Value lastUIWidth, lastUIHeight; 42 | constexpr const static std::array IDs{zlstate::uiStyle::ID, 43 | zlstate::windowW::ID, zlstate::windowH::ID}; 44 | 45 | void valueChanged(juce::Value &) override; 46 | 47 | void parameterChanged(const juce::String ¶meterID, float newValue) override; 48 | 49 | void handleAsyncUpdate() override; 50 | 51 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginEditor) 52 | }; 53 | -------------------------------------------------------------------------------- /source/PluginProcessor.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2023 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | 18 | #include "dsp/dsp.hpp" 19 | #include "state/dummy_processor.h" 20 | #include "state/state_definitions.h" 21 | 22 | //============================================================================== 23 | /** 24 | */ 25 | class PluginProcessor : public juce::AudioProcessor 26 | #if JucePlugin_Enable_ARA 27 | , 28 | public juce::AudioProcessorARAExtension 29 | #endif 30 | { 31 | public: 32 | DummyProcessor dummyProcessor; 33 | juce::AudioProcessorValueTreeState parameters; 34 | juce::AudioProcessorValueTreeState states; 35 | 36 | //============================================================================== 37 | PluginProcessor(); 38 | 39 | ~PluginProcessor() override; 40 | 41 | //============================================================================== 42 | void prepareToPlay(double sampleRate, int samplesPerBlock) override; 43 | 44 | void releaseResources() override; 45 | 46 | #ifndef JucePlugin_PreferredChannelConfigurations 47 | 48 | bool isBusesLayoutSupported(const BusesLayout &layouts) const override; 49 | 50 | #endif 51 | 52 | void process(juce::dsp::ProcessContextReplacing context); 53 | 54 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override; 55 | 56 | void reset() override; 57 | 58 | //============================================================================== 59 | juce::AudioProcessorEditor *createEditor() override; 60 | 61 | bool hasEditor() const override; 62 | 63 | //============================================================================== 64 | const juce::String getName() const override; 65 | 66 | bool acceptsMidi() const override; 67 | 68 | bool producesMidi() const override; 69 | 70 | bool isMidiEffect() const override; 71 | 72 | double getTailLengthSeconds() const override; 73 | 74 | //============================================================================== 75 | int getNumPrograms() override; 76 | 77 | int getCurrentProgram() override; 78 | 79 | void setCurrentProgram(int index) override; 80 | 81 | const juce::String getProgramName(int index) override; 82 | 83 | void changeProgramName(int index, const juce::String &newName) override; 84 | 85 | //============================================================================== 86 | void getStateInformation(juce::MemoryBlock &destData) override; 87 | 88 | void setStateInformation(const void *data, int sizeInBytes) override; 89 | 90 | inline zlDSP::Controller &getController() { return controller; } 91 | 92 | private: 93 | //============================================================================== 94 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginProcessor) 95 | 96 | zlDSP::Controller controller; 97 | zlDSP::ControllerAttach controllerAttach; 98 | }; 99 | -------------------------------------------------------------------------------- /source/dsp/controller.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2024 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #include "controller.hpp" 14 | 15 | namespace zlDSP { 16 | template 17 | void Controller::prepare(const juce::dsp::ProcessSpec &spec) { 18 | inMeter.prepare(spec); 19 | outMeter.prepare(spec); 20 | inGain.prepare(spec); 21 | outGain.prepare(spec); 22 | { 23 | juce::ScopedLock lock(oversampleLock); 24 | for (size_t i = 0; i < overSamplers.size(); ++i) { 25 | overSamplers[i] = std::make_unique>( 26 | spec.numChannels, i, 27 | juce::dsp::Oversampling::filterHalfBandFIREquiripple, true, 28 | true); 29 | overSamplers[i]->initProcessing(spec.maximumBlockSize); 30 | } 31 | } 32 | mainSpec = spec; 33 | setOverSampleID(oversampleID); 34 | } 35 | 36 | template 37 | void Controller::reset() { 38 | 39 | } 40 | 41 | template 42 | void Controller::process(juce::AudioBuffer &buffer) { 43 | juce::dsp::AudioBlock block(buffer); 44 | juce::dsp::ProcessContextReplacing context(block); 45 | inGain.process(block); 46 | inMeter.process(block); 47 | { 48 | juce::ScopedLock lock1(oversampleLock); 49 | auto oversampled_block = 50 | overSamplers[oversampleID]->processSamplesUp(context.getInputBlock()); 51 | 52 | if (isSplitterON.load()) { 53 | splitter.split(oversampled_block); 54 | 55 | auto lBlock = juce::dsp::AudioBlock(splitter.getLBuffer()); 56 | auto mBlock = juce::dsp::AudioBlock(splitter.getMBuffer()); 57 | auto hBlock = juce::dsp::AudioBlock(splitter.getHBuffer()); 58 | 59 | if (isShaperON.load()) { 60 | shaper.process(lBlock); 61 | shaper.process(mBlock); 62 | shaper.process(hBlock); 63 | } 64 | 65 | splitter.combine(oversampled_block); 66 | } else { 67 | if (isShaperON.load()) { 68 | shaper.process(oversampled_block); 69 | } 70 | } 71 | overSamplers[oversampleID]->processSamplesDown(block); 72 | } 73 | outGain.process(block); 74 | outMeter.process(block); 75 | } 76 | 77 | template 78 | void Controller::setOverSampleID(const size_t idx) { 79 | juce::ScopedLock lock(oversampleLock); 80 | oversampleID = idx; 81 | juce::dsp::ProcessSpec overSampleSpec{ 82 | mainSpec.sampleRate * static_cast(overSampleRate[idx]), 83 | mainSpec.maximumBlockSize * static_cast(overSampleRate[idx]), 84 | mainSpec.numChannels 85 | }; 86 | shaper.prepare(overSampleSpec); 87 | splitter.prepare(overSampleSpec); 88 | if (overSamplers[oversampleID] != nullptr) { 89 | latency.store(static_cast(overSamplers[oversampleID]->getLatencyInSamples())); 90 | } 91 | } 92 | 93 | template 94 | class Controller; 95 | 96 | template 97 | class Controller; 98 | } // zlDSP 99 | -------------------------------------------------------------------------------- /source/dsp/controller.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2024 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #ifndef ZLWarm_CONTROLLER_HPP 14 | #define ZLWarm_CONTROLLER_HPP 15 | 16 | #include "waveshaper/waveshaper.hpp" 17 | #include "meter/meter.hpp" 18 | #include "splitter/splitter.hpp" 19 | #include "gain/gain.hpp" 20 | 21 | namespace zlDSP { 22 | template 23 | class Controller { 24 | public: 25 | Controller() = default; 26 | 27 | void prepare(const juce::dsp::ProcessSpec &spec); 28 | 29 | void reset(); 30 | 31 | void process(juce::AudioBuffer &buffer); 32 | 33 | zlMeter::SingleMeter &getInMeter() { return inMeter; } 34 | 35 | zlMeter::SingleMeter &getOutMeter() { return outMeter; } 36 | 37 | zlSplitter::IIRSplitter &getSplitter() { return splitter; } 38 | 39 | zlWaveShaper::WarmInflator &getShaper() { return shaper; } 40 | 41 | inline void setInGain(const FloatType x) { 42 | inGain.setGainDecibels(x); 43 | } 44 | 45 | inline void setOutGain(const FloatType x) { 46 | outGain.setGainDecibels(x); 47 | } 48 | 49 | void setOverSampleID(size_t idx); 50 | 51 | inline void enableSplitter(const bool x) { isSplitterON.store(x); } 52 | 53 | inline void enableShaper(const bool x) { isShaperON.store(x); } 54 | 55 | inline int getLatency() const { return latency.load(); } 56 | 57 | private: 58 | zlMeter::SingleMeter inMeter, outMeter; 59 | zlSplitter::IIRSplitter splitter; 60 | std::atomic isSplitterON; 61 | zlWaveShaper::WarmInflator shaper; 62 | std::atomic isShaperON; 63 | 64 | zlGain::Gain inGain{}, outGain{}; 65 | 66 | std::array >, 5> overSamplers{}; 67 | std::array overSampleRate = {1, 2, 4, 8, 16}; 68 | size_t oversampleID{0}; 69 | std::atomic latency{0}; 70 | juce::CriticalSection oversampleLock; 71 | juce::dsp::ProcessSpec mainSpec{44100, 512, 2}; 72 | }; 73 | } // zlDSP 74 | 75 | #endif //ZLWarm_CONTROLLER_HPP 76 | -------------------------------------------------------------------------------- /source/dsp/controller_attach.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2023 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #include "controller_attach.hpp" 14 | 15 | namespace zlDSP { 16 | template 17 | ControllerAttach::ControllerAttach(juce::AudioProcessor &processor, 18 | juce::AudioProcessorValueTreeState ¶meters, 19 | Controller &controller) 20 | : processorRef(processor), 21 | parametersRef(parameters), 22 | controllerRef(controller) { 23 | for (size_t i = 0; i < defaultVs.size(); ++i) { 24 | handleParameterChange(IDs[i], defaultVs[i]); 25 | } 26 | for (auto &ID: IDs) { 27 | parametersRef.addParameterListener(ID, this); 28 | } 29 | } 30 | 31 | template 32 | ControllerAttach::~ControllerAttach() { 33 | for (auto &ID: IDs) { 34 | parametersRef.removeParameterListener(ID, this); 35 | } 36 | } 37 | 38 | 39 | template 40 | void ControllerAttach::parameterChanged(const juce::String ¶meterID, float newValue) { 41 | handleParameterChange(parameterID, newValue); 42 | } 43 | 44 | template 45 | void ControllerAttach::handleParameterChange(const juce::String ¶meterID, float newValue) { 46 | auto value = static_cast(newValue); 47 | if (parameterID == inputGain::ID) { 48 | controllerRef.setInGain(value); 49 | } else if (parameterID == outputGain::ID) { 50 | controllerRef.setOutGain(value); 51 | } else if (parameterID == wet::ID) { 52 | controllerRef.getShaper().setWet(wet::formatV(value)); 53 | } else if (parameterID == warm::ID) { 54 | controllerRef.getShaper().setWarm(warm::formatV(value)); 55 | } else if (parameterID == curve::ID) { 56 | controllerRef.getShaper().setCurve(curve::formatV(value)); 57 | } else if (parameterID == lowSplit::ID) { 58 | controllerRef.getSplitter().setLowFreq(value); 59 | } else if (parameterID == highSplit::ID) { 60 | controllerRef.getSplitter().setHighFreq(value); 61 | } else if (parameterID == effectOff::ID) { 62 | controllerRef.enableShaper(!static_cast(value)); 63 | } else if (parameterID == bandSplit::ID) { 64 | controllerRef.enableSplitter(static_cast(value)); 65 | } else if (parameterID == overSample::ID) { 66 | controllerRef.setOverSampleID(static_cast(value)); 67 | triggerAsyncUpdate(); 68 | } 69 | } 70 | 71 | template 72 | void ControllerAttach::handleAsyncUpdate() { 73 | processorRef.setLatencySamples(controllerRef.getLatency()); 74 | } 75 | 76 | template 77 | class ControllerAttach; 78 | 79 | template 80 | class ControllerAttach; 81 | } // zlDSP 82 | -------------------------------------------------------------------------------- /source/dsp/controller_attach.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2023 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #ifndef ZLWarm_CONTROLLER_ATTACH_HPP 14 | #define ZLWarm_CONTROLLER_ATTACH_HPP 15 | 16 | #include "controller.hpp" 17 | #include "dsp_definitions.hpp" 18 | 19 | namespace zlDSP { 20 | template 21 | class ControllerAttach : private juce::AudioProcessorValueTreeState::Listener, 22 | private juce::AsyncUpdater { 23 | public: 24 | explicit ControllerAttach(juce::AudioProcessor &processor, 25 | juce::AudioProcessorValueTreeState ¶meters, 26 | Controller &controller); 27 | 28 | ~ControllerAttach() override; 29 | 30 | private: 31 | juce::AudioProcessor &processorRef; 32 | juce::AudioProcessorValueTreeState ¶metersRef; 33 | Controller &controllerRef; 34 | 35 | constexpr static std::array IDs{ 36 | inputGain::ID, outputGain::ID, wet::ID, 37 | warm::ID, curve::ID, 38 | lowSplit::ID, highSplit::ID, 39 | effectOff::ID, bandSplit::ID, overSample::ID 40 | }; 41 | 42 | inline static std::array defaultVs { 43 | static_cast(inputGain::defaultV), static_cast(outputGain::defaultV), 44 | static_cast(wet::defaultV), 45 | static_cast(warm::defaultV), static_cast(curve::defaultV), 46 | static_cast(lowSplit::defaultV), static_cast(highSplit::defaultV), 47 | static_cast(effectOff::defaultV), static_cast(bandSplit::defaultV), 48 | static_cast(overSample::defaultI) 49 | }; 50 | 51 | void parameterChanged(const juce::String ¶meterID, float newValue) override; 52 | 53 | void handleParameterChange(const juce::String ¶meterID, float newValue); 54 | 55 | void handleAsyncUpdate() override; 56 | }; 57 | } // zlDSP 58 | 59 | #endif //ZLWarm_CONTROLLER_ATTACH_HPP 60 | -------------------------------------------------------------------------------- /source/dsp/dsp.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2024 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #ifndef ZLWarm_DSP_HPP 14 | #define ZLWarm_DSP_HPP 15 | 16 | #include "controller.hpp" 17 | #include "controller_attach.hpp" 18 | #include "meter/meter.hpp" 19 | #include "waveshaper/waveshaper.hpp" 20 | #include "splitter/splitter.hpp" 21 | #include "gain/gain.hpp" 22 | #include "oversample/over_sampler.hpp" 23 | #include "dsp_definitions.hpp" 24 | 25 | #endif //ZLWarm_DSP_HPP 26 | -------------------------------------------------------------------------------- /source/dsp/gain/auto_gain.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #include "auto_gain.hpp" 11 | 12 | namespace zlGain { 13 | template 14 | void AutoGain::prepare(const juce::dsp::ProcessSpec &spec) { 15 | gainDSP.prepare(spec); 16 | gainDSP.setRampDurationSeconds(1.0); 17 | } 18 | template 19 | void AutoGain::processPre(juce::AudioBuffer &buffer) { 20 | auto block = juce::dsp::AudioBlock(buffer); 21 | processPre(block); 22 | } 23 | 24 | template 25 | void AutoGain::processPre(juce::dsp::AudioBlock block) { 26 | if (isON.load()) { 27 | if (toReset.load()) { 28 | gainDSP.setGainLinear(1); 29 | gainDSP.reset(); 30 | toReset.store(false); 31 | } 32 | preRMS = juce::Decibels::gainToDecibels(calculateRMS(block), FloatType(-240)); 33 | isPreProcessed.store(true); 34 | } 35 | } 36 | 37 | template 38 | void AutoGain::processPost(juce::AudioBuffer &buffer) { 39 | auto block = juce::dsp::AudioBlock(buffer); 40 | processPost(block); 41 | } 42 | 43 | template 44 | void AutoGain::processPost(juce::dsp::AudioBlock block) { 45 | if (isON.load() && isPreProcessed.load()) { 46 | postRMS = juce::Decibels::gainToDecibels(calculateRMS(block), FloatType(-240)); 47 | gainDSP.setGainDecibels(preRMS - postRMS); 48 | juce::dsp::ProcessContextReplacing context(block); 49 | gainDSP.process(context); 50 | } 51 | isPreProcessed.store(false); 52 | } 53 | 54 | template 55 | FloatType AutoGain::calculateRMS(juce::dsp::AudioBlock block) { 56 | FloatType _ms = 0; 57 | for (size_t channel = 0; channel < block.getNumChannels(); channel++) { 58 | auto data = block.getChannelPointer(channel); 59 | for (size_t i = 0; i < block.getNumSamples(); i++) { 60 | _ms += data[i] * data[i]; 61 | } 62 | } 63 | return std::sqrt(_ms / static_cast(block.getNumChannels())); 64 | } 65 | 66 | template 67 | void AutoGain::setRampDurationSeconds(double newDurationSeconds) { 68 | gainDSP.setRampDurationSeconds(newDurationSeconds); 69 | } 70 | 71 | template 72 | void AutoGain::enable(const bool f) { 73 | if (f) { 74 | toReset.store(true); 75 | isON.store(true); 76 | } else { 77 | isON.store(false); 78 | } 79 | } 80 | 81 | template 82 | class AutoGain; 83 | 84 | template 85 | class AutoGain; 86 | } // zlGain -------------------------------------------------------------------------------- /source/dsp/gain/auto_gain.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef ZLEqualizer_AUTO_GAIN_HPP 11 | #define ZLEqualizer_AUTO_GAIN_HPP 12 | 13 | #include 14 | 15 | namespace zlGain { 16 | /** 17 | * a lock free, thread safe auto-gain class 18 | * @tparam FloatType 19 | */ 20 | template 21 | class AutoGain { 22 | public: 23 | AutoGain() = default; 24 | 25 | void prepare(const juce::dsp::ProcessSpec &spec); 26 | 27 | void processPre(juce::AudioBuffer &buffer); 28 | 29 | void processPre(juce::dsp::AudioBlock block); 30 | 31 | void processPost(juce::AudioBuffer &buffer); 32 | 33 | void processPost(juce::dsp::AudioBlock block); 34 | 35 | void setRampDurationSeconds(double newDurationSeconds); 36 | 37 | void enable(bool f); 38 | 39 | private: 40 | std::atomic isON{false}, toReset{false}, isPreProcessed{false}; 41 | FloatType preRMS, postRMS; 42 | juce::dsp::Gain gainDSP; 43 | 44 | FloatType calculateRMS(juce::dsp::AudioBlock block); 45 | }; 46 | } // zlGain 47 | 48 | #endif //ZLEqualizer_AUTO_GAIN_HPP 49 | -------------------------------------------------------------------------------- /source/dsp/gain/gain.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Zishu Liu on 3/12/24. 3 | // 4 | 5 | #ifndef ZLEqualizer_GAIN_HPP 6 | #define ZLEqualizer_GAIN_HPP 7 | 8 | #include "simple_gain.hpp" 9 | #include "auto_gain.hpp" 10 | 11 | #endif //ZLEqualizer_GAIN_HPP 12 | -------------------------------------------------------------------------------- /source/dsp/gain/simple_gain.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #include "simple_gain.hpp" 11 | 12 | namespace zlGain { 13 | template 14 | void Gain::prepare(const juce::dsp::ProcessSpec &spec) { 15 | gainDSP.prepare(spec); 16 | } 17 | 18 | template 19 | void Gain::process(juce::AudioBuffer &buffer) { 20 | auto block = juce::dsp::AudioBlock(buffer); 21 | process(block); 22 | } 23 | 24 | template 25 | void Gain::process(juce::dsp::AudioBlock block) { 26 | if (std::abs(gain.load() - 1) <= FloatType(1e-6)) { return; } 27 | gainDSP.setGainLinear(gain.load()); 28 | juce::dsp::ProcessContextReplacing context(block); 29 | gainDSP.process(context); 30 | } 31 | 32 | template 33 | class Gain; 34 | 35 | template 36 | class Gain; 37 | } // zlGain 38 | -------------------------------------------------------------------------------- /source/dsp/gain/simple_gain.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef ZLEqualizer_SIMPLE_GAIN_HPP 11 | #define ZLEqualizer_SIMPLE_GAIN_HPP 12 | 13 | #include 14 | 15 | namespace zlGain { 16 | /** 17 | * a lock free, thread safe gain class 18 | * it will not process the signal if the gain is equal to 1 19 | * @tparam FloatType 20 | */ 21 | template 22 | class Gain { 23 | public: 24 | Gain() = default; 25 | 26 | void prepare(const juce::dsp::ProcessSpec &spec); 27 | 28 | void process(juce::AudioBuffer &buffer); 29 | 30 | void process(juce::dsp::AudioBlock block); 31 | 32 | void setGainLinear(const FloatType x) { gain.store(x); } 33 | 34 | void setGainDecibels(const FloatType x) { 35 | gain.store(juce::Decibels::decibelsToGain(x, FloatType(-240))); 36 | } 37 | 38 | private: 39 | std::atomic gain{FloatType(1)}; 40 | juce::dsp::Gain gainDSP; 41 | }; 42 | } // zlGain 43 | 44 | #endif //ZLEqualizer_SIMPLE_GAIN_HPP -------------------------------------------------------------------------------- /source/dsp/meter/meter.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2023 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #ifndef ZLWarm_METER_HPP 14 | #define ZLWarm_METER_HPP 15 | 16 | #include "single_meter.hpp" 17 | 18 | #endif //ZLWarm_METER_HPP 19 | -------------------------------------------------------------------------------- /source/dsp/meter/single_meter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2023 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #include "single_meter.hpp" 14 | 15 | namespace zlMeter { 16 | template 17 | void SingleMeter::reset() { 18 | for (size_t idx = 0; idx < maxPeak.size(); ++idx) { 19 | maxPeak[idx].store(-160.f); 20 | bufferPeak[idx].store(-160.f); 21 | } 22 | } 23 | 24 | template 25 | void SingleMeter::prepare(const juce::dsp::ProcessSpec &spec) { 26 | sampleRate.store(static_cast(spec.sampleRate)); 27 | juce::ScopedLock lock(resizeLock); 28 | maxPeak.resize(static_cast(spec.numChannels)); 29 | bufferPeak.resize(static_cast(spec.numChannels)); 30 | tempPeak.resize(static_cast(spec.numChannels)); 31 | currentDecay.resize(static_cast(spec.numChannels)); 32 | reset(); 33 | } 34 | 35 | template 36 | void SingleMeter::process(juce::dsp::AudioBlock block) { 37 | auto outputBlock = block; 38 | if (!isON.load()) return; 39 | const auto decay = decayRate.load() * static_cast(outputBlock.getNumSamples()) / sampleRate.load(); 40 | 41 | std::fill(tempPeak.begin(), tempPeak.end(), FloatType(0)); 42 | for (size_t channel = 0; channel < maxPeak.size(); ++channel) { 43 | for (size_t idx = 0; idx < outputBlock.getNumSamples(); ++idx) { 44 | tempPeak[channel] = std::max(tempPeak[channel], 45 | std::abs(outputBlock.getSample( 46 | static_cast(channel), static_cast(idx)))); 47 | } 48 | } 49 | 50 | for (size_t channel = 0; channel < maxPeak.size(); ++channel) { 51 | tempPeak[channel] = juce::Decibels::gainToDecibels(tempPeak[channel]); 52 | const auto currentPeak = bufferPeak[channel].load() - currentDecay[channel]; 53 | if (currentPeak <= tempPeak[channel]) { 54 | bufferPeak[channel].store(tempPeak[channel]); 55 | currentDecay[channel] = 0; 56 | } else { 57 | bufferPeak[channel].store(currentPeak); 58 | currentDecay[channel] += decay; 59 | } 60 | maxPeak[channel].store(std::max(maxPeak[channel].load(), tempPeak[channel])); 61 | } 62 | } 63 | 64 | template 65 | class SingleMeter; 66 | 67 | template 68 | class SingleMeter; 69 | } // zlMeter 70 | -------------------------------------------------------------------------------- /source/dsp/meter/single_meter.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2023 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #ifndef ZL_SINGLE_METER_HPP 14 | #define ZL_SINGLE_METER_HPP 15 | 16 | // #include "juce_audio_processors/juce_audio_processors.h" 17 | #include "juce_dsp/juce_dsp.h" 18 | 19 | namespace zlMeter { 20 | template 21 | class SingleMeter { 22 | public: 23 | SingleMeter() = default; 24 | 25 | void reset(); 26 | 27 | void prepare(const juce::dsp::ProcessSpec &spec); 28 | 29 | void process(juce::dsp::AudioBlock block); 30 | 31 | std::deque > &getmaxPeak() { return maxPeak; } 32 | 33 | std::deque > &getBufferPeak() { return bufferPeak; } 34 | 35 | void enable(const bool x) { isON.store(x); } 36 | 37 | juce::CriticalSection &getLock() { return resizeLock; } 38 | 39 | private: 40 | std::deque > maxPeak, bufferPeak; 41 | std::vector tempPeak; 42 | std::atomic decayRate{2}, sampleRate; 43 | std::vector currentDecay; 44 | std::atomic isON = false; 45 | 46 | juce::CriticalSection resizeLock; 47 | }; 48 | } // zlMeter 49 | 50 | #endif //ZL_SINGLE_METER_HPP 51 | -------------------------------------------------------------------------------- /source/dsp/oversample/over_sampler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2024 - zsliu98 4 | This file is part of ZLWarm 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #include "over_sampler.hpp" 14 | 15 | namespace zlOverSample { 16 | } // zlOverSample -------------------------------------------------------------------------------- /source/dsp/oversample/over_sampler.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2024 - zsliu98 4 | This file is part of ZLWarm 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #ifndef ZLWarm_OVER_SAMPLER_HPP 14 | #define ZLWarm_OVER_SAMPLER_HPP 15 | 16 | namespace zlOverSample { 17 | 18 | class OverSampler { 19 | 20 | }; 21 | 22 | } // zlOverSample 23 | 24 | #endif //ZLWarm_OVER_SAMPLER_HPP 25 | -------------------------------------------------------------------------------- /source/dsp/splitter/iir_splitter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2024 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #include "iir_splitter.hpp" 14 | 15 | namespace zlSplitter { 16 | template 17 | void IIRSplitter::reset() { 18 | for (auto &f: {&low1, &low2, &high1, &high2, &all1, &all2}) { 19 | f->reset(); 20 | } 21 | } 22 | 23 | template 24 | void IIRSplitter::prepare(const juce::dsp::ProcessSpec &spec) { 25 | lBuffer.setSize(static_cast(spec.numChannels), static_cast(spec.maximumBlockSize)); 26 | mBuffer.setSize(static_cast(spec.numChannels), static_cast(spec.maximumBlockSize)); 27 | hBuffer.setSize(static_cast(spec.numChannels), static_cast(spec.maximumBlockSize)); 28 | for (auto &f: {&low1, &low2, &high1, &high2, &all1, &all2}) { 29 | f->prepare(spec); 30 | } 31 | low1.setType(juce::dsp::LinkwitzRileyFilterType::lowpass); 32 | low2.setType(juce::dsp::LinkwitzRileyFilterType::lowpass); 33 | high1.setType(juce::dsp::LinkwitzRileyFilterType::highpass); 34 | high2.setType(juce::dsp::LinkwitzRileyFilterType::highpass); 35 | all1.setType(juce::dsp::LinkwitzRileyFilterType::allpass); 36 | all2.setType(juce::dsp::LinkwitzRileyFilterType::allpass); 37 | } 38 | 39 | template 40 | void IIRSplitter::split(juce::dsp::AudioBlock block) { 41 | auto inputBlock = block; 42 | lBuffer.setSize(static_cast(block.getNumChannels()), static_cast(block.getNumSamples()), 43 | true, false, true); 44 | mBuffer.setSize(static_cast(block.getNumChannels()), static_cast(block.getNumSamples()), 45 | true, false, true); 46 | hBuffer.setSize(static_cast(block.getNumChannels()), static_cast(block.getNumSamples()), 47 | true, false, true); 48 | auto lBlock = juce::dsp::AudioBlock(lBuffer); 49 | auto mBlock = juce::dsp::AudioBlock(mBuffer); 50 | auto hBlock = juce::dsp::AudioBlock(hBuffer); 51 | 52 | lBlock.copyFrom(inputBlock); 53 | mBlock.copyFrom(inputBlock); 54 | 55 | auto lContext = juce::dsp::ProcessContextReplacing(lBlock); 56 | auto mContext = juce::dsp::ProcessContextReplacing(mBlock); 57 | auto hContext = juce::dsp::ProcessContextReplacing(hBlock); 58 | 59 | juce::ScopedLock lock(paraLock); 60 | low1.process(lContext); 61 | all2.process(lContext); 62 | 63 | high1.process(mContext); 64 | hBlock.copyFrom(mBlock); 65 | 66 | low2.process(mContext); 67 | high2.process(hContext); 68 | } 69 | 70 | template 71 | void IIRSplitter::combine(juce::dsp::AudioBlock block) { 72 | auto outputBlock = block; 73 | 74 | auto lBlock = juce::dsp::AudioBlock(lBuffer); 75 | auto mBlock = juce::dsp::AudioBlock(mBuffer); 76 | auto hBlock = juce::dsp::AudioBlock(hBuffer); 77 | 78 | outputBlock.copyFrom(lBlock); 79 | outputBlock.add(mBlock); 80 | outputBlock.add(hBlock); 81 | } 82 | 83 | template 84 | void IIRSplitter::setLowFreq(FloatType freq) { 85 | juce::ScopedLock lock(paraLock); 86 | for (auto &f: {&low1, &high1, &all1}) { 87 | f->setCutoffFrequency(freq); 88 | } 89 | } 90 | 91 | template 92 | void IIRSplitter::setHighFreq(FloatType freq) { 93 | juce::ScopedLock lock(paraLock); 94 | for (auto &f: {&low2, &high2, &all2}) { 95 | f->setCutoffFrequency(freq); 96 | } 97 | } 98 | 99 | template 100 | class IIRSplitter; 101 | 102 | template 103 | class IIRSplitter; 104 | } // zlSplitter 105 | -------------------------------------------------------------------------------- /source/dsp/splitter/iir_splitter.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2024 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #ifndef ZLWarm_IIR_SPLITTER_HPP 14 | #define ZLWarm_IIR_SPLITTER_HPP 15 | 16 | #include 17 | #include 18 | 19 | namespace zlSplitter { 20 | /** 21 | * a three-band Linkwitz-Riley filter 22 | * @tparam FloatType 23 | */ 24 | template 25 | class IIRSplitter { 26 | public: 27 | IIRSplitter() = default; 28 | 29 | void reset(); 30 | 31 | void prepare(const juce::dsp::ProcessSpec &spec); 32 | 33 | /** 34 | * split the audio buffer into internal low, mid and high buffers 35 | * @param block 36 | */ 37 | void split(juce::dsp::AudioBlock block); 38 | 39 | /** 40 | * combine the internal low, mid and high buffers into the audio buffer 41 | * @param block 42 | */ 43 | void combine(juce::dsp::AudioBlock block); 44 | 45 | void setLowFreq(FloatType freq); 46 | 47 | void setHighFreq(FloatType freq); 48 | 49 | inline juce::AudioBuffer &getLBuffer() { return lBuffer; } 50 | 51 | inline juce::AudioBuffer &getMBuffer() { return mBuffer; } 52 | 53 | inline juce::AudioBuffer &getHBuffer() { return hBuffer; } 54 | 55 | private: 56 | juce::AudioBuffer lBuffer, mBuffer, hBuffer; 57 | juce::dsp::LinkwitzRileyFilter low1, high1, all1; 58 | juce::dsp::LinkwitzRileyFilter low2, high2, all2; 59 | 60 | juce::CriticalSection paraLock; 61 | }; 62 | } // zlSplitter 63 | 64 | #endif //ZLWarm_IIR_SPLITTER_HPP 65 | -------------------------------------------------------------------------------- /source/dsp/splitter/lr_splitter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #include "lr_splitter.hpp" 11 | 12 | namespace zlSplitter { 13 | template 14 | void LRSplitter::reset() { 15 | lBuffer.clear(); 16 | rBuffer.clear(); 17 | } 18 | 19 | template 20 | void LRSplitter::prepare(const juce::dsp::ProcessSpec &spec) { 21 | lBuffer.setSize(1, static_cast(spec.maximumBlockSize)); 22 | rBuffer.setSize(1, static_cast(spec.maximumBlockSize)); 23 | } 24 | 25 | template 26 | void LRSplitter::split(juce::AudioBuffer &buffer) { 27 | lBuffer.copyFrom(0, 0, buffer, 0, 0, buffer.getNumSamples()); 28 | rBuffer.copyFrom(0, 0, buffer, 1, 0, buffer.getNumSamples()); 29 | lBuffer.setSize(1, buffer.getNumSamples(), true, false, true); 30 | rBuffer.setSize(1, buffer.getNumSamples(), true, false, true); 31 | } 32 | 33 | template 34 | void LRSplitter::combine(juce::AudioBuffer &buffer) { 35 | buffer.copyFrom(0, 0, lBuffer, 0, 0, buffer.getNumSamples()); 36 | buffer.copyFrom(1, 0, rBuffer, 0, 0, buffer.getNumSamples()); 37 | } 38 | 39 | template 40 | class LRSplitter; 41 | 42 | template 43 | class LRSplitter; 44 | } -------------------------------------------------------------------------------- /source/dsp/splitter/lr_splitter.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef ZLEQUALIZER_LRSPLITER_H 11 | #define ZLEQUALIZER_LRSPLITER_H 12 | 13 | #include 14 | #include 15 | 16 | namespace zlSplitter { 17 | /** 18 | * a splitter that splits the stereo audio signal input left signal and right signal 19 | * @tparam FloatType 20 | */ 21 | template 22 | class LRSplitter { 23 | public: 24 | LRSplitter() = default; 25 | 26 | void reset(); 27 | 28 | void prepare(const juce::dsp::ProcessSpec &spec); 29 | 30 | /** 31 | * split the audio buffer into internal left buffer and right buffer 32 | * @param buffer 33 | */ 34 | void split(juce::AudioBuffer &buffer); 35 | 36 | /** 37 | * combine the internal left buffer and right buffer into the audio buffer 38 | * @param buffer 39 | */ 40 | void combine(juce::AudioBuffer &buffer); 41 | 42 | inline juce::AudioBuffer &getLBuffer() { return lBuffer; } 43 | 44 | inline juce::AudioBuffer &getRBuffer() { return rBuffer; } 45 | 46 | private: 47 | juce::AudioBuffer lBuffer, rBuffer; 48 | }; 49 | } 50 | 51 | #endif //ZLEQUALIZER_LRSPLITER_H 52 | -------------------------------------------------------------------------------- /source/dsp/splitter/ms_splitter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #include "ms_splitter.hpp" 11 | namespace zlSplitter { 12 | template 13 | void MSSplitter::reset() { 14 | mBuffer.clear(); 15 | sBuffer.clear(); 16 | } 17 | 18 | template 19 | void MSSplitter::prepare(const juce::dsp::ProcessSpec &spec) { 20 | mBuffer.setSize(1, static_cast(spec.maximumBlockSize)); 21 | sBuffer.setSize(1, static_cast(spec.maximumBlockSize)); 22 | } 23 | 24 | template 25 | void MSSplitter::split(juce::AudioBuffer &buffer) { 26 | auto lBuffer = buffer.getReadPointer(0); 27 | auto rBuffer = buffer.getReadPointer(1); 28 | auto _mBuffer = mBuffer.getWritePointer(0); 29 | auto _sBuffer = sBuffer.getWritePointer(0); 30 | for (size_t i = 0; i < static_cast(buffer.getNumSamples()); ++i) { 31 | _mBuffer[i] = FloatType(0.5) * (lBuffer[i] + rBuffer[i]); 32 | _sBuffer[i] = FloatType(0.5) * (lBuffer[i] - rBuffer[i]); 33 | } 34 | mBuffer.setSize(1, buffer.getNumSamples(), true, false, true); 35 | sBuffer.setSize(1, buffer.getNumSamples(), true, false, true); 36 | } 37 | 38 | template 39 | void MSSplitter::combine(juce::AudioBuffer &buffer) { 40 | auto lBuffer = buffer.getWritePointer(0); 41 | auto rBuffer = buffer.getWritePointer(1); 42 | auto _mBuffer = mBuffer.getReadPointer(0); 43 | auto _sBuffer = sBuffer.getReadPointer(0); 44 | for (size_t i = 0; i < static_cast(buffer.getNumSamples()); ++i) { 45 | lBuffer[i] = _mBuffer[i] + _sBuffer[i]; 46 | rBuffer[i] = _mBuffer[i] - _sBuffer[i]; 47 | } 48 | } 49 | 50 | template 51 | class MSSplitter; 52 | 53 | template 54 | class MSSplitter; 55 | } -------------------------------------------------------------------------------- /source/dsp/splitter/ms_splitter.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef ZLEQUALIZER_MS_SPLITTER_HPP 11 | #define ZLEQUALIZER_MS_SPLITTER_HPP 12 | 13 | #include 14 | #include 15 | 16 | namespace zlSplitter { 17 | /** 18 | * a splitter that splits the stereo audio signal input mid signal and side signal 19 | * @tparam FloatType 20 | */ 21 | template 22 | class MSSplitter { 23 | public: 24 | MSSplitter() = default; 25 | 26 | void reset(); 27 | 28 | void prepare(const juce::dsp::ProcessSpec &spec); 29 | 30 | /** 31 | * split the audio buffer into internal mid buffer and side buffer 32 | * @param buffer 33 | */ 34 | void split(juce::AudioBuffer &buffer); 35 | 36 | /** 37 | * combine the internal mid buffer and side buffer into the audio buffer 38 | * @param buffer 39 | */ 40 | void combine(juce::AudioBuffer &buffer); 41 | 42 | inline juce::AudioBuffer &getMBuffer() { return mBuffer; } 43 | 44 | inline juce::AudioBuffer &getSBuffer() { return sBuffer; } 45 | 46 | private: 47 | juce::AudioBuffer mBuffer, sBuffer; 48 | }; 49 | } 50 | 51 | #endif //ZLEQUALIZER_MS_SPLITTER_HPP 52 | -------------------------------------------------------------------------------- /source/dsp/splitter/splitter.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef ZLEQUALIZER_SPLITTER_HPP 11 | #define ZLEQUALIZER_SPLITTER_HPP 12 | 13 | #include "lr_splitter.hpp" 14 | #include "ms_splitter.hpp" 15 | #include "iir_splitter.hpp" 16 | 17 | #endif //ZLEQUALIZER_SPLITTER_HPP 18 | -------------------------------------------------------------------------------- /source/dsp/waveshaper/warm_inflator.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Zishu Liu on 2/18/24. 3 | // 4 | 5 | #include "warm_inflator.hpp" 6 | 7 | namespace zlWaveShaper { 8 | template 9 | void WarmInflator::prepare(const juce::dsp::ProcessSpec &spec) { 10 | juce::ignoreUnused(spec); 11 | } 12 | 13 | template 14 | void WarmInflator::process(juce::dsp::AudioBlock block) { 15 | juce::ScopedLock lock(paraUpdateLock); 16 | for (int i = 0; i < static_cast(block.getNumChannels()); ++i) { 17 | for (int j = 0; j < static_cast(block.getNumSamples()); ++j) { 18 | const auto x = juce::jlimit(FloatType(-1), FloatType(1), 19 | block.getSample(i, j)); 20 | block.setSample(i, j, wet * shape(x) + (1 - wet) * x); 21 | } 22 | } 23 | } 24 | 25 | template 26 | void WarmInflator::setCurve(FloatType x) { 27 | juce::ScopedLock lock(paraUpdateLock); 28 | pShaper.setParameters(x); 29 | nShaper.setParameters(x); 30 | } 31 | 32 | template 33 | void WarmInflator::setWarm(FloatType x) { 34 | juce::ScopedLock lock(paraUpdateLock); 35 | warm = x; 36 | } 37 | 38 | template 39 | void WarmInflator::setWet(FloatType x) { 40 | juce::ScopedLock lock(paraUpdateLock); 41 | wet = x; 42 | } 43 | 44 | template 45 | class WarmInflator; 46 | 47 | template 48 | class WarmInflator; 49 | } // zlWaveShaper 50 | -------------------------------------------------------------------------------- /source/dsp/waveshaper/warm_inflator.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Zishu Liu on 2/18/24. 3 | // 4 | 5 | #ifndef ZLWarm_WARM_INFLATOR_HPP 6 | #define ZLWarm_WARM_INFLATOR_HPP 7 | 8 | #include "juce_audio_processors/juce_audio_processors.h" 9 | #include "juce_dsp/juce_dsp.h" 10 | 11 | namespace zlWaveShaper { 12 | template 13 | class WarmInflator { 14 | private: 15 | class PositiveShaper { 16 | public: 17 | inline FloatType shape(FloatType x) const { return basic(x); } 18 | 19 | void setParameters(FloatType curve) { 20 | a = FloatType(0.25) * (curve - 1); 21 | b = FloatType(0.5) * (curve - 1); 22 | c = FloatType(0.75) - FloatType(1.75) * curve; 23 | d = curve + 1; 24 | auto_compensate = 1 / (FloatType(0.5625) * curve + FloatType(1.125)); 25 | } 26 | 27 | private: 28 | FloatType a, b, c, d, auto_compensate; 29 | 30 | inline FloatType basic(FloatType x) const { return auto_compensate * x * (d + x * (c + x * (b + a * x))); } 31 | }; 32 | 33 | class NegativeShaper { 34 | public: 35 | FloatType shape(FloatType x) const { return basic(x); } 36 | 37 | void setParameters(FloatType curve) { 38 | a = FloatType(1.35); 39 | b = FloatType(-3.35) + FloatType(0.75) * curve; 40 | c = FloatType(1.95) - FloatType(1.75) * curve; 41 | d = curve + 1; 42 | auto_compensate = 1 / (FloatType(0.5625) * curve + FloatType(1.125)); 43 | } 44 | 45 | private: 46 | FloatType a, b, c, d, auto_compensate; 47 | 48 | FloatType basic(FloatType x) const { return auto_compensate * x * (d + x * (c + x * (b + a * x))); } 49 | }; 50 | 51 | public: 52 | WarmInflator() = default; 53 | 54 | void prepare(const juce::dsp::ProcessSpec &spec); 55 | 56 | void process(juce::dsp::AudioBlock block); 57 | 58 | void setCurve(FloatType x); 59 | 60 | void setWarm(FloatType x); 61 | 62 | void setWet(FloatType x); 63 | 64 | private: 65 | PositiveShaper pShaper; 66 | NegativeShaper nShaper; 67 | FloatType warm, wet{1}; 68 | 69 | juce::CriticalSection paraUpdateLock; 70 | 71 | inline FloatType shape(FloatType x) { 72 | return (x > 0 73 | ? pShaper.shape(std::abs(x)) 74 | : -warm * nShaper.shape(std::abs(x)) - (1 - warm) * pShaper.shape(std::abs(x))); 75 | } 76 | }; 77 | } // zlWaveShaper 78 | 79 | #endif //ZLWarm_WARM_INFLATOR_HPP 80 | -------------------------------------------------------------------------------- /source/dsp/waveshaper/waveshaper.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Zishu Liu on 2/18/24. 3 | // 4 | 5 | #ifndef ZLWarm_WAVESHAPER_HPP 6 | #define ZLWarm_WAVESHAPER_HPP 7 | 8 | #include "warm_inflator.hpp" 9 | 10 | #endif //ZLWarm_WAVESHAPER_HPP 11 | -------------------------------------------------------------------------------- /source/gui/button/button.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef ZLINTERFACE_BUTTON_H 11 | #define ZLINTERFACE_BUTTON_H 12 | 13 | #include "compact_button/compact_button.hpp" 14 | #include "regular_button/regular_button.hpp" 15 | #include "click_button/click_button.hpp" 16 | 17 | #endif //ZLINTERFACE_BUTTON_H 18 | -------------------------------------------------------------------------------- /source/gui/button/click_button/click_button.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #include "click_button.hpp" 11 | #include "click_button_look_and_feel.hpp" 12 | 13 | namespace zlInterface { 14 | ClickButton::ClickButton(juce::Drawable *image, UIBase &base) 15 | : button("", juce::DrawableButton::ButtonStyle::ImageFitted), lookAndFeel(image, base) { 16 | button.setLookAndFeel(&lookAndFeel); 17 | setBufferedToImage(true); 18 | addAndMakeVisible(button); 19 | } 20 | 21 | ClickButton::~ClickButton() { 22 | button.setLookAndFeel(nullptr); 23 | } 24 | 25 | void ClickButton::resized() { 26 | button.setBounds(getLocalBounds()); 27 | } 28 | 29 | 30 | } // zlInterface 31 | -------------------------------------------------------------------------------- /source/gui/button/click_button/click_button.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef ZLEqualizer_CLICK_BUTTON_HPP 11 | #define ZLEqualizer_CLICK_BUTTON_HPP 12 | 13 | #include 14 | 15 | #include "click_button_look_and_feel.hpp" 16 | 17 | namespace zlInterface { 18 | class ClickButton final : public juce::Component { 19 | public: 20 | explicit ClickButton(juce::Drawable *image, UIBase &base); 21 | 22 | ~ClickButton() override; 23 | 24 | void resized() override; 25 | 26 | inline juce::DrawableButton &getButton() { return button; } 27 | 28 | inline ClickButtonLookAndFeel &getLookAndFeel() { return lookAndFeel; } 29 | 30 | private: 31 | juce::DrawableButton button; 32 | ClickButtonLookAndFeel lookAndFeel; 33 | }; 34 | } // zlInterface 35 | 36 | #endif //ZLEqualizer_CLICK_BUTTON_HPP 37 | -------------------------------------------------------------------------------- /source/gui/button/click_button/click_button_look_and_feel.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef ZLEqualizer_CLICK_BUTTON_LOOK_AND_FEEL_HPP 11 | #define ZLEqualizer_CLICK_BUTTON_LOOK_AND_FEEL_HPP 12 | 13 | #include 14 | 15 | #include "../../interface_definitions.hpp" 16 | 17 | namespace zlInterface { 18 | class ClickButtonLookAndFeel : public juce::LookAndFeel_V4 { 19 | public: 20 | explicit ClickButtonLookAndFeel(juce::Drawable *image, UIBase &base) : drawable(image), uiBase(base) {} 21 | 22 | void drawDrawableButton(juce::Graphics &g, juce::DrawableButton &button, bool shouldDrawButtonAsHighlighted, 23 | bool shouldDrawButtonAsDown) override { 24 | juce::ignoreUnused(button); 25 | auto bound = button.getLocalBounds().toFloat(); 26 | bound = bound.withSizeKeepingCentre(bound.getWidth() - padding.load(), 27 | bound.getHeight() - padding.load()); 28 | if (drawable != nullptr) { 29 | const auto tempDrawable = drawable->createCopy(); 30 | tempDrawable->replaceColour(juce::Colour(0, 0, 0), uiBase.getTextColor()); 31 | if (editable.load()) { 32 | if (shouldDrawButtonAsDown) { 33 | tempDrawable->drawWithin(g, bound, juce::RectanglePlacement::centred, 1.f); 34 | } else if (shouldDrawButtonAsHighlighted) { 35 | tempDrawable->drawWithin(g, bound, juce::RectanglePlacement::centred, .75f); 36 | } else { 37 | tempDrawable->drawWithin(g, bound, juce::RectanglePlacement::centred, .5f); 38 | } 39 | } else { 40 | tempDrawable->drawWithin(g, bound, juce::RectanglePlacement::centred, .25f); 41 | } 42 | } 43 | } 44 | 45 | inline void setEditable(const bool f) { editable.store(f); } 46 | 47 | inline void setCornerSize(const float x) { cornerSize.store(x); } 48 | 49 | inline void setPadding(const float x) { padding.store(x); } 50 | 51 | inline void setCurve(const bool tl, const bool tr, const bool bl, const bool br) { 52 | curveTL.store(tl); 53 | curveTR.store(tr); 54 | curveBL.store(bl); 55 | curveBR.store(br); 56 | } 57 | 58 | private: 59 | std::atomic editable = true; 60 | std::atomic cornerSize = 0.f, padding = 0.f; 61 | std::atomic curveTL = false, curveTR = false, curveBL = false, curveBR = false; 62 | juce::Drawable *drawable; 63 | 64 | UIBase &uiBase; 65 | }; 66 | } 67 | 68 | #endif //ZLEqualizer_CLICK_BUTTON_LOOK_AND_FEEL_HPP 69 | -------------------------------------------------------------------------------- /source/gui/button/compact_button/compact_button.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #include "compact_button.hpp" 11 | 12 | namespace zlInterface { 13 | CompactButton::CompactButton(const juce::String &labelText, UIBase &base) : uiBase(base), lookAndFeel(uiBase), 14 | animator{} { 15 | setBufferedToImage(true); 16 | button.setClickingTogglesState(true); 17 | button.setButtonText(labelText); 18 | button.setLookAndFeel(&lookAndFeel); 19 | button.onClick = [this]() { this->buttonDownAnimation(); }; 20 | addAndMakeVisible(button); 21 | 22 | setEditable(true); 23 | } 24 | 25 | CompactButton::~CompactButton() { 26 | button.setLookAndFeel(nullptr); 27 | } 28 | 29 | void CompactButton::resized() { 30 | if (fit.load()) { 31 | button.setBounds(getLocalBounds()); 32 | } else { 33 | auto bound = getLocalBounds().toFloat(); 34 | const auto radius = juce::jmin(bound.getHeight(), bound.getWidth()); 35 | bound = bound.withSizeKeepingCentre(radius, radius); 36 | button.setBounds(bound.toNearestInt()); 37 | } 38 | } 39 | 40 | void CompactButton::buttonDownAnimation() { 41 | if (button.getToggleState() && lookAndFeel.getDepth() < 0.1f) { 42 | if (animator.getAnimation(animationId) != nullptr) 43 | return; 44 | auto effect{ 45 | friz::makeAnimation( 46 | // ID of the animation 47 | animationId, {0.f}, {1.f}, animationDuration, friz::Parametric::kLinear) 48 | }; 49 | effect->updateFn = [this](int id, const auto &vals) { 50 | juce::ignoreUnused(id); 51 | lookAndFeel.setDepth(vals[0]); 52 | repaint(); 53 | }; 54 | 55 | // pass the animation object to the animator, which will start running it immediately. 56 | animator.addAnimation(std::move(effect)); 57 | } else if (!button.getToggleState()) { 58 | lookAndFeel.setDepth(0.f); 59 | animator.cancelAnimation(animationId, false); 60 | repaint(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /source/gui/button/compact_button/compact_button.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef COMPACT_BUTTON_H 11 | #define COMPACT_BUTTON_H 12 | 13 | #include 14 | #include 15 | 16 | #include "../../interface_definitions.hpp" 17 | #include "compact_button_look_and_feel.hpp" 18 | 19 | namespace zlInterface { 20 | class CompactButton : public juce::Component { 21 | public: 22 | explicit CompactButton(const juce::String &labelText, UIBase &base); 23 | 24 | ~CompactButton() override; 25 | 26 | void resized() override; 27 | 28 | void buttonDownAnimation(); 29 | 30 | inline juce::ToggleButton &getButton() { return button; } 31 | 32 | inline void setEditable(const bool x) { 33 | lookAndFeel.setEditable(x); 34 | button.setInterceptsMouseClicks(x, false); 35 | } 36 | 37 | inline void setDrawable(juce::Drawable *x) { lookAndFeel.setDrawable(x); } 38 | 39 | CompactButtonLookAndFeel &getLAF() {return lookAndFeel;} 40 | 41 | private: 42 | UIBase &uiBase; 43 | 44 | juce::ToggleButton button; 45 | CompactButtonLookAndFeel lookAndFeel; 46 | static constexpr int animationId = 1; 47 | static constexpr float animationDuration = 200.f; 48 | 49 | std::atomic fit = false; 50 | 51 | friz::Animator animator; 52 | }; 53 | } 54 | 55 | 56 | #endif //COMPACT_BUTTON_H 57 | -------------------------------------------------------------------------------- /source/gui/button/compact_button/compact_button_look_and_feel.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef COMPACT_BUTTON_LOOK_AND_FEEL_H 11 | #define COMPACT_BUTTON_LOOK_AND_FEEL_H 12 | 13 | #include 14 | 15 | #include "../../interface_definitions.hpp" 16 | 17 | namespace zlInterface { 18 | class CompactButtonLookAndFeel : public juce::LookAndFeel_V4 { 19 | public: 20 | explicit CompactButtonLookAndFeel(UIBase &base) : uiBase(base) { 21 | } 22 | 23 | void drawToggleButton(juce::Graphics &g, juce::ToggleButton &button, bool shouldDrawButtonAsHighlighted, 24 | bool shouldDrawButtonAsDown) override { 25 | juce::ignoreUnused(shouldDrawButtonAsHighlighted, shouldDrawButtonAsDown); 26 | 27 | auto bounds = button.getLocalBounds().toFloat(); 28 | if (withShadow.load()) { 29 | bounds = uiBase.drawShadowEllipse(g, bounds, uiBase.getFontSize() * 0.4f, {}); 30 | bounds = uiBase.drawInnerShadowEllipse(g, bounds, uiBase.getFontSize() * 0.15f, {.flip = true}); 31 | } else { 32 | bounds = uiBase.getShadowEllipseArea(bounds, uiBase.getFontSize() * 0.3f, {}); 33 | g.setColour(uiBase.getBackgroundColor()); 34 | g.fillEllipse(bounds); 35 | } 36 | if (button.getToggleState()) { 37 | const auto innerBound = uiBase.getShadowEllipseArea(bounds, uiBase.getFontSize() * 0.1f, {}); 38 | uiBase.drawInnerShadowEllipse(g, innerBound, uiBase.getFontSize() * 0.375f, { 39 | .darkShadowColor = uiBase.getDarkShadowColor(). 40 | withMultipliedAlpha(buttonDepth), 41 | .brightShadowColor = uiBase.getBrightShadowColor(). 42 | withMultipliedAlpha(buttonDepth), 43 | .changeDark = true, 44 | .changeBright = true 45 | }); 46 | } 47 | if (editable.load()) { 48 | if (drawable == nullptr) { 49 | const auto textBound = button.getLocalBounds().toFloat(); 50 | if (button.getToggleState()) { 51 | g.setColour(uiBase.getTextColor().withAlpha(1.f)); 52 | } else { 53 | g.setColour(uiBase.getTextColor().withAlpha(0.5f)); 54 | } 55 | g.setFont(uiBase.getFontSize() * FontLarge); 56 | g.drawText(button.getButtonText(), textBound.toNearestInt(), juce::Justification::centred); 57 | } else { 58 | const auto tempDrawable = drawable->createCopy(); 59 | tempDrawable->replaceColour(juce::Colour(0, 0, 0), uiBase.getTextColor()); 60 | const auto radius = juce::jmin(bounds.getWidth(), bounds.getHeight()) * .5f; 61 | const auto drawBound = bounds.withSizeKeepingCentre(radius, radius); 62 | if (button.getToggleState()) { 63 | tempDrawable->drawWithin(g, drawBound, juce::RectanglePlacement::Flags::centred, 1.f); 64 | } else { 65 | tempDrawable->drawWithin(g, drawBound, juce::RectanglePlacement::Flags::centred, .5f); 66 | } 67 | } 68 | } 69 | } 70 | 71 | inline void setEditable(const bool f) { editable.store(f); } 72 | 73 | inline float getDepth() const { return buttonDepth.load(); } 74 | 75 | inline void setDepth(const float x) { buttonDepth = x; } 76 | 77 | inline void setDrawable(juce::Drawable *x) { 78 | drawable = x; 79 | } 80 | 81 | void enableShadow(const bool f) { withShadow.store(f); } 82 | 83 | private: 84 | std::atomic editable = true, withShadow = true; 85 | std::atomic buttonDepth = 0.f; 86 | juce::Drawable *drawable = nullptr; 87 | 88 | UIBase &uiBase; 89 | }; 90 | } 91 | 92 | #endif //COMPACT_BUTTON_LOOK_AND_FEEL_H 93 | -------------------------------------------------------------------------------- /source/gui/button/regular_button/regular_button.hpp: -------------------------------------------------------------------------------- 1 | // ============================================================================== 2 | // Copyright (C) 2023 - zsliu98 3 | // This file is part of ZLEComp 4 | // 5 | // ZLEComp 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. 6 | // ZLEComp 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEComp. If not, see . 9 | // ============================================================================== 10 | 11 | #ifndef ZL_REGULAR_BUTTON_COMPONENT_H 12 | #define ZL_REGULAR_BUTTON_COMPONENT_H 13 | 14 | #include "regular_button_look_and_feel.hpp" 15 | #include "../../label/name_look_and_feel.hpp" 16 | 17 | namespace zlInterface { 18 | class RegularButton : public juce::Component { 19 | public: 20 | explicit RegularButton(const juce::String &labelText, UIBase &base) : 21 | myLookAndFeel(base), nameLookAndFeel(base) { 22 | uiBase = &base; 23 | 24 | button.setClickingTogglesState(true); 25 | button.setLookAndFeel(&myLookAndFeel); 26 | addAndMakeVisible(button); 27 | label.setText(labelText, juce::dontSendNotification); 28 | label.setLookAndFeel(&nameLookAndFeel); 29 | addAndMakeVisible(label); 30 | } 31 | 32 | ~RegularButton() override { 33 | button.setLookAndFeel(nullptr); 34 | label.setLookAndFeel(nullptr); 35 | } 36 | 37 | void resized() override { 38 | auto bound = getLocalBounds().toFloat(); 39 | auto labelBound = bound.removeFromTop(labelHeight * bound.getHeight()); 40 | label.setBounds(labelBound.toNearestInt()); 41 | button.setBounds(bound.toNearestInt()); 42 | } 43 | 44 | void paint(juce::Graphics &g) override { 45 | juce::ignoreUnused(g); 46 | } 47 | 48 | juce::ToggleButton &getButton() { return button; } 49 | 50 | juce::Label &getLabel() { return label; } 51 | 52 | void setEditable(const bool f) { 53 | myLookAndFeel.setEditable(f); 54 | nameLookAndFeel.setEditable(f); 55 | } 56 | 57 | private: 58 | RegularButtonLookAndFeel myLookAndFeel; 59 | NameLookAndFeel nameLookAndFeel; 60 | juce::ToggleButton button; 61 | juce::Label label; 62 | 63 | constexpr static float buttonHeight = 0.7f; 64 | constexpr static float labelHeight = 1.f - buttonHeight; 65 | constexpr static float buttonRatio = 0.45f; 66 | 67 | UIBase *uiBase; 68 | }; 69 | } 70 | 71 | #endif //ZL_REGULAR_BUTTON_COMPONENT_H 72 | -------------------------------------------------------------------------------- /source/gui/button/regular_button/regular_button_look_and_feel.hpp: -------------------------------------------------------------------------------- 1 | // ============================================================================== 2 | // Copyright (C) 2023 - zsliu98 3 | // This file is part of ZLEComp 4 | // 5 | // ZLEComp 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. 6 | // ZLEComp 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEComp. If not, see . 9 | // ============================================================================== 10 | 11 | #ifndef ZL_REGULAR_BUTTON_LOOK_AND_FEEL_H 12 | #define ZL_REGULAR_BUTTON_LOOK_AND_FEEL_H 13 | 14 | #include 15 | 16 | #include "../../interface_definitions.hpp" 17 | 18 | namespace zlInterface { 19 | class RegularButtonLookAndFeel : public juce::LookAndFeel_V4 { 20 | public: 21 | explicit RegularButtonLookAndFeel(UIBase &base) { 22 | uiBase = &base; 23 | } 24 | 25 | void drawToggleButton(juce::Graphics &g, juce::ToggleButton &button, bool shouldDrawButtonAsHighlighted, 26 | bool shouldDrawButtonAsDown) override { 27 | juce::ignoreUnused(shouldDrawButtonAsDown); 28 | auto bounds = button.getLocalBounds().toFloat(); 29 | // draw button 30 | bounds = uiBase->fillRoundedShadowRectangle(g, bounds, uiBase->getFontSize() * 0.5f, {}); 31 | uiBase->fillRoundedInnerShadowRectangle(g, bounds, uiBase->getFontSize() * 0.5f, {.blurRadius=0.45f, .flip=true}); 32 | // draw ON/OFF 33 | if (editable.load()) { 34 | g.setColour(uiBase->getTextColor()); 35 | } else { 36 | g.setColour(uiBase->getTextInactiveColor()); 37 | } 38 | if (uiBase->getFontSize() > 0) { 39 | g.setFont(uiBase->getFontSize() * FontLarge); 40 | } else { 41 | g.setFont(bounds.getHeight() * 0.35f); 42 | } 43 | if (button.getToggleState()) { 44 | g.drawSingleLineText(juce::String("ON"), 45 | juce::roundToInt(bounds.getCentre().x + bounds.getWidth() * 0.22 + 46 | g.getCurrentFont().getHorizontalScale() * 0.5f), 47 | juce::roundToInt(bounds.getCentre().y + g.getCurrentFont().getDescent()), 48 | juce::Justification::horizontallyCentred); 49 | } else { 50 | g.drawSingleLineText(juce::String("OFF"), 51 | juce::roundToInt(bounds.getCentre().x - bounds.getWidth() * 0.22 + 52 | g.getCurrentFont().getHorizontalScale() * 0.5f), 53 | juce::roundToInt(bounds.getCentre().y + g.getCurrentFont().getDescent()), 54 | juce::Justification::horizontallyCentred); 55 | } 56 | g.setColour(TextHideColor); 57 | if (shouldDrawButtonAsHighlighted) { 58 | if (!button.getToggleState()) { 59 | g.drawSingleLineText(juce::String("ON"), 60 | juce::roundToInt(bounds.getCentre().x + bounds.getWidth() * 0.22 + 61 | g.getCurrentFont().getHorizontalScale() * 0.5f), 62 | juce::roundToInt(bounds.getCentre().y + g.getCurrentFont().getDescent()), 63 | juce::Justification::horizontallyCentred); 64 | } else { 65 | g.drawSingleLineText(juce::String("OFF"), 66 | juce::roundToInt(bounds.getCentre().x - bounds.getWidth() * 0.22 + 67 | g.getCurrentFont().getHorizontalScale() * 0.5f), 68 | juce::roundToInt(bounds.getCentre().y + g.getCurrentFont().getDescent()), 69 | juce::Justification::horizontallyCentred); 70 | } 71 | } 72 | } 73 | inline void setEditable(const bool f) { editable.store(f); } 74 | 75 | private: 76 | std::atomic editable = true; 77 | 78 | UIBase *uiBase; 79 | }; 80 | } 81 | #endif //ZL_REGULAR_BUTTON_LOOK_AND_FEEL_H 82 | -------------------------------------------------------------------------------- /source/gui/calloutbox/call_out_box_laf.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef ZL_CALLOUTBOXLAF_HPP 11 | #define ZL_CALLOUTBOXLAF_HPP 12 | 13 | #include 14 | 15 | #include "../interface_definitions.hpp" 16 | 17 | namespace zlInterface { 18 | class CallOutBoxLAF final : public juce::LookAndFeel_V4 { 19 | public: 20 | explicit CallOutBoxLAF(UIBase &base) : uiBase(base) { 21 | } 22 | 23 | void drawCallOutBoxBackground(juce::CallOutBox &box, juce::Graphics &g, 24 | const juce::Path &, 25 | juce::Image &) override { 26 | // g.setColour(uiBase.getBackgroundColor().withMultipliedAlpha(.25f)); 27 | // g.fillRoundedRectangle(box.getLocalBounds().toFloat(), uiBase.getFontSize() * .5f); 28 | // g.setColour(uiBase.getTextColor().withMultipliedAlpha(.25f)); 29 | g.setColour(uiBase.getBackgroundColor()); 30 | g.fillRoundedRectangle(box.getLocalBounds().toFloat(), uiBase.getFontSize() * .5f); 31 | } 32 | 33 | int getCallOutBoxBorderSize(const juce::CallOutBox &) override { 34 | return 0; 35 | } 36 | 37 | float getCallOutBoxCornerSize(const juce::CallOutBox &) override { 38 | return 0.f; 39 | } 40 | 41 | private: 42 | UIBase &uiBase; 43 | }; 44 | } 45 | #endif //ZL_CALLOUTBOXLAF_HPP 46 | -------------------------------------------------------------------------------- /source/gui/combobox/combobox.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Zishu Liu on 12/30/23. 3 | // 4 | 5 | #ifndef ZLINTERFACE_COMBOBOX_H 6 | #define ZLINTERFACE_COMBOBOX_H 7 | 8 | #include "compact_combobox/compact_combobox.hpp" 9 | #include "left_right_combobox/left_right_combobox.hpp" 10 | #include "regular_combobox/regular_combobox.hpp" 11 | 12 | #endif //ZLINTERFACE_COMBOBOX_H 13 | -------------------------------------------------------------------------------- /source/gui/combobox/compact_combobox/compact_combobox.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #include "compact_combobox.hpp" 11 | 12 | namespace zlInterface { 13 | CompactCombobox::CompactCombobox(const juce::String &labelText, const juce::StringArray &choices, 14 | UIBase &base) : uiBase(base), boxLookAndFeel(base), 15 | animator{} { 16 | juce::ignoreUnused(labelText); 17 | comboBox.addItemList(choices, 1); 18 | comboBox.setScrollWheelEnabled(false); 19 | comboBox.setInterceptsMouseClicks(false, false); 20 | comboBox.setBufferedToImage(true); 21 | comboBox.setLookAndFeel(&boxLookAndFeel); 22 | addAndMakeVisible(comboBox); 23 | 24 | setEditable(true); 25 | } 26 | 27 | 28 | CompactCombobox::~CompactCombobox() { 29 | comboBox.setLookAndFeel(nullptr); 30 | } 31 | 32 | void CompactCombobox::resized() { 33 | auto bound = getLocalBounds().toFloat(); 34 | bound = bound.withSizeKeepingCentre(bound.getWidth(), juce::jmin(bound.getHeight(), 35 | uiBase.getFontSize() * 2.f)); 36 | comboBox.setBounds(bound.toNearestInt()); 37 | } 38 | 39 | void CompactCombobox::mouseUp(const juce::MouseEvent &event) { 40 | comboBox.mouseUp(event); 41 | } 42 | 43 | void CompactCombobox::mouseDown(const juce::MouseEvent &event) { 44 | comboBox.mouseDown(event); 45 | } 46 | 47 | void CompactCombobox::mouseDrag(const juce::MouseEvent &event) { 48 | comboBox.mouseDrag(event); 49 | } 50 | 51 | void CompactCombobox::mouseEnter(const juce::MouseEvent &event) { 52 | comboBox.mouseEnter(event); 53 | animator.cancelAnimation(animationId, false); 54 | if (animator.getAnimation(animationId) != nullptr) 55 | return; 56 | auto effect{ 57 | friz::makeAnimation( 58 | animationId, {boxLookAndFeel.getBoxAlpha()}, {1.f}, 1000, friz::Parametric::kEaseInQuad) 59 | }; 60 | effect->updateFn = [this](int, const auto &vals) { 61 | boxLookAndFeel.setBoxAlpha(vals[0]); 62 | comboBox.repaint(); 63 | }; 64 | animator.addAnimation(std::move(effect)); 65 | } 66 | 67 | void CompactCombobox::mouseExit(const juce::MouseEvent &event) { 68 | comboBox.mouseExit(event); 69 | animator.cancelAnimation(animationId, false); 70 | if (animator.getAnimation(animationId) != nullptr) 71 | return; 72 | auto effect{ 73 | friz::makeAnimation( 74 | animationId, {boxLookAndFeel.getBoxAlpha()}, {0.f}, 1000, friz::Parametric::kEaseOutQuad) 75 | }; 76 | effect->updateFn = [this](int, const auto &vals) { 77 | boxLookAndFeel.setBoxAlpha(vals[0]); 78 | comboBox.repaint(); 79 | }; 80 | animator.addAnimation(std::move(effect)); 81 | } 82 | 83 | void CompactCombobox::mouseMove(const juce::MouseEvent &event) { 84 | comboBox.mouseMove(event); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /source/gui/combobox/compact_combobox/compact_combobox.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef COMPACT_COMBOBOX_H 11 | #define COMPACT_COMBOBOX_H 12 | 13 | #include 14 | 15 | #include "compact_combobox_look_and_feel.hpp" 16 | 17 | namespace zlInterface { 18 | class CompactCombobox : public juce::Component { 19 | public: 20 | CompactCombobox(const juce::String &labelText, const juce::StringArray &choices, UIBase &base); 21 | 22 | ~CompactCombobox() override; 23 | 24 | void resized() override; 25 | 26 | void mouseUp(const juce::MouseEvent &event) override; 27 | 28 | void mouseDown(const juce::MouseEvent &event) override; 29 | 30 | void mouseDrag(const juce::MouseEvent &event) override; 31 | 32 | void mouseEnter(const juce::MouseEvent &event) override; 33 | 34 | void mouseExit(const juce::MouseEvent &event) override; 35 | 36 | void mouseMove(const juce::MouseEvent &event) override; 37 | 38 | inline void setEditable(const bool x) { 39 | boxLookAndFeel.setEditable(x); 40 | setInterceptsMouseClicks(x, false); 41 | } 42 | 43 | inline juce::ComboBox &getBox() { return comboBox; } 44 | 45 | inline CompactComboboxLookAndFeel &getLAF() { return boxLookAndFeel; } 46 | 47 | private: 48 | zlInterface::UIBase &uiBase; 49 | CompactComboboxLookAndFeel boxLookAndFeel; 50 | juce::ComboBox comboBox; 51 | 52 | friz::Animator animator; 53 | static constexpr int animationId = 1; 54 | }; 55 | } 56 | 57 | 58 | #endif //COMPACT_COMBOBOX_H 59 | -------------------------------------------------------------------------------- /source/gui/combobox/left_right_combobox/left_right_button_look_and_feel.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef ZLEqualizer_LEFT_RIGHT_BUTTON_LOOK_AND_FEEL_HPP 11 | #define ZLEqualizer_LEFT_RIGHT_BUTTON_LOOK_AND_FEEL_HPP 12 | 13 | namespace zlInterface { 14 | class LeftRightButtonLookAndFeel : public juce::LookAndFeel_V4 { 15 | public: 16 | explicit LeftRightButtonLookAndFeel(UIBase &base) : uiBase(base) { 17 | } 18 | 19 | void drawDrawableButton(juce::Graphics &g, juce::DrawableButton &button, 20 | bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) override { 21 | juce::ignoreUnused(button, shouldDrawButtonAsHighlighted, shouldDrawButtonAsDown); 22 | 23 | if (shouldDrawButtonAsDown && editable.load()) { 24 | g.setColour(uiBase.getTextColor()); 25 | } else { 26 | g.setColour(uiBase.getTextInactiveColor()); 27 | } 28 | 29 | juce::Path path; 30 | const auto d = direction.load(); 31 | const auto bound = button.getLocalBounds().toFloat(); 32 | if (d < 0.1f) { 33 | path.startNewSubPath(bound.getTopLeft()); 34 | path.lineTo(bound.getBottomLeft()); 35 | path.lineTo(bound.getRight(), bound.getCentreY()); 36 | } else if (0.2f < d && d < 0.3f) { 37 | 38 | } else if (0.45f < d && d < 0.55f) { 39 | path.startNewSubPath(bound.getTopRight()); 40 | path.lineTo(bound.getBottomRight()); 41 | path.lineTo(bound.getX(), bound.getCentreY()); 42 | } else if (0.7f < d && d < 0.8f) { 43 | 44 | } 45 | path.closeSubPath(); 46 | g.fillPath(path); 47 | } 48 | 49 | inline void setEditable(const bool f) { editable.store(f); } 50 | 51 | inline float getDepth() const { return buttonDepth.load(); } 52 | 53 | inline void setDepth(const float x) { buttonDepth = x; } 54 | 55 | inline void setDirection(const float x) { direction.store(x); } 56 | 57 | private: 58 | std::atomic editable = true; 59 | std::atomic buttonDepth = 0.f, direction=0.f; 60 | 61 | UIBase &uiBase; 62 | }; 63 | } 64 | 65 | #endif //ZLEqualizer_LEFT_RIGHT_BUTTON_LOOK_AND_FEEL_HPP 66 | -------------------------------------------------------------------------------- /source/gui/combobox/left_right_combobox/left_right_combobox.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #include "left_right_combobox.hpp" 11 | 12 | namespace zlInterface { 13 | LeftRightCombobox::LeftRightCombobox(const juce::StringArray &choices, UIBase &base) 14 | : uiBase(base), 15 | leftButton("", juce::DrawableButton::ButtonStyle::ImageFitted), 16 | rightButton("", juce::DrawableButton::ButtonStyle::ImageFitted), 17 | lLAF(base), rLAF(base), lookAndFeel(base) { 18 | box.addItemList(choices, 1); 19 | box.setScrollWheelEnabled(false); 20 | box.setLookAndFeel(&lookAndFeel); 21 | box.setInterceptsMouseClicks(false, false); 22 | 23 | lLAF.setDirection(0.5f); 24 | leftButton.setLookAndFeel(&lLAF); 25 | rLAF.setDirection(0.0f); 26 | rightButton.setLookAndFeel(&rLAF); 27 | leftButton.onClick = [this]() { selectLeft(); }; 28 | rightButton.onClick = [this]() { selectRight(); }; 29 | 30 | setInterceptsMouseClicks(false, true); 31 | 32 | addAndMakeVisible(box); 33 | addAndMakeVisible(leftButton); 34 | addAndMakeVisible(rightButton); 35 | } 36 | 37 | LeftRightCombobox::~LeftRightCombobox() { 38 | box.setLookAndFeel(nullptr); 39 | leftButton.setLookAndFeel(nullptr); 40 | rightButton.setLookAndFeel(nullptr); 41 | } 42 | 43 | void LeftRightCombobox::resized() { 44 | auto bound = getLocalBounds().toFloat(); 45 | bound = bound.withSizeKeepingCentre(bound.getWidth() - lrPad.load(), 46 | uiBase.getFontSize() - ubPad.load()); 47 | const auto leftBound = bound.removeFromLeft(uiBase.getFontSize()); 48 | const auto rightBound = bound.removeFromRight(uiBase.getFontSize()); 49 | leftButton.setBounds(leftBound.toNearestInt()); 50 | rightButton.setBounds(rightBound.toNearestInt()); 51 | box.setBounds(bound.toNearestInt()); 52 | } 53 | 54 | void LeftRightCombobox::selectLeft() { 55 | if (box.getSelectedId() <= 1) { 56 | box.setSelectedId(box.getNumItems()); 57 | } else { 58 | box.setSelectedId(box.getSelectedId() - 1); 59 | } 60 | } 61 | 62 | void LeftRightCombobox::selectRight() { 63 | if (box.getSelectedId() == box.getNumItems()) { 64 | box.setSelectedId(1); 65 | } else { 66 | box.setSelectedId(box.getSelectedId() + 1); 67 | } 68 | } 69 | } // zlInterface 70 | -------------------------------------------------------------------------------- /source/gui/combobox/left_right_combobox/left_right_combobox.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef ZLEqualizer_LEFT_RIGHT_COMBOBOX_HPP 11 | #define ZLEqualizer_LEFT_RIGHT_COMBOBOX_HPP 12 | 13 | #include "left_right_combobox_look_and_feel.hpp" 14 | #include "left_right_button_look_and_feel.hpp" 15 | 16 | namespace zlInterface { 17 | class LeftRightCombobox final : public juce::Component { 18 | public: 19 | explicit LeftRightCombobox(const juce::StringArray &choices, UIBase &base); 20 | 21 | ~LeftRightCombobox() override; 22 | 23 | void resized() override; 24 | 25 | inline juce::ComboBox& getBox() {return box;} 26 | 27 | inline void setPadding(const float lr, const float ub) { 28 | lrPad.store(lr); 29 | ubPad.store(ub); 30 | } 31 | 32 | void selectLeft(); 33 | 34 | void selectRight(); 35 | 36 | private: 37 | UIBase &uiBase; 38 | juce::DrawableButton leftButton, rightButton; 39 | LeftRightButtonLookAndFeel lLAF, rLAF; 40 | juce::ComboBox box; 41 | LeftRightComboboxLookAndFeel lookAndFeel; 42 | 43 | std::atomic lrPad = 0, ubPad = 0; 44 | }; 45 | } // zlInterface 46 | 47 | #endif //ZLEqualizer_LEFT_RIGHT_COMBOBOX_HPP 48 | -------------------------------------------------------------------------------- /source/gui/combobox/left_right_combobox/left_right_combobox_look_and_feel.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef ZLEqualizer_LEFT_RIGHT_COMBOBOX_LOOK_AND_FEEL_HPP 11 | #define ZLEqualizer_LEFT_RIGHT_COMBOBOX_LOOK_AND_FEEL_HPP 12 | 13 | #include 14 | 15 | #include "../../interface_definitions.hpp" 16 | 17 | 18 | namespace zlInterface { 19 | class LeftRightComboboxLookAndFeel : public juce::LookAndFeel_V4 { 20 | public: 21 | // rounded menu box 22 | explicit LeftRightComboboxLookAndFeel(UIBase &base) { 23 | uiBase = &base; 24 | } 25 | 26 | void drawComboBox(juce::Graphics &g, int width, int height, bool isButtonDown, int, int, int, int, 27 | juce::ComboBox &box) override { 28 | juce::ignoreUnused(g, width, height, isButtonDown, box); 29 | } 30 | 31 | void positionComboBoxText(juce::ComboBox &box, juce::Label &label) override { 32 | label.setBounds(box.getLocalBounds()); 33 | } 34 | 35 | void drawLabel(juce::Graphics &g, juce::Label &label) override { 36 | if (editable.load()) { 37 | g.setColour(uiBase->getTextColor()); 38 | } else { 39 | g.setColour(uiBase->getTextInactiveColor()); 40 | } 41 | g.setFont(uiBase->getFontSize() * fontScale); 42 | g.drawText(label.getText(), label.getLocalBounds(), juce::Justification::centred); 43 | } 44 | 45 | int getMenuWindowFlags() override { 46 | return 1; 47 | } 48 | 49 | inline void setEditable(bool f) { editable.store(f); } 50 | 51 | inline void setBoxAlpha(const float x) { boxAlpha.store(x); } 52 | 53 | inline float getBoxAlpha() const { return boxAlpha.load(); } 54 | 55 | private: 56 | std::atomic editable = true; 57 | std::atomic boxAlpha; 58 | static constexpr float fontScale = 1.5f; 59 | 60 | UIBase *uiBase; 61 | }; 62 | } 63 | 64 | #endif //ZLEqualizer_LEFT_RIGHT_COMBOBOX_LOOK_AND_FEEL_HPP 65 | -------------------------------------------------------------------------------- /source/gui/combobox/regular_combobox/regular_combobox.hpp: -------------------------------------------------------------------------------- 1 | // ============================================================================== 2 | // Copyright (C) 2023 - zsliu98 3 | // This file is part of ZLEComp 4 | // 5 | // ZLEComp 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. 6 | // ZLEComp 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEComp. If not, see . 9 | // ============================================================================== 10 | 11 | #ifndef ZL_REGULAR_COMBOBOX_COMPONENT_H 12 | #define ZL_REGULAR_COMBOBOX_COMPONENT_H 13 | 14 | #include "regular_combobox_look_and_feel.hpp" 15 | #include "../../label/name_look_and_feel.hpp" 16 | 17 | namespace zlInterface { 18 | class RegularCombobox : public juce::Component { 19 | public: 20 | explicit RegularCombobox(const juce::String &labelText, const juce::StringArray &choices, UIBase &base) : 21 | myLookAndFeel(base), nameLookAndFeel(base) { 22 | uiBase = &base; 23 | comboBox.addItemList(choices, 1); 24 | comboBox.setLookAndFeel(&myLookAndFeel); 25 | comboBox.setScrollWheelEnabled(false); 26 | addAndMakeVisible(comboBox); 27 | label.setText(labelText, juce::dontSendNotification); 28 | label.setLookAndFeel(&nameLookAndFeel); 29 | addAndMakeVisible(label); 30 | 31 | uiBase = &base; 32 | } 33 | 34 | ~RegularCombobox() override { 35 | comboBox.setLookAndFeel(nullptr); 36 | label.setLookAndFeel(nullptr); 37 | } 38 | 39 | void resized() override { 40 | auto bound = getLocalBounds().toFloat(); 41 | auto labelBound = bound.removeFromTop(labelHeight * bound.getHeight()); 42 | label.setBounds(labelBound.toNearestInt()); 43 | comboBox.setBounds(bound.toNearestInt()); 44 | } 45 | 46 | void paint(juce::Graphics &g) override { 47 | juce::ignoreUnused(g); 48 | } 49 | 50 | juce::ComboBox &getComboBox() { return comboBox; } 51 | 52 | juce::Label &getLabel() { return label; } 53 | 54 | void setEditable(bool f) { 55 | myLookAndFeel.setEditable(f); 56 | nameLookAndFeel.setEditable(f); 57 | } 58 | 59 | private: 60 | RegularComboboxLookAndFeel myLookAndFeel; 61 | NameLookAndFeel nameLookAndFeel; 62 | juce::ComboBox comboBox; 63 | juce::Label label; 64 | 65 | constexpr static float boxHeight = 0.7f; 66 | constexpr static float labelHeight = 1.f - boxHeight; 67 | constexpr static float boxRatio = 0.45f; 68 | 69 | UIBase *uiBase; 70 | }; 71 | } 72 | #endif //ZL_REGULAR_COMBOBOX_COMPONENT_H 73 | -------------------------------------------------------------------------------- /source/gui/dragger2d/dragger2d.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef ZLTest_DRAGGER2D_HPP 11 | #define ZLTest_DRAGGER2D_HPP 12 | 13 | #include "dragger_component.hpp" 14 | #include "dragger_parameter_attach.hpp" 15 | 16 | #endif //ZLTest_DRAGGER2D_HPP 17 | -------------------------------------------------------------------------------- /source/gui/dragger2d/dragger_component.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef ZLTest_DRAGGER_COMPONENT_HPP 11 | #define ZLTest_DRAGGER_COMPONENT_HPP 12 | 13 | #include 14 | 15 | #include "../interface_definitions.hpp" 16 | #include "dragger_look_and_feel.hpp" 17 | 18 | namespace zlInterface { 19 | class Dragger final : public juce::Component { 20 | public: 21 | explicit Dragger(UIBase &base); 22 | 23 | ~Dragger() override; 24 | 25 | void mouseDown(const juce::MouseEvent &event) override; 26 | 27 | void mouseUp(const juce::MouseEvent &event) override; 28 | 29 | void mouseDrag(const juce::MouseEvent &event) override; 30 | 31 | void resized() override; 32 | 33 | juce::ToggleButton &getButton() { return button; } 34 | 35 | void setXPortion(float x); 36 | 37 | void setYPortion(float y); 38 | 39 | float getXPortion() const; 40 | 41 | float getYPortion() const; 42 | 43 | void setScale(const float x) {scale.store(x);} 44 | 45 | float getScale() const {return scale.load();} 46 | 47 | class Listener { 48 | public: 49 | virtual ~Listener() = default; 50 | 51 | virtual void draggerValueChanged(Dragger *dragger) = 0; 52 | 53 | virtual void dragStarted(Dragger *dragger) = 0; 54 | 55 | virtual void dragEnded(Dragger *dragger) = 0; 56 | }; 57 | 58 | /** Adds a listener to be called when this slider's value changes. */ 59 | void addListener(Listener *listener); 60 | 61 | /** Removes a previously-registered listener. */ 62 | void removeListener(Listener *listener); 63 | 64 | void setPadding(const float left, const float right, 65 | const float uppper, const float bottom) { 66 | lPadding = left; 67 | rPadding = right; 68 | uPadding = uppper; 69 | bPadding = bottom; 70 | } 71 | 72 | void setActive(const bool f) { draggerLAF.setActive(f); } 73 | 74 | DraggerLookAndFeel &getLAF() {return draggerLAF;} 75 | 76 | private: 77 | UIBase &uiBase; 78 | 79 | juce::ToggleButton button; 80 | DraggerLookAndFeel draggerLAF; 81 | juce::ComponentDragger dragger; 82 | juce::ComponentBoundsConstrainer constrainer; 83 | std::atomic isSelected; 84 | std::atomic xPortion, yPortion; 85 | 86 | juce::Rectangle buttonArea; 87 | float lPadding {0.f}, rPadding {0.f}, uPadding {0.f}, bPadding {0.f}; 88 | std::atomic scale {1.f}; 89 | 90 | juce::ListenerList listeners; 91 | }; 92 | } // zlInterface 93 | 94 | #endif //ZLTest_DRAGGER_COMPONENT_HPP 95 | -------------------------------------------------------------------------------- /source/gui/dragger2d/dragger_parameter_attach.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #include "dragger_parameter_attach.hpp" 11 | 12 | namespace zlInterface { 13 | DraggerParameterAttach::DraggerParameterAttach(juce::RangedAudioParameter ¶meterX, 14 | juce::NormalisableRange nRangeX, 15 | juce::RangedAudioParameter ¶meterY, 16 | juce::NormalisableRange nRangeY, 17 | Dragger &draggerC, 18 | juce::UndoManager *undoManager) 19 | : dragger(draggerC), 20 | attachmentX(parameterX, [this](const float f) { setX(f); }, undoManager), 21 | attachmentY(parameterY, [this](const float f) { setY(f); }, undoManager), 22 | rangeX(std::move(nRangeX)), rangeY(std::move(nRangeY)) { 23 | dragger.addListener(this); 24 | } 25 | 26 | DraggerParameterAttach::~DraggerParameterAttach() { 27 | dragger.removeListener(this); 28 | } 29 | 30 | void DraggerParameterAttach::sendInitialUpdate() { 31 | attachmentX.sendInitialUpdate(); 32 | attachmentY.sendInitialUpdate(); 33 | } 34 | 35 | void DraggerParameterAttach::setX(const float newValue) const { 36 | dragger.setXPortion(rangeX.convertTo0to1(rangeX.snapToLegalValue(newValue))); 37 | } 38 | 39 | void DraggerParameterAttach::setY(const float newValue) const { 40 | dragger.setYPortion(rangeY.convertTo0to1(rangeY.snapToLegalValue(newValue))); 41 | } 42 | 43 | void DraggerParameterAttach::dragStarted(Dragger *) { 44 | attachmentX.beginGesture(); 45 | attachmentY.beginGesture(); 46 | } 47 | 48 | void DraggerParameterAttach::dragEnded(Dragger *) { 49 | attachmentX.endGesture(); 50 | attachmentY.endGesture(); 51 | } 52 | 53 | void DraggerParameterAttach::draggerValueChanged(Dragger *) { 54 | if (isXAttached.load()) attachmentX.setValueAsPartOfGesture(rangeX.convertFrom0to1(dragger.getXPortion())); 55 | if (isYAttached.load()) attachmentY.setValueAsPartOfGesture(rangeY.convertFrom0to1(dragger.getYPortion())); 56 | } 57 | } // zlInterface 58 | -------------------------------------------------------------------------------- /source/gui/dragger2d/dragger_parameter_attach.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef ZLTest_DRAGGER_PARAMETER_ATTACH_HPP 11 | #define ZLTest_DRAGGER_PARAMETER_ATTACH_HPP 12 | 13 | #include 14 | #include 15 | 16 | #include "dragger_component.hpp" 17 | 18 | namespace zlInterface { 19 | class DraggerParameterAttach final : private Dragger::Listener { 20 | public: 21 | DraggerParameterAttach(juce::RangedAudioParameter ¶meterX, 22 | juce::NormalisableRange nRangeX, 23 | juce::RangedAudioParameter ¶meterY, 24 | juce::NormalisableRange nRangeY, 25 | Dragger &draggerC, 26 | juce::UndoManager *undoManager = nullptr); 27 | 28 | ~DraggerParameterAttach() override; 29 | 30 | void sendInitialUpdate(); 31 | 32 | void enableX(const bool f) { isXAttached.store(f); } 33 | 34 | void enableY(const bool f) { isYAttached.store(f); } 35 | 36 | void setX(float newValue) const; 37 | 38 | void setY(float newValue) const; 39 | 40 | private: 41 | void draggerValueChanged(Dragger *dragger) override; 42 | 43 | void dragStarted(Dragger *dragger) override; 44 | 45 | void dragEnded(Dragger *dragger) override; 46 | 47 | Dragger &dragger; 48 | juce::ParameterAttachment attachmentX, attachmentY; 49 | juce::NormalisableRange rangeX, rangeY; 50 | std::atomic isXAttached{true}, isYAttached{true}; 51 | }; 52 | } // zlInterface 53 | 54 | #endif //ZLTest_DRAGGER_PARAMETER_ATTACH_HPP 55 | -------------------------------------------------------------------------------- /source/gui/gui.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef ZL_GUI_H 11 | #define ZL_GUI_H 12 | 13 | #include "interface_definitions.hpp" 14 | #include "button/button.hpp" 15 | #include "combobox/combobox.hpp" 16 | #include "slider/slider.hpp" 17 | #include "dragger2d/dragger2d.hpp" 18 | #include "calloutbox/call_out_box_laf.hpp" 19 | 20 | #endif //ZL_GUI_H 21 | -------------------------------------------------------------------------------- /source/gui/label/name_look_and_feel.hpp: -------------------------------------------------------------------------------- 1 | // ============================================================================== 2 | // Copyright (C) 2023 - zsliu98 3 | // This file is part of ZLEComp 4 | // 5 | // ZLEComp 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. 6 | // ZLEComp 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEComp. If not, see . 9 | // ============================================================================== 10 | 11 | #ifndef ZL_NAME_LOOK_AND_FEEL_H 12 | #define ZL_NAME_LOOK_AND_FEEL_H 13 | 14 | #include 15 | 16 | #include "../interface_definitions.hpp" 17 | 18 | namespace zlInterface { 19 | class NameLookAndFeel final : public juce::LookAndFeel_V4 { 20 | public: 21 | explicit NameLookAndFeel(UIBase &base, const int multiLine = 0) 22 | : isMultiLine(multiLine) { 23 | uiBase = &base; 24 | } 25 | 26 | void drawLabel(juce::Graphics &g, juce::Label &label) override { 27 | if (label.isBeingEdited()) { 28 | return; 29 | } 30 | if (editable) { 31 | g.setColour(uiBase->getTextColor().withMultipliedAlpha(alpha.load())); 32 | } else { 33 | g.setColour(uiBase->getTextInactiveColor().withMultipliedAlpha(alpha.load())); 34 | } 35 | g.setFont(uiBase->getFontSize() * fontScale.load()); 36 | auto bound = label.getLocalBounds().toFloat(); 37 | bound.removeFromTop(uPadding.load()); 38 | bound.removeFromBottom(dPadding.load()); 39 | bound.removeFromLeft(lPadding.load()); 40 | bound.removeFromRight(rPadding.load()); 41 | if (isMultiLine >= 1) { 42 | g.drawFittedText(label.getText(), bound.toNearestInt(), justification.load(), 2, 1.f); 43 | } else { 44 | g.drawText(label.getText(), bound, justification.load()); 45 | } 46 | } 47 | 48 | inline void setEditable(const bool f) { editable.store(f); } 49 | 50 | inline void setAlpha(const float x) { alpha.store(x); } 51 | 52 | inline void setFontScale(const float x) { fontScale.store(x); } 53 | 54 | inline void setJustification(const juce::Justification j) { justification.store(j); } 55 | 56 | inline void setPadding(const float l, const float r, const float u, const float d) { 57 | lPadding.store(l); 58 | rPadding.store(r); 59 | uPadding.store(u); 60 | dPadding.store(d); 61 | } 62 | 63 | private: 64 | std::atomic editable{true}; 65 | std::atomic alpha{1.f}; 66 | std::atomic fontScale{FontNormal}; 67 | std::atomic justification{juce::Justification::centred}; 68 | std::atomic lPadding{0.f}, rPadding{0.f}, uPadding{0.f}, dPadding{0.f}; 69 | 70 | UIBase *uiBase; 71 | int isMultiLine; 72 | }; 73 | } 74 | 75 | #endif //ZL_NAME_LOOK_AND_FEEL_H 76 | -------------------------------------------------------------------------------- /source/gui/slider/compact_linear_slider/compact_linear_slider.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Zishu Liu on 12/30/23. 3 | // 4 | 5 | #ifndef COMPACT_LINEAR_SLIDER_H 6 | #define COMPACT_LINEAR_SLIDER_H 7 | 8 | #include 9 | 10 | #include "../../label/name_look_and_feel.hpp" 11 | #include "compact_linear_slider_look_and_feel.hpp" 12 | 13 | namespace zlInterface { 14 | class CompactLinearSlider : public juce::Component { 15 | public: 16 | explicit CompactLinearSlider(const juce::String &labelText, UIBase &base); 17 | 18 | ~CompactLinearSlider() override; 19 | 20 | void resized() override; 21 | 22 | void mouseUp(const juce::MouseEvent &event) override; 23 | 24 | void mouseDown(const juce::MouseEvent &event) override; 25 | 26 | void mouseDrag(const juce::MouseEvent &event) override; 27 | 28 | void mouseEnter(const juce::MouseEvent &event) override; 29 | 30 | void mouseExit(const juce::MouseEvent &event) override; 31 | 32 | void mouseMove(const juce::MouseEvent &event) override; 33 | 34 | void mouseDoubleClick(const juce::MouseEvent &event) override; 35 | 36 | void mouseWheelMove(const juce::MouseEvent &event, const juce::MouseWheelDetails &wheel) override; 37 | 38 | inline juce::Slider& getSlider() {return slider;} 39 | 40 | inline void setEditable(const bool x) { 41 | nameLookAndFeel.setEditable(x); 42 | textLookAndFeel.setEditable(x); 43 | setInterceptsMouseClicks(x, false); 44 | } 45 | 46 | inline void setPadding(const float lr, const float ub) { 47 | lrPad.store(lr); 48 | ubPad.store(ub); 49 | } 50 | 51 | private: 52 | UIBase &uiBase; 53 | 54 | CompactLinearSliderLookAndFeel sliderLookAndFeel; 55 | NameLookAndFeel nameLookAndFeel, textLookAndFeel; 56 | juce::Slider slider; 57 | juce::Label label, text; 58 | 59 | std::atomic lrPad = 0, ubPad = 0; 60 | 61 | friz::Animator animator; 62 | static constexpr int animationId = 1; 63 | 64 | juce::String getDisplayValue(juce::Slider &s); 65 | }; 66 | } 67 | 68 | #endif //COMPACT_LINEAR_SLIDER_H 69 | -------------------------------------------------------------------------------- /source/gui/slider/compact_linear_slider/compact_linear_slider_look_and_feel.hpp: -------------------------------------------------------------------------------- 1 | // ============================================================================== 2 | // Copyright (C) 2023 - zsliu98 3 | // This file is part of ZLEComp 4 | // 5 | // ZLEComp 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. 6 | // ZLEComp 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEComp. If not, see . 9 | // ============================================================================== 10 | 11 | #ifndef ZL_COMPACT_LINEAR_SLIDER_LOOK_AND_FEEL_H 12 | #define ZL_COMPACT_LINEAR_SLIDER_LOOK_AND_FEEL_H 13 | 14 | #include 15 | 16 | #include "../../interface_definitions.hpp" 17 | 18 | namespace zlInterface { 19 | class CompactLinearSliderLookAndFeel : public juce::LookAndFeel_V4 { 20 | public: 21 | explicit CompactLinearSliderLookAndFeel(UIBase &base): uiBase(base) { 22 | } 23 | 24 | void drawLinearSlider(juce::Graphics &g, int x, int y, int width, int height, 25 | float sliderPos, float minSliderPos, float maxSliderPos, 26 | const juce::Slider::SliderStyle, juce::Slider &slider) override { 27 | juce::ignoreUnused(slider, minSliderPos, maxSliderPos); 28 | auto bound = juce::Rectangle(x, y, width, height).toFloat(); 29 | uiBase.fillRoundedInnerShadowRectangle(g, bound, uiBase.getFontSize() * 0.5f, {.blurRadius = 0.66f}); 30 | 31 | juce::Path mask; 32 | mask.addRoundedRectangle(bound, uiBase.getFontSize() * 0.5f); 33 | g.saveState(); 34 | g.reduceClipRegion(mask); 35 | auto proportion = sliderPos / static_cast(width); 36 | auto shadowBound = bound.withWidth(proportion * bound.getWidth()); 37 | g.setColour(uiBase.getTextHideColor()); 38 | g.fillRect(shadowBound); 39 | g.restoreState(); 40 | } 41 | 42 | juce::Slider::SliderLayout getSliderLayout(juce::Slider &slider) override { 43 | juce::Slider::SliderLayout layout; 44 | layout.sliderBounds = slider.getLocalBounds(); 45 | return layout; 46 | } 47 | 48 | inline void setEditable(const bool f) { editable.store(f); } 49 | 50 | inline void setTextAlpha(const float x) { textAlpha.store(x); } 51 | 52 | private: 53 | std::atomic editable = true; 54 | std::atomic textAlpha; 55 | 56 | UIBase &uiBase; 57 | }; 58 | } 59 | 60 | #endif //ZL_COMPACT_LINEAR_SLIDER_LOOK_AND_FEEL_H 61 | -------------------------------------------------------------------------------- /source/gui/slider/linear_slider/linear_slider.hpp: -------------------------------------------------------------------------------- 1 | // ============================================================================== 2 | // Copyright (C) 2023 - zsliu98 3 | // This file is part of ZLEComp 4 | // 5 | // ZLEComp 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. 6 | // ZLEComp 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEComp. If not, see . 9 | // ============================================================================== 10 | 11 | #ifndef ZL_LINEAR_SLIDER_H 12 | #define ZL_LINEAR_SLIDER_H 13 | 14 | #include "../../label/name_look_and_feel.hpp" 15 | #include "linear_slider_look_and_feel.hpp" 16 | 17 | namespace zlInterface { 18 | class LinearSlider : public juce::Component { 19 | public: 20 | explicit LinearSlider(const juce::String &labelText, UIBase &base) : 21 | myLookAndFeel(base), nameLookAndFeel(base) { 22 | uiBase = &base; 23 | // setup slider 24 | slider.setSliderStyle(juce::Slider::LinearHorizontal); 25 | slider.setTextBoxIsEditable(false); 26 | slider.setDoubleClickReturnValue(true, 0.0); 27 | slider.setLookAndFeel(&myLookAndFeel); 28 | slider.setScrollWheelEnabled(true); 29 | addAndMakeVisible(slider); 30 | 31 | // setup label 32 | label.setText(labelText, juce::dontSendNotification); 33 | label.setLookAndFeel(&nameLookAndFeel); 34 | addAndMakeVisible(label); 35 | } 36 | 37 | ~LinearSlider() override { 38 | slider.setLookAndFeel(nullptr); 39 | label.setLookAndFeel(nullptr); 40 | } 41 | 42 | void resized() override { 43 | auto bound = getLocalBounds().toFloat(); 44 | auto labelBound = bound.removeFromTop(labelHeight * bound.getHeight()); 45 | label.setBounds(labelBound.toNearestInt()); 46 | bound = bound.withSizeKeepingCentre(bound.getWidth(), bound.getWidth() * sliderRatio); 47 | slider.setBounds(bound.toNearestInt()); 48 | } 49 | 50 | void paint(juce::Graphics &g) override { 51 | juce::ignoreUnused(g); 52 | } 53 | 54 | juce::Slider &getSlider() { return slider; } 55 | 56 | juce::Label &getLabel() { return label; } 57 | 58 | void setEditable(bool f) { 59 | myLookAndFeel.setEditable(f); 60 | nameLookAndFeel.setEditable(f); 61 | } 62 | 63 | private: 64 | LinearSliderLookAndFeel myLookAndFeel; 65 | NameLookAndFeel nameLookAndFeel; 66 | juce::Slider slider; 67 | juce::Label label; 68 | 69 | constexpr static float sliderHeight = 0.7f; 70 | constexpr static float labelHeight = 1.f - sliderHeight; 71 | constexpr static float sliderRatio = 0.45f; 72 | 73 | UIBase *uiBase; 74 | }; 75 | } 76 | 77 | #endif //ZL_LINEAR_SLIDER_H 78 | -------------------------------------------------------------------------------- /source/gui/slider/linear_slider/linear_slider_look_and_feel.hpp: -------------------------------------------------------------------------------- 1 | // ============================================================================== 2 | // Copyright (C) 2023 - zsliu98 3 | // This file is part of ZLEComp 4 | // 5 | // ZLEComp 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. 6 | // ZLEComp 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEComp. If not, see . 9 | // ============================================================================== 10 | 11 | #ifndef ZL_LINEAR_SLIDER_LOOK_AND_FEEL_H 12 | #define ZL_LINEAR_SLIDER_LOOK_AND_FEEL_H 13 | 14 | #include 15 | 16 | #include "../../interface_definitions.hpp" 17 | 18 | namespace zlInterface { 19 | class LinearSliderLookAndFeel : public juce::LookAndFeel_V4 { 20 | public: 21 | explicit LinearSliderLookAndFeel(UIBase &base) { 22 | uiBase = &base; 23 | } 24 | 25 | void drawLinearSlider(juce::Graphics &g, int x, int y, int width, int height, 26 | float sliderPos, float minSliderPos, float maxSliderPos, 27 | const juce::Slider::SliderStyle, juce::Slider &slider) override { 28 | juce::ignoreUnused(slider, minSliderPos, maxSliderPos); 29 | auto bound = juce::Rectangle(x, y, width, height).toFloat(); 30 | bound = uiBase->getRoundedShadowRectangleArea(bound, uiBase->getFontSize() * 0.5f, {}); 31 | uiBase->fillRoundedInnerShadowRectangle(g, bound, uiBase->getFontSize() * 0.5f, {.blurRadius = 0.66f}); 32 | 33 | juce::Path mask; 34 | mask.addRoundedRectangle(bound, uiBase->getFontSize() * 0.5f); 35 | g.saveState(); 36 | g.reduceClipRegion(mask); 37 | auto proportion = sliderPos / static_cast(width); 38 | auto shadowBound = bound.withWidth(proportion * bound.getWidth()); 39 | g.setColour(uiBase->getTextHideColor()); 40 | g.fillRect(shadowBound); 41 | g.restoreState(); 42 | } 43 | 44 | juce::Label *createSliderTextBox(juce::Slider &) override { 45 | auto *l = new juce::Label(); 46 | l->setJustificationType(juce::Justification::centred); 47 | l->setInterceptsMouseClicks(false, false); 48 | return l; 49 | } 50 | 51 | juce::Slider::SliderLayout getSliderLayout(juce::Slider &slider) override { 52 | auto localBounds = slider.getLocalBounds().toFloat(); 53 | juce::Slider::SliderLayout layout; 54 | auto textBounds = localBounds; 55 | layout.textBoxBounds = textBounds.toNearestInt(); 56 | layout.sliderBounds = slider.getLocalBounds(); 57 | return layout; 58 | } 59 | 60 | void drawLabel(juce::Graphics &g, juce::Label &label) override { 61 | if (editable.load()) { 62 | g.setColour(uiBase->getTextColor()); 63 | } else { 64 | g.setColour(uiBase->getTextInactiveColor()); 65 | } 66 | auto labelArea{label.getLocalBounds().toFloat()}; 67 | auto center = labelArea.getCentre(); 68 | if (uiBase->getFontSize() > 0) { 69 | g.setFont(uiBase->getFontSize() * FontLarge); 70 | } else { 71 | g.setFont(labelArea.getHeight() * 0.6f); 72 | } 73 | g.drawSingleLineText(juce::String(label.getText()), 74 | juce::roundToInt(center.x + g.getCurrentFont().getHorizontalScale()), 75 | juce::roundToInt(center.y + g.getCurrentFont().getDescent()), 76 | juce::Justification::horizontallyCentred); 77 | } 78 | 79 | void setEditable(bool f) { 80 | editable.store(f); 81 | } 82 | 83 | void setMouseOver(bool f) { 84 | mouseOver.store(f); 85 | } 86 | 87 | private: 88 | std::atomic editable = true, mouseOver = false; 89 | 90 | UIBase *uiBase; 91 | }; 92 | } 93 | 94 | #endif //ZL_LINEAR_SLIDER_LOOK_AND_FEEL_H 95 | -------------------------------------------------------------------------------- /source/gui/slider/rotary_slider/rotary_slider.hpp: -------------------------------------------------------------------------------- 1 | // ============================================================================== 2 | // Copyright (C) 2023 - zsliu98 3 | // This file is part of ZLEComp 4 | // 5 | // ZLEComp 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. 6 | // ZLEComp 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEComp. If not, see . 9 | // ============================================================================== 10 | 11 | #ifndef ZL_ROTARY_SLIDER_COMPONENT_H 12 | #define ZL_ROTARY_SLIDER_COMPONENT_H 13 | 14 | #include "../../label/name_look_and_feel.hpp" 15 | #include "rotary_slider_look_and_feel.hpp" 16 | 17 | namespace zlInterface { 18 | class RotarySlider : public juce::Component { 19 | public: 20 | explicit RotarySlider(const juce::String &labelText, UIBase &base) : 21 | myLookAndFeel(base), nameLookAndFeel(base), uiBase(base){ 22 | // setup slider 23 | slider.setSliderStyle(juce::Slider::Rotary); 24 | slider.setTextBoxIsEditable(false); 25 | slider.setDoubleClickReturnValue(true, 0.0); 26 | slider.setLookAndFeel(&myLookAndFeel); 27 | slider.setScrollWheelEnabled(true); 28 | addAndMakeVisible(slider); 29 | 30 | // setup label 31 | label.setText(labelText, juce::dontSendNotification); 32 | label.setLookAndFeel(&nameLookAndFeel); 33 | addAndMakeVisible(label); 34 | } 35 | 36 | ~RotarySlider() override { 37 | slider.setLookAndFeel(nullptr); 38 | label.setLookAndFeel(nullptr); 39 | } 40 | 41 | void resized() override { 42 | auto bound = getLocalBounds().toFloat(); 43 | auto boundMinWH = juce::jmin(bound.getWidth(), bound.getHeight() - uiBase.getFontSize() * FontHuge); 44 | bound = bound.withSizeKeepingCentre(boundMinWH, boundMinWH + uiBase.getFontSize() * FontHuge); 45 | auto textBound = bound.removeFromTop(uiBase.getFontSize() * FontHuge); 46 | label.setBounds(textBound.toNearestInt()); 47 | auto bounds = bound; 48 | auto radius = juce::jmin(bounds.getWidth(), bounds.getHeight()) * 0.9f; 49 | auto buttonBounds = bounds.withSizeKeepingCentre(radius, radius); 50 | slider.setBounds(buttonBounds.toNearestInt()); 51 | } 52 | 53 | void paint(juce::Graphics &g) override { 54 | juce::ignoreUnused(g); 55 | } 56 | 57 | juce::Slider &getSlider() { return slider; } 58 | 59 | juce::Label &getLabel() { return label; } 60 | 61 | void setEditable(bool f) { 62 | myLookAndFeel.setEditable(f); 63 | nameLookAndFeel.setEditable(f); 64 | } 65 | 66 | private: 67 | RotarySliderLookAndFeel myLookAndFeel; 68 | NameLookAndFeel nameLookAndFeel; 69 | juce::Slider slider; 70 | juce::Label label; 71 | 72 | UIBase &uiBase; 73 | 74 | constexpr static float sliderHeight = 0.85f; 75 | constexpr static float labelHeight = 1.f - sliderHeight; 76 | }; 77 | } 78 | #endif //ZL_ROTARY_SLIDER_COMPONENT_H 79 | -------------------------------------------------------------------------------- /source/gui/slider/slider.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Zishu Liu on 12/30/23. 3 | // 4 | 5 | #ifndef ZLINTERFACE_SLIDER_H 6 | #define ZLINTERFACE_SLIDER_H 7 | 8 | #include "compact_linear_slider/compact_linear_slider.hpp" 9 | #include "linear_slider/linear_slider.hpp" 10 | #include "rotary_slider/rotary_slider.hpp" 11 | #include "two_value_rotary_slider/two_value_rotary_slider.hpp" 12 | 13 | #endif //ZLINTERFACE_SLIDER_H 14 | -------------------------------------------------------------------------------- /source/gui/slider/two_value_rotary_slider/second_rotary_slider_look_and_feel.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Zishu Liu on 12/28/23. 3 | // 4 | 5 | #ifndef TWO_VALUE_ROTARY_SLIDER_LOOK_AND_FEEL_H 6 | #define TWO_VALUE_ROTARY_SLIDER_LOOK_AND_FEEL_H 7 | 8 | #include 9 | 10 | #include "../../interface_definitions.hpp" 11 | 12 | namespace zlInterface { 13 | class SecondRotarySliderLookAndFeel : public juce::LookAndFeel_V4 { 14 | public: 15 | explicit SecondRotarySliderLookAndFeel(UIBase &base) { 16 | uiBase = &base; 17 | } 18 | 19 | void drawRotarySlider(juce::Graphics &g, int x, int y, int width, int height, float sliderPos, 20 | const float rotaryStartAngle, const float rotaryEndAngle, juce::Slider &slider) override { 21 | juce::ignoreUnused(slider); 22 | if (!editable.load()) { 23 | return; 24 | } 25 | // calculate values 26 | auto rotationAngle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle); 27 | auto bounds = juce::Rectangle(x, y, width, height).toFloat(); 28 | auto diameter = juce::jmin(bounds.getWidth(), bounds.getHeight()); 29 | bounds = bounds.withSizeKeepingCentre(diameter, diameter); 30 | // draw knob 31 | auto oldBounds = uiBase->getInnerShadowEllipseArea(bounds, uiBase->getFontSize() * 0.5f, {}); 32 | auto newBounds = uiBase->getShadowEllipseArea(oldBounds, uiBase->getFontSize() * 0.5f, {}); 33 | // uiBase->drawInnerShadowEllipse(g, newBounds, uiBase->getFontSize() * 0.15f, {.flip=true}); 34 | // draw arrow 35 | auto arrowUnit = (diameter - newBounds.getWidth()) * 0.5f; 36 | auto arrowBound = juce::Rectangle( 37 | -0.5f * arrowUnit + bounds.getCentreX() + 38 | (0.5f * diameter - 0.5f * arrowUnit) * std::sin(rotationAngle), 39 | -0.5f * arrowUnit + bounds.getCentreY() + 40 | (0.5f * diameter - 0.5f * arrowUnit) * (-std::cos(rotationAngle)), 41 | arrowUnit, arrowUnit); 42 | 43 | juce::Path mask; 44 | mask.addEllipse(bounds); 45 | mask.setUsingNonZeroWinding(false); 46 | mask.addEllipse(newBounds); 47 | g.saveState(); 48 | g.reduceClipRegion(mask); 49 | uiBase->drawShadowEllipse(g, arrowBound, uiBase->getFontSize() * 0.5f, 50 | { 51 | .fit = false, .drawBright = false, .drawDark = true, 52 | .mainColour = uiBase->getColorMap2(0), 53 | .changeMain = true 54 | }); 55 | g.restoreState(); 56 | } 57 | 58 | void setEditable(const bool f) { editable.store(f); } 59 | 60 | private: 61 | std::atomic editable = true; 62 | 63 | UIBase *uiBase; 64 | }; 65 | } 66 | 67 | #endif //TWO_VALUE_ROTARY_SLIDER_LOOK_AND_FEEL_H 68 | -------------------------------------------------------------------------------- /source/gui/slider/two_value_rotary_slider/two_value_rotary_slider.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Zishu Liu on 12/28/23. 3 | // 4 | 5 | #ifndef TWO_VALUE_ROTARY_SLIDER_COMPONENT_H 6 | #define TWO_VALUE_ROTARY_SLIDER_COMPONENT_H 7 | 8 | #include 9 | #include 10 | 11 | #include "../../interface_definitions.hpp" 12 | #include "first_rotary_slider_look_and_feel.hpp" 13 | #include "second_rotary_slider_look_and_feel.hpp" 14 | #include "../../label/name_look_and_feel.hpp" 15 | 16 | namespace zlInterface { 17 | class TwoValueRotarySlider : public juce::Component, 18 | private juce::Label::Listener, private juce::Slider::Listener { 19 | public: 20 | explicit TwoValueRotarySlider(const juce::String &labelText, UIBase &base); 21 | 22 | ~TwoValueRotarySlider() override; 23 | 24 | // void paintOverChildren(juce::Graphics &g) override; 25 | 26 | void mouseUp(const juce::MouseEvent &event) override; 27 | 28 | void mouseDown(const juce::MouseEvent &event) override; 29 | 30 | void mouseDrag(const juce::MouseEvent &event) override; 31 | 32 | void mouseEnter(const juce::MouseEvent &event) override; 33 | 34 | void mouseExit(const juce::MouseEvent &event) override; 35 | 36 | void mouseMove(const juce::MouseEvent &event) override; 37 | 38 | void mouseDoubleClick(const juce::MouseEvent &event) override; 39 | 40 | void mouseWheelMove(const juce::MouseEvent &event, const juce::MouseWheelDetails &wheel) override; 41 | 42 | void resized() override; 43 | 44 | inline juce::Slider &getSlider1() { return slider1; } 45 | 46 | inline juce::Slider &getSlider2() { return slider2; } 47 | 48 | void setShowSlider2(bool x); 49 | 50 | inline void setPadding(const float lr, const float ub) { 51 | lrPad.store(lr); 52 | ubPad.store(ub); 53 | } 54 | 55 | inline void setEditable(const bool x) { 56 | editable.store(x); 57 | labelLookAndFeel.setEditable(x); 58 | labelLookAndFeel1.setEditable(x); 59 | labelLookAndFeel2.setEditable(x); 60 | setInterceptsMouseClicks(x, false); 61 | } 62 | 63 | inline bool getEditable() const { return editable.load(); } 64 | 65 | zlInterface::NameLookAndFeel &getLabelLAF() { return labelLookAndFeel; } 66 | 67 | private: 68 | UIBase &uiBase; 69 | 70 | juce::Slider slider1, slider2; 71 | FirstRotarySliderLookAndFeel slider1LAF; 72 | SecondRotarySliderLookAndFeel slider2LAF; 73 | 74 | juce::Label label, label1, label2; 75 | NameLookAndFeel labelLookAndFeel, labelLookAndFeel1, labelLookAndFeel2; 76 | 77 | NameLookAndFeel textBoxLAF; 78 | 79 | std::atomic showSlider2 = true, mouseOver, editable; 80 | std::atomic lrPad = 0, ubPad = 0; 81 | 82 | friz::Animator animator; 83 | static constexpr int animationId = 1; 84 | 85 | static juce::String getDisplayValue(juce::Slider &s); 86 | 87 | void labelTextChanged(juce::Label *labelThatHasChanged) override; 88 | 89 | void editorShown(juce::Label *l, juce::TextEditor &editor) override; 90 | 91 | void editorHidden(juce::Label *l, juce::TextEditor &editor) override; 92 | 93 | void sliderValueChanged(juce::Slider *slider) override; 94 | }; 95 | } 96 | 97 | #endif //TWO_VALUE_ROTARY_SLIDER_COMPONENT_H 98 | -------------------------------------------------------------------------------- /source/panel/control_panel.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2023 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #ifndef ZLINFLATOR_CONTROLPANEL_H 14 | #define ZLINFLATOR_CONTROLPANEL_H 15 | 16 | #include "../gui/gui.hpp" 17 | #include "../dsp/dsp.hpp" 18 | #include "panel_definitions.h" 19 | #include 20 | 21 | class ControlPanel : public juce::Component, public juce::AudioProcessorValueTreeState::Listener, 22 | private juce::AsyncUpdater { 23 | public: 24 | explicit ControlPanel(juce::AudioProcessorValueTreeState &apvts, zlInterface::UIBase &base); 25 | 26 | ~ControlPanel() override; 27 | 28 | //============================================================================== 29 | void paint(juce::Graphics &) override; 30 | 31 | void resized() override; 32 | 33 | void parameterChanged(const juce::String ¶meterID, float newValue) override; 34 | 35 | private: 36 | juce::AudioProcessorValueTreeState ¶metersRef; 37 | zlInterface::UIBase &uiBase; 38 | 39 | juce::Label gainLabel, splitLabel, saturateLabel; 40 | zlInterface::NameLookAndFeel nameLAF; 41 | zlInterface::TwoValueRotarySlider inputGainSlider, outputGainSlider, lowSplitSlider; 42 | zlInterface::TwoValueRotarySlider highSplitSlider, warmSlider, curveSlider; 43 | juce::OwnedArray sliderAttachments; 44 | 45 | std::array visibleChangeIDs = {zlDSP::bandSplit::ID}; 46 | 47 | void handleAsyncUpdate() override; 48 | 49 | void handleParameterChanges(const juce::String ¶meterID, float newValue); 50 | 51 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ControlPanel) 52 | }; 53 | 54 | #endif //ZLINFLATOR_CONTROLPANEL_H 55 | -------------------------------------------------------------------------------- /source/panel/logo_panel.cpp: -------------------------------------------------------------------------------- 1 | // ============================================================================== 2 | // Copyright (C) 2023 - zsliu98 3 | // This file is part of ZLEComp 4 | // 5 | // ZLEComp 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. 6 | // ZLEComp 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEComp. If not, see . 9 | // ============================================================================== 10 | 11 | #include "logo_panel.h" 12 | 13 | namespace zlpanel { 14 | LogoPanel::LogoPanel(PluginProcessor &p, 15 | zlInterface::UIBase &base) : 16 | brandDrawable(juce::Drawable::createFromImageData(BinaryData::zlaudio_svg, BinaryData::zlaudio_svgSize)), 17 | logoDrawable(juce::Drawable::createFromImageData(BinaryData::logo_svg, BinaryData::logo_svgSize)) { 18 | processorRef = &p; 19 | uiBase = &base; 20 | uiBase->setStyle(static_cast(*p.states.getRawParameterValue(zlstate::uiStyle::ID))); 21 | } 22 | 23 | LogoPanel::~LogoPanel() = default; 24 | 25 | void LogoPanel::paint(juce::Graphics &g) { 26 | auto tempBrand = brandDrawable->createCopy(); 27 | auto tempLogo = logoDrawable->createCopy(); 28 | tempBrand->replaceColour(juce::Colour(0, 0, 0), uiBase->getTextColor()); 29 | tempLogo->replaceColour(juce::Colour(0, 0, 0), uiBase->getTextColor()); 30 | 31 | auto bound = getLocalBounds().toFloat(); 32 | auto padding = juce::jmin(uiBase->getFontSize() * 0.5f, uiBase->getFontSize() * 0.5f); 33 | bound = bound.withSizeKeepingCentre(bound.getWidth() - padding, bound.getHeight() - padding); 34 | 35 | auto boundToUse = juce::Rectangle(bound.getWidth(), uiBase->getFontSize() * 2.f); 36 | bound = justification.appliedToRectangle(boundToUse, bound); 37 | 38 | auto logoWOH = static_cast(logoDrawable->getWidth()) / static_cast(logoDrawable->getHeight()); 39 | auto brandWOH = static_cast(brandDrawable->getWidth()) / static_cast(brandDrawable->getHeight()); 40 | auto widthOverHeight = logoWOH + brandWOH + 0.1f; 41 | auto width = juce::jmin(bound.getWidth(), bound.getHeight() * widthOverHeight); 42 | auto height = juce::jmin(bound.getHeight(), bound.getWidth() / widthOverHeight); 43 | 44 | boundToUse = juce::Rectangle(width, height); 45 | bound = justification.appliedToRectangle(boundToUse, bound); 46 | 47 | tempBrand->setTransform( 48 | juce::AffineTransform::scale(bound.getHeight() / static_cast(brandDrawable->getHeight()))); 49 | tempBrand->drawAt(g, bound.getX(), bound.getY(), 1.0f); 50 | 51 | tempLogo->setTransform( 52 | juce::AffineTransform::scale(bound.getHeight() / static_cast(logoDrawable->getHeight()))); 53 | tempLogo->drawAt(g, bound.getX() + bound.getHeight() * (widthOverHeight - logoWOH), bound.getY(), 1.0f); 54 | } 55 | 56 | void LogoPanel::mouseDoubleClick(const juce::MouseEvent &event) { 57 | juce::ignoreUnused(event); 58 | auto styleID = static_cast(*processorRef->states.getRawParameterValue(zlstate::uiStyle::ID)); 59 | styleID = (styleID + 1) % (zlstate::uiStyle::maxV + 1); 60 | uiBase->setStyle(styleID); 61 | auto *para = processorRef->states.getParameter(zlstate::uiStyle::ID); 62 | para->beginChangeGesture(); 63 | para->setValueNotifyingHost(zlstate::uiStyle::convertTo01(static_cast(styleID))); 64 | para->endChangeGesture(); 65 | } 66 | 67 | void LogoPanel::setJustification(int justificationFlags) { 68 | justification = justificationFlags; 69 | } 70 | 71 | } -------------------------------------------------------------------------------- /source/panel/logo_panel.h: -------------------------------------------------------------------------------- 1 | // ============================================================================== 2 | // Copyright (C) 2023 - zsliu98 3 | // This file is part of ZLEComp 4 | // 5 | // ZLEComp 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. 6 | // ZLEComp 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEComp. If not, see . 9 | // ============================================================================== 10 | 11 | #ifndef ZLLMATCH_LOGOPANEL_H 12 | #define ZLLMATCH_LOGOPANEL_H 13 | 14 | #include "BinaryData.h" 15 | #include "juce_audio_processors/juce_audio_processors.h" 16 | #include "../gui/gui.hpp" 17 | #include "../state/state_definitions.h" 18 | #include "../PluginProcessor.h" 19 | 20 | namespace zlpanel { 21 | class LogoPanel : public juce::Component { 22 | public: 23 | explicit LogoPanel(PluginProcessor &p, 24 | zlInterface::UIBase &base); 25 | 26 | ~LogoPanel() override; 27 | 28 | void paint(juce::Graphics &g) override; 29 | 30 | void mouseDoubleClick(const juce::MouseEvent &event) override; 31 | 32 | void setJustification(int justificationFlags); 33 | 34 | private: 35 | const std::unique_ptr brandDrawable, logoDrawable; 36 | zlInterface::UIBase *uiBase; 37 | PluginProcessor *processorRef; 38 | juce::Justification justification = juce::Justification::topLeft; 39 | }; 40 | } 41 | #endif //ZLLMATCH_LOGOPANEL_H 42 | -------------------------------------------------------------------------------- /source/panel/main_panel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2023 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #include "main_panel.h" 14 | 15 | MainPanel::MainPanel(PluginProcessor &p) : 16 | uiBase(), 17 | controlPanel(p.parameters, uiBase), 18 | topPanel(p, uiBase), 19 | meterPanel(p.getController(), uiBase), 20 | logoPanel(p, uiBase) { 21 | addAndMakeVisible(controlPanel); 22 | addAndMakeVisible(topPanel); 23 | addAndMakeVisible(meterPanel); 24 | logoPanel.setJustification(juce::Justification::centredLeft); 25 | addAndMakeVisible(logoPanel); 26 | } 27 | 28 | MainPanel::~MainPanel() = default; 29 | 30 | void MainPanel::paint(juce::Graphics &g) { 31 | g.fillAll(uiBase.getBackgroundColor()); 32 | auto bound = getLocalBounds().toFloat(); 33 | float fontSize = bound.getHeight() * 0.048f; 34 | bound = uiBase.fillRoundedShadowRectangle(g, bound, fontSize * 0.5f, {}); 35 | uiBase.fillRoundedInnerShadowRectangle(g, bound, fontSize * 0.5f, {.blurRadius=0.45f, .flip=true}); 36 | } 37 | 38 | void MainPanel::resized() { 39 | auto bound = getLocalBounds().toFloat(); 40 | auto fontSize = bound.getWidth() * 0.033838297872340425f; 41 | bound = zlInterface::UIBase::getRoundedShadowRectangleArea(bound, fontSize * 0.5f, {}); 42 | bound = zlInterface::UIBase::getRoundedShadowRectangleArea(bound, fontSize * 0.5f, {}); 43 | 44 | uiBase.setFontSize(fontSize); 45 | 46 | juce::Grid grid; 47 | using Track = juce::Grid::TrackInfo; 48 | using Fr = juce::Grid::Fr; 49 | 50 | grid.templateRows = {Track(Fr(10)), Track(Fr(48))}; 51 | grid.templateColumns = {Track(Fr(6)), Track(Fr(15))}; 52 | 53 | grid.items = { 54 | juce::GridItem(logoPanel).withArea(1, 1, 2, 2), 55 | juce::GridItem(meterPanel).withArea(2, 1, 3, 2), 56 | juce::GridItem(topPanel).withArea(1, 2, 2, 3), 57 | juce::GridItem(controlPanel).withArea(2, 2, 3, 3), 58 | }; 59 | 60 | grid.performLayout(bound.toNearestInt()); 61 | } -------------------------------------------------------------------------------- /source/panel/main_panel.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2023 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #ifndef ZLINFLATOR_MAINPANEL_H 14 | #define ZLINFLATOR_MAINPANEL_H 15 | 16 | #include 17 | #include "../gui/gui.hpp" 18 | #include "control_panel.h" 19 | #include "top_panel.h" 20 | #include "meter_panel.h" 21 | #include "logo_panel.h" 22 | 23 | class MainPanel : public juce::Component { 24 | public: 25 | explicit MainPanel(PluginProcessor &p); 26 | 27 | ~MainPanel() override; 28 | 29 | void paint(juce::Graphics &) override; 30 | 31 | void resized() override; 32 | private: 33 | zlInterface::UIBase uiBase; 34 | 35 | ControlPanel controlPanel; 36 | TopPanel topPanel; 37 | MeterPanel meterPanel; 38 | zlpanel::LogoPanel logoPanel; 39 | 40 | 41 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainPanel) 42 | }; 43 | 44 | #endif //ZLINFLATOR_MAINPANEL_H 45 | -------------------------------------------------------------------------------- /source/panel/meter_panel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2023 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #include "meter_panel.h" 14 | 15 | MeterPanel::MeterPanel(zlDSP::Controller &controller, zlInterface::UIBase &base) 16 | : uiBase(base), 17 | inPanel(controller.getInMeter(), base), 18 | outPanel(controller.getOutMeter(), base), 19 | inLabel("", "IN"), 20 | outLabel("", "OUT"), 21 | labelLAF(uiBase) { 22 | addAndMakeVisible(inPanel); 23 | addAndMakeVisible(outPanel); 24 | 25 | labelLAF.setJustification(juce::Justification::centred); 26 | labelLAF.setFontScale(1.25f); 27 | inLabel.setLookAndFeel(&labelLAF); 28 | outLabel.setLookAndFeel(&labelLAF); 29 | addAndMakeVisible(inLabel); 30 | addAndMakeVisible(outLabel); 31 | startTimerHz(30); 32 | } 33 | 34 | MeterPanel::~MeterPanel() { 35 | stopTimer(); 36 | inLabel.setLookAndFeel(nullptr); 37 | outLabel.setLookAndFeel(nullptr); 38 | } 39 | 40 | void MeterPanel::resized() { 41 | auto bound = getLocalBounds().toFloat(); 42 | bound.removeFromRight(uiBase.getFontSize() * .5f); 43 | 44 | juce::Grid grid; 45 | using Track = juce::Grid::TrackInfo; 46 | using Fr = juce::Grid::Fr; 47 | 48 | grid.templateRows = {Track(Fr(11)), Track(Fr(150))}; 49 | grid.templateColumns = {Track(Fr(6)), Track(Fr(6))}; 50 | 51 | grid.items = { 52 | juce::GridItem(inLabel).withArea(1, 1, 2, 2), 53 | juce::GridItem(outLabel).withArea(1, 2, 2, 3), 54 | juce::GridItem(inPanel).withArea(2, 1, 3, 2), 55 | juce::GridItem(outPanel).withArea(2, 2, 3, 3), 56 | }; 57 | grid.setGap(juce::Grid::Px(uiBase.getFontSize() * .25f)); 58 | grid.performLayout(bound.toNearestInt()); 59 | } 60 | 61 | void MeterPanel::timerCallback() { 62 | inPanel.repaint(); 63 | outPanel.repaint(); 64 | } 65 | -------------------------------------------------------------------------------- /source/panel/meter_panel.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2023 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #ifndef ZLINFLATOR_METERPANEL_H 14 | #define ZLINFLATOR_METERPANEL_H 15 | 16 | #include "../dsp/dsp.hpp" 17 | #include "../gui/gui.hpp" 18 | #include "meter_panel/single_meter_panel.hpp" 19 | 20 | class MeterPanel final : public juce::Component, private juce::Timer { 21 | public: 22 | explicit MeterPanel(zlDSP::Controller &controller, 23 | zlInterface::UIBase &base); 24 | 25 | ~MeterPanel() override; 26 | 27 | void resized() override; 28 | 29 | private: 30 | zlInterface::UIBase &uiBase; 31 | zlPanel::SingleMeterPanel inPanel, outPanel; 32 | juce::Label inLabel, outLabel; 33 | zlInterface::NameLookAndFeel labelLAF; 34 | 35 | void timerCallback() override; 36 | }; 37 | 38 | #endif //ZLINFLATOR_METERPANEL_H 39 | -------------------------------------------------------------------------------- /source/panel/meter_panel/meter_scale_panel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Zishu Liu on 2/19/24. 3 | // 4 | 5 | #include "meter_scale_panel.hpp" 6 | 7 | namespace zlPanel { 8 | MeterScalePanel::MeterScalePanel(zlInterface::UIBase &base) 9 | : uiBase(base) { 10 | setBufferedToImage(true); 11 | setInterceptsMouseClicks(false, false); 12 | } 13 | 14 | void MeterScalePanel::paint(juce::Graphics &g) { 15 | auto bound = getLocalBounds().toFloat(); 16 | bound.removeFromTop(bound.getHeight() * labelPortion); 17 | auto startDB = juce::roundToInt(maxDB); 18 | const auto intervalDB = juce::roundToInt((maxDB - minDB) / static_cast(numScales)); 19 | g.setFont(uiBase.getFontSize() * 1.125f); 20 | const auto thickness = uiBase.getFontSize() * .125f; 21 | for (size_t i = 0; i < numScales; ++i) { 22 | const auto portion = (static_cast(startDB) - minDB) / (maxDB - minDB); 23 | const auto y = bound.getY() + (1 - portion) * bound.getHeight(); 24 | const auto fontBound = juce::Rectangle(bound.getX(), y - uiBase.getFontSize(), 25 | bound.getWidth(), 2 * uiBase.getFontSize()); 26 | if (!ignoreFirst || i != 0) { 27 | g.setColour(uiBase.getTextColor()); 28 | g.drawText(juce::String(-startDB), fontBound, juce::Justification::centred); 29 | g.drawLine(fontBound.getCentreX() - .55f * uiBase.getFontSize(), y, 30 | fontBound.getCentreX() - .875f * uiBase.getFontSize(), y, 31 | thickness); 32 | g.drawLine(fontBound.getCentreX() + .55f * uiBase.getFontSize(), y, 33 | fontBound.getCentreX() + .875f * uiBase.getFontSize(), y, 34 | thickness); 35 | } else { 36 | g.setColour(uiBase.getTextInactiveColor()); 37 | g.drawLine(fontBound.getCentreX() - .875f * uiBase.getFontSize(), y, 38 | fontBound.getCentreX() + .875f * uiBase.getFontSize(), y, 39 | thickness * .5f); 40 | } 41 | startDB -= intervalDB; 42 | } 43 | } 44 | } // zlPanel 45 | -------------------------------------------------------------------------------- /source/panel/meter_panel/meter_scale_panel.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Zishu Liu on 2/19/24. 3 | // 4 | 5 | #ifndef ZLWarm_METER_SCALE_PANEL_HPP 6 | #define ZLWarm_METER_SCALE_PANEL_HPP 7 | 8 | #include "../../gui/gui.hpp" 9 | 10 | namespace zlPanel { 11 | 12 | class MeterScalePanel final : public juce::Component { 13 | public: 14 | explicit MeterScalePanel(zlInterface::UIBase &base); 15 | 16 | void paint(juce::Graphics &g) override; 17 | 18 | private: 19 | zlInterface::UIBase &uiBase; 20 | constexpr static float maxDB = 0.f, minDB = -60.f; 21 | constexpr static size_t numScales = 5; 22 | constexpr static float labelPortion = .075f; 23 | constexpr static bool ignoreFirst = true; 24 | }; 25 | 26 | } // zlPanel 27 | 28 | #endif //ZLWarm_METER_SCALE_PANEL_HPP 29 | -------------------------------------------------------------------------------- /source/panel/meter_panel/single_meter_panel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2023 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #include "single_meter_panel.hpp" 14 | 15 | namespace zlPanel { 16 | SingleMeterPanel::SingleMeterPanel(zlMeter::SingleMeter &meter, zlInterface::UIBase &base) 17 | : m(meter), uiBase(base), 18 | scalePanel(uiBase) { 19 | m.enable(true); 20 | setInterceptsMouseClicks(true, false); 21 | addAndMakeVisible(scalePanel); 22 | } 23 | 24 | SingleMeterPanel::~SingleMeterPanel() { 25 | m.enable(false); 26 | } 27 | 28 | void SingleMeterPanel::paint(juce::Graphics &g) { 29 | juce::ScopedLock lock(m.getLock()); 30 | const auto &maxPeak = m.getmaxPeak(); 31 | const auto &bufferPeak = m.getBufferPeak(); 32 | auto rectBound = getLocalBounds().toFloat(); 33 | auto labelBound = rectBound.removeFromTop(rectBound.getHeight() * labelPortion); 34 | const auto width = rectBound.getWidth() / static_cast(maxPeak.size()); 35 | // draw max peak labels 36 | g.setFont(uiBase.getFontSize() * 1.125f); 37 | auto mmaxPeak = -160.f; 38 | for (auto &v: maxPeak) { 39 | mmaxPeak = std::max(mmaxPeak, v.load()); 40 | } 41 | if (mmaxPeak > minDB) { 42 | if (mmaxPeak >= 0.f) { 43 | g.setColour(uiBase.getTextColor()); 44 | g.drawText(juce::String(mmaxPeak).substring(0, 4), 45 | labelBound, juce::Justification::centredBottom); 46 | } else { 47 | g.setColour(uiBase.getTextInactiveColor()); 48 | g.drawText(juce::String(mmaxPeak).substring(0, 5), 49 | labelBound, juce::Justification::centredBottom); 50 | } 51 | } else { 52 | g.setColour(uiBase.getTextInactiveColor()); 53 | g.drawText("-inf", labelBound, juce::Justification::centredBottom); 54 | } 55 | // draw rectangles 56 | g.setColour(uiBase.getTextInactiveColor()); 57 | for (size_t i = 0; i < bufferPeak.size(); ++i) { 58 | auto currentBound = rectBound.removeFromLeft(width); 59 | currentBound = currentBound.withSizeKeepingCentre( 60 | currentBound.getWidth() - paddingPortion * uiBase.getFontSize(), 61 | currentBound.getHeight()); 62 | const auto peakPortion = juce::jlimit( 63 | -1.f, 1.f, (bufferPeak[i].load() - minDB) / (maxDB - minDB)); 64 | if (peakPortion > 0.f) { 65 | juce::Rectangle boundToFill{ 66 | currentBound.getX(), currentBound.getY() + (1 - peakPortion) * currentBound.getHeight(), 67 | currentBound.getWidth(), peakPortion * currentBound.getHeight() 68 | }; 69 | path.clear(); 70 | if (i == 0) { 71 | path.addRoundedRectangle( 72 | boundToFill.getX(), boundToFill.getY(), 73 | boundToFill.getWidth(), boundToFill.getHeight(), 74 | uiBase.getFontSize() * .5f, uiBase.getFontSize() * .5f, 75 | false, false, true, false); 76 | } else if (i == bufferPeak.size() - 1) { 77 | path.addRoundedRectangle( 78 | boundToFill.getX(), boundToFill.getY(), 79 | boundToFill.getWidth(), boundToFill.getHeight(), 80 | uiBase.getFontSize() * .5f, uiBase.getFontSize() * .5f, 81 | false, false, false, true); 82 | } else { 83 | path.addRectangle(boundToFill); 84 | } 85 | g.fillPath(path); 86 | } 87 | } 88 | } 89 | 90 | void SingleMeterPanel::mouseDown(const juce::MouseEvent &event) { 91 | juce::ignoreUnused(event); 92 | m.reset(); 93 | } 94 | 95 | void SingleMeterPanel::resized() { 96 | scalePanel.setBounds(getLocalBounds()); 97 | } 98 | } // zlPanel 99 | -------------------------------------------------------------------------------- /source/panel/meter_panel/single_meter_panel.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2023 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #ifndef ZLWarm_SINGLE_METER_PANEL_HPP 14 | #define ZLWarm_SINGLE_METER_PANEL_HPP 15 | 16 | #include "../../dsp/dsp.hpp" 17 | #include "meter_scale_panel.hpp" 18 | #include "../../gui/gui.hpp" 19 | 20 | namespace zlPanel { 21 | 22 | class SingleMeterPanel final : public juce::Component { 23 | public: 24 | explicit SingleMeterPanel(zlMeter::SingleMeter &meter, zlInterface::UIBase &base); 25 | 26 | ~SingleMeterPanel() override; 27 | 28 | void paint(juce::Graphics &g) override; 29 | 30 | void resized() override; 31 | 32 | void mouseDown(const juce::MouseEvent &event) override; 33 | 34 | private: 35 | zlMeter::SingleMeter &m; 36 | zlInterface::UIBase &uiBase; 37 | constexpr static float maxDB = 0.f, minDB = -60.f; 38 | constexpr static size_t numScales = 5; 39 | constexpr static float labelPortion = .075f, paddingPortion = .2f; 40 | 41 | MeterScalePanel scalePanel; 42 | 43 | juce::Path path; 44 | }; 45 | 46 | } // zlPanel 47 | 48 | #endif //ZLWarm_SINGLE_METER_PANEL_HPP 49 | -------------------------------------------------------------------------------- /source/panel/panel_definitions.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 - zsliu98 2 | // This file is part of ZLEqualizer 3 | // 4 | // ZLEqualizer 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. 5 | // 6 | // ZLEqualizer 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEqualizer. If not, see . 9 | 10 | #ifndef ZLEqualizer_PANEL_DEFINITONS_HPP 11 | #define ZLEqualizer_PANEL_DEFINITONS_HPP 12 | 13 | #include 14 | 15 | namespace zlPanel { 16 | inline void attach(const std::vector &buttons, 17 | const std::vector &ids, 18 | juce::AudioProcessorValueTreeState ¶meters, 19 | juce::OwnedArray &attachments) { 20 | for (size_t i = 0; i < buttons.size(); ++i) { 21 | attachments.add( 22 | std::make_unique( 23 | parameters, ids[i], *buttons[i])); 24 | } 25 | } 26 | 27 | inline void attach(const std::vector &boxes, 28 | const std::vector &ids, 29 | juce::AudioProcessorValueTreeState ¶meters, 30 | juce::OwnedArray &attachments) { 31 | for (size_t i = 0; i < boxes.size(); ++i) { 32 | attachments.add( 33 | std::make_unique( 34 | parameters, ids[i], *boxes[i])); 35 | } 36 | } 37 | 38 | inline void attach(const std::vector &sliders, 39 | const std::vector &ids, 40 | juce::AudioProcessorValueTreeState ¶meters, 41 | juce::OwnedArray &attachments) { 42 | for (size_t i = 0; i < sliders.size(); ++i) { 43 | attachments.add( 44 | std::make_unique( 45 | parameters, ids[i], *sliders[i])); 46 | } 47 | } 48 | } 49 | 50 | #endif //ZLEqualizer_PANEL_DEFINITONS_HPP -------------------------------------------------------------------------------- /source/panel/top_panel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2023 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #include "top_panel.h" 14 | 15 | #include "BinaryData.h" 16 | 17 | TopPanel::TopPanel(PluginProcessor &p, zlInterface::UIBase &base) 18 | : uiBase(base), 19 | wetS("Wet", base), 20 | bypassC("", base), 21 | bandSplitC("", base), 22 | oversampleC("", zlDSP::overSample::choices, base), 23 | oversampleL("", "OS:"), 24 | nameLAF(base), 25 | bypassDrawable( 26 | juce::Drawable::createFromImageData(BinaryData::shutdownline_svg, BinaryData::shutdownline_svgSize)), 27 | splitDrawable(juce::Drawable::createFromImageData(BinaryData::splitcellshorizontal_svg, 28 | BinaryData::splitcellshorizontal_svgSize)) { 29 | juce::ignoreUnused(p); 30 | zlPanel::attach({&wetS.getSlider()}, {zlDSP::wet::ID}, p.parameters, sliderAttachments); 31 | 32 | bypassC.setDrawable(bypassDrawable.get()); 33 | bandSplitC.setDrawable(splitDrawable.get()); 34 | zlPanel::attach({&bypassC.getButton(), &bandSplitC.getButton()}, 35 | {zlDSP::effectOff::ID, zlDSP::bandSplit::ID}, 36 | p.parameters, buttonAttachments); 37 | 38 | nameLAF.setJustification(juce::Justification::centredRight); 39 | nameLAF.setFontScale(1.5f); 40 | 41 | oversampleL.setLookAndFeel(&nameLAF); 42 | zlPanel::attach({&oversampleC.getBox()}, {zlDSP::overSample::ID}, p.parameters, comboboxAttachments); 43 | 44 | addAndMakeVisible(wetS); 45 | addAndMakeVisible(bypassC); 46 | addAndMakeVisible(bandSplitC); 47 | addAndMakeVisible(oversampleL); 48 | addAndMakeVisible(oversampleC); 49 | } 50 | 51 | TopPanel::~TopPanel() { 52 | oversampleL.setLookAndFeel(nullptr); 53 | } 54 | 55 | void TopPanel::paint(juce::Graphics &g) { juce::ignoreUnused(g); } 56 | 57 | void TopPanel::resized() { 58 | // nameLAF.setPadding(0.f, 0.f, uiBase.getFontSize() * .2f, 0.f); 59 | wetS.setPadding(uiBase.getFontSize(), 0.f); 60 | 61 | juce::Grid grid; 62 | using Track = juce::Grid::TrackInfo; 63 | using Fr = juce::Grid::Fr; 64 | 65 | grid.templateRows = {Track(Fr(1))}; 66 | grid.templateColumns = {Track(Fr(20)), Track(Fr(10)), Track(Fr(10)), 67 | Track(Fr(9)), Track(Fr(11))}; 68 | 69 | juce::Array items; 70 | items.add(wetS); 71 | items.add(bypassC); 72 | items.add(bandSplitC); 73 | items.add(oversampleL); 74 | items.add(oversampleC); 75 | 76 | grid.items = items; 77 | grid.performLayout(getLocalBounds()); 78 | } 79 | -------------------------------------------------------------------------------- /source/panel/top_panel.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (C) 2023 - zsliu98 4 | This file is part of ZLInflator 5 | 6 | ZLInflator 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. 7 | ZLInflator 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. 8 | 9 | You should have received a copy of the GNU General Public License along with ZLInflator. If not, see . 10 | ============================================================================== 11 | */ 12 | 13 | #ifndef ZLINFLATOR_TOPPANEL_H 14 | #define ZLINFLATOR_TOPPANEL_H 15 | 16 | #include 17 | #include 18 | 19 | #include "../gui/gui.hpp" 20 | #include "logo_panel.h" 21 | #include "panel_definitions.h" 22 | 23 | class TopPanel final : public juce::Component { 24 | public: 25 | explicit TopPanel(PluginProcessor &p, zlInterface::UIBase &base); 26 | 27 | ~TopPanel() override; 28 | 29 | //============================================================================== 30 | void paint(juce::Graphics &) override; 31 | 32 | void resized() override; 33 | 34 | private: 35 | zlInterface::UIBase &uiBase; 36 | 37 | zlInterface::CompactLinearSlider wetS; 38 | juce::OwnedArray sliderAttachments; 39 | 40 | zlInterface::CompactButton bypassC, bandSplitC; 41 | juce::OwnedArray buttonAttachments; 42 | 43 | zlInterface::CompactCombobox oversampleC; 44 | juce::OwnedArray comboboxAttachments; 45 | juce::Label oversampleL; 46 | zlInterface::NameLookAndFeel nameLAF; 47 | 48 | const std::unique_ptr bypassDrawable, splitDrawable; 49 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TopPanel) 50 | }; 51 | 52 | #endif //ZLINFLATOR_TOPPANEL_H 53 | -------------------------------------------------------------------------------- /source/state/dummy_processor.cpp: -------------------------------------------------------------------------------- 1 | // ============================================================================== 2 | // Copyright (C) 2023 - zsliu98 3 | // This file is part of ZLEComp 4 | // 5 | // ZLEComp 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. 6 | // ZLEComp 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEComp. If not, see . 9 | // ============================================================================== 10 | 11 | #include "dummy_processor.h" 12 | -------------------------------------------------------------------------------- /source/state/dummy_processor.h: -------------------------------------------------------------------------------- 1 | // ============================================================================== 2 | // Copyright (C) 2023 - zsliu98 3 | // This file is part of ZLEComp 4 | // 5 | // ZLEComp 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. 6 | // ZLEComp 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. 7 | // 8 | // You should have received a copy of the GNU General Public License along with ZLEComp. If not, see . 9 | // ============================================================================== 10 | 11 | #ifndef ZLECOMP_DUMMY_PROCESSOR_H 12 | #define ZLECOMP_DUMMY_PROCESSOR_H 13 | 14 | #include 15 | 16 | class DummyProcessor : public juce::AudioProcessor { 17 | public: 18 | DummyProcessor() = default; 19 | 20 | ~DummyProcessor() override = default; 21 | 22 | void prepareToPlay(double, int) override {} 23 | 24 | void releaseResources() override {} 25 | 26 | bool isBusesLayoutSupported(const BusesLayout &) const override { return true; } 27 | 28 | void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override {} 29 | 30 | juce::AudioProcessorEditor *createEditor() override { return nullptr; } 31 | 32 | bool hasEditor() const override { return false; } 33 | 34 | const juce::String getName() const override { return {}; } 35 | 36 | bool acceptsMidi() const override { return false; } 37 | 38 | bool producesMidi() const override { return false; } 39 | 40 | bool isMidiEffect() const override { return false; } 41 | 42 | double getTailLengthSeconds() const override { return 0; } 43 | 44 | int getNumPrograms() override { return 1; } 45 | 46 | int getCurrentProgram() override { return 0; } 47 | 48 | void setCurrentProgram(int) override {} 49 | 50 | const juce::String getProgramName(int) override { return {}; } 51 | 52 | void changeProgramName(int, const juce::String &) override {} 53 | 54 | void getStateInformation(juce::MemoryBlock &) override {} 55 | 56 | void setStateInformation(const void *, int) override {} 57 | 58 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DummyProcessor) 59 | }; 60 | 61 | 62 | #endif //ZLECOMP_DUMMY_PROCESSOR_H 63 | -------------------------------------------------------------------------------- /source/state/property.cpp: -------------------------------------------------------------------------------- 1 | // ============================================================================== 2 | // Copyright (C) 2023 - zsliu98 3 | // This file is part of ZLEComp 4 | // 5 | // ZLEComp is free software: you can redistribute it and/or modify it under the 6 | // terms of the GNU General Public License as published by the Free Software 7 | // Foundation, either version 3 of the License, or (at your option) any later 8 | // version. ZLEComp is distributed in the hope that it will be useful, but 9 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 11 | // details. 12 | // 13 | // You should have received a copy of the GNU General Public License along with 14 | // ZLEComp. If not, see . 15 | // ============================================================================== 16 | 17 | #include "property.h" 18 | 19 | namespace zlstate { 20 | 21 | Property::Property() { 22 | if (!path.isDirectory()) { 23 | path.createDirectory(); 24 | } 25 | uiFile = std::make_unique( 26 | uiPath, juce::PropertiesFile::Options()); 27 | } 28 | 29 | Property::Property(juce::AudioProcessorValueTreeState &apvts) { 30 | if (!path.isDirectory()) { 31 | path.createDirectory(); 32 | } 33 | uiFile = std::make_unique( 34 | uiPath, juce::PropertiesFile::Options()); 35 | loadAPVTS(apvts); 36 | } 37 | 38 | void Property::loadAPVTS(juce::AudioProcessorValueTreeState &apvts) { 39 | const juce::ScopedReadLock myScopedLock(readWriteLock); 40 | auto file = uiFile->getFile(); 41 | if (auto xml = juce::XmlDocument::parse(file)) { 42 | apvts.replaceState(juce::ValueTree::fromXml(*xml)); 43 | } 44 | } 45 | 46 | void Property::saveAPVTS(juce::AudioProcessorValueTreeState &apvts) { 47 | const juce::ScopedWriteLock myScopedLock(readWriteLock); 48 | auto file = uiFile->getFile(); 49 | if (auto xml = apvts.copyState().createXml()) { 50 | xml->writeTo(file); 51 | } 52 | } 53 | } // namespace zlstate -------------------------------------------------------------------------------- /source/state/property.h: -------------------------------------------------------------------------------- 1 | // ============================================================================== 2 | // Copyright (C) 2023 - zsliu98 3 | // This file is part of ZLEComp 4 | // 5 | // ZLEComp is free software: you can redistribute it and/or modify it under the 6 | // terms of the GNU General Public License as published by the Free Software 7 | // Foundation, either version 3 of the License, or (at your option) any later 8 | // version. ZLEComp is distributed in the hope that it will be useful, but 9 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 11 | // details. 12 | // 13 | // You should have received a copy of the GNU General Public License along with 14 | // ZLEComp. If not, see . 15 | // ============================================================================== 16 | 17 | #ifndef ZLECOMP_PROPERTY_H 18 | #define ZLECOMP_PROPERTY_H 19 | 20 | #include 21 | #include 22 | 23 | namespace zlstate { 24 | 25 | class Property { 26 | public: 27 | Property(); 28 | 29 | explicit Property(juce::AudioProcessorValueTreeState &apvts); 30 | 31 | void loadAPVTS(juce::AudioProcessorValueTreeState &apvts); 32 | 33 | void saveAPVTS(juce::AudioProcessorValueTreeState &apvts); 34 | 35 | private: 36 | std::unique_ptr uiFile; 37 | juce::ReadWriteLock readWriteLock; 38 | 39 | inline auto static const path = 40 | juce::File::getSpecialLocation(juce::File::userApplicationDataDirectory) 41 | .getChildFile("Audio") 42 | .getChildFile("Presets") 43 | .getChildFile(JucePlugin_Manufacturer) 44 | .getChildFile(JucePlugin_Name); 45 | inline auto static const uiPath = 46 | path.getChildFile("ui.xml"); 47 | }; 48 | 49 | } // namespace zlstate 50 | 51 | #endif // ZLECOMP_PROPERTY_H 52 | --------------------------------------------------------------------------------