├── .gitignore ├── conanfile.txt ├── .github ├── dependabot.yml └── workflows │ ├── codeql.yml │ └── ci.yml ├── gcovr.cfg ├── cmake ├── 70-mustang-uaccess.rules ├── 70-mustang-plugdev.rules ├── plug.desktop ├── template │ └── Version.cpp.in ├── LTO.cmake ├── Template.cmake ├── DeprecatedOptions.cmake ├── Sanitizer.cmake ├── ClangFormat.cmake ├── Install.cmake ├── Coverage.cmake ├── 50-mustang.rules └── Findlibusb-1.0.cmake ├── script ├── image_build.sh ├── ci_setup.sh └── ci_build.sh ├── SECURITY.md ├── test ├── mocks │ ├── CMakeLists.txt │ ├── MockConnection.h │ ├── UsbDeviceMock.h │ ├── LibUsbMocks.h │ ├── UsbDeviceMock.cpp │ └── LibUsbMocks.cpp ├── matcher │ ├── Matcher.h │ ├── PacketMatcher.h │ └── TypeMatcher.h ├── DeviceModelTest.cpp ├── FxSlotTest.cpp ├── CMakeLists.txt ├── helper │ └── MustangConstants.h ├── ConnectionFactoryTest.cpp ├── UsbCommTest.cpp └── IdLookupTest.cpp ├── doc ├── Setup.md └── USB.md ├── src ├── com │ ├── CMakeLists.txt │ ├── LibUsbCompat.cpp │ ├── UsbException.cpp │ ├── UsbComm.cpp │ ├── UsbContext.cpp │ ├── ConnectionFactory.cpp │ ├── UsbDevice.cpp │ ├── MustangUpdater.cpp │ └── Mustang.cpp ├── CMakeLists.txt ├── ui │ ├── CMakeLists.txt │ ├── loadfromamp.cpp │ ├── settings.cpp │ ├── settings.ui │ ├── saveonamp.cpp │ ├── save_effects.cpp │ ├── loadfromamp.ui │ ├── amp_advanced.cpp │ ├── saveonamp.ui │ ├── savetofile.ui │ ├── save_effects.ui │ ├── library.cpp │ └── library.ui └── Main.cpp ├── .clang-format ├── include ├── Version.h ├── com │ ├── ConnectionFactory.h │ ├── MustangUpdater.h │ ├── CommunicationException.h │ ├── UsbContext.h │ ├── UsbException.h │ ├── UsbComm.h │ ├── LibUsbCompat.h │ ├── Connection.h │ ├── Mustang.h │ ├── UsbDevice.h │ ├── PacketSerializer.h │ └── IdLookup.h ├── ui │ ├── defaulteffects.h │ ├── settings.h │ ├── save_effects.h │ ├── loadfromfile.h │ ├── loadfromamp.h │ ├── saveonamp.h │ ├── savetofile.h │ ├── library.h │ ├── amp_advanced.h │ ├── quickpresets.h │ ├── effect.h │ ├── amplifier.h │ └── mainwindow.h ├── FxSlot.h ├── DeviceModel.h ├── data_structs.h ├── SignalChain.h └── effects_enum.h ├── .gitlab-ci.yml ├── CONTRIBUTING.md ├── CMakeLists.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | CMakeUserPresets.json 3 | cppcheck-* 4 | *.cppcheck 5 | -------------------------------------------------------------------------------- /conanfile.txt: -------------------------------------------------------------------------------- 1 | [requires] 2 | gtest/1.17.0 3 | 4 | [generators] 5 | CMakeToolchain 6 | CMakeDeps 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | -------------------------------------------------------------------------------- /gcovr.cfg: -------------------------------------------------------------------------------- 1 | exclude = test/ 2 | filter = src/ 3 | filter = include/ 4 | html = yes 5 | html-details = yes 6 | output = build/coverage/coverage.html 7 | print-summary = yes 8 | -------------------------------------------------------------------------------- /cmake/70-mustang-uaccess.rules: -------------------------------------------------------------------------------- 1 | ACTION!="add|bind", GOTO="mustang_plug_uaccess_end" 2 | 3 | ENV{ID_AUDIO_MODELING_AMP}=="?*", TAG+="uaccess" 4 | 5 | LABEL="mustang_plug_uaccess_end" 6 | -------------------------------------------------------------------------------- /cmake/70-mustang-plugdev.rules: -------------------------------------------------------------------------------- 1 | ACTION!="add|bind", GOTO="mustang_plug_plugdev_end" 2 | 3 | ENV{ID_AUDIO_MODELING_AMP}=="?*", GROUP="plugdev" 4 | 5 | LABEL="mustang_plug_plugdev_end" 6 | 7 | -------------------------------------------------------------------------------- /script/image_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -ex 4 | 5 | IMG=$1 6 | 7 | docker build --pull --build-arg COMPILER="${IMG}" -t "${DOCKER_IMG}/${IMG}" . 8 | docker push "${DOCKER_IMG}/${IMG}" 9 | 10 | -------------------------------------------------------------------------------- /cmake/plug.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Version=1.0 4 | Name=Plug 5 | Comment=Software for Fender Mustang Amps. 6 | Exec=plug 7 | Icon=mustang-plug 8 | Terminal=false 9 | Categories=AudioVideo;Audio;Music;Qt 10 | 11 | -------------------------------------------------------------------------------- /cmake/template/Version.cpp.in: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * This is a generated file - Do not edit 4 | */ 5 | 6 | #include "Version.h" 7 | 8 | namespace plug 9 | { 10 | std::string version() 11 | { 12 | return "@PROJECT_VERSION@"; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /cmake/LTO.cmake: -------------------------------------------------------------------------------- 1 | 2 | include(CheckIPOSupported) 3 | check_ipo_supported(RESULT lto_supported OUTPUT lto_error) 4 | 5 | if( lto_supported ) 6 | message(STATUS "IPO / LTO enabled") 7 | set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) 8 | else() 9 | message(STATUS "IPO / LTO not supported by the compiler") 10 | endif() 11 | -------------------------------------------------------------------------------- /cmake/Template.cmake: -------------------------------------------------------------------------------- 1 | 2 | set(TEMPLATE_DIR "${CMAKE_SOURCE_DIR}/cmake/template") 3 | set(GENERATED_DIR "${CMAKE_BINARY_DIR}/generated") 4 | 5 | 6 | configure_file(${TEMPLATE_DIR}/Version.cpp.in 7 | ${GENERATED_DIR}/Version.cpp 8 | @ONLY 9 | ) 10 | 11 | add_library(plug-version ${GENERATED_DIR}/Version.cpp) 12 | -------------------------------------------------------------------------------- /cmake/DeprecatedOptions.cmake: -------------------------------------------------------------------------------- 1 | 2 | function(deprecate_options) 3 | foreach (arg IN LISTS ARGN) 4 | if (DEFINED ${arg}) 5 | message(WARNING "Option ${arg} is deprecated, please use PLUG_${arg} instead, value will be ignored!") 6 | endif() 7 | endforeach() 8 | endfunction() 9 | 10 | deprecate_options(UNITTEST 11 | COVERAGE 12 | LTO 13 | SANITIZER_ASAN 14 | SANITIZER_UBSAN 15 | ) 16 | -------------------------------------------------------------------------------- /cmake/Sanitizer.cmake: -------------------------------------------------------------------------------- 1 | 2 | add_library(build-libs INTERFACE) 3 | 4 | macro(enable_sanitizer san) 5 | set(SAN_FLAG "-fsanitize=${san}") 6 | add_compile_options(${SAN_FLAG}) 7 | target_link_libraries(build-libs INTERFACE ${SAN_FLAG}) 8 | endmacro() 9 | 10 | 11 | if( PLUG_SANITIZER_ASAN ) 12 | enable_sanitizer(address) 13 | endif() 14 | 15 | if( PLUG_SANITIZER_UBSAN ) 16 | enable_sanitizer(undefined) 17 | endif() 18 | 19 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | To report a security issue, please use [*Report a Vulnerability*](https://github.com/offa/plug/security/advisories/new). **Do not** submit a public issue. 6 | 7 | ## Responsible Disclosure 8 | 9 | Security vulnerabilities are taken seriously, and help in disclosing them responsibly is appreciated. Please refrain from disclosing the vulnerability publicly until it has been addressed. 10 | -------------------------------------------------------------------------------- /script/ci_setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | # Install dependencies 6 | apt-get update 7 | apt-get install -y --no-install-recommends \ 8 | pkg-config \ 9 | qt6-base-dev \ 10 | libglx-dev \ 11 | libgl1-mesa-dev \ 12 | libusb-1.0-0-dev 13 | 14 | git clone --depth=1 --branch=v1.17.0 https://github.com/google/googletest.git 15 | mkdir googletest/build 16 | cd googletest/build 17 | cmake -DCMAKE_CXX_STANDARD=20 .. 18 | make -j install 19 | -------------------------------------------------------------------------------- /cmake/ClangFormat.cmake: -------------------------------------------------------------------------------- 1 | 2 | find_program(CLANG_FORMAT clang-format DOC "Clang Format executable") 3 | 4 | if( CLANG_FORMAT ) 5 | file(GLOB_RECURSE FORMAT_SRC_FILES 6 | "${PROJECT_SOURCE_DIR}/include/**.h" 7 | "${PROJECT_SOURCE_DIR}/src/**.cpp" 8 | "${PROJECT_SOURCE_DIR}/test/**.h" 9 | "${PROJECT_SOURCE_DIR}/test/**.cpp" 10 | ) 11 | 12 | add_custom_target(clang-format COMMAND ${CLANG_FORMAT} -i ${FORMAT_SRC_FILES}) 13 | endif() 14 | 15 | -------------------------------------------------------------------------------- /test/mocks/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(LibUsbMocks LibUsbMocks.cpp) 2 | target_link_libraries(LibUsbMocks PRIVATE TestLibs) 3 | target_include_directories(LibUsbMocks PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") 4 | 5 | add_library(UsbDeviceMock UsbDeviceMock.cpp) 6 | target_link_libraries(UsbDeviceMock PRIVATE TestLibs) 7 | 8 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 9 | target_compile_options(LibUsbMocks PUBLIC -Wno-gnu-zero-variadic-macro-arguments) 10 | target_compile_options(UsbDeviceMock PUBLIC -Wno-gnu-zero-variadic-macro-arguments) 11 | endif() 12 | -------------------------------------------------------------------------------- /doc/Setup.md: -------------------------------------------------------------------------------- 1 | # Setup 2 | 3 | List of packages required to build the software. 4 | 5 | For development [*Google Test*](https://github.com/google/googletest) (`gtest`) is needed for testing. 6 | 7 | It can be installed via the system package manger, [Conan](https://github.com/conan-io/conan) or build from source. 8 | 9 | ## Arch Linux 10 | 11 | ```sh 12 | sudo pacman -S \ 13 | cmake \ 14 | libusb \ 15 | qt6-base 16 | ``` 17 | 18 | ## Debian / Ubuntu 19 | 20 | ```sh 21 | sudo apt-get install \ 22 | pkg-config \ 23 | qt6-base-dev \ 24 | libglx-dev \ 25 | libgl1-mesa-dev \ 26 | libusb-1.0-0-dev 27 | ``` 28 | 29 | -------------------------------------------------------------------------------- /src/com/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_library(plug-mustang Mustang.cpp PacketSerializer.cpp Packet.cpp) 3 | add_library(plug-communication 4 | UsbComm.cpp 5 | ConnectionFactory.cpp 6 | ) 7 | 8 | add_library(plug-communication-usb 9 | UsbContext.cpp 10 | UsbException.cpp 11 | UsbDevice.cpp 12 | ) 13 | target_link_libraries(plug-communication-usb PRIVATE libusb-1.0::libusb-1.0) 14 | 15 | add_library(plug-libusb LibUsbCompat.cpp) 16 | target_link_libraries(plug-libusb PUBLIC libusb-1.0::libusb-1.0) 17 | 18 | add_library(plug-updater MustangUpdater.cpp) 19 | target_link_libraries(plug-updater PRIVATE libusb-1.0::libusb-1.0) 20 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(com) 2 | add_subdirectory(ui) 3 | 4 | add_executable(plug Main.cpp) 5 | target_link_libraries(plug 6 | PRIVATE 7 | plug-version 8 | plug-ui 9 | plug-mustang 10 | plug-communication 11 | plug-communication-usb 12 | plug-libusb 13 | plug-updater 14 | build-libs 15 | ) 16 | 17 | install(TARGETS plug EXPORT plug-config DESTINATION ${CMAKE_INSTALL_BINDIR}) 18 | -------------------------------------------------------------------------------- /cmake/Install.cmake: -------------------------------------------------------------------------------- 1 | install(FILES 2 | ${CMAKE_SOURCE_DIR}/cmake/50-mustang.rules 3 | ${CMAKE_SOURCE_DIR}/cmake/70-mustang-uaccess.rules 4 | ${CMAKE_SOURCE_DIR}/cmake/70-mustang-plugdev.rules 5 | DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/udev/rules.d 6 | ) 7 | install(FILES ${CMAKE_SOURCE_DIR}/cmake/plug.desktop 8 | DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications 9 | ) 10 | 11 | install(FILES ${CMAKE_SOURCE_DIR}/cmake/mustang-plug.svg 12 | DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps/ 13 | ) 14 | 15 | install(EXPORT plug-config DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/plug) 16 | -------------------------------------------------------------------------------- /cmake/Coverage.cmake: -------------------------------------------------------------------------------- 1 | 2 | find_program(GCOVR gcovr DOC "gcovr program") 3 | 4 | if( NOT GCOVR ) 5 | message(SEND_ERROR "gcovr not found") 6 | else() 7 | message(STATUS "Found gcovr: ${GCOVR}") 8 | endif() 9 | 10 | 11 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage") 12 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") 13 | 14 | set(COV_DIR "${CMAKE_BINARY_DIR}/coverage") 15 | 16 | if( NOT EXISTS ${COV_DIR} ) 17 | file(MAKE_DIRECTORY ${COV_DIR}) 18 | endif() 19 | 20 | 21 | add_custom_target(coverage ${CMAKE_COMMAND} -E make_directory ${COV_DIR} 22 | COMMAND ${GCOVR} --root ${PROJECT_SOURCE_DIR} 23 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} 24 | COMMENT "Generate coverage data" 25 | VERBATIM 26 | ) 27 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | AccessModifierOffset: '-4' 3 | AllowShortBlocksOnASingleLine: 'false' 4 | AllowShortCaseLabelsOnASingleLine: 'false' 5 | AllowShortFunctionsOnASingleLine: None 6 | AllowShortIfStatementsOnASingleLine: 'false' 7 | AllowShortLoopsOnASingleLine: 'false' 8 | AlwaysBreakTemplateDeclarations: 'true' 9 | BreakBeforeBraces: Allman 10 | ColumnLimit: '0' 11 | FixNamespaceComments: 'false' 12 | IndentCaseLabels: 'true' 13 | IndentWidth: '4' 14 | InsertBraces: 'true' 15 | Language: Cpp 16 | MaxEmptyLinesToKeep: '2' 17 | NamespaceIndentation: All 18 | NamespaceMacros: ['TEST_GROUP'] 19 | PointerAlignment: Left 20 | SortIncludes: 'false' 21 | SpaceAfterCStyleCast: 'true' 22 | SpaceInEmptyParentheses: 'false' 23 | TabWidth: '4' 24 | UseTab: Never 25 | 26 | ... 27 | -------------------------------------------------------------------------------- /src/ui/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CMAKE_AUTOMOC ON) 2 | set(CMAKE_AUTOUIC ON) 3 | set(CMAKE_AUTORCC ON) 4 | 5 | add_library(plug-ui amp_advanced.cpp 6 | amplifier.cpp 7 | defaulteffects.cpp 8 | effect.cpp 9 | library.cpp 10 | loadfromamp.cpp 11 | loadfromfile.cpp 12 | mainwindow.cpp 13 | quickpresets.cpp 14 | save_effects.cpp 15 | saveonamp.cpp 16 | savetofile.cpp 17 | settings.cpp 18 | ) 19 | 20 | target_link_libraries(plug-ui 21 | PUBLIC 22 | Qt6::Widgets 23 | Qt6::Gui 24 | Qt6::Core 25 | ) 26 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: codeql 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: '0 5 * * 3' 8 | 9 | permissions: 10 | contents: read 11 | pull-requests: read 12 | security-events: write 13 | 14 | jobs: 15 | codeql: 16 | runs-on: ubuntu-latest 17 | container: 18 | image: "registry.gitlab.com/offa/docker-images/gcc:15" 19 | name: "CodeQL" 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v6 23 | - name: Setup 24 | run: script/ci_setup.sh 25 | - name: CodeQL Initialization 26 | uses: github/codeql-action/init@v4 27 | with: 28 | languages: cpp, actions 29 | queries: +security-and-quality 30 | build-mode: none 31 | config: | 32 | paths-ignore: 33 | - 'googletest/**' 34 | - name: CodeQL Analysis 35 | uses: github/codeql-action/analyze@v4 36 | -------------------------------------------------------------------------------- /include/Version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include 25 | 26 | namespace plug 27 | { 28 | std::string version(); 29 | } 30 | -------------------------------------------------------------------------------- /include/com/ConnectionFactory.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include 24 | 25 | namespace plug::com 26 | { 27 | class Mustang; 28 | 29 | 30 | std::unique_ptr connect(); 31 | } 32 | -------------------------------------------------------------------------------- /include/com/MustangUpdater.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | namespace plug::com 25 | { 26 | int updateFirmware(const char* filename); 27 | } 28 | -------------------------------------------------------------------------------- /doc/USB.md: -------------------------------------------------------------------------------- 1 | # Known USB devices 2 | 3 | | Device | VID | PID | Note | 4 | |----------------|:----:|:----:|------| 5 | | **v1** | | | | 6 | | Mustang I | 1ed8 | 0004 | | 7 | | Mustang II | 1ed8 | 0004 | | 8 | | Mustang III | 1ed8 | 0005 | | 9 | | Mustang IV | 1ed8 | 0005 | | 10 | | Mustang V | 1ed8 | 0005 | | 11 | | Mustang Bronco | 1ed8 | 000a | | 12 | | Mustang Mini | 1ed8 | 0010 | | 13 | | Mustang Floor | 1ed8 | 0012 | | 14 | | **v2** | | | | 15 | | Mustang I | 1ed8 | 0014 | | 16 | | Mustang II | 1ed8 | 0014 | | 17 | | Mustang III | 1ed8 | 0016 | | 18 | | Mustang IV | 1ed8 | 0016 | | 19 | | Mustang V | 1ed8 | 0016 | | 20 | 21 | 22 | ## Other devices 23 | 24 | | Device | VID | PID | Note | 25 | |----------------|:----:|:----:|------| 26 | | Mustang LT 25 | 1ed8 | 0037 | | 27 | | Mustang LT 40S | 1ed8 | 0046 | | 28 | | Rumble LT 25 | 1ed8 | 0038 | | 29 | | Mustang GT 40 | 1ed8 | 0032 | | 30 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | GTEST_COLOR: "yes" 3 | 4 | 5 | build: 6 | parallel: 7 | matrix: 8 | - COMPILER: gcc 9 | VERSION: [15, 14] 10 | - COMPILER: clang 11 | VERSION: [21, 20] 12 | image: registry.gitlab.com/offa/docker-images/${COMPILER}:${VERSION} 13 | script: 14 | - script/ci_setup.sh 15 | - script/ci_build.sh -asan -ubsan 16 | 17 | coverage: 18 | image: registry.gitlab.com/offa/docker-images/gcc:15 19 | script: 20 | - script/ci_setup.sh 21 | - script/ci_build.sh -cov 22 | coverage: /^\s*lines:\s*\d+.\d+\%/ 23 | 24 | formatting: 25 | image: docker:latest 26 | variables: 27 | CLANGFORMAT_VERSION: 19 28 | services: 29 | - docker:dind 30 | before_script: 31 | - apk add --no-cache git 32 | - git clone --depth=1 https://github.com/DoozyX/clang-format-lint-action.git 33 | - docker build -t clang-format-lint clang-format-lint-action 34 | script: 35 | - docker run --rm --workdir /src -v ${PWD}:/src clang-format-lint --clang-format-executable /clang-format/clang-format${CLANGFORMAT_VERSION} -r --exclude .git . 36 | -------------------------------------------------------------------------------- /src/com/LibUsbCompat.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "com/LibUsbCompat.h" 22 | 23 | namespace plug::com::usb::libusb 24 | { 25 | const char* strerror(ErrorCodeAdapter errorCode) 26 | { 27 | return libusb_strerror(errorCode); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /script/ci_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | declare -a BUILD_ARGS 6 | BUILD_TYPE="Debug" 7 | COVERAGE=false 8 | 9 | for arg in "$@" 10 | do 11 | case "${arg}" in 12 | -asan) 13 | BUILD_ARGS+=("-DPLUG_SANITIZER_ASAN=ON") 14 | ;; 15 | -ubsan) 16 | BUILD_ARGS+=("-DPLUG_SANITIZER_UBSAN=ON") 17 | ;; 18 | -cov) 19 | BUILD_ARGS+=("-DPLUG_COVERAGE=ON") 20 | COVERAGE=true; 21 | BUILD_TYPE="Debug" 22 | export PATH=$HOME/.local/bin:$PATH 23 | apt-get install -y --no-install-recommends pipx 24 | pipx install gcovr 25 | 26 | GCC_VERSION="$(${CC} -dumpfullversion | cut -f1 -d.)" 27 | ln -sf /usr/bin/gcov-${GCC_VERSION} /usr/bin/gcov 28 | ;; 29 | esac 30 | done 31 | 32 | BUILD_ARGS+=("-DCMAKE_BUILD_TYPE=${BUILD_TYPE}") 33 | export GTEST_BRIEF=1 34 | 35 | 36 | mkdir -p build && cd build 37 | cmake "${BUILD_ARGS[@]}" .. 38 | make -j 39 | make unittest 40 | 41 | 42 | if [[ "${COVERAGE}" == true ]] 43 | then 44 | make coverage 45 | fi 46 | -------------------------------------------------------------------------------- /test/matcher/Matcher.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include 24 | 25 | namespace plug::test::matcher 26 | { 27 | MATCHER_P(BufferIs, expected, "") 28 | { 29 | return std::equal(expected.cbegin(), expected.cend(), arg); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /cmake/50-mustang.rules: -------------------------------------------------------------------------------- 1 | # udev rules for Fender Mustang Amps. Used by Plug. 2 | 3 | ACTION!="add|bind", GOTO="mustang_plug_rules_end" 4 | SUBSYSTEM!="usb", GOTO="mustang_plug_rules_end" 5 | 6 | ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0004", ENV{ID_AUDIO_MODELING_AMP}="1" 7 | ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0005", ENV{ID_AUDIO_MODELING_AMP}="1" 8 | ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0006", ENV{ID_AUDIO_MODELING_AMP}="1" 9 | ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0007", ENV{ID_AUDIO_MODELING_AMP}="1" 10 | ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0010", ENV{ID_AUDIO_MODELING_AMP}="1" 11 | ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0011", ENV{ID_AUDIO_MODELING_AMP}="1" 12 | ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0012", ENV{ID_AUDIO_MODELING_AMP}="1" 13 | ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0013", ENV{ID_AUDIO_MODELING_AMP}="1" 14 | ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0014", ENV{ID_AUDIO_MODELING_AMP}="1" 15 | ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0015", ENV{ID_AUDIO_MODELING_AMP}="1" 16 | ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0016", ENV{ID_AUDIO_MODELING_AMP}="1" 17 | ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0017", ENV{ID_AUDIO_MODELING_AMP}="1" 18 | 19 | LABEL="mustang_plug_rules_end" 20 | -------------------------------------------------------------------------------- /include/com/CommunicationException.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include 24 | #include 25 | 26 | namespace plug::com 27 | { 28 | 29 | class CommunicationException : public std::runtime_error 30 | { 31 | public: 32 | explicit CommunicationException(const std::string& msg) 33 | : std::runtime_error(msg) 34 | { 35 | } 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | 4 | ## Issues 5 | 6 | **Issues** are used to report bugs, problems, feature requests, ask questions or other kind of suggestions. An issue ***should include***: 7 | 8 | - Good and meaningful title 9 | - Detailed description 10 | 11 | ### Problems and Bugs 12 | 13 | Problem and bug reports ***need also***: 14 | 15 | - Expected and actual behaviour 16 | - Used version, compiler and platform 17 | - Minimal example or steps to reproduce 18 | 19 | 20 | ## Pull Requests 21 | 22 | **Pull requests** are used to submit contributions to the project. A pull request ***should include***: 23 | 24 | - Good and meaningful title 25 | - Detailed description 26 | - Descriptive commit messages 27 | 28 | If the PR is related to an *Issue*, please reference it in the description or title. 29 | 30 | ### Code 31 | 32 | The contributed code should match these criteria: 33 | 34 | - Pass all Unit Tests and CI Builds 35 | - Proper Test Cases 36 | - Merge cleanly, without conflicts 37 | - Follow the projects code style 38 | - Does not introduce external dependencies 39 | - 4 Spaces – no Tabs 40 | - UTF-8 encoding 41 | 42 | 43 | 44 | ## Further readings 45 | 46 | - [Github Guide: How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) 47 | 48 | -------------------------------------------------------------------------------- /cmake/Findlibusb-1.0.cmake: -------------------------------------------------------------------------------- 1 | find_package(PkgConfig) 2 | pkg_check_modules(PKG_libusb-1.0 QUIET libusb-1.0) 3 | set(libusb-1.0_DEFINITIONS ${PKG_libusb-1.0_CFLAGS_OTHER}) 4 | 5 | find_path(libusb-1.0_INCLUDE_DIR "libusb-1.0/libusb.h" 6 | HINTS ${PKG_libusb-1.0_INCLUDE_DIRS} 7 | ) 8 | 9 | find_library(libusb-1.0_LIBRARY NAMES usb-1.0 10 | HINTS ${PKG_libusb-1.0_LIBDIR} 11 | ${PKG_libusb-1.0_LIBRARY_DIRS} 12 | "${libusb-1.0_DIR}/lib" 13 | ) 14 | 15 | include(FindPackageHandleStandardArgs) 16 | find_package_handle_standard_args(libusb-1.0 DEFAULT_MSG 17 | libusb-1.0_LIBRARY 18 | libusb-1.0_INCLUDE_DIR 19 | ) 20 | mark_as_advanced(libusb-1.0_INCLUDE_DIR libusb-1.0_LIBRARY) 21 | 22 | 23 | add_library(libusb-1.0::libusb-1.0 UNKNOWN IMPORTED) 24 | set_target_properties(libusb-1.0::libusb-1.0 PROPERTIES 25 | IMPORTED_LOCATION "${libusb-1.0_LIBRARY}" 26 | IMPORTED_LINK_INTERFACE_LANGUAGES C 27 | INTERFACE_INCLUDE_DIRECTORIES "${libusb-1.0_INCLUDE_DIR}" 28 | ) 29 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: [push, pull_request] 4 | 5 | permissions: 6 | contents: read 7 | pull-requests: read 8 | 9 | jobs: 10 | build_linux: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | compiler: 15 | - gcc:15 16 | - gcc:14 17 | - clang:21 18 | - clang:20 19 | container: 20 | image: "registry.gitlab.com/offa/docker-images/${{ matrix.compiler }}" 21 | name: "${{ matrix.compiler }}" 22 | steps: 23 | - uses: actions/checkout@main 24 | - name: Setup 25 | run: script/ci_setup.sh 26 | - name: Build 27 | run: script/ci_build.sh -asan -ubsan 28 | 29 | formatting-check: 30 | name: "formatting" 31 | runs-on: ubuntu-latest 32 | steps: 33 | - uses: actions/checkout@main 34 | - uses: jidicula/clang-format-action@fb1a7a56a9341d16f79d610e65f81963ae33871d 35 | name: "Verify formatting" 36 | with: 37 | clang-format-version: 19 38 | 39 | coverage: 40 | name: "coverage" 41 | runs-on: ubuntu-latest 42 | container: 43 | image: "registry.gitlab.com/offa/docker-images/gcc:15" 44 | steps: 45 | - uses: actions/checkout@main 46 | - name: Setup 47 | run: script/ci_setup.sh 48 | - name: Build 49 | run: script/ci_build.sh -cov 50 | -------------------------------------------------------------------------------- /include/com/UsbContext.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include 24 | #include 25 | 26 | namespace plug::com::usb 27 | { 28 | class Context 29 | { 30 | public: 31 | Context(); 32 | Context(const Context&) = delete; 33 | ~Context(); 34 | 35 | Context& operator=(const Context&) = delete; 36 | 37 | private: 38 | void init(); 39 | void deinit(); 40 | }; 41 | 42 | std::vector listDevices(); 43 | 44 | } 45 | -------------------------------------------------------------------------------- /test/DeviceModelTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "DeviceModel.h" 22 | #include 23 | 24 | namespace plug::test 25 | { 26 | class DeviceModelTest : public testing::Test 27 | { 28 | }; 29 | 30 | 31 | TEST_F(DeviceModelTest, deviceInfos) 32 | { 33 | const DeviceModel model{"Mustang I", DeviceModel::Category::MustangV1, 100}; 34 | EXPECT_EQ(model.name(), "Mustang I"); 35 | EXPECT_EQ(model.category(), DeviceModel::Category::MustangV1); 36 | EXPECT_EQ(model.numberOfPresets(), 100); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /include/com/UsbException.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include 24 | #include 25 | 26 | namespace plug::com::usb 27 | { 28 | class UsbException : public std::exception 29 | { 30 | public: 31 | explicit UsbException(int errorCode); 32 | 33 | int code() const noexcept; 34 | std::string name() const; 35 | std::string message() const; 36 | 37 | const char* what() const noexcept override; 38 | 39 | private: 40 | int error_; 41 | std::string name_; 42 | std::string message_; 43 | }; 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/Main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #include "com/UsbContext.h" 23 | #include "com/Mustang.h" 24 | #include "ui/mainwindow.h" 25 | #include "Version.h" 26 | #include 27 | 28 | int main(int argc, char* argv[]) 29 | { 30 | QApplication app{argc, argv}; 31 | QCoreApplication::setOrganizationName("offa"); 32 | QCoreApplication::setApplicationName("Plug"); 33 | QCoreApplication::setApplicationVersion(QString::fromStdString(plug::version())); 34 | 35 | plug::com::usb::Context context{}; 36 | 37 | plug::MainWindow window; 38 | window.show(); 39 | 40 | return app.exec(); 41 | } 42 | -------------------------------------------------------------------------------- /test/FxSlotTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "FxSlot.h" 22 | #include 23 | 24 | 25 | namespace plug::test 26 | { 27 | class FxSlotTest : public testing::Test 28 | { 29 | }; 30 | 31 | TEST_F(FxSlotTest, validSlotId) 32 | { 33 | constexpr FxSlot slotPre{0}; 34 | EXPECT_EQ(slotPre.id(), 0); 35 | EXPECT_FALSE(slotPre.isFxLoop()); 36 | 37 | constexpr FxSlot slotPost{4}; 38 | EXPECT_EQ(slotPost.id(), 4); 39 | EXPECT_TRUE(slotPost.isFxLoop()); 40 | } 41 | 42 | TEST_F(FxSlotTest, invalidSlotIdThrows) 43 | { 44 | EXPECT_THROW(FxSlot{9}, std::invalid_argument); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /include/com/UsbComm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "com/Connection.h" 24 | #include 25 | 26 | 27 | namespace plug::com 28 | { 29 | 30 | class UsbComm : public Connection 31 | { 32 | public: 33 | UsbComm(usb::Device device); 34 | 35 | void close() override; 36 | bool isOpen() const override; 37 | 38 | std::vector receive(std::size_t recvSize) override; 39 | 40 | std::string name() const override; 41 | 42 | private: 43 | std::size_t sendImpl(std::uint8_t* data, std::size_t size) override; 44 | 45 | usb::Device device_; 46 | const std::string name_; 47 | }; 48 | } 49 | -------------------------------------------------------------------------------- /include/ui/defaulteffects.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include "data_structs.h" 25 | #include 26 | #include 27 | 28 | namespace Ui 29 | { 30 | class DefaultEffects; 31 | } 32 | 33 | namespace plug 34 | { 35 | 36 | class DefaultEffects : public QDialog 37 | { 38 | Q_OBJECT 39 | 40 | public: 41 | explicit DefaultEffects(QWidget* parent = nullptr); 42 | 43 | private: 44 | const std::unique_ptr ui; 45 | 46 | private slots: 47 | void choose_fx(int); 48 | void get_settings(); 49 | void save_default_effects(); 50 | }; 51 | } 52 | -------------------------------------------------------------------------------- /include/com/LibUsbCompat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include 24 | 25 | namespace plug::com::usb::libusb 26 | { 27 | class ErrorCodeAdapter 28 | { 29 | public: 30 | constexpr explicit ErrorCodeAdapter(int errorCode) 31 | : errorCode_(errorCode) 32 | { 33 | } 34 | 35 | constexpr operator int() const noexcept 36 | { 37 | return errorCode_; 38 | } 39 | 40 | constexpr operator libusb_error() const noexcept 41 | { 42 | return static_cast(errorCode_); 43 | } 44 | 45 | private: 46 | int errorCode_; 47 | }; 48 | 49 | 50 | const char* strerror(ErrorCodeAdapter errorCode); 51 | } 52 | -------------------------------------------------------------------------------- /include/ui/settings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | namespace Ui 29 | { 30 | class Settings; 31 | } 32 | 33 | namespace plug 34 | { 35 | 36 | class Settings : public QDialog 37 | { 38 | Q_OBJECT 39 | 40 | public: 41 | explicit Settings(QWidget* parent = nullptr); 42 | 43 | private slots: 44 | void change_connect(bool); 45 | void change_oneset(bool); 46 | void change_keepopen(bool); 47 | void change_popupwindows(bool); 48 | void change_effectvalues(bool); 49 | 50 | private: 51 | const std::unique_ptr ui; 52 | }; 53 | } 54 | -------------------------------------------------------------------------------- /include/ui/save_effects.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include 25 | #include 26 | 27 | namespace Ui 28 | { 29 | class Save_effects; 30 | } 31 | 32 | namespace plug 33 | { 34 | 35 | class SaveEffects : public QDialog 36 | { 37 | Q_OBJECT 38 | 39 | public: 40 | explicit SaveEffects(QWidget* parent = nullptr); 41 | SaveEffects(const SaveEffects&) = delete; 42 | ~SaveEffects() override; 43 | 44 | SaveEffects& operator=(const SaveEffects&) = delete; 45 | 46 | 47 | private: 48 | const std::unique_ptr ui; 49 | 50 | private slots: 51 | void select_checkbox(); 52 | void send(); 53 | }; 54 | } 55 | -------------------------------------------------------------------------------- /include/com/Connection.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | namespace plug::com 28 | { 29 | 30 | class Connection 31 | { 32 | public: 33 | virtual ~Connection() = default; 34 | 35 | virtual void close() = 0; 36 | virtual bool isOpen() const = 0; 37 | 38 | template 39 | std::size_t send(Container c) 40 | { 41 | return sendImpl(c.data(), c.size()); 42 | } 43 | 44 | virtual std::vector receive(std::size_t recvSize) = 0; 45 | 46 | virtual std::string name() const = 0; 47 | 48 | private: 49 | virtual std::size_t sendImpl(std::uint8_t* data, std::size_t size) = 0; 50 | }; 51 | } 52 | -------------------------------------------------------------------------------- /include/ui/loadfromfile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include "data_structs.h" 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | namespace plug 31 | { 32 | class LoadFromFile 33 | { 34 | public: 35 | struct Settings 36 | { 37 | QString name; 38 | std::vector effects; 39 | amp_settings amp; 40 | }; 41 | 42 | explicit LoadFromFile(QFile* file); 43 | 44 | Settings loadfile(); 45 | 46 | private: 47 | QXmlStreamReader xml; 48 | 49 | amp_settings parseAmp(); 50 | std::vector parseFX(); 51 | QString parseFUSE(); 52 | }; 53 | } 54 | -------------------------------------------------------------------------------- /test/mocks/MockConnection.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "com/Connection.h" 24 | #include 25 | 26 | namespace plug::test::mock 27 | { 28 | class MockConnection : public plug::com::Connection 29 | { 30 | public: 31 | virtual ~MockConnection() 32 | { 33 | } 34 | 35 | MOCK_METHOD(void, open, (std::uint16_t, std::uint16_t) ); 36 | MOCK_METHOD(void, openFirst, (std::uint16_t, std::initializer_list) ); 37 | MOCK_METHOD(void, close, ()); 38 | MOCK_METHOD(bool, isOpen, (), (const)); 39 | MOCK_METHOD(std::vector, receive, (std::size_t) ); 40 | MOCK_METHOD(std::size_t, sendImpl, (std::uint8_t*, std::size_t) ); 41 | MOCK_METHOD(std::string, name, (), (const)); 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /src/com/UsbException.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "com/UsbException.h" 22 | #include "com/LibUsbCompat.h" 23 | #include 24 | 25 | namespace plug::com::usb 26 | { 27 | UsbException::UsbException(int errorCode) 28 | : error_(errorCode), 29 | name_(libusb_error_name(errorCode)), 30 | message_(libusb::strerror(libusb::ErrorCodeAdapter{errorCode})) 31 | { 32 | } 33 | 34 | int UsbException::code() const noexcept 35 | { 36 | return error_; 37 | } 38 | 39 | std::string UsbException::name() const 40 | { 41 | return name_; 42 | } 43 | 44 | std::string UsbException::message() const 45 | { 46 | return message_; 47 | } 48 | 49 | const char* UsbException::what() const noexcept 50 | { 51 | return message_.c_str(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /include/ui/loadfromamp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | namespace Ui 29 | { 30 | class LoadFromAmp; 31 | } 32 | 33 | namespace plug 34 | { 35 | 36 | class LoadFromAmp : public QMainWindow 37 | { 38 | Q_OBJECT 39 | 40 | public: 41 | explicit LoadFromAmp(QWidget* parent = nullptr); 42 | LoadFromAmp(const LoadFromAmp&) = delete; 43 | ~LoadFromAmp() override; 44 | 45 | void load_names(const std::vector& names); 46 | void delete_items(); 47 | void change_name(int, QString*); 48 | 49 | LoadFromAmp& operator=(const LoadFromAmp&) = delete; 50 | 51 | private: 52 | const std::unique_ptr ui; 53 | 54 | private slots: 55 | void load(); 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /include/FxSlot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | namespace plug 28 | { 29 | class FxSlot 30 | { 31 | public: 32 | constexpr explicit FxSlot(std::uint8_t id) 33 | : id_(checkRange(id)) 34 | { 35 | } 36 | 37 | constexpr std::uint8_t id() const 38 | { 39 | return id_; 40 | } 41 | 42 | constexpr bool isFxLoop() const 43 | { 44 | return id_ >= 4; 45 | } 46 | 47 | private: 48 | constexpr std::uint8_t checkRange(std::uint8_t value) const 49 | { 50 | if (value > 7) 51 | { 52 | throw std::invalid_argument{"Slot ID out of range: " + std::to_string(value)}; 53 | } 54 | return value; 55 | } 56 | 57 | std::uint8_t id_; 58 | }; 59 | 60 | } 61 | -------------------------------------------------------------------------------- /include/ui/saveonamp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | namespace Ui 29 | { 30 | class SaveOnAmp; 31 | } 32 | 33 | namespace plug 34 | { 35 | 36 | class SaveOnAmp : public QMainWindow 37 | { 38 | Q_OBJECT 39 | 40 | public: 41 | explicit SaveOnAmp(QWidget* parent = nullptr); 42 | SaveOnAmp(const SaveOnAmp&) = delete; 43 | ~SaveOnAmp() override; 44 | 45 | void load_names(const std::vector& names); 46 | void delete_items(); 47 | 48 | SaveOnAmp& operator=(const SaveOnAmp&) = delete; 49 | 50 | public slots: 51 | void change_index(int, const QString&); 52 | 53 | private: 54 | const std::unique_ptr ui; 55 | 56 | private slots: 57 | void save(); 58 | }; 59 | } 60 | -------------------------------------------------------------------------------- /include/DeviceModel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include 24 | 25 | namespace plug 26 | { 27 | class DeviceModel 28 | { 29 | public: 30 | enum class Category 31 | { 32 | MustangV1, 33 | MustangV2, 34 | Other 35 | }; 36 | 37 | DeviceModel(const std::string& name, Category category, std::size_t numberPresets) 38 | : name_(name), category_(category), numberPresets_(numberPresets) 39 | { 40 | } 41 | 42 | std::string name() const 43 | { 44 | return name_; 45 | } 46 | Category category() const 47 | { 48 | return category_; 49 | } 50 | std::size_t numberOfPresets() const 51 | { 52 | return numberPresets_; 53 | } 54 | 55 | private: 56 | std::string name_; 57 | Category category_; 58 | std::size_t numberPresets_; 59 | }; 60 | } 61 | -------------------------------------------------------------------------------- /include/ui/savetofile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include "data_structs.h" 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | namespace Ui 31 | { 32 | class SaveToFile; 33 | } 34 | 35 | namespace plug 36 | { 37 | 38 | class SaveToFile : public QDialog 39 | { 40 | Q_OBJECT 41 | 42 | public: 43 | explicit SaveToFile(QWidget* parent = nullptr); 44 | 45 | private slots: 46 | QString choose_destination(); 47 | void savefile(); 48 | 49 | signals: 50 | void destination_chosen(QString); 51 | 52 | private: 53 | const std::unique_ptr ui; 54 | std::unique_ptr xml; 55 | 56 | void writeAmp(amp_settings); 57 | void manageWriteFX(const std::vector& settings); 58 | void writeFX(fx_pedal_settings); 59 | void writeFUSE(); 60 | void writeUSBGain(int); 61 | }; 62 | } 63 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12.0) 2 | 3 | project(plug VERSION 1.5.0) 4 | message(STATUS "~~~ ${PROJECT_NAME} v${PROJECT_VERSION} ~~~") 5 | 6 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") 7 | option(PLUG_UNITTEST "Build Unit Tests" ON) 8 | message(STATUS "Unit Tests : ${PLUG_UNITTEST}") 9 | 10 | option(PLUG_COVERAGE "Enable Coverage" OFF) 11 | message(STATUS "Coverage : ${PLUG_COVERAGE}") 12 | 13 | option(PLUG_LTO "Enable LTO" OFF) 14 | message(STATUS "LTO : ${PLUG_LTO}") 15 | 16 | option(PLUG_SANITIZER_ASAN "Enable ASan" OFF) 17 | message(STATUS "ASan : ${PLUG_SANITIZER_ASAN}") 18 | 19 | option(PLUG_SANITIZER_UBSAN "Enable UBSan" OFF) 20 | message(STATUS "UBSan : ${PLUG_SANITIZER_UBSAN}") 21 | 22 | include(DeprecatedOptions) 23 | 24 | 25 | if( CMAKE_BUILD_TYPE ) 26 | message(STATUS "Build Type : ${CMAKE_BUILD_TYPE}") 27 | else() 28 | message(STATUS "Build Type : None") 29 | endif() 30 | 31 | include(GNUInstallDirs) 32 | 33 | if( PLUG_LTO ) 34 | include(LTO) 35 | endif() 36 | 37 | if( PLUG_COVERAGE ) 38 | include(Coverage) 39 | endif() 40 | 41 | include(Sanitizer) 42 | include(Install) 43 | include(Template) 44 | include(ClangFormat) 45 | 46 | add_compile_options(-Wall 47 | -Wextra 48 | -pedantic 49 | -pedantic-errors 50 | -Werror 51 | -Wshadow 52 | -Wold-style-cast 53 | -Wnull-dereference 54 | -Wnon-virtual-dtor 55 | -Woverloaded-virtual 56 | ) 57 | 58 | set(CMAKE_CXX_STANDARD 20) 59 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 60 | set(CMAKE_CXX_EXTENSIONS OFF) 61 | 62 | find_package(Qt6 COMPONENTS Core Widgets Gui REQUIRED) 63 | find_package(libusb-1.0 REQUIRED) 64 | 65 | 66 | include_directories("include") 67 | add_subdirectory(src) 68 | 69 | 70 | if( PLUG_UNITTEST ) 71 | enable_testing() 72 | add_subdirectory("test") 73 | endif() 74 | 75 | -------------------------------------------------------------------------------- /test/mocks/UsbDeviceMock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "com/UsbContext.h" 24 | #include "com/UsbDevice.h" 25 | #include 26 | 27 | namespace plug::test::mock 28 | { 29 | struct UsbContextMock 30 | { 31 | MOCK_METHOD(std::vector, listDevices, ()); 32 | }; 33 | 34 | UsbContextMock* resetUsbContextMock(); 35 | UsbContextMock* getUsbContextMock(); 36 | void clearUsbContextMock(); 37 | 38 | 39 | struct UsbDeviceMock 40 | { 41 | MOCK_METHOD(void, open, ()); 42 | MOCK_METHOD(void, close, ()); 43 | MOCK_METHOD(bool, isOpen, (), (const, noexcept)); 44 | MOCK_METHOD(std::uint16_t, vendorId, (), (const noexcept)); 45 | MOCK_METHOD(std::uint16_t, productId, (), (const noexcept)); 46 | MOCK_METHOD(std::size_t, write, (std::uint8_t, std::uint8_t*, std::size_t) ); 47 | MOCK_METHOD(std::vector, receive, (std::uint8_t, std::size_t) ); 48 | MOCK_METHOD(std::string, name, ()); 49 | }; 50 | 51 | 52 | UsbDeviceMock* resetUsbDeviceMock(); 53 | UsbDeviceMock* getUsbDeviceMock(); 54 | void clearUsbDeviceMock(); 55 | 56 | } 57 | -------------------------------------------------------------------------------- /include/data_structs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include "FxSlot.h" 25 | #include "effects_enum.h" 26 | #include 27 | 28 | namespace plug 29 | { 30 | 31 | struct amp_settings 32 | { 33 | amps amp_num; 34 | std::uint8_t gain; 35 | std::uint8_t volume; 36 | std::uint8_t treble; 37 | std::uint8_t middle; 38 | std::uint8_t bass; 39 | cabinets cabinet; 40 | std::uint8_t noise_gate; 41 | std::uint8_t master_vol; 42 | std::uint8_t gain2; 43 | std::uint8_t presence; 44 | std::uint8_t threshold; 45 | std::uint8_t depth; 46 | std::uint8_t bias; 47 | std::uint8_t sag; 48 | bool brightness; 49 | std::uint8_t usb_gain; 50 | }; 51 | 52 | struct fx_pedal_settings 53 | { 54 | FxSlot slot; 55 | effects effect_num; 56 | std::uint8_t knob1; 57 | std::uint8_t knob2; 58 | std::uint8_t knob3; 59 | std::uint8_t knob4; 60 | std::uint8_t knob5; 61 | std::uint8_t knob6; 62 | bool enabled{true}; 63 | }; 64 | } 65 | -------------------------------------------------------------------------------- /include/ui/library.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | namespace Ui 30 | { 31 | class Library; 32 | } 33 | 34 | namespace plug 35 | { 36 | 37 | class Library : public QDialog 38 | { 39 | Q_OBJECT 40 | 41 | public: 42 | explicit Library(const std::vector& names, QWidget* parent = nullptr); 43 | Library(const Library&) = delete; 44 | ~Library() override; 45 | 46 | Library& operator=(const Library&) = delete; 47 | 48 | 49 | private: 50 | const std::unique_ptr ui; 51 | const std::unique_ptr files; 52 | void resizeEvent(QResizeEvent*) override; 53 | 54 | private slots: 55 | void load_slot(int slot); 56 | void get_directory(); 57 | void get_files(const QString&); 58 | void load_file(int row); 59 | void change_font_size(int); 60 | void change_font_family(QFont); 61 | 62 | signals: 63 | void directory_changed(QString); 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /include/ui/amp_advanced.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | namespace Ui 29 | { 30 | class Amp_Advanced; 31 | } 32 | 33 | namespace plug 34 | { 35 | 36 | class Amp_Advanced : public QDialog 37 | { 38 | Q_OBJECT 39 | 40 | public: 41 | explicit Amp_Advanced(QWidget* parent = nullptr); 42 | Amp_Advanced(const Amp_Advanced&) = delete; 43 | ~Amp_Advanced() override; 44 | 45 | Amp_Advanced& operator=(const Amp_Advanced&) = delete; 46 | 47 | public slots: 48 | void change_cabinet(int); 49 | void change_noise_gate(int); 50 | void set_master_vol(int); 51 | void set_gain2(int); 52 | void set_presence(int); 53 | void set_depth(int); 54 | void set_threshold(int); 55 | void set_bias(int); 56 | void set_sag(int); 57 | void set_brightness(bool); 58 | void set_usb_gain(int); 59 | 60 | private slots: 61 | void activate_custom_ng(int); 62 | 63 | private: 64 | const std::unique_ptr ui; 65 | }; 66 | } 67 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(GTest REQUIRED) 2 | 3 | 4 | add_library(TestLibs INTERFACE) 5 | target_link_libraries(TestLibs INTERFACE 6 | GTest::gmock_main 7 | build-libs 8 | ) 9 | 10 | add_subdirectory(mocks) 11 | 12 | 13 | 14 | add_executable(MustangTest 15 | MustangTest.cpp 16 | PacketSerializerTest.cpp 17 | PacketTest.cpp 18 | FxSlotTest.cpp 19 | DeviceModelTest.cpp 20 | ) 21 | add_test(MustangTest MustangTest) 22 | target_link_libraries(MustangTest PRIVATE 23 | plug-mustang 24 | plug-communication 25 | TestLibs 26 | LibUsbMocks 27 | ) 28 | 29 | 30 | 31 | add_executable(CommunicationTest 32 | ConnectionFactoryTest.cpp 33 | UsbCommTest.cpp 34 | ) 35 | add_test(CommunicationTest CommunicationTest) 36 | target_link_libraries(CommunicationTest PRIVATE 37 | plug-communication 38 | plug-mustang 39 | TestLibs 40 | UsbDeviceMock 41 | ) 42 | 43 | add_executable(UsbTest 44 | UsbTest.cpp 45 | ) 46 | add_test(UsbTest UsbTest) 47 | target_link_libraries(UsbTest PRIVATE 48 | plug-communication-usb 49 | TestLibs 50 | LibUsbMocks 51 | ) 52 | 53 | 54 | add_executable(IdLookupTest IdLookupTest.cpp) 55 | add_test(IdLookupTest IdLookupTest) 56 | target_link_libraries(IdLookupTest PRIVATE 57 | TestLibs 58 | ) 59 | 60 | 61 | add_custom_target(unittest MustangTest 62 | COMMAND CommunicationTest 63 | COMMAND UsbTest 64 | COMMAND IdLookupTest 65 | 66 | COMMENT "Running unittests\n\n" 67 | VERBATIM 68 | ) 69 | -------------------------------------------------------------------------------- /include/ui/quickpresets.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | namespace Ui 29 | { 30 | class QuickPresets; 31 | } 32 | 33 | namespace plug 34 | { 35 | 36 | class QuickPresets : public QDialog 37 | { 38 | Q_OBJECT 39 | 40 | public: 41 | explicit QuickPresets(QWidget* parent = nullptr); 42 | 43 | void load_names(const std::vector& names); 44 | void delete_items(); 45 | void change_name(int, QString*); 46 | 47 | protected: 48 | void changeEvent(QEvent* e) override; 49 | 50 | private slots: 51 | void setDefaultPreset0(int); 52 | void setDefaultPreset1(int); 53 | void setDefaultPreset2(int); 54 | void setDefaultPreset3(int); 55 | void setDefaultPreset4(int); 56 | void setDefaultPreset5(int); 57 | void setDefaultPreset6(int); 58 | void setDefaultPreset7(int); 59 | void setDefaultPreset8(int); 60 | void setDefaultPreset9(int); 61 | 62 | private: 63 | const std::unique_ptr ui; 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /src/com/UsbComm.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "com/UsbComm.h" 22 | #include "com/CommunicationException.h" 23 | #include 24 | #include 25 | 26 | namespace plug::com 27 | { 28 | namespace 29 | { 30 | inline constexpr std::uint8_t endpointSend{0x01}; 31 | inline constexpr std::uint8_t endpointRecv{0x81}; 32 | 33 | usb::Device openDevice(usb::Device&& device) 34 | { 35 | device.open(); 36 | return std::move(device); 37 | } 38 | } 39 | 40 | UsbComm::UsbComm(usb::Device device) 41 | : device_(openDevice(std::move(device))), name_(device_.name()) 42 | { 43 | } 44 | 45 | void UsbComm::close() 46 | { 47 | device_.close(); 48 | } 49 | 50 | bool UsbComm::isOpen() const 51 | { 52 | return device_.isOpen(); 53 | } 54 | 55 | std::vector UsbComm::receive(std::size_t recvSize) 56 | { 57 | return device_.receive(endpointRecv, recvSize); 58 | } 59 | 60 | std::string UsbComm::name() const 61 | { 62 | return name_; 63 | } 64 | 65 | std::size_t UsbComm::sendImpl(std::uint8_t* data, std::size_t size) 66 | { 67 | return device_.write(endpointSend, data, size); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /include/com/Mustang.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include "SignalChain.h" 25 | #include "DeviceModel.h" 26 | #include "com/Connection.h" 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace plug::com 33 | { 34 | struct InitialData 35 | { 36 | SignalChain signalChain; 37 | std::vector presetNames; 38 | }; 39 | 40 | class Mustang 41 | { 42 | public: 43 | Mustang(DeviceModel deviceModel, std::shared_ptr connection); 44 | Mustang(const Mustang&) = delete; 45 | 46 | InitialData start_amp(); 47 | void stop_amp(); 48 | void set_effect(fx_pedal_settings value); 49 | void set_amplifier(amp_settings value); 50 | void save_on_amp(std::string_view name, std::uint8_t slot); 51 | SignalChain load_memory_bank(std::uint8_t slot); 52 | void save_effects(std::uint8_t slot, std::string_view name, const std::vector& effects); 53 | 54 | DeviceModel getDeviceModel() const; 55 | 56 | 57 | Mustang& operator=(const Mustang&) = delete; 58 | 59 | 60 | private: 61 | InitialData loadData(); 62 | void initializeAmp(); 63 | 64 | const DeviceModel model; 65 | const std::shared_ptr conn; 66 | }; 67 | } 68 | -------------------------------------------------------------------------------- /src/com/UsbContext.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "com/UsbContext.h" 22 | #include "com/UsbException.h" 23 | #include 24 | #include 25 | 26 | namespace plug::com::usb 27 | { 28 | Context::Context() 29 | { 30 | init(); 31 | } 32 | 33 | Context::~Context() 34 | { 35 | deinit(); 36 | } 37 | 38 | void Context::init() 39 | { 40 | if (const int status = libusb_init(nullptr); status != LIBUSB_SUCCESS) 41 | { 42 | throw UsbException{status}; 43 | } 44 | } 45 | 46 | void Context::deinit() 47 | { 48 | libusb_exit(nullptr); 49 | } 50 | 51 | 52 | std::vector listDevices() 53 | { 54 | libusb_device** devices; 55 | const auto n = libusb_get_device_list(nullptr, &devices); 56 | 57 | if (n < 0) 58 | { 59 | throw UsbException(n); 60 | } 61 | 62 | std::vector devicesFound; 63 | devicesFound.reserve(n); 64 | 65 | std::for_each(devices, std::next(devices, n), [&devicesFound](auto* dev) 66 | { 67 | try 68 | { 69 | devicesFound.emplace_back(dev); 70 | } 71 | catch (const UsbException&) 72 | { 73 | } }); 74 | 75 | libusb_free_device_list(devices, 1); 76 | return devicesFound; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /include/SignalChain.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "data_structs.h" 24 | #include "effects_enum.h" 25 | #include 26 | #include 27 | #include 28 | 29 | namespace plug 30 | { 31 | 32 | class SignalChain 33 | { 34 | public: 35 | SignalChain() 36 | : name_(""), amp_(), effects_() 37 | { 38 | } 39 | 40 | SignalChain(const std::string& name, amp_settings amp, const std::vector& effects) 41 | : name_(name), amp_(amp), effects_(effects) 42 | { 43 | } 44 | 45 | 46 | std::string name() const 47 | { 48 | return name_; 49 | } 50 | 51 | void setName(const std::string& name) 52 | { 53 | name_ = name; 54 | } 55 | 56 | amp_settings amp() const 57 | { 58 | return amp_; 59 | } 60 | 61 | void setAmp(amp_settings amp) 62 | { 63 | amp_ = amp; 64 | } 65 | 66 | std::vector effects() const 67 | { 68 | return effects_; 69 | } 70 | 71 | void setEffects(const std::vector& effects) 72 | { 73 | effects_ = effects; 74 | } 75 | 76 | 77 | private: 78 | std::string name_; 79 | amp_settings amp_; 80 | std::vector effects_; 81 | }; 82 | 83 | } 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Plug 2 | 3 | ### [[GitHub](https://github.com/offa/plug)] [[GitLab](https://gitlab.com/offa/plug)] 4 | 5 | [![CI](https://github.com/offa/plug/workflows/ci/badge.svg)](https://github.com/offa/plug/actions) 6 | [![Pipeline Status](https://gitlab.com/offa/plug/badges/master/pipeline.svg)](https://gitlab.com/offa/plug/commits/master) 7 | [![Coverage Report](https://gitlab.com/offa/plug/badges/master/coverage.svg)](https://gitlab.com/offa/plug/commits/master) 8 | [![GitHub release](https://img.shields.io/github/release/offa/plug.svg)](https://github.com/offa/plug/releases) 9 | [![License](https://img.shields.io/badge/license-GPLv3-yellow.svg)](LICENSE) 10 | ![C++](https://img.shields.io/badge/c++-20-green.svg) 11 | 12 | A client Software for Fender Mustang Amps. This is a fork of ***piorekf's Plug***. 13 | 14 | Plug is an alternative to the (discontinued) FUSE software. It allows to control the amplifier and organize presets. 15 | 16 | Please see [Contributing](CONTRIBUTING.md) for how to contribute to this project. 17 | 18 | 19 | ## Requirements 20 | 21 | - [**Qt6**](https://www.qt.io/) 22 | - [**libusb-1.0**](http://libusb.info/) 23 | 24 | See [Setup](./doc/Setup.md) for installation instructions. 25 | 26 | 27 | ## Building 28 | 29 | Building and testing is done through CMake: 30 | 31 | ``` 32 | mkdir build && cd build 33 | cmake .. 34 | make 35 | make unittest 36 | ``` 37 | 38 | 39 | ## Installation 40 | 41 | CMake will install the application and *udev* rules using: 42 | 43 | ``` 44 | make install 45 | ``` 46 | 47 | The *udev* rule allows the USB access without *root* for the users of the `plugdev` group. 48 | 49 | 50 | ## Libusb Logging 51 | 52 | Debug message logging of [*libusb*](https://libusb.sourceforge.io/api-1.0/) can be controlled by the `LIBUSB_DEBUG` variable (0: None, 1: Error, 2: Warning, 3: Info, 4: Debug). 53 | 54 | 55 | ## Credits 56 | 57 | Thanks to *piorekf* and all Plug contributors. 58 | 59 | 60 | ## License 61 | 62 | **GNU General Public License (GPLv3+)** 63 | 64 | This program is free software: you can redistribute it and/or modify 65 | it under the terms of the GNU General Public License as published by 66 | the Free Software Foundation, either version 3 of the License, or 67 | (at your option) any later version. 68 | 69 | This program is distributed in the hope that it will be useful, 70 | but WITHOUT ANY WARRANTY; without even the implied warranty of 71 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 72 | GNU General Public License for more details. 73 | 74 | You should have received a copy of the GNU General Public License 75 | along with this program. If not, see . 76 | -------------------------------------------------------------------------------- /include/com/UsbDevice.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | struct libusb_device; 29 | struct libusb_device_handle; 30 | 31 | namespace plug::com::usb 32 | { 33 | template 34 | struct ReleaseFunction 35 | { 36 | template 37 | void operator()(T* ptr) 38 | { 39 | Fn(ptr); 40 | } 41 | }; 42 | 43 | template 44 | using Ressource = std::unique_ptr>; 45 | 46 | 47 | namespace detail 48 | { 49 | void releaseDevice(libusb_device* device); 50 | void releaseHandle(libusb_device_handle* handle); 51 | } 52 | 53 | 54 | class Device 55 | { 56 | public: 57 | explicit Device(libusb_device* device); 58 | Device(Device&&) = default; 59 | 60 | void open(); 61 | void close(); 62 | bool isOpen() const noexcept; 63 | 64 | std::uint16_t vendorId() const noexcept; 65 | std::uint16_t productId() const noexcept; 66 | std::string name() const; 67 | 68 | std::size_t write(std::uint8_t endpoint, std::uint8_t* data, std::size_t dataSize); 69 | std::vector receive(std::uint8_t endpoint, std::size_t dataSize); 70 | 71 | Device& operator=(Device&&) = default; 72 | 73 | 74 | private: 75 | struct Descriptor 76 | { 77 | std::uint16_t vid; 78 | std::uint16_t pid; 79 | std::uint8_t stringDescriptorIndex; 80 | }; 81 | 82 | Descriptor getDeviceDescriptor(libusb_device* device) const; 83 | 84 | Ressource device_; 85 | Ressource handle_; 86 | Descriptor descriptor_; 87 | }; 88 | } 89 | -------------------------------------------------------------------------------- /test/helper/MustangConstants.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include 25 | #include 26 | 27 | namespace plug::com 28 | { 29 | namespace v1 30 | { 31 | // effect array fields 32 | inline constexpr std::size_t DSP{2}; 33 | inline constexpr std::size_t EFFECT{16}; 34 | inline constexpr std::size_t FXSLOT{18}; 35 | inline constexpr std::size_t KNOB1{32}; 36 | inline constexpr std::size_t KNOB2{33}; 37 | inline constexpr std::size_t KNOB3{34}; 38 | inline constexpr std::size_t KNOB4{35}; 39 | inline constexpr std::size_t KNOB5{36}; 40 | inline constexpr std::size_t KNOB6{37}; 41 | 42 | // amp array fields 43 | inline constexpr std::size_t AMPLIFIER{16}; 44 | inline constexpr std::size_t VOLUME{32}; 45 | inline constexpr std::size_t GAIN{33}; 46 | inline constexpr std::size_t TREBLE{36}; 47 | inline constexpr std::size_t MIDDLE{37}; 48 | inline constexpr std::size_t BASS{38}; 49 | inline constexpr std::size_t CABINET{49}; 50 | inline constexpr std::size_t NOISE_GATE{47}; 51 | inline constexpr std::size_t THRESHOLD{48}; 52 | inline constexpr std::size_t MASTER_VOL{35}; 53 | inline constexpr std::size_t GAIN2{34}; 54 | inline constexpr std::size_t PRESENCE{39}; 55 | inline constexpr std::size_t DEPTH{41}; 56 | inline constexpr std::size_t BIAS{42}; 57 | inline constexpr std::size_t SAG{51}; 58 | inline constexpr std::size_t BRIGHTNESS{52}; 59 | 60 | inline constexpr std::size_t USB_GAIN{16}; 61 | inline constexpr std::size_t NAME{16}; 62 | 63 | // save fields 64 | inline constexpr std::size_t SAVE_SLOT{4}; 65 | inline constexpr std::size_t FXKNOB{3}; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /include/ui/effect.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include "data_structs.h" 25 | #include "effects_enum.h" 26 | #include "FxSlot.h" 27 | #include 28 | #include 29 | 30 | namespace Ui 31 | { 32 | class Effect; 33 | } 34 | 35 | namespace plug 36 | { 37 | 38 | class Effect : public QMainWindow 39 | { 40 | Q_OBJECT 41 | 42 | public: 43 | Effect(QWidget* parent, FxSlot fxSlot); 44 | Effect(const Effect&) = delete; 45 | ~Effect() override; 46 | 47 | void set_changed(bool); 48 | bool get_changed() const; 49 | 50 | fx_pedal_settings getSettings() const; 51 | 52 | Effect& operator=(const Effect&) = delete; 53 | 54 | private: 55 | void setTitleTexts(int slotNumber, const QString& name); 56 | void setDialValues(int d1, int d2, int d3, int d4, int d5, int d6); 57 | 58 | const std::unique_ptr ui; 59 | FxSlot slot; 60 | effects effect_num; 61 | unsigned char knob1; 62 | unsigned char knob2; 63 | unsigned char knob3; 64 | unsigned char knob4; 65 | unsigned char knob5; 66 | unsigned char knob6; 67 | bool enabled; 68 | bool changed; 69 | QString temp1; 70 | QString temp2; 71 | 72 | public slots: 73 | // functions to set variables 74 | void set_knob1(int); 75 | void set_knob2(int); 76 | void set_knob3(int); 77 | void set_knob4(int); 78 | void set_knob5(int); 79 | void set_knob6(int); 80 | void choose_fx(int); 81 | void off_switch(bool); 82 | void enable_set_button(bool); 83 | 84 | // send settings to the amplifier 85 | void send_fx(); 86 | 87 | void load(fx_pedal_settings); 88 | void load_default_fx(); 89 | 90 | void showAndActivate(); 91 | }; 92 | } 93 | -------------------------------------------------------------------------------- /include/com/PacketSerializer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include "data_structs.h" 25 | #include "effects_enum.h" 26 | #include "com/Packet.h" 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace plug::com 33 | { 34 | template 35 | Packet fromRawData(const std::array& data) 36 | { 37 | Packet packet{}; 38 | packet.fromBytes(data); 39 | return packet; 40 | } 41 | 42 | std::string decodeNameFromData(const Packet& packet); 43 | amp_settings decodeAmpFromData(const Packet& packet, const Packet& packetUsbGain); 44 | 45 | std::vector decodeEffectsFromData(const std::array, 4>& packet); 46 | std::vector decodePresetListFromData(const std::vector>& packet); 47 | 48 | Packet serializeAmpSettings(const amp_settings& value); 49 | Packet serializeAmpSettingsUsbGain(const amp_settings& value); 50 | Packet serializeName(std::uint8_t slot, std::string_view name); 51 | Packet serializeEffectSettings(const fx_pedal_settings& value); 52 | Packet serializeClearEffectSettings(fx_pedal_settings effect); 53 | Packet serializeSaveEffectName(std::uint8_t slot, std::string_view name, const std::vector& effects); 54 | std::vector> serializeSaveEffectPacket(std::uint8_t slot, const std::vector& effects); 55 | 56 | Packet serializeLoadSlotCommand(std::uint8_t slot); 57 | Packet serializeLoadCommand(); 58 | Packet serializeApplyCommand(); 59 | Packet serializeApplyCommand(fx_pedal_settings effect); 60 | 61 | std::array, 2> serializeInitCommand(); 62 | 63 | } 64 | -------------------------------------------------------------------------------- /test/ConnectionFactoryTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "com/ConnectionFactory.h" 22 | #include "com/CommunicationException.h" 23 | #include "com/Mustang.h" 24 | #include "mocks/UsbDeviceMock.h" 25 | #include 26 | #include 27 | #include 28 | 29 | namespace plug::test 30 | { 31 | using namespace plug::com; 32 | using namespace testing; 33 | 34 | class ConnectionFactoryTest : public testing::Test 35 | { 36 | protected: 37 | void SetUp() override 38 | { 39 | contextMock = mock::resetUsbContextMock(); 40 | deviceMock = mock::resetUsbDeviceMock(); 41 | } 42 | 43 | void TearDown() override 44 | { 45 | mock::clearUsbContextMock(); 46 | mock::clearUsbDeviceMock(); 47 | } 48 | 49 | mock::UsbContextMock* contextMock{nullptr}; 50 | mock::UsbDeviceMock* deviceMock{nullptr}; 51 | }; 52 | 53 | 54 | TEST_F(ConnectionFactoryTest, connectThrowsIfNoDeviceFound) 55 | { 56 | EXPECT_CALL(*contextMock, listDevices).WillOnce(Return(ByMove(std::vector{}))); 57 | 58 | EXPECT_THROW(connect(), CommunicationException); 59 | } 60 | 61 | TEST_F(ConnectionFactoryTest, connectReturnsFirstDeviceFound) 62 | { 63 | std::vector devices{}; 64 | devices.emplace_back(nullptr); 65 | devices.emplace_back(nullptr); 66 | devices.emplace_back(nullptr); 67 | EXPECT_CALL(*contextMock, listDevices).WillOnce(Return(ByMove(std::move(devices)))); 68 | EXPECT_CALL(*deviceMock, open()); 69 | EXPECT_CALL(*deviceMock, name()); 70 | EXPECT_CALL(*deviceMock, vendorId()) 71 | .WillOnce(Return(0xf0f0)) 72 | .WillOnce(Return(0x1ed8)); 73 | EXPECT_CALL(*deviceMock, productId()) 74 | .WillOnce(Return(0xff04)) 75 | .WillRepeatedly(Return(0x0005)); 76 | 77 | auto device = connect(); 78 | EXPECT_THAT(device, NotNull()); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /include/ui/amplifier.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include "data_structs.h" 25 | #include "effects_enum.h" 26 | #include "DeviceModel.h" 27 | #include 28 | #include 29 | 30 | namespace Ui 31 | { 32 | class Amplifier; 33 | } 34 | 35 | namespace plug 36 | { 37 | class Amp_Advanced; 38 | } 39 | 40 | namespace plug 41 | { 42 | 43 | class Amplifier : public QMainWindow 44 | { 45 | Q_OBJECT 46 | 47 | public: 48 | explicit Amplifier(QWidget* parent = nullptr); 49 | Amplifier(const Amplifier&) = delete; 50 | ~Amplifier() override; 51 | 52 | Amplifier& operator=(const Amplifier&) = delete; 53 | 54 | void setDeviceModel(DeviceModel model); 55 | 56 | private: 57 | const std::unique_ptr ui; 58 | std::unique_ptr advanced; 59 | amps amp_num; 60 | unsigned char gain, volume, treble, middle, bass; 61 | cabinets cabinet; 62 | unsigned char noise_gate, presence, gain2, master_vol, threshold, depth, bias, sag, usb_gain; 63 | bool changed, brightness; 64 | 65 | public slots: 66 | // set basic variables 67 | void set_gain(int); 68 | void set_volume(int); 69 | void set_treble(int); 70 | void set_middle(int); 71 | void set_bass(int); 72 | void choose_amp(int); 73 | 74 | // set advanced variables 75 | void set_cabinet(int); 76 | void set_noise_gate(int); 77 | void set_presence(int); 78 | void set_gain2(int); 79 | void set_master_vol(int); 80 | void set_threshold(int); 81 | void set_depth(int); 82 | void set_bias(int); 83 | void set_sag(int); 84 | void set_brightness(bool); 85 | void set_usb_gain(int); 86 | 87 | // send settings to the amplifier 88 | void send_amp(); 89 | 90 | void load(amp_settings); 91 | void get_settings(amp_settings*); 92 | void enable_set_button(bool); 93 | 94 | void showAndActivate(); 95 | }; 96 | } 97 | -------------------------------------------------------------------------------- /src/ui/loadfromamp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #include "ui/loadfromamp.h" 23 | #include "ui/mainwindow.h" 24 | #include "ui_loadfromamp.h" 25 | #include 26 | #include 27 | 28 | namespace plug 29 | { 30 | 31 | LoadFromAmp::LoadFromAmp(QWidget* parent) 32 | : QMainWindow(parent), 33 | ui(std::make_unique()) 34 | { 35 | ui->setupUi(this); 36 | 37 | QSettings settings; 38 | restoreGeometry(settings.value("Windows/loadAmpPresetWindowGeometry").toByteArray()); 39 | 40 | connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(load())); 41 | connect(ui->pushButton_2, SIGNAL(clicked()), this, SLOT(close())); 42 | } 43 | 44 | LoadFromAmp::~LoadFromAmp() 45 | { 46 | QSettings settings; 47 | settings.setValue("Windows/loadAmpPresetWindowGeometry", saveGeometry()); 48 | } 49 | 50 | void LoadFromAmp::load() 51 | { 52 | QSettings settings; 53 | 54 | dynamic_cast(parent())->load_from_amp(ui->comboBox->currentIndex()); 55 | dynamic_cast(parent())->set_index(ui->comboBox->currentIndex()); 56 | 57 | if (!settings.value("Settings/keepWindowsOpen").toBool()) 58 | { 59 | this->close(); 60 | } 61 | } 62 | 63 | void LoadFromAmp::load_names(const std::vector& names) 64 | { 65 | std::size_t index{1}; 66 | std::for_each(names.cbegin(), names.cend(), [&index, this](const auto& name) 67 | { 68 | ui->comboBox->addItem(QString("[%1] %2").arg(index).arg(QString::fromStdString(name))); 69 | ++index; }); 70 | } 71 | 72 | void LoadFromAmp::delete_items() 73 | { 74 | for (int i = 0; i < ui->comboBox->count(); ++i) 75 | { 76 | ui->comboBox->removeItem(0); 77 | } 78 | } 79 | 80 | void LoadFromAmp::change_name(int slot, QString* name) 81 | { 82 | ui->comboBox->setItemText(slot, *name); 83 | ui->comboBox->setCurrentIndex(slot); 84 | } 85 | } 86 | 87 | #include "ui/moc_loadfromamp.moc" 88 | -------------------------------------------------------------------------------- /test/mocks/LibUsbMocks.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include 24 | #include 25 | 26 | namespace plug::test::mock 27 | { 28 | class UsbMock 29 | { 30 | public: 31 | MOCK_METHOD(int, init, (libusb_context**) ); 32 | MOCK_METHOD(void, close, (libusb_device_handle*) ); 33 | MOCK_METHOD(libusb_device_handle*, open_device_with_vid_pid, (libusb_context*, uint16_t, uint16_t) ); 34 | MOCK_METHOD(void, exit, (libusb_context*) ); 35 | MOCK_METHOD(int, kernel_driver_active, (libusb_device_handle*, int) ); 36 | MOCK_METHOD(int, detach_kernel_driver, (libusb_device_handle*, int) ); 37 | MOCK_METHOD(int, attach_kernel_driver, (libusb_device_handle*, int) ); 38 | MOCK_METHOD(int, set_auto_detach_kernel_driver, (libusb_device_handle*, int) ); 39 | MOCK_METHOD(int, release_interface, (libusb_device_handle*, int) ); 40 | MOCK_METHOD(int, claim_interface, (libusb_device_handle*, int) ); 41 | MOCK_METHOD(int, interrupt_transfer, (libusb_device_handle*, unsigned char, unsigned char*, int, int*, unsigned int) ); 42 | MOCK_METHOD(const char*, error_name, (int) ); 43 | MOCK_METHOD(const char*, strerror, (int) ); 44 | MOCK_METHOD(ssize_t, get_device_list, (libusb_context*, libusb_device***) ); 45 | MOCK_METHOD(int, get_device_descriptor, (libusb_device*, libusb_device_descriptor*) ); 46 | MOCK_METHOD(void, free_device_list, (libusb_device**, int) ); 47 | MOCK_METHOD(libusb_device*, ref_device, (libusb_device*) ); 48 | MOCK_METHOD(void, unref_device, (libusb_device*) ); 49 | MOCK_METHOD(int, open, (libusb_device*, libusb_device_handle**) ); 50 | MOCK_METHOD(int, get_string_descriptor_ascii, (libusb_device_handle*, uint8_t, unsigned char*, int) ); 51 | }; 52 | 53 | UsbMock* getUsbMock(); 54 | UsbMock* resetUsbMock(); 55 | void clearUsbMock(); 56 | } 57 | 58 | 59 | extern "C" 60 | { 61 | struct libusb_device 62 | { 63 | uint16_t idVendor; 64 | uint16_t idProduct; 65 | uint8_t iProduct; 66 | }; 67 | 68 | 69 | struct libusb_device_handle 70 | { 71 | char dummy; 72 | }; 73 | } 74 | -------------------------------------------------------------------------------- /src/ui/settings.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #include "ui/settings.h" 23 | #include "ui_settings.h" 24 | 25 | namespace plug 26 | { 27 | 28 | Settings::Settings(QWidget* parent) 29 | : QDialog(parent), 30 | ui(std::make_unique()) 31 | { 32 | QSettings settings; 33 | 34 | ui->setupUi(this); 35 | 36 | ui->checkBox_2->setChecked(settings.value("Settings/connectOnStartup").toBool()); 37 | ui->checkBox_3->setChecked(settings.value("Settings/oneSetToSetThemAll").toBool()); 38 | ui->checkBox_4->setChecked(settings.value("Settings/keepWindowsOpen").toBool()); 39 | ui->checkBox_5->setChecked(settings.value("Settings/popupChangedWindows").toBool()); 40 | ui->checkBox_6->setChecked(settings.value("Settings/defaultEffectValues").toBool()); 41 | 42 | connect(ui->checkBox_2, SIGNAL(toggled(bool)), this, SLOT(change_connect(bool))); 43 | connect(ui->checkBox_3, SIGNAL(toggled(bool)), this, SLOT(change_oneset(bool))); 44 | connect(ui->checkBox_4, SIGNAL(toggled(bool)), this, SLOT(change_keepopen(bool))); 45 | connect(ui->checkBox_5, SIGNAL(toggled(bool)), this, SLOT(change_popupwindows(bool))); 46 | connect(ui->checkBox_6, SIGNAL(toggled(bool)), this, SLOT(change_effectvalues(bool))); 47 | } 48 | 49 | void Settings::change_connect(bool value) 50 | { 51 | QSettings settings; 52 | 53 | settings.setValue("Settings/connectOnStartup", value); 54 | } 55 | 56 | void Settings::change_oneset(bool value) 57 | { 58 | QSettings settings; 59 | 60 | settings.setValue("Settings/oneSetToSetThemAll", value); 61 | } 62 | 63 | void Settings::change_keepopen(bool value) 64 | { 65 | QSettings settings; 66 | 67 | settings.setValue("Settings/keepWindowsOpen", value); 68 | } 69 | 70 | void Settings::change_popupwindows(bool value) 71 | { 72 | QSettings settings; 73 | 74 | settings.setValue("Settings/popupChangedWindows", value); 75 | } 76 | 77 | void Settings::change_effectvalues(bool value) 78 | { 79 | QSettings settings; 80 | 81 | settings.setValue("Settings/defaultEffectValues", value); 82 | } 83 | } 84 | 85 | #include "ui/moc_settings.moc" 86 | -------------------------------------------------------------------------------- /src/ui/settings.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Settings 4 | 5 | 6 | 7 | 0 8 | 0 9 | 480 10 | 201 11 | 12 | 13 | 14 | Settings 15 | 16 | 17 | Settings window 18 | 19 | 20 | Here you can set some settings of this program 21 | 22 | 23 | 24 | 25 | 26 | Connect to the amplifier on startup 27 | 28 | 29 | true 30 | 31 | 32 | 33 | 34 | 35 | 36 | Clicking any "Set" button sets everything 37 | 38 | 39 | 40 | 41 | 42 | 43 | Do not close Load/Save windows after loading/saving 44 | 45 | 46 | 47 | 48 | 49 | 50 | Open changed windows after loading/connecting 51 | 52 | 53 | true 54 | 55 | 56 | 57 | 58 | 59 | 60 | Set default knob values when choosing effect 61 | 62 | 63 | true 64 | 65 | 66 | 67 | 68 | 69 | 70 | OK 71 | 72 | 73 | Save settings and close this window 74 | 75 | 76 | OK 77 | 78 | 79 | Return, Esc 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | pushButton 89 | clicked() 90 | Settings 91 | close() 92 | 93 | 94 | 367 95 | 600 96 | 97 | 98 | 278 99 | 594 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /src/ui/saveonamp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #include "ui/saveonamp.h" 23 | #include "ui/mainwindow.h" 24 | #include "ui_saveonamp.h" 25 | #include 26 | #include 27 | 28 | namespace plug 29 | { 30 | 31 | SaveOnAmp::SaveOnAmp(QWidget* parent) 32 | : QMainWindow(parent), 33 | ui(std::make_unique()) 34 | { 35 | ui->setupUi(this); 36 | 37 | QSettings settings; 38 | restoreGeometry(settings.value("Windows/saveAmpPresetWindowGeometry").toByteArray()); 39 | 40 | connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(save())); 41 | connect(ui->pushButton_2, SIGNAL(clicked()), this, SLOT(close())); 42 | } 43 | 44 | SaveOnAmp::~SaveOnAmp() 45 | { 46 | QSettings settings; 47 | settings.setValue("Windows/saveAmpPresetWindowGeometry", saveGeometry()); 48 | } 49 | 50 | void SaveOnAmp::save() 51 | { 52 | QSettings settings; 53 | QString name(QString("[%1] %2").arg(ui->comboBox->currentIndex()).arg(ui->lineEdit->text())); 54 | 55 | ui->comboBox->setItemText(ui->comboBox->currentIndex(), name); 56 | dynamic_cast(parent())->change_name(ui->comboBox->currentIndex(), &name); 57 | dynamic_cast(parent())->save_on_amp(ui->lineEdit->text().toLatin1().data(), ui->comboBox->currentIndex()); 58 | if (!settings.value("Settings/keepWindowsOpen").toBool()) 59 | { 60 | this->close(); 61 | } 62 | } 63 | 64 | void SaveOnAmp::load_names(const std::vector& names) 65 | { 66 | std::size_t index{1}; 67 | std::for_each(names.cbegin(), names.cend(), [&index, this](const auto& name) 68 | { 69 | ui->comboBox->addItem(QString("[%1] %2").arg(index).arg(QString::fromStdString(name))); 70 | ++index; }); 71 | } 72 | 73 | void SaveOnAmp::delete_items() 74 | { 75 | for (int i = 0; i < ui->comboBox->count(); ++i) 76 | { 77 | ui->comboBox->removeItem(0); 78 | } 79 | } 80 | 81 | void SaveOnAmp::change_index(int value, const QString& name) 82 | { 83 | if (value > 0) 84 | { 85 | ui->comboBox->setCurrentIndex(value); 86 | } 87 | ui->lineEdit->setText(name); 88 | } 89 | } 90 | 91 | #include "ui/moc_saveonamp.moc" 92 | -------------------------------------------------------------------------------- /src/ui/save_effects.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #include "ui/save_effects.h" 23 | #include "ui/mainwindow.h" 24 | #include "ui_save_effects.h" 25 | #include 26 | 27 | namespace plug 28 | { 29 | 30 | SaveEffects::SaveEffects(QWidget* parent) 31 | : QDialog(parent), 32 | ui(std::make_unique()) 33 | { 34 | ui->setupUi(this); 35 | 36 | QSettings settings; 37 | restoreGeometry(settings.value("Windows/saveEffectPresetWindowGeometry").toByteArray()); 38 | 39 | connect(ui->checkBox, SIGNAL(clicked()), this, SLOT(select_checkbox())); 40 | connect(ui->checkBox_2, SIGNAL(clicked()), this, SLOT(select_checkbox())); 41 | connect(ui->checkBox_3, SIGNAL(clicked()), this, SLOT(select_checkbox())); 42 | connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(send())); 43 | connect(ui->pushButton_2, SIGNAL(clicked()), this, SLOT(close())); 44 | } 45 | 46 | SaveEffects::~SaveEffects() 47 | { 48 | QSettings settings; 49 | settings.setValue("Windows/saveEffectPresetWindowGeometry", saveGeometry()); 50 | } 51 | 52 | void SaveEffects::select_checkbox() 53 | { 54 | const bool buttonDisabled = (!ui->checkBox->isChecked() && !ui->checkBox_2->isChecked() && !ui->checkBox_3->isChecked()); 55 | ui->pushButton->setDisabled(buttonDisabled); 56 | 57 | if (sender() == ui->checkBox) 58 | { 59 | ui->checkBox_2->setChecked(false); 60 | ui->checkBox_3->setChecked(false); 61 | } 62 | else 63 | { 64 | ui->checkBox->setChecked(false); 65 | } 66 | } 67 | 68 | void SaveEffects::send() 69 | { 70 | int number = 0; 71 | 72 | if (ui->checkBox->isChecked()) 73 | { 74 | number = 1; 75 | } 76 | else 77 | { 78 | if (ui->checkBox_2->isChecked()) 79 | { 80 | ++number; 81 | } 82 | if (ui->checkBox_3->isChecked()) 83 | { 84 | ++number; 85 | } 86 | } 87 | 88 | dynamic_cast(parent())->save_effects(ui->comboBox->currentIndex(), ui->lineEdit->text().toLatin1().data(), number, 89 | ui->checkBox->isChecked(), ui->checkBox_2->isChecked(), ui->checkBox_3->isChecked()); 90 | this->close(); 91 | } 92 | } 93 | 94 | #include "ui/moc_save_effects.moc" 95 | -------------------------------------------------------------------------------- /include/ui/mainwindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include "data_structs.h" 25 | #include 26 | #include 27 | #include 28 | 29 | namespace Ui 30 | { 31 | class MainWindow; 32 | } 33 | 34 | namespace plug 35 | { 36 | class Effect; 37 | class Amplifier; 38 | class SaveEffects; 39 | class SaveToFile; 40 | class SaveOnAmp; 41 | class LoadFromAmp; 42 | class Settings; 43 | class QuickPresets; 44 | 45 | namespace com 46 | { 47 | class Mustang; 48 | } 49 | } 50 | 51 | 52 | namespace plug 53 | { 54 | 55 | class MainWindow : public QMainWindow 56 | { 57 | Q_OBJECT 58 | 59 | public: 60 | explicit MainWindow(QWidget* parent = nullptr); 61 | MainWindow(const MainWindow&) = delete; 62 | ~MainWindow() override; 63 | 64 | MainWindow& operator=(const MainWindow&) = delete; 65 | 66 | public slots: 67 | void start_amp(); 68 | void stop_amp(); 69 | void set_effect(fx_pedal_settings); 70 | void set_amplifier(amp_settings); 71 | void save_on_amp(char*, int); 72 | void load_from_amp(int); 73 | void enable_buttons(); 74 | void change_name(int, QString*); 75 | void save_effects(int, char*, int, bool, bool, bool); 76 | void set_index(int); 77 | void loadfile(QString filename = QString()); 78 | void get_settings(amp_settings*, std::vector&); 79 | void change_title(const QString&); 80 | void update_firmware(); 81 | void empty_other(int, Effect*); 82 | 83 | private: 84 | const std::unique_ptr ui; 85 | 86 | QString current_name; 87 | std::vector presetNames; 88 | bool connected; 89 | std::unique_ptr amp_ops; 90 | Amplifier* amp; 91 | std::array effectComponents; 92 | SaveOnAmp* save; 93 | LoadFromAmp* load; 94 | SaveEffects* seffects; 95 | Settings* settings_win; 96 | SaveToFile* saver; 97 | QuickPresets* quickpres; 98 | 99 | private slots: 100 | void about(); 101 | void showEffect(std::uint8_t slot); 102 | void show_amp(); 103 | void show_library(); 104 | void show_default_effects(); 105 | void loadPreset(std::size_t number); 106 | 107 | 108 | signals: 109 | void started(); 110 | }; 111 | } 112 | -------------------------------------------------------------------------------- /test/matcher/PacketMatcher.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "com/Packet.h" 24 | #include "data_structs.h" 25 | #include 26 | #include 27 | 28 | 29 | namespace plug::test::matcher 30 | { 31 | MATCHER_P4(AmpDataIs, ampId, v0, v1, v2, "") 32 | { 33 | constexpr std::size_t posAmpId{16}; 34 | const std::tuple actual{arg[posAmpId], arg[40], arg[43], arg[44], arg[45], arg[46], arg[50], arg[54]}; 35 | const auto [a0, a1, a2, a3, a4, a5, a6, a7] = actual; 36 | *result_listener << " with amp specific values: (" 37 | << int{a0} << ", {" << int{a1} << ", " << int{a2} << "}, {" 38 | << int{a3} << ", " << int{a4} << ", " << int{a5} << ", " << int{a6} 39 | << "}, " << int{a7} << ")"; 40 | return std::tuple{ampId, v0, v0, v1, v1, v1, v1, v2} == actual; 41 | } 42 | 43 | MATCHER_P(CabinetDataIs, cabinetValue, "") 44 | { 45 | constexpr std::size_t posCabId{49}; 46 | const auto actual = arg[posCabId]; 47 | *result_listener << " with cabinet data: " << int{actual}; 48 | return actual == cabinetValue; 49 | } 50 | 51 | MATCHER_P4(EffectDataIs, dsp, effect, v0, v1, "") 52 | { 53 | constexpr std::size_t posDspId{2}; 54 | constexpr std::size_t posEffectId{16}; 55 | const std::tuple actual{arg[posDspId], arg[posEffectId], arg[19], arg[20]}; 56 | const auto [a0, a1, a2, a3] = actual; 57 | *result_listener << " with effect values: (" << int{a0} << ", " << int{a1} 58 | << ", " << int{a2} << ", " << int{a3} << ")"; 59 | 60 | return std::tuple{dsp, effect, v0, v1} == actual; 61 | } 62 | 63 | MATCHER_P6(KnobsAre, k1, k2, k3, k4, k5, k6, "") 64 | { 65 | constexpr std::size_t posKnob1{32}; 66 | constexpr std::size_t posKnob2{33}; 67 | constexpr std::size_t posKnob3{34}; 68 | constexpr std::size_t posKnob4{35}; 69 | constexpr std::size_t posKnob5{36}; 70 | constexpr std::size_t posKnob6{37}; 71 | const std::tuple actual{arg[posKnob1], arg[posKnob2], arg[posKnob3], 72 | arg[posKnob4], arg[posKnob5], arg[posKnob6]}; 73 | const auto [a1, a2, a3, a4, a5, a6] = actual; 74 | *result_listener << " with knobs: (" << int{a1} << ", " << int{a2} << ", " << int{a3} 75 | << ", " << int{a4} << ", " << int{a5} << ", " << int{a6} << ")"; 76 | return std::tuple{k1, k2, k3, k4, k5, k6} == actual; 77 | } 78 | 79 | MATCHER_P(FxKnobIs, value, "") 80 | { 81 | constexpr std::size_t posFxKnobId{3}; 82 | const auto a = arg[posFxKnobId]; 83 | *result_listener << " with FX Knob " << int{a}; 84 | return value == a; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/ui/loadfromamp.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | LoadFromAmp 4 | 5 | 6 | 7 | 0 8 | 0 9 | 300 10 | 100 11 | 12 | 13 | 14 | Load from Amplifier 15 | 16 | 17 | Load preset from amplifier 18 | 19 | 20 | Window which allows you to load presets from amplifier 21 | 22 | 23 | 24 | 25 | 26 | 27 | Qt::Vertical 28 | 29 | 30 | 31 | 20 32 | 40 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | &Slot: 43 | 44 | 45 | comboBox 46 | 47 | 48 | 49 | 50 | 51 | 52 | Slot 53 | 54 | 55 | Choose which slot to load 56 | 57 | 58 | 20 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | Qt::Vertical 68 | 69 | 70 | 71 | 17 72 | 32 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | Cancel 83 | 84 | 85 | Quit window without loading anything 86 | 87 | 88 | &Cancel 89 | 90 | 91 | Esc 92 | 93 | 94 | 95 | 96 | 97 | 98 | Load 99 | 100 | 101 | Load's selected setting from amplifier and closes the window 102 | 103 | 104 | &Load 105 | 106 | 107 | Return 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /test/matcher/TypeMatcher.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "data_structs.h" 24 | #include 25 | 26 | namespace plug::test::matcher 27 | { 28 | MATCHER_P(EffectIs, value, "") 29 | { 30 | std::uint8_t valueSlot = value.slot.id(); 31 | std::uint8_t argSlot = value.slot.id(); 32 | return std::tie(valueSlot, value.effect_num, value.knob1, value.knob2, value.knob3, 33 | value.knob4, value.knob5, value.knob6) == 34 | std::tie(argSlot, arg.effect_num, arg.knob1, arg.knob2, arg.knob3, 35 | arg.knob4, arg.knob5, arg.knob6); 36 | } 37 | 38 | MATCHER_P(AmpIs, value, "") 39 | { 40 | return std::tie(value.amp_num, value.volume, value.gain, value.treble, value.middle, value.bass, 41 | value.cabinet, value.noise_gate, value.threshold, value.master_vol, value.gain2, 42 | value.presence, value.depth, value.bias, value.sag, value.brightness, value.usb_gain) == 43 | std::tie(arg.amp_num, arg.volume, arg.gain, arg.treble, arg.middle, arg.bass, 44 | arg.cabinet, arg.noise_gate, arg.threshold, arg.master_vol, arg.gain2, 45 | arg.presence, arg.depth, arg.bias, arg.sag, arg.brightness, arg.usb_gain); 46 | } 47 | } 48 | 49 | 50 | namespace plug 51 | { 52 | 53 | inline void PrintTo(const fx_pedal_settings& e, std::ostream* os) 54 | { 55 | *os << "[slot: " + std::to_string(e.slot.id()) 56 | << ", effect: " << std::to_string(static_cast(e.effect_num)) 57 | << ", knobs: (" << std::to_string(e.knob1) << ", " << std::to_string(e.knob2) 58 | << ", " << std::to_string(e.knob3) << ", " << std::to_string(e.knob4) 59 | << ", " << std::to_string(e.knob5) << ", " << std::to_string(e.knob6) << ")]"; 60 | } 61 | 62 | 63 | inline void PrintTo(const amp_settings& a, std::ostream* os) 64 | { 65 | *os << "[amp.num: " << std::to_string(static_cast(a.amp_num)) 66 | << ", volume: " << std::to_string(a.volume) 67 | << ", gain: " << std::to_string(a.gain) 68 | << ", treble: " << std::to_string(a.treble) 69 | << ", middle: " << std::to_string(a.middle) 70 | << ", bass: " << std::to_string(a.bass) 71 | << ", cabinet: " << std::to_string(static_cast(a.cabinet)) 72 | << ", noise_gate: " << std::to_string(a.noise_gate) 73 | << ", threshold: " << std::to_string(a.threshold) 74 | << ", master_vol: " << std::to_string(a.master_vol) 75 | << ", gain2: " << std::to_string(a.gain2) 76 | << ", presence: " << std::to_string(a.presence) 77 | << ", depth: " << std::to_string(a.depth) 78 | << ", bias: " << std::to_string(a.bias) 79 | << ", sag: " << std::to_string(a.sag) 80 | << ", brightness: " << std::to_string(a.brightness) 81 | << ", usb_gain: " << std::to_string(a.usb_gain) << "]"; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /test/UsbCommTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "com/UsbComm.h" 22 | #include "com/CommunicationException.h" 23 | #include "mocks/UsbDeviceMock.h" 24 | #include "matcher/Matcher.h" 25 | #include 26 | #include 27 | 28 | namespace plug::test 29 | { 30 | using plug::com::UsbComm; 31 | using plug::com::usb::Device; 32 | using namespace plug::test::matcher; 33 | using namespace testing; 34 | 35 | class UsbCommTest : public testing::Test 36 | { 37 | protected: 38 | void SetUp() override 39 | { 40 | deviceMock = mock::resetUsbDeviceMock(); 41 | } 42 | 43 | void TearDown() override 44 | { 45 | mock::clearUsbDeviceMock(); 46 | } 47 | 48 | UsbComm create() const 49 | { 50 | return UsbComm{Device{nullptr}}; 51 | } 52 | 53 | mock::UsbDeviceMock* deviceMock{nullptr}; 54 | }; 55 | 56 | TEST_F(UsbCommTest, ctorOpensDevice) 57 | { 58 | EXPECT_CALL(*deviceMock, open()); 59 | EXPECT_CALL(*deviceMock, name()); 60 | UsbComm com{Device{nullptr}}; 61 | } 62 | 63 | TEST_F(UsbCommTest, closeClosesDevice) 64 | { 65 | EXPECT_CALL(*deviceMock, open()); 66 | EXPECT_CALL(*deviceMock, name()); 67 | EXPECT_CALL(*deviceMock, close()); 68 | 69 | UsbComm com = create(); 70 | com.close(); 71 | } 72 | 73 | TEST_F(UsbCommTest, isOpenReturnDeviceState) 74 | { 75 | EXPECT_CALL(*deviceMock, open()); 76 | EXPECT_CALL(*deviceMock, name()); 77 | 78 | UsbComm com = create(); 79 | EXPECT_CALL(*deviceMock, isOpen()).WillOnce(Return(false)); 80 | EXPECT_THAT(com.isOpen(), IsFalse()); 81 | EXPECT_CALL(*deviceMock, isOpen()).WillOnce(Return(true)); 82 | EXPECT_THAT(com.isOpen(), IsTrue()); 83 | } 84 | 85 | TEST_F(UsbCommTest, sendSendsData) 86 | { 87 | EXPECT_CALL(*deviceMock, open()); 88 | EXPECT_CALL(*deviceMock, name()); 89 | 90 | const std::array data{{0x00, 0xa1, 0xb2, 0xb3}}; 91 | EXPECT_CALL(*deviceMock, write(0x01, BufferIs(data), data.size())).WillOnce(Return(data.size())); 92 | 93 | UsbComm com = create(); 94 | const auto n = com.send(data); 95 | EXPECT_THAT(n, Eq(4)); 96 | } 97 | 98 | TEST_F(UsbCommTest, receiveReceivesData) 99 | { 100 | EXPECT_CALL(*deviceMock, open()); 101 | EXPECT_CALL(*deviceMock, name()); 102 | 103 | std::vector data{{0x00, 0xa1, 0xb2, 0xb3, 0xc4}}; 104 | EXPECT_CALL(*deviceMock, receive(0x81, data.size())).WillOnce(Return(data)); 105 | 106 | UsbComm com = create(); 107 | const auto received = com.receive(data.size()); 108 | EXPECT_THAT(received, Eq(data)); 109 | } 110 | 111 | TEST_F(UsbCommTest, modelName) 112 | { 113 | EXPECT_CALL(*deviceMock, open()); 114 | EXPECT_CALL(*deviceMock, name()).WillOnce(Return("USB Device Name")); 115 | 116 | UsbComm com = create(); 117 | EXPECT_THAT(com.name(), Eq("USB Device Name")); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /test/mocks/UsbDeviceMock.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "UsbDeviceMock.h" 22 | #include 23 | 24 | namespace plug::test::mock 25 | { 26 | static std::unique_ptr usbContextMock; 27 | static std::unique_ptr usbDeviceMock; 28 | 29 | 30 | UsbContextMock* resetUsbContextMock() 31 | { 32 | usbContextMock = std::make_unique(); 33 | return getUsbContextMock(); 34 | } 35 | 36 | UsbContextMock* getUsbContextMock() 37 | { 38 | if (usbContextMock == nullptr) 39 | { 40 | throw std::logic_error{"Usb Device Mock not initialized."}; 41 | } 42 | return usbContextMock.get(); 43 | } 44 | 45 | void clearUsbContextMock() 46 | { 47 | usbContextMock = nullptr; 48 | } 49 | 50 | UsbDeviceMock* resetUsbDeviceMock() 51 | { 52 | usbDeviceMock = std::make_unique(); 53 | return getUsbDeviceMock(); 54 | } 55 | 56 | UsbDeviceMock* getUsbDeviceMock() 57 | { 58 | if (usbDeviceMock == nullptr) 59 | { 60 | throw std::logic_error{"Usb Device Mock not initialized."}; 61 | } 62 | return usbDeviceMock.get(); 63 | } 64 | 65 | void clearUsbDeviceMock() 66 | { 67 | usbDeviceMock.reset(); 68 | } 69 | } 70 | 71 | 72 | namespace plug::com::usb 73 | { 74 | namespace detail 75 | { 76 | void releaseDevice([[maybe_unused]] libusb_device* device) 77 | { 78 | } 79 | 80 | void releaseHandle([[maybe_unused]] libusb_device_handle* handle) 81 | { 82 | } 83 | } 84 | 85 | std::vector listDevices() 86 | { 87 | return plug::test::mock::usbContextMock->listDevices(); 88 | } 89 | 90 | 91 | Device::Device(libusb_device* device) 92 | : device_(device), handle_(nullptr), descriptor_({}) 93 | { 94 | } 95 | 96 | void Device::open() 97 | { 98 | plug::test::mock::usbDeviceMock->open(); 99 | } 100 | 101 | void Device::close() 102 | { 103 | plug::test::mock::usbDeviceMock->close(); 104 | } 105 | 106 | bool Device::isOpen() const noexcept 107 | { 108 | return plug::test::mock::usbDeviceMock->isOpen(); 109 | } 110 | 111 | std::uint16_t Device::vendorId() const noexcept 112 | { 113 | return plug::test::mock::usbDeviceMock->vendorId(); 114 | } 115 | 116 | std::uint16_t Device::productId() const noexcept 117 | { 118 | return plug::test::mock::usbDeviceMock->productId(); 119 | } 120 | 121 | std::string Device::name() const 122 | { 123 | return plug::test::mock::usbDeviceMock->name(); 124 | } 125 | 126 | std::size_t Device::write(std::uint8_t endpoint, std::uint8_t* data, std::size_t dataSize) 127 | { 128 | return plug::test::mock::usbDeviceMock->write(endpoint, data, dataSize); 129 | } 130 | 131 | std::vector Device::receive(std::uint8_t endpoint, std::size_t dataSize) 132 | { 133 | return plug::test::mock::usbDeviceMock->receive(endpoint, dataSize); 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /include/effects_enum.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include 25 | 26 | namespace plug 27 | { 28 | 29 | // list of all amplifiers 30 | enum class amps 31 | { 32 | FENDER_57_DELUXE, 33 | FENDER_59_BASSMAN, 34 | FENDER_57_CHAMP, 35 | FENDER_65_DELUXE_REVERB, 36 | FENDER_65_PRINCETON, 37 | FENDER_65_TWIN_REVERB, 38 | FENDER_SUPER_SONIC, 39 | BRITISH_60S, 40 | BRITISH_70S, 41 | BRITISH_80S, 42 | AMERICAN_90S, 43 | METAL_2000, 44 | 45 | // Mustang v2 46 | STUDIO_PREAMP, 47 | FENDER_57_TWIN, 48 | FENDER_60_THRIFT, 49 | BRITISH_COLOUR, 50 | BRITISH_WATTS 51 | }; 52 | 53 | constexpr bool isV2Amp(amps amp) 54 | { 55 | switch (amp) 56 | { 57 | case amps::STUDIO_PREAMP: 58 | case amps::FENDER_57_TWIN: 59 | case amps::FENDER_60_THRIFT: 60 | case amps::BRITISH_COLOUR: 61 | case amps::BRITISH_WATTS: 62 | return true; 63 | default: 64 | return false; 65 | } 66 | } 67 | 68 | // list of all effects 69 | enum class effects 70 | { 71 | EMPTY, 72 | OVERDRIVE, 73 | WAH, 74 | TOUCH_WAH, 75 | FUZZ, 76 | FUZZ_TOUCH_WAH, 77 | SIMPLE_COMP, 78 | COMPRESSOR, 79 | 80 | SINE_CHORUS, 81 | TRIANGLE_CHORUS, 82 | SINE_FLANGER, 83 | TRIANGLE_FLANGER, 84 | VIBRATONE, 85 | VINTAGE_TREMOLO, 86 | SINE_TREMOLO, 87 | RING_MODULATOR, 88 | STEP_FILTER, 89 | PHASER, 90 | PITCH_SHIFTER, 91 | 92 | MONO_DELAY, 93 | MONO_ECHO_FILTER, 94 | STEREO_ECHO_FILTER, 95 | MULTITAP_DELAY, 96 | PING_PONG_DELAY, 97 | DUCKING_DELAY, 98 | REVERSE_DELAY, 99 | TAPE_DELAY, 100 | STEREO_TAPE_DELAY, 101 | 102 | SMALL_HALL_REVERB, 103 | LARGE_HALL_REVERB, 104 | SMALL_ROOM_REVERB, 105 | LARGE_ROOM_REVERB, 106 | SMALL_PLATE_REVERB, 107 | LARGE_PLATE_REVERB, 108 | AMBIENT_REVERB, 109 | ARENA_REVERB, 110 | FENDER_63_SPRING_REVERB, 111 | FENDER_65_SPRING_REVERB 112 | }; 113 | 114 | // list of all cabinets 115 | enum class cabinets 116 | { 117 | OFF, 118 | cab57DLX, 119 | cabBSSMN, 120 | cab65DLX, 121 | cab65PRN, 122 | cabCHAMP, 123 | cab4x12M, 124 | cab2x12C, 125 | cab4x12G, 126 | cab65TWN, 127 | cab4x12V, 128 | cabSS212, 129 | cabSS112 130 | }; 131 | 132 | 133 | // Helper functions - for compatibility only. 134 | constexpr auto value(amps a) 135 | { 136 | return static_cast(a); 137 | } 138 | 139 | constexpr auto value(effects e) 140 | { 141 | return static_cast(e); 142 | } 143 | 144 | constexpr auto value(cabinets c) 145 | { 146 | return static_cast(c); 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /src/com/ConnectionFactory.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "com/ConnectionFactory.h" 22 | #include "com/CommunicationException.h" 23 | #include "com/Mustang.h" 24 | #include "com/UsbComm.h" 25 | #include "com/UsbContext.h" 26 | #include "DeviceModel.h" 27 | #include 28 | 29 | namespace plug::com 30 | { 31 | namespace 32 | { 33 | inline constexpr std::uint16_t usbVID{0x1ed8}; 34 | 35 | namespace usbPID 36 | { 37 | inline constexpr std::uint16_t mustangI_II{0x0004}; 38 | inline constexpr std::uint16_t mustangIII_IV_V{0x0005}; 39 | inline constexpr std::uint16_t mustangBronco{0x000a}; 40 | inline constexpr std::uint16_t mustangMini{0x0010}; 41 | inline constexpr std::uint16_t mustangFloor{0x0012}; 42 | inline constexpr std::uint16_t mustangI_II_v2{0x0014}; 43 | inline constexpr std::uint16_t mustangIII_IV_V_v2{0x0016}; 44 | } 45 | 46 | inline constexpr std::initializer_list pids{ 47 | usbPID::mustangI_II, 48 | usbPID::mustangIII_IV_V, 49 | usbPID::mustangBronco, 50 | usbPID::mustangMini, 51 | usbPID::mustangFloor, 52 | usbPID::mustangI_II_v2, 53 | usbPID::mustangIII_IV_V_v2}; 54 | 55 | DeviceModel getModel(std::uint16_t pid) 56 | { 57 | switch (pid) 58 | { 59 | case usbPID::mustangI_II: 60 | return DeviceModel{"Mustang I/II", DeviceModel::Category::MustangV1, 24}; 61 | case usbPID::mustangIII_IV_V: 62 | return DeviceModel{"Mustang III/IV/V", DeviceModel::Category::MustangV1, 100}; 63 | case usbPID::mustangBronco: 64 | return DeviceModel{"Mustang Bronco", DeviceModel::Category::MustangV1, 0}; 65 | case usbPID::mustangMini: 66 | return DeviceModel{"Mustang Mini", DeviceModel::Category::MustangV1, 0}; 67 | case usbPID::mustangFloor: 68 | return DeviceModel{"Mustang Floor", DeviceModel::Category::MustangV1, 0}; 69 | case usbPID::mustangI_II_v2: 70 | return DeviceModel{"Mustang I/II", DeviceModel::Category::MustangV2, 24}; 71 | case usbPID::mustangIII_IV_V_v2: 72 | return DeviceModel{"Mustang III/IV/V", DeviceModel::Category::MustangV2, 100}; 73 | default: 74 | throw CommunicationException{"Unknown device pid: " + std::to_string(pid)}; 75 | } 76 | } 77 | 78 | } 79 | 80 | std::unique_ptr connect() 81 | { 82 | auto devices = usb::listDevices(); 83 | 84 | auto itr = std::find_if(devices.begin(), devices.end(), [](const auto& dev) 85 | { return (dev.vendorId() == usbVID) && std::any_of(pids.begin(), pids.end(), [&dev](std::uint16_t pid) 86 | { return dev.productId() == pid; }); }); 87 | 88 | if (itr == devices.end()) 89 | { 90 | throw CommunicationException{"No device found"}; 91 | } 92 | return std::make_unique(getModel(itr->productId()), std::make_shared(std::move(*itr))); 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/ui/amp_advanced.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #include "ui/amp_advanced.h" 23 | #include "ui_amp_advanced.h" 24 | 25 | namespace plug 26 | { 27 | 28 | Amp_Advanced::Amp_Advanced(QWidget* parent) 29 | : QDialog(parent), 30 | ui(std::make_unique()) 31 | { 32 | ui->setupUi(this); 33 | 34 | // load window size 35 | QSettings settings; 36 | restoreGeometry(settings.value("Windows/amplifierAdvancedWindowGeometry").toByteArray()); 37 | 38 | connect(ui->comboBox, SIGNAL(currentIndexChanged(int)), parent, SLOT(set_cabinet(int))); 39 | connect(ui->comboBox_2, SIGNAL(currentIndexChanged(int)), parent, SLOT(set_noise_gate(int))); 40 | connect(ui->comboBox_2, SIGNAL(currentIndexChanged(int)), this, SLOT(activate_custom_ng(int))); 41 | connect(ui->dial, SIGNAL(valueChanged(int)), parent, SLOT(set_master_vol(int))); 42 | connect(ui->dial_2, SIGNAL(valueChanged(int)), parent, SLOT(set_gain2(int))); 43 | connect(ui->dial_3, SIGNAL(valueChanged(int)), parent, SLOT(set_presence(int))); 44 | connect(ui->dial_4, SIGNAL(valueChanged(int)), parent, SLOT(set_depth(int))); 45 | connect(ui->dial_5, SIGNAL(valueChanged(int)), parent, SLOT(set_threshold(int))); 46 | connect(ui->dial_6, SIGNAL(valueChanged(int)), parent, SLOT(set_bias(int))); 47 | connect(ui->dial_7, SIGNAL(valueChanged(int)), parent, SLOT(set_sag(int))); 48 | connect(ui->dial_8, SIGNAL(valueChanged(int)), parent, SLOT(set_usb_gain(int))); 49 | connect(ui->checkBox, SIGNAL(toggled(bool)), parent, SLOT(set_brightness(bool))); 50 | } 51 | 52 | Amp_Advanced::~Amp_Advanced() 53 | { 54 | QSettings settings; 55 | settings.setValue("Windows/amplifierAdvancedWindowGeometry", saveGeometry()); 56 | } 57 | 58 | void Amp_Advanced::change_cabinet(int value) 59 | { 60 | ui->comboBox->setCurrentIndex(value); 61 | } 62 | 63 | void Amp_Advanced::change_noise_gate(int value) 64 | { 65 | ui->comboBox_2->setCurrentIndex(value); 66 | } 67 | 68 | void Amp_Advanced::activate_custom_ng(int value) 69 | { 70 | const bool disabled = (value != 5); 71 | ui->dial_5->setDisabled(disabled); 72 | ui->spinBox_5->setDisabled(disabled); 73 | ui->dial_4->setDisabled(disabled); 74 | ui->spinBox_4->setDisabled(disabled); 75 | } 76 | 77 | void Amp_Advanced::set_master_vol(int value) 78 | { 79 | ui->dial->setValue(value); 80 | } 81 | 82 | void Amp_Advanced::set_gain2(int value) 83 | { 84 | ui->dial_2->setValue(value); 85 | } 86 | 87 | void Amp_Advanced::set_presence(int value) 88 | { 89 | ui->dial_3->setValue(value); 90 | } 91 | 92 | void Amp_Advanced::set_depth(int value) 93 | { 94 | ui->dial_4->setValue(value); 95 | } 96 | 97 | void Amp_Advanced::set_threshold(int value) 98 | { 99 | ui->dial_5->setValue(value); 100 | } 101 | 102 | void Amp_Advanced::set_bias(int value) 103 | { 104 | ui->dial_6->setValue(value); 105 | } 106 | 107 | void Amp_Advanced::set_sag(int value) 108 | { 109 | ui->dial_7->setValue(value); 110 | } 111 | 112 | void Amp_Advanced::set_usb_gain(int value) 113 | { 114 | ui->dial_8->setValue(value); 115 | } 116 | 117 | void Amp_Advanced::set_brightness(bool value) 118 | { 119 | ui->checkBox->setChecked(value); 120 | } 121 | } 122 | 123 | #include "ui/moc_amp_advanced.moc" 124 | -------------------------------------------------------------------------------- /src/ui/saveonamp.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | SaveOnAmp 4 | 5 | 6 | 7 | 0 8 | 0 9 | 300 10 | 120 11 | 12 | 13 | 14 | Save on Amplifier 15 | 16 | 17 | Save on amplifier window 18 | 19 | 20 | Allows you to set current settings on the amplifier 21 | 22 | 23 | 24 | 25 | 26 | 27 | Qt::Vertical 28 | 29 | 30 | 31 | 20 32 | 17 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | S&lot: 43 | 44 | 45 | comboBox 46 | 47 | 48 | 49 | 50 | 51 | 52 | Slot 53 | 54 | 55 | Select slot where current settings will be saved 56 | 57 | 58 | 20 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | &Name: 70 | 71 | 72 | lineEdit 73 | 74 | 75 | 76 | 77 | 78 | 79 | Name 80 | 81 | 82 | Select name for your preset 83 | 84 | 85 | 31 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | Qt::Vertical 95 | 96 | 97 | 98 | 20 99 | 18 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | Cancel 110 | 111 | 112 | Do not save anything and close this window 113 | 114 | 115 | &Cancel 116 | 117 | 118 | Esc 119 | 120 | 121 | 122 | 123 | 124 | 125 | Save 126 | 127 | 128 | Save preset and close this window 129 | 130 | 131 | &Save 132 | 133 | 134 | Return 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /src/com/UsbDevice.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "com/UsbDevice.h" 22 | #include "com/UsbException.h" 23 | #include 24 | #include 25 | #include 26 | 27 | namespace plug::com::usb 28 | { 29 | namespace 30 | { 31 | inline constexpr std::chrono::milliseconds usbTimeout{500}; 32 | } 33 | 34 | namespace detail 35 | { 36 | void releaseDevice(libusb_device* device) 37 | { 38 | libusb_unref_device(device); 39 | } 40 | 41 | void releaseHandle(libusb_device_handle* handle) 42 | { 43 | libusb_release_interface(handle, 0); 44 | libusb_close(handle); 45 | } 46 | } 47 | 48 | 49 | Device::Device(libusb_device* device) 50 | : device_(libusb_ref_device(device)), handle_(nullptr), descriptor_(getDeviceDescriptor(device)) 51 | { 52 | } 53 | 54 | void Device::open() 55 | { 56 | libusb_device_handle* h{nullptr}; 57 | 58 | if (const int result = libusb_open(device_.get(), &h); result != LIBUSB_SUCCESS) 59 | { 60 | throw UsbException{result}; 61 | } 62 | handle_.reset(h); 63 | 64 | if (const int result = libusb_set_auto_detach_kernel_driver(handle_.get(), 1); result != LIBUSB_SUCCESS) 65 | { 66 | throw UsbException{result}; 67 | } 68 | 69 | if (const int result = libusb_claim_interface(handle_.get(), 0); result != LIBUSB_SUCCESS) 70 | { 71 | throw UsbException{result}; 72 | } 73 | } 74 | 75 | void Device::close() 76 | { 77 | handle_ = nullptr; 78 | } 79 | 80 | bool Device::isOpen() const noexcept 81 | { 82 | return handle_ != nullptr; 83 | } 84 | 85 | std::uint16_t Device::vendorId() const noexcept 86 | { 87 | return descriptor_.vid; 88 | } 89 | 90 | std::uint16_t Device::productId() const noexcept 91 | { 92 | return descriptor_.pid; 93 | } 94 | 95 | std::string Device::name() const 96 | { 97 | std::array buffer{{}}; 98 | const int n = libusb_get_string_descriptor_ascii(handle_.get(), descriptor_.stringDescriptorIndex, buffer.data(), buffer.size()); 99 | 100 | if (n < 0) 101 | { 102 | throw UsbException{n}; 103 | } 104 | return std::string{buffer.cbegin(), std::next(buffer.cbegin(), n)}; 105 | } 106 | 107 | std::size_t Device::write(std::uint8_t endpoint, std::uint8_t* data, std::size_t dataSize) 108 | { 109 | int transfered{0}; 110 | 111 | if (const auto result = libusb_interrupt_transfer(handle_.get(), endpoint, data, dataSize, &transfered, usbTimeout.count()); result != LIBUSB_SUCCESS) 112 | { 113 | throw UsbException{result}; 114 | } 115 | return transfered; 116 | } 117 | 118 | std::vector Device::receive(std::uint8_t endpoint, std::size_t dataSize) 119 | { 120 | std::vector buffer(dataSize); 121 | int transfered{0}; 122 | 123 | if (const auto result = libusb_interrupt_transfer(handle_.get(), endpoint, buffer.data(), dataSize, &transfered, usbTimeout.count()); (result != LIBUSB_SUCCESS) && (result != LIBUSB_ERROR_TIMEOUT)) 124 | { 125 | throw UsbException{result}; 126 | } 127 | buffer.resize(transfered); 128 | return buffer; 129 | } 130 | 131 | Device::Descriptor Device::getDeviceDescriptor(libusb_device* device) const 132 | { 133 | libusb_device_descriptor descriptor; 134 | 135 | if (const auto result = libusb_get_device_descriptor(device, &descriptor); result != LIBUSB_SUCCESS) 136 | { 137 | throw UsbException{result}; 138 | } 139 | return {descriptor.idVendor, descriptor.idProduct, descriptor.iProduct}; 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /src/ui/savetofile.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | SaveToFile 4 | 5 | 6 | 7 | 0 8 | 0 9 | 333 10 | 168 11 | 12 | 13 | 14 | Save to File 15 | 16 | 17 | Save to file window 18 | 19 | 20 | Allows you to save current settings to a file 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | &Name: 29 | 30 | 31 | lineEdit_2 32 | 33 | 34 | 35 | 36 | 37 | 38 | Name 39 | 40 | 41 | Allows you to set the name of the preset 42 | 43 | 44 | 45 | 46 | 47 | 48 | &Author: 49 | 50 | 51 | lineEdit_3 52 | 53 | 54 | 55 | 56 | 57 | 58 | Author 59 | 60 | 61 | Allows you to set the author of the preset 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | Save &to: 73 | 74 | 75 | lineEdit 76 | 77 | 78 | 79 | 80 | 81 | 82 | Path to a file 83 | 84 | 85 | Enter the path and file name where to save the preset 86 | 87 | 88 | 89 | 90 | 91 | 92 | Choose path and file name 93 | 94 | 95 | Allows you to choose path and filename of the preset 96 | 97 | 98 | ... 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | Cancel 110 | 111 | 112 | Do not save anything and close this window 113 | 114 | 115 | &Cancel 116 | 117 | 118 | Esc 119 | 120 | 121 | 122 | 123 | 124 | 125 | Save 126 | 127 | 128 | Save preset and close this window 129 | 130 | 131 | &Save 132 | 133 | 134 | Return 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | lineEdit_2 144 | lineEdit_3 145 | pushButton 146 | pushButton_2 147 | pushButton_3 148 | lineEdit 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /src/ui/save_effects.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Save_effects 4 | 5 | 6 | 7 | 0 8 | 0 9 | 300 10 | 250 11 | 12 | 13 | 14 | Save Effects 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | &Name: 23 | 24 | 25 | lineEdit 26 | 27 | 28 | 29 | 30 | 31 | 32 | 23 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | &Knob slot: 44 | 45 | 46 | comboBox 47 | 48 | 49 | 50 | 51 | 52 | 53 | 12 54 | 55 | 56 | 57 | A1 58 | 59 | 60 | 61 | 62 | A2 63 | 64 | 65 | 66 | 67 | A3 68 | 69 | 70 | 71 | 72 | B1 73 | 74 | 75 | 76 | 77 | B2 78 | 79 | 80 | 81 | 82 | B3 83 | 84 | 85 | 86 | 87 | C1 88 | 89 | 90 | 91 | 92 | C2 93 | 94 | 95 | 96 | 97 | C3 98 | 99 | 100 | 101 | 102 | D1 103 | 104 | 105 | 106 | 107 | D2 108 | 109 | 110 | 111 | 112 | D3 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | &Modulation 125 | 126 | 127 | 128 | 129 | 130 | 131 | &Delay 132 | 133 | 134 | 135 | 136 | 137 | 138 | &Reverb 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | <b>NOTE</b>: Modulation will be taken from "Effect 2" slot, Delay from "Effect 3" slot and Reverb from "Effect4" slot. 148 | 149 | 150 | true 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | &Cancel 160 | 161 | 162 | Esc 163 | 164 | 165 | 166 | 167 | 168 | 169 | false 170 | 171 | 172 | &Save 173 | 174 | 175 | Return 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /test/mocks/LibUsbMocks.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "LibUsbMocks.h" 22 | #include "com/LibUsbCompat.h" 23 | #include 24 | 25 | namespace plug::test::mock 26 | { 27 | static std::unique_ptr usbmock; 28 | 29 | 30 | UsbMock* getUsbMock() 31 | { 32 | if (usbmock == nullptr) 33 | { 34 | throw std::logic_error{"Usb Mock not initialized."}; 35 | } 36 | return usbmock.get(); 37 | } 38 | 39 | UsbMock* resetUsbMock() 40 | { 41 | usbmock = std::make_unique(); 42 | return getUsbMock(); 43 | } 44 | 45 | 46 | void clearUsbMock() 47 | { 48 | usbmock.reset(); 49 | } 50 | } 51 | 52 | 53 | extern "C" 54 | { 55 | int libusb_init(libusb_context** ctx) 56 | { 57 | return plug::test::mock::getUsbMock()->init(ctx); 58 | } 59 | 60 | void libusb_exit(libusb_context* ctx) 61 | { 62 | plug::test::mock::getUsbMock()->exit(ctx); 63 | } 64 | 65 | libusb_device_handle* libusb_open_device_with_vid_pid(libusb_context* ctx, uint16_t vendor_id, uint16_t product_id) 66 | { 67 | return plug::test::mock::getUsbMock()->open_device_with_vid_pid(ctx, vendor_id, product_id); 68 | } 69 | 70 | int libusb_interrupt_transfer(libusb_device_handle* dev_handle, unsigned char endpoint, 71 | unsigned char* data, int length, int* actual_length, unsigned int timeout) 72 | { 73 | return plug::test::mock::getUsbMock()->interrupt_transfer(dev_handle, endpoint, data, length, actual_length, timeout); 74 | } 75 | 76 | int libusb_claim_interface(libusb_device_handle* dev_handle, int interface_number) 77 | { 78 | return plug::test::mock::getUsbMock()->claim_interface(dev_handle, interface_number); 79 | } 80 | 81 | int libusb_detach_kernel_driver(libusb_device_handle* dev_handle, int interface_number) 82 | { 83 | return plug::test::mock::getUsbMock()->detach_kernel_driver(dev_handle, interface_number); 84 | } 85 | 86 | int libusb_kernel_driver_active(libusb_device_handle* dev_handle, int interface_number) 87 | { 88 | return plug::test::mock::getUsbMock()->kernel_driver_active(dev_handle, interface_number); 89 | } 90 | 91 | int libusb_attach_kernel_driver(libusb_device_handle* dev_handle, int interface_number) 92 | { 93 | return plug::test::mock::getUsbMock()->attach_kernel_driver(dev_handle, interface_number); 94 | } 95 | 96 | int libusb_set_auto_detach_kernel_driver(libusb_device_handle* dev_handle, int enable) 97 | { 98 | return plug::test::mock::getUsbMock()->set_auto_detach_kernel_driver(dev_handle, enable); 99 | } 100 | 101 | void libusb_close(libusb_device_handle* dev_handle) 102 | { 103 | plug::test::mock::getUsbMock()->close(dev_handle); 104 | } 105 | 106 | int libusb_release_interface(libusb_device_handle* dev_handle, int interface_number) 107 | { 108 | return plug::test::mock::getUsbMock()->release_interface(dev_handle, interface_number); 109 | } 110 | 111 | const char* libusb_error_name(int error_code) 112 | { 113 | return plug::test::mock::getUsbMock()->error_name(error_code); 114 | } 115 | 116 | ssize_t libusb_get_device_list(libusb_context* ctx, libusb_device*** list) 117 | { 118 | return plug::test::mock::getUsbMock()->get_device_list(ctx, list); 119 | } 120 | 121 | int libusb_get_device_descriptor(libusb_device* dev, libusb_device_descriptor* desc) 122 | { 123 | return plug::test::mock::getUsbMock()->get_device_descriptor(dev, desc); 124 | } 125 | 126 | void libusb_free_device_list(libusb_device** list, int unref_devices) 127 | { 128 | plug::test::mock::getUsbMock()->free_device_list(list, unref_devices); 129 | } 130 | 131 | libusb_device* libusb_ref_device(libusb_device* dev) 132 | { 133 | return plug::test::mock::getUsbMock()->ref_device(dev); 134 | } 135 | 136 | void libusb_unref_device(libusb_device* dev) 137 | { 138 | return plug::test::mock::getUsbMock()->unref_device(dev); 139 | } 140 | 141 | int libusb_open(libusb_device* dev, libusb_device_handle** dev_handle) 142 | { 143 | return plug::test::mock::getUsbMock()->open(dev, dev_handle); 144 | } 145 | 146 | int libusb_get_string_descriptor_ascii(libusb_device_handle* dev_handle, uint8_t desc_index, unsigned char* data, int length) 147 | { 148 | return plug::test::mock::getUsbMock()->get_string_descriptor_ascii(dev_handle, desc_index, data, length); 149 | } 150 | } 151 | 152 | 153 | namespace plug::com::usb::libusb 154 | { 155 | const char* strerror(ErrorCodeAdapter errorCode) 156 | { 157 | return plug::test::mock::getUsbMock()->strerror(errorCode); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/ui/library.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #include "ui/library.h" 23 | #include "ui/mainwindow.h" 24 | #include "ui_library.h" 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | namespace plug 31 | { 32 | 33 | Library::Library(const std::vector& names, QWidget* parent) 34 | : QDialog(parent), 35 | ui(std::make_unique()), 36 | files(std::make_unique>()) 37 | { 38 | ui->setupUi(this); 39 | QSettings settings; 40 | restoreGeometry(settings.value("Windows/libraryWindowGeometry").toByteArray()); 41 | 42 | if (settings.contains("Library/lastDirectory")) 43 | { 44 | ui->label_3->setText(settings.value("Library/lastDirectory").toString()); 45 | get_files(settings.value("Library/lastDirectory").toString()); 46 | } 47 | 48 | QFont font(settings.value("Library/FontFamily", ui->listWidget->font().family()).toString(), settings.value("Library/FontSize", ui->listWidget->font().pointSize()).toInt()); 49 | ui->listWidget->setFont(font); 50 | ui->listWidget_2->setFont(font); 51 | 52 | ui->spinBox->setValue(font.pointSize()); 53 | ui->fontComboBox->setCurrentFont(font); 54 | 55 | std::size_t index{1}; 56 | std::for_each(names.cbegin(), names.cend(), [&index, this](const auto& name) 57 | { 58 | ui->listWidget->addItem(QString("[%1] %2").arg(index).arg(QString::fromStdString(name))); 59 | ++index; }); 60 | 61 | connect(ui->listWidget, SIGNAL(currentRowChanged(int)), this, SLOT(load_slot(int))); 62 | connect(ui->listWidget_2, SIGNAL(currentRowChanged(int)), this, SLOT(load_file(int))); 63 | connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(get_directory())); 64 | connect(this, SIGNAL(directory_changed(QString)), ui->label_3, SLOT(setText(QString))); 65 | connect(this, SIGNAL(directory_changed(QString)), this, SLOT(get_files(QString))); 66 | connect(ui->spinBox, SIGNAL(valueChanged(int)), this, SLOT(change_font_size(int))); 67 | connect(ui->fontComboBox, SIGNAL(currentFontChanged(QFont)), this, SLOT(change_font_family(QFont))); 68 | } 69 | 70 | Library::~Library() 71 | { 72 | QSettings settings; 73 | settings.setValue("Windows/libraryWindowGeometry", saveGeometry()); 74 | } 75 | 76 | void Library::load_slot(int slot) 77 | { 78 | ui->listWidget_2->setCurrentRow(-1); 79 | dynamic_cast(parent())->load_from_amp(slot); 80 | } 81 | 82 | void Library::get_directory() 83 | { 84 | QSettings settings; 85 | QString directory = QFileDialog::getExistingDirectory(this, tr("Choose directory"), settings.value("Library/lastDirectory", QDir::homePath()).toString()); 86 | 87 | if (directory.isEmpty()) 88 | { 89 | return; 90 | } 91 | 92 | settings.setValue("Library/lastDirectory", directory); 93 | emit directory_changed(directory); 94 | } 95 | 96 | void Library::get_files(const QString& path) 97 | { 98 | QDir directory(path, "*.fuse", (QDir::Name | QDir::IgnoreCase), (QDir::Files | QDir::NoDotAndDotDot | QDir::Readable)); 99 | 100 | if (!files->isEmpty()) 101 | { 102 | files->clear(); 103 | } 104 | ui->listWidget_2->clear(); 105 | *files = directory.entryInfoList(QDir::Files | QDir::NoDotAndDotDot | QDir::Readable); 106 | for (int i = 0; i < files->size(); ++i) 107 | { 108 | ui->listWidget_2->addItem((*files)[i].completeBaseName()); 109 | } 110 | } 111 | 112 | void Library::load_file(int row) 113 | { 114 | ui->listWidget->setCurrentRow(-1); 115 | dynamic_cast(parent())->loadfile((*files)[row].canonicalFilePath()); 116 | } 117 | 118 | void Library::resizeEvent(QResizeEvent* event) 119 | { 120 | ui->label_3->setMaximumWidth((event->size().width() / 2) - ui->pushButton->size().width()); 121 | } 122 | 123 | void Library::change_font_size(int value) 124 | { 125 | QSettings settings; 126 | QFont font(ui->listWidget_2->font()); 127 | 128 | font.setPointSize(value); 129 | ui->listWidget->setFont(font); 130 | ui->listWidget_2->setFont(font); 131 | 132 | settings.setValue("Library/FontSize", value); 133 | } 134 | 135 | void Library::change_font_family(QFont font) 136 | { 137 | QSettings settings; 138 | 139 | font.setPointSize(ui->spinBox->value()); 140 | ui->listWidget->setFont(font); 141 | ui->listWidget_2->setFont(font); 142 | 143 | settings.setValue("Library/FontFamily", font.family()); 144 | } 145 | } 146 | 147 | #include "ui/moc_library.moc" 148 | -------------------------------------------------------------------------------- /test/IdLookupTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include "com/IdLookup.h" 22 | #include 23 | 24 | namespace plug::test 25 | { 26 | 27 | class IdLookupTest : public testing::Test 28 | { 29 | protected: 30 | }; 31 | 32 | 33 | TEST_F(IdLookupTest, lookupAmpById) 34 | { 35 | EXPECT_EQ(lookupAmpById(0x67), amps::FENDER_57_DELUXE); 36 | EXPECT_EQ(lookupAmpById(0x64), amps::FENDER_59_BASSMAN); 37 | EXPECT_EQ(lookupAmpById(0x7c), amps::FENDER_57_CHAMP); 38 | EXPECT_EQ(lookupAmpById(0x53), amps::FENDER_65_DELUXE_REVERB); 39 | EXPECT_EQ(lookupAmpById(0x6a), amps::FENDER_65_PRINCETON); 40 | EXPECT_EQ(lookupAmpById(0x75), amps::FENDER_65_TWIN_REVERB); 41 | EXPECT_EQ(lookupAmpById(0x72), amps::FENDER_SUPER_SONIC); 42 | EXPECT_EQ(lookupAmpById(0x61), amps::BRITISH_60S); 43 | EXPECT_EQ(lookupAmpById(0x79), amps::BRITISH_70S); 44 | EXPECT_EQ(lookupAmpById(0x5e), amps::BRITISH_80S); 45 | EXPECT_EQ(lookupAmpById(0x5d), amps::AMERICAN_90S); 46 | EXPECT_EQ(lookupAmpById(0x6d), amps::METAL_2000); 47 | 48 | EXPECT_EQ(lookupAmpById(0xf1), amps::STUDIO_PREAMP); 49 | EXPECT_EQ(lookupAmpById(0xf6), amps::FENDER_57_TWIN); 50 | EXPECT_EQ(lookupAmpById(0xf9), amps::FENDER_60_THRIFT); 51 | EXPECT_EQ(lookupAmpById(0xfc), amps::BRITISH_COLOUR); 52 | EXPECT_EQ(lookupAmpById(0xff), amps::BRITISH_WATTS); 53 | } 54 | 55 | TEST_F(IdLookupTest, lookupAmpByIdThrowsOnInvalidId) 56 | { 57 | EXPECT_THROW(lookupAmpById(0x00), std::invalid_argument); 58 | } 59 | 60 | TEST_F(IdLookupTest, lookupEffectById) 61 | { 62 | EXPECT_EQ(lookupEffectById(0x00), effects::EMPTY); 63 | EXPECT_EQ(lookupEffectById(0x3c), effects::OVERDRIVE); 64 | EXPECT_EQ(lookupEffectById(0x49), effects::WAH); 65 | EXPECT_EQ(lookupEffectById(0x4a), effects::TOUCH_WAH); 66 | EXPECT_EQ(lookupEffectById(0x1a), effects::FUZZ); 67 | EXPECT_EQ(lookupEffectById(0x1c), effects::FUZZ_TOUCH_WAH); 68 | EXPECT_EQ(lookupEffectById(0x88), effects::SIMPLE_COMP); 69 | EXPECT_EQ(lookupEffectById(0x07), effects::COMPRESSOR); 70 | EXPECT_EQ(lookupEffectById(0x12), effects::SINE_CHORUS); 71 | EXPECT_EQ(lookupEffectById(0x13), effects::TRIANGLE_CHORUS); 72 | EXPECT_EQ(lookupEffectById(0x18), effects::SINE_FLANGER); 73 | EXPECT_EQ(lookupEffectById(0x19), effects::TRIANGLE_FLANGER); 74 | EXPECT_EQ(lookupEffectById(0x2d), effects::VIBRATONE); 75 | EXPECT_EQ(lookupEffectById(0x40), effects::VINTAGE_TREMOLO); 76 | EXPECT_EQ(lookupEffectById(0x41), effects::SINE_TREMOLO); 77 | EXPECT_EQ(lookupEffectById(0x22), effects::RING_MODULATOR); 78 | EXPECT_EQ(lookupEffectById(0x29), effects::STEP_FILTER); 79 | EXPECT_EQ(lookupEffectById(0x4f), effects::PHASER); 80 | EXPECT_EQ(lookupEffectById(0x1f), effects::PITCH_SHIFTER); 81 | EXPECT_EQ(lookupEffectById(0x16), effects::MONO_DELAY); 82 | EXPECT_EQ(lookupEffectById(0x43), effects::MONO_ECHO_FILTER); 83 | EXPECT_EQ(lookupEffectById(0x48), effects::STEREO_ECHO_FILTER); 84 | EXPECT_EQ(lookupEffectById(0x44), effects::MULTITAP_DELAY); 85 | EXPECT_EQ(lookupEffectById(0x45), effects::PING_PONG_DELAY); 86 | EXPECT_EQ(lookupEffectById(0x15), effects::DUCKING_DELAY); 87 | EXPECT_EQ(lookupEffectById(0x46), effects::REVERSE_DELAY); 88 | EXPECT_EQ(lookupEffectById(0x2b), effects::TAPE_DELAY); 89 | EXPECT_EQ(lookupEffectById(0x2a), effects::STEREO_TAPE_DELAY); 90 | EXPECT_EQ(lookupEffectById(0x24), effects::SMALL_HALL_REVERB); 91 | EXPECT_EQ(lookupEffectById(0x3a), effects::LARGE_HALL_REVERB); 92 | EXPECT_EQ(lookupEffectById(0x26), effects::SMALL_ROOM_REVERB); 93 | EXPECT_EQ(lookupEffectById(0x3b), effects::LARGE_ROOM_REVERB); 94 | EXPECT_EQ(lookupEffectById(0x4e), effects::SMALL_PLATE_REVERB); 95 | EXPECT_EQ(lookupEffectById(0x4b), effects::LARGE_PLATE_REVERB); 96 | EXPECT_EQ(lookupEffectById(0x4c), effects::AMBIENT_REVERB); 97 | EXPECT_EQ(lookupEffectById(0x4d), effects::ARENA_REVERB); 98 | EXPECT_EQ(lookupEffectById(0x21), effects::FENDER_63_SPRING_REVERB); 99 | EXPECT_EQ(lookupEffectById(0x0b), effects::FENDER_65_SPRING_REVERB); 100 | } 101 | 102 | TEST_F(IdLookupTest, lookupEffectByIdThrowsOnInvalidId) 103 | { 104 | EXPECT_THROW(lookupEffectById(0xff), std::invalid_argument); 105 | } 106 | 107 | TEST_F(IdLookupTest, lookupCabinetById) 108 | { 109 | EXPECT_EQ(lookupCabinetById(0x00), cabinets::OFF); 110 | EXPECT_EQ(lookupCabinetById(0x01), cabinets::cab57DLX); 111 | EXPECT_EQ(lookupCabinetById(0x02), cabinets::cabBSSMN); 112 | EXPECT_EQ(lookupCabinetById(0x03), cabinets::cab65DLX); 113 | EXPECT_EQ(lookupCabinetById(0x04), cabinets::cab65PRN); 114 | EXPECT_EQ(lookupCabinetById(0x05), cabinets::cabCHAMP); 115 | EXPECT_EQ(lookupCabinetById(0x06), cabinets::cab4x12M); 116 | EXPECT_EQ(lookupCabinetById(0x07), cabinets::cab2x12C); 117 | EXPECT_EQ(lookupCabinetById(0x08), cabinets::cab4x12G); 118 | EXPECT_EQ(lookupCabinetById(0x09), cabinets::cab65TWN); 119 | EXPECT_EQ(lookupCabinetById(0x0a), cabinets::cab4x12V); 120 | EXPECT_EQ(lookupCabinetById(0x0b), cabinets::cabSS212); 121 | EXPECT_EQ(lookupCabinetById(0x0c), cabinets::cabSS112); 122 | } 123 | 124 | TEST_F(IdLookupTest, lookupCabinetByIdThrowsOnInvalidId) 125 | { 126 | EXPECT_THROW(lookupCabinetById(0xff), std::invalid_argument); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/ui/library.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Library 4 | 5 | 6 | 7 | 0 8 | 0 9 | 480 10 | 550 11 | 12 | 13 | 14 | PLUG Library 15 | 16 | 17 | Library window 18 | 19 | 20 | Allows to quickly load presets from amplifier and files 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | &Amplifier: 31 | 32 | 33 | listWidget 34 | 35 | 36 | 37 | 38 | 39 | 40 | Presets from amplifier 41 | 42 | 43 | This list shows presets on ampplifier 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | &Files from: 55 | 56 | 57 | listWidget_2 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 0 68 | 0 69 | 70 | 71 | 72 | [choose directory] 73 | 74 | 75 | Qt::TextSelectableByMouse 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 0 84 | 0 85 | 86 | 87 | 88 | Choose directory 89 | 90 | 91 | Choose directory where preset files are stored 92 | 93 | 94 | &... 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | Presets from files 104 | 105 | 106 | This list shows presets from files 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | Qt::Horizontal 120 | 121 | 122 | 123 | 40 124 | 20 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | F&ont 133 | 134 | 135 | fontComboBox 136 | 137 | 138 | 139 | 140 | 141 | 142 | Choose font 143 | 144 | 145 | Allows to choose font which will be used to display presets 146 | 147 | 148 | 149 | 150 | 151 | 152 | &Size 153 | 154 | 155 | spinBox 156 | 157 | 158 | 159 | 160 | 161 | 162 | Choose font size 163 | 164 | 165 | Allows to choose font size which will be used to display presets 166 | 167 | 168 | 32 169 | 170 | 171 | 172 | 173 | 174 | 175 | Qt::Horizontal 176 | 177 | 178 | 179 | 40 180 | 20 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | pushButton 191 | listWidget 192 | listWidget_2 193 | 194 | 195 | 196 | 197 | -------------------------------------------------------------------------------- /src/com/MustangUpdater.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #include "com/MustangUpdater.h" 23 | #include "com/Mustang.h" 24 | #include "com/Packet.h" 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace plug::com 32 | { 33 | namespace 34 | { 35 | // amp's VID and PID while in update mode 36 | inline constexpr std::uint16_t USB_UPDATE_VID{0x1ed8}; 37 | inline constexpr std::uint16_t SMALL_AMPS_USB_UPDATE_PID{0x0006}; // Mustang I and II 38 | inline constexpr std::uint16_t BIG_AMPS_USB_UPDATE_PID{0x0007}; // Mustang III, IV, V 39 | inline constexpr std::uint16_t MINI_USB_UPDATE_PID{0x0011}; // Mustang Mini 40 | inline constexpr std::uint16_t FLOOR_USB_UPDATE_PID{0x0013}; // Mustang Floor 41 | inline constexpr std::uint16_t SMALL_AMPS_V2_USB_UPDATE_PID{0x0015}; // Mustang I & II V2 42 | inline constexpr std::uint16_t BIG_AMPS_V2_USB_UPDATE_PID{0x0017}; // Mustang III+ V2 43 | } 44 | 45 | namespace 46 | { 47 | void closeUsb(libusb_device_handle* handle) 48 | { 49 | if (handle != nullptr) 50 | { 51 | const int ret = libusb_release_interface(handle, 0); 52 | 53 | if (ret != LIBUSB_ERROR_NO_DEVICE) 54 | { 55 | libusb_attach_kernel_driver(handle, 0); 56 | } 57 | 58 | libusb_close(handle); 59 | libusb_exit(nullptr); 60 | } 61 | } 62 | 63 | 64 | inline constexpr std::chrono::milliseconds timeout{500}; 65 | inline constexpr std::size_t sizeOfPacket = packetRawTypeSize; 66 | } 67 | 68 | 69 | int updateFirmware(const char* filename) 70 | { 71 | // initialize libusb 72 | int ret = libusb_init(nullptr); 73 | if (ret != 0) 74 | { 75 | return ret; 76 | } 77 | 78 | // get handle for the device 79 | libusb_device_handle* amp_hand = libusb_open_device_with_vid_pid(nullptr, USB_UPDATE_VID, SMALL_AMPS_USB_UPDATE_PID); 80 | if (amp_hand == nullptr) 81 | { 82 | amp_hand = libusb_open_device_with_vid_pid(nullptr, USB_UPDATE_VID, BIG_AMPS_USB_UPDATE_PID); 83 | if (amp_hand == nullptr) 84 | { 85 | amp_hand = libusb_open_device_with_vid_pid(nullptr, USB_UPDATE_VID, SMALL_AMPS_V2_USB_UPDATE_PID); 86 | if (amp_hand == nullptr) 87 | { 88 | amp_hand = libusb_open_device_with_vid_pid(nullptr, USB_UPDATE_VID, BIG_AMPS_V2_USB_UPDATE_PID); 89 | if (amp_hand == nullptr) 90 | { 91 | amp_hand = libusb_open_device_with_vid_pid(nullptr, USB_UPDATE_VID, MINI_USB_UPDATE_PID); 92 | if (amp_hand == nullptr) 93 | { 94 | amp_hand = libusb_open_device_with_vid_pid(nullptr, USB_UPDATE_VID, FLOOR_USB_UPDATE_PID); 95 | if (amp_hand == nullptr) 96 | { 97 | libusb_exit(nullptr); 98 | return -100; 99 | } 100 | } 101 | } 102 | } 103 | } 104 | } 105 | 106 | // detach kernel driver 107 | ret = libusb_kernel_driver_active(amp_hand, 0); 108 | if (ret != 0) 109 | { 110 | ret = libusb_detach_kernel_driver(amp_hand, 0); 111 | if (ret != 0) 112 | { 113 | closeUsb(amp_hand); 114 | return ret; 115 | } 116 | } 117 | 118 | // claim the device 119 | ret = libusb_claim_interface(amp_hand, 0); 120 | if (ret != 0) 121 | { 122 | closeUsb(amp_hand); 123 | return ret; 124 | } 125 | 126 | FILE* file = fopen(filename, "rb"); 127 | // send date when firmware was created 128 | fseek(file, 0x1a, SEEK_SET); 129 | unsigned char array[sizeOfPacket]; 130 | memset(array, 0x00, sizeOfPacket); 131 | array[0] = 0x02; 132 | array[1] = 0x03; 133 | array[2] = 0x01; 134 | array[3] = 0x06; 135 | [[maybe_unused]] const auto n = fread(array + 4, 1, 11, file); 136 | int recieved{0}; 137 | ret = libusb_interrupt_transfer(amp_hand, 0x01, array, sizeOfPacket, &recieved, timeout.count()); 138 | libusb_interrupt_transfer(amp_hand, 0x81, array, sizeOfPacket, &recieved, timeout.count()); 139 | usleep(10000); 140 | 141 | // send firmware 142 | fseek(file, 0x110, SEEK_SET); 143 | for (;;) 144 | { 145 | memset(array, 0x00, sizeOfPacket); 146 | unsigned char number{0}; 147 | array[0] = array[1] = 0x03; 148 | array[2] = number; 149 | ++number; 150 | array[3] = static_cast(fread(array + 4, 1, sizeOfPacket - 8, file)); 151 | ret = libusb_interrupt_transfer(amp_hand, 0x01, array, sizeOfPacket, &recieved, timeout.count()); 152 | libusb_interrupt_transfer(amp_hand, 0x81, array, sizeOfPacket, &recieved, timeout.count()); 153 | usleep(10000); 154 | 155 | if (feof(file) != 0) // if reached end of the file 156 | { 157 | break; // exit loop 158 | } 159 | } 160 | fclose(file); 161 | 162 | // send "finished" packet 163 | memset(array, 0x00, sizeOfPacket); 164 | array[0] = 0x04; 165 | array[1] = 0x03; 166 | libusb_interrupt_transfer(amp_hand, 0x01, array, sizeOfPacket, &recieved, timeout.count()); 167 | libusb_interrupt_transfer(amp_hand, 0x81, array, sizeOfPacket, &recieved, timeout.count()); 168 | 169 | closeUsb(amp_hand); 170 | 171 | return 0; 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /include/com/IdLookup.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "effects_enum.h" 24 | #include 25 | #include 26 | #include 27 | 28 | namespace plug 29 | { 30 | 31 | constexpr amps lookupAmpById(std::uint8_t id) 32 | { 33 | switch (id) 34 | { 35 | case 0x67: 36 | return amps::FENDER_57_DELUXE; 37 | case 0x64: 38 | return amps::FENDER_59_BASSMAN; 39 | case 0x7c: 40 | return amps::FENDER_57_CHAMP; 41 | case 0x53: 42 | return amps::FENDER_65_DELUXE_REVERB; 43 | case 0x6a: 44 | return amps::FENDER_65_PRINCETON; 45 | case 0x75: 46 | return amps::FENDER_65_TWIN_REVERB; 47 | case 0x72: 48 | return amps::FENDER_SUPER_SONIC; 49 | case 0x61: 50 | return amps::BRITISH_60S; 51 | case 0x79: 52 | return amps::BRITISH_70S; 53 | case 0x5e: 54 | return amps::BRITISH_80S; 55 | case 0x5d: 56 | return amps::AMERICAN_90S; 57 | case 0x6d: 58 | return amps::METAL_2000; 59 | case 0xf1: 60 | return amps::STUDIO_PREAMP; 61 | case 0xf6: 62 | return amps::FENDER_57_TWIN; 63 | case 0xf9: 64 | return amps::FENDER_60_THRIFT; 65 | case 0xfc: 66 | return amps::BRITISH_COLOUR; 67 | case 0xff: 68 | return amps::BRITISH_WATTS; 69 | default: 70 | throw std::invalid_argument{"Invalid amp id: " + std::to_string(id)}; 71 | } 72 | } 73 | 74 | 75 | constexpr effects lookupEffectById(std::uint8_t id) 76 | { 77 | switch (id) 78 | { 79 | case 0x00: 80 | return effects::EMPTY; 81 | case 0x3c: 82 | return effects::OVERDRIVE; 83 | case 0x49: 84 | return effects::WAH; 85 | case 0x4a: 86 | return effects::TOUCH_WAH; 87 | case 0x1a: 88 | return effects::FUZZ; 89 | case 0x1c: 90 | return effects::FUZZ_TOUCH_WAH; 91 | case 0x88: 92 | return effects::SIMPLE_COMP; 93 | case 0x07: 94 | return effects::COMPRESSOR; 95 | case 0x12: 96 | return effects::SINE_CHORUS; 97 | case 0x13: 98 | return effects::TRIANGLE_CHORUS; 99 | case 0x18: 100 | return effects::SINE_FLANGER; 101 | case 0x19: 102 | return effects::TRIANGLE_FLANGER; 103 | case 0x2d: 104 | return effects::VIBRATONE; 105 | case 0x40: 106 | return effects::VINTAGE_TREMOLO; 107 | case 0x41: 108 | return effects::SINE_TREMOLO; 109 | case 0x22: 110 | return effects::RING_MODULATOR; 111 | case 0x29: 112 | return effects::STEP_FILTER; 113 | case 0x4f: 114 | return effects::PHASER; 115 | case 0x1f: 116 | return effects::PITCH_SHIFTER; 117 | case 0x16: 118 | return effects::MONO_DELAY; 119 | case 0x43: 120 | return effects::MONO_ECHO_FILTER; 121 | case 0x48: 122 | return effects::STEREO_ECHO_FILTER; 123 | case 0x44: 124 | return effects::MULTITAP_DELAY; 125 | case 0x45: 126 | return effects::PING_PONG_DELAY; 127 | case 0x15: 128 | return effects::DUCKING_DELAY; 129 | case 0x46: 130 | return effects::REVERSE_DELAY; 131 | case 0x2b: 132 | return effects::TAPE_DELAY; 133 | case 0x2a: 134 | return effects::STEREO_TAPE_DELAY; 135 | case 0x24: 136 | return effects::SMALL_HALL_REVERB; 137 | case 0x3a: 138 | return effects::LARGE_HALL_REVERB; 139 | case 0x26: 140 | return effects::SMALL_ROOM_REVERB; 141 | case 0x3b: 142 | return effects::LARGE_ROOM_REVERB; 143 | case 0x4e: 144 | return effects::SMALL_PLATE_REVERB; 145 | case 0x4b: 146 | return effects::LARGE_PLATE_REVERB; 147 | case 0x4c: 148 | return effects::AMBIENT_REVERB; 149 | case 0x4d: 150 | return effects::ARENA_REVERB; 151 | case 0x21: 152 | return effects::FENDER_63_SPRING_REVERB; 153 | case 0x0b: 154 | return effects::FENDER_65_SPRING_REVERB; 155 | default: 156 | throw std::invalid_argument{"Invalid effect id: " + std::to_string(id)}; 157 | } 158 | } 159 | 160 | 161 | constexpr cabinets lookupCabinetById(std::uint8_t id) 162 | { 163 | switch (id) 164 | { 165 | case 0x00: 166 | return cabinets::OFF; 167 | case 0x01: 168 | return cabinets::cab57DLX; 169 | case 0x02: 170 | return cabinets::cabBSSMN; 171 | case 0x03: 172 | return cabinets::cab65DLX; 173 | case 0x04: 174 | return cabinets::cab65PRN; 175 | case 0x05: 176 | return cabinets::cabCHAMP; 177 | case 0x06: 178 | return cabinets::cab4x12M; 179 | case 0x07: 180 | return cabinets::cab2x12C; 181 | case 0x08: 182 | return cabinets::cab4x12G; 183 | case 0x09: 184 | return cabinets::cab65TWN; 185 | case 0x0a: 186 | return cabinets::cab4x12V; 187 | case 0x0b: 188 | return cabinets::cabSS212; 189 | case 0x0c: 190 | return cabinets::cabSS112; 191 | default: 192 | throw std::invalid_argument{"Invalid cabinet id: " + std::to_string(id)}; 193 | } 194 | } 195 | 196 | } 197 | -------------------------------------------------------------------------------- /src/com/Mustang.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PLUG - software to operate Fender Mustang amplifier 3 | * Linux replacement for Fender FUSE software 4 | * 5 | * Copyright (C) 2017-2025 offa 6 | * Copyright (C) 2010-2016 piorekf 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #include "com/Mustang.h" 23 | #include "com/PacketSerializer.h" 24 | #include "com/CommunicationException.h" 25 | #include "com/Packet.h" 26 | #include 27 | 28 | namespace plug::com 29 | { 30 | SignalChain decode_data(const std::array& data) 31 | { 32 | const auto name = decodeNameFromData(fromRawData(data[0])); 33 | const auto amp = decodeAmpFromData(fromRawData(data[1]), fromRawData(data[6])); 34 | const auto effects = decodeEffectsFromData({{fromRawData(data[2]), fromRawData(data[3]), 35 | fromRawData(data[4]), fromRawData(data[5])}}); 36 | 37 | return SignalChain{name, amp, effects}; 38 | } 39 | 40 | std::vector receivePacket(Connection& conn) 41 | { 42 | return conn.receive(packetRawTypeSize); 43 | } 44 | 45 | 46 | void sendCommand(Connection& conn, const PacketRawType& packet) 47 | { 48 | conn.send(packet); 49 | receivePacket(conn); 50 | } 51 | 52 | void sendApplyCommand(Connection& conn) 53 | { 54 | sendCommand(conn, serializeApplyCommand().getBytes()); 55 | } 56 | 57 | std::array loadBankData(Connection& conn, std::uint8_t slot) 58 | { 59 | std::array data{{}}; 60 | 61 | const auto loadCommand = serializeLoadSlotCommand(slot); 62 | auto n = conn.send(loadCommand.getBytes()); 63 | 64 | for (std::size_t i = 0; n != 0; ++i) 65 | { 66 | const auto recvData = receivePacket(conn); 67 | n = recvData.size(); 68 | 69 | if (i < 7) 70 | { 71 | std::copy(recvData.cbegin(), recvData.cend(), data[i].begin()); 72 | } 73 | } 74 | return data; 75 | } 76 | 77 | 78 | Mustang::Mustang(DeviceModel deviceModel, std::shared_ptr connection) 79 | : model(deviceModel), conn(connection) 80 | { 81 | } 82 | 83 | InitialData Mustang::start_amp() 84 | { 85 | if (conn->isOpen() == false) 86 | { 87 | throw CommunicationException{"Device not connected"}; 88 | } 89 | 90 | initializeAmp(); 91 | 92 | return loadData(); 93 | } 94 | 95 | void Mustang::stop_amp() 96 | { 97 | conn->close(); 98 | } 99 | 100 | void Mustang::set_effect(fx_pedal_settings value) 101 | { 102 | const auto clearEffectPacket = serializeClearEffectSettings(value); 103 | sendCommand(*conn, clearEffectPacket.getBytes()); 104 | sendApplyCommand(*conn); 105 | 106 | if ((value.enabled == true) && (value.effect_num != effects::EMPTY)) 107 | { 108 | const auto settingsPacket = serializeEffectSettings(value); 109 | sendCommand(*conn, settingsPacket.getBytes()); 110 | sendApplyCommand(*conn); 111 | } 112 | } 113 | 114 | void Mustang::set_amplifier(amp_settings value) 115 | { 116 | const auto settingsPacket = serializeAmpSettings(value); 117 | sendCommand(*conn, settingsPacket.getBytes()); 118 | sendApplyCommand(*conn); 119 | 120 | const auto settingsGainPacket = serializeAmpSettingsUsbGain(value); 121 | sendCommand(*conn, settingsGainPacket.getBytes()); 122 | sendApplyCommand(*conn); 123 | } 124 | 125 | void Mustang::save_on_amp(std::string_view name, std::uint8_t slot) 126 | { 127 | const auto data = serializeName(slot, name).getBytes(); 128 | sendCommand(*conn, data); 129 | loadBankData(*conn, slot); 130 | } 131 | 132 | SignalChain Mustang::load_memory_bank(std::uint8_t slot) 133 | { 134 | return decode_data(loadBankData(*conn, slot)); 135 | } 136 | 137 | void Mustang::save_effects(std::uint8_t slot, std::string_view name, const std::vector& effects) 138 | { 139 | const auto saveNamePacket = serializeSaveEffectName(slot, name, effects); 140 | sendCommand(*conn, saveNamePacket.getBytes()); 141 | 142 | const auto packets = serializeSaveEffectPacket(slot, effects); 143 | std::for_each(packets.cbegin(), packets.cend(), [this](const auto& p) 144 | { sendCommand(*conn, p.getBytes()); }); 145 | 146 | sendCommand(*conn, serializeApplyCommand(effects[0]).getBytes()); 147 | } 148 | 149 | DeviceModel Mustang::getDeviceModel() const 150 | { 151 | return model; 152 | } 153 | 154 | 155 | InitialData Mustang::loadData() 156 | { 157 | std::vector> recieved_data; 158 | 159 | const auto loadCommand = serializeLoadCommand(); 160 | auto recieved = conn->send(loadCommand.getBytes()); 161 | 162 | while (recieved != 0) 163 | { 164 | const auto recvData = receivePacket(*conn); 165 | recieved = recvData.size(); 166 | PacketRawType p{}; 167 | std::copy(recvData.cbegin(), recvData.cend(), p.begin()); 168 | recieved_data.push_back(p); 169 | } 170 | 171 | const std::size_t numPresetPackets = model.numberOfPresets() > 0 ? (model.numberOfPresets() * 2) : (recieved_data.size() > 143 ? 200 : 48); 172 | std::vector> presetListData; 173 | presetListData.reserve(numPresetPackets); 174 | std::transform(recieved_data.cbegin(), std::next(recieved_data.cbegin(), numPresetPackets), std::back_inserter(presetListData), [](const auto& p) 175 | { 176 | Packet packet{}; 177 | packet.fromBytes(p); 178 | return packet; }); 179 | auto presetNames = decodePresetListFromData(presetListData); 180 | 181 | std::array presetData{{}}; 182 | std::copy(std::next(recieved_data.cbegin(), numPresetPackets), std::next(recieved_data.cbegin(), numPresetPackets + 7), presetData.begin()); 183 | 184 | return {decode_data(presetData), presetNames}; 185 | } 186 | 187 | void Mustang::initializeAmp() 188 | { 189 | const auto packets = serializeInitCommand(); 190 | std::for_each(packets.cbegin(), packets.cend(), [this](const auto& p) 191 | { sendCommand(*conn, p.getBytes()); }); 192 | } 193 | } 194 | --------------------------------------------------------------------------------