diff --git a/.appveyor.yml b/.appveyor.yml index 3b632d1f3..7ca7d58c4 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -19,5 +19,9 @@ build_script: - cmake -DUSE_COMPILE_CACHE=ON -DCACHE_TOOL=%APPVEYOR_BUILD_FOLDER%/clcache.4.1.0/clcache-4.1.0/clcache.exe -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_PREFIX_PATH=c:/Qt/5.12/msvc2017%QT_SUFFIX%;c:/tools/vcpkg/installed/%PLATFORM%-windows -DCMAKE_GENERATOR_PLATFORM="%CMAKE_PLATFORM%" .. - cmake --build . -- /maxcpucount:4 - cmake --build . --target tests + - cmake --build . --target package +artifacts: + - path: 'build\lmms-*.exe' + name: Installer cache: - c:/tools/vcpkg/installed diff --git a/.circleci/config.yml b/.circleci/config.yml index 4174ba1ef..a3be541b5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,6 +12,18 @@ shared: key: ccache-{{ arch }}-{{ .Environment.CIRCLE_JOB }}-{{ .Branch }}-{{ .BuildNum }} paths: - ~/.ccache + restore_homebrew_cache: &restore_homebrew_cache + restore_cache: + keys: + - homebrew-{{ arch }}-{{ .Environment.CIRCLE_JOB }}-{{ .Branch }} + - homebrew-{{ arch }}-{{ .Environment.CIRCLE_JOB }} + - homebrew-{{ arch }} + save_homebrew_cache: &save_homebrew_cache + save_cache: + key: homebrew-{{ arch }}-{{ .Environment.CIRCLE_JOB }}-{{ .Branch }}-{{ .BuildNum }} + paths: + - ~/Library/Caches/Homebrew + - /usr/local/Homebrew ccache_stats: &ccache_stats run: @@ -30,6 +42,14 @@ shared: mkdir -p /tmp/artifacts # Workaround for failing submodule fetching git config --global --unset url."ssh://git@github.com".insteadOf || true + if [[ -n "${CIRCLE_PR_NUMBER}" ]] + then + echo "Fetching out merged pull request" + git fetch -u origin refs/pull/${CIRCLE_PR_NUMBER}/merge:pr/merge + git checkout pr/merge + else + echo "Not a pull request" + fi # Commmon environment variables common_environment: &common_environment @@ -59,6 +79,15 @@ jobs: - run: name: Build tests command: cd build && make tests + - run: + name: Build installer + command: | + cd build + make package + cp ./lmms-*.exe /tmp/artifacts/ + - store_artifacts: + path: /tmp/artifacts/ + destination: / - *ccache_stats - *save_cache mingw64: @@ -79,11 +108,20 @@ jobs: - run: name: Build tests command: cd build && make tests + - run: + name: Build installer + command: | + cd build + make package + cp ./lmms-*.exe /tmp/artifacts/ + - store_artifacts: + path: /tmp/artifacts/ + destination: / - *ccache_stats - *save_cache linux.gcc: docker: - - image: lmmsci/linux.gcc:18.04 + - image: lmmsci/linux.gcc:16.04 environment: <<: *common_environment steps: @@ -92,7 +130,10 @@ jobs: - *restore_cache - run: name: Configure - command: mkdir build && cd build && cmake .. $CMAKE_OPTS -DCMAKE_INSTALL_PREFIX=./install + command: | + source /opt/qt5*/bin/qt5*-env.sh || true + mkdir build && cd build + cmake .. $CMAKE_OPTS -DCMAKE_INSTALL_PREFIX=./install - run: name: Build command: cd build && make @@ -125,10 +166,53 @@ jobs: - run: name: Shellcheck command: shellcheck $(find "./cmake/" -type f -name '*.sh' -o -name "*.sh.in") + macos: + environment: + <<: *common_environment + macos: + xcode: "9.3.1" + steps: + - checkout + - *init + - *restore_homebrew_cache + - *restore_cache + - run: + name: Install Homebrew dependencies + command: brew update && brew install ccache fftw cmake pkg-config libogg libvorbis lame libsndfile libsamplerate jack sdl libgig libsoundio stk fluid-synth portaudio fltk qt5 carla + - run: + name: Install nodejs dependencies + command: npm install -g appdmg + - run: + name: Building + command: | + mkdir build && cd build + cmake .. -DCMAKE_INSTALL_PREFIX="../target" -DCMAKE_PREFIX_PATH="$(brew --prefix qt5)" $CMAKE_OPTS -DUSE_WERROR=OFF + make + - run: + name: Build tests + command: cd build && make tests + - run: + name: Run tests + command: build/tests/tests + - run: + name: Build DMG + command: | + cd build + make install + make dmg + cp ./lmms-*.dmg /tmp/artifacts/ + - store_artifacts: + path: /tmp/artifacts/ + destination: / + - *save_cache + - *save_homebrew_cache + + workflows: version: 2 build-and-test: jobs: + - macos - mingw32 - mingw64 - linux.gcc diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..2c22146ae --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,30 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +# Please search the issue tracker for existing bug reports before submitting your own. Delete this line to confirm no similar report has been posted yet. + +### Bug Summary + +#### Steps to reproduce + +#### Expected behavior + +#### Actual behavior + +#### Screenshot + +#### LMMS version used + +#### Logs +
+ Click to expand +
+
+
+
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..2c51f276e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,4 @@ +contact_links: +- name: Get help on Discord + url: https://lmms.io/chat/ + about: Need help? Have a question? Reach out to other LMMS users on our Discord server! diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..f9a0ae192 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,18 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +# Please search the issue tracker for existing feature requests before submitting your own. Delete this line to confirm no similar request has been posted yet. + +### Enhancement Summary + +#### Justification + +#### Mockup + + diff --git a/.gitmodules b/.gitmodules index 28d6c5d46..56b7f3eab 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,3 +34,6 @@ [submodule "doc/wiki"] path = doc/wiki url = https://github.com/lmms/lmms.wiki.git +[submodule "src/3rdparty/ringbuffer"] + path = src/3rdparty/ringbuffer + url = https://github.com/JohannesLorenz/ringbuffer.git diff --git a/.mailmap b/.mailmap index 71b6697c8..14d4754ce 100644 --- a/.mailmap +++ b/.mailmap @@ -29,3 +29,5 @@ grejppi Johannes Lorenz Johannes Lorenz <1042576+JohannesLorenz@users.noreply.github.com> Noah Brecht +Olivier Humbert +Hussam al-Homsi Hussam Eddin Alhomsi diff --git a/.travis.yml b/.travis.yml index b3cb8aa7c..f94aa0846 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,6 @@ matrix: include: - env: TYPE=style - os: linux - - env: TARGET_OS=win32 - - env: TARGET_OS=win64 - env: TARGET_OS=debian-sid TARGET_DEPLOY=True git: depth: false @@ -24,7 +22,7 @@ matrix: git: depth: false - os: osx - osx_image: xcode8.3 + osx_image: xcode9.4 before_install: # appdmg doesn't work with old Node.js - if [ "$TRAVIS_OS_NAME" = osx ]; then nvm install 10; fi diff --git a/.travis/script.sh b/.travis/script.sh index 70391a762..b723f5dd0 100755 --- a/.travis/script.sh +++ b/.travis/script.sh @@ -42,5 +42,7 @@ else fi echo "Uploading $PACKAGE to transfer.sh..." - curl --upload-file "$PACKAGE" "https://transfer.sh/$PACKAGE" || true + # Limit the connection time to 3 minutes and total upload time to 5 minutes + # Otherwise the build may hang + curl --connect-timeout 180 --max-time 300 --upload-file "$PACKAGE" "https://transfer.sh/$PACKAGE" || true fi diff --git a/CMakeLists.txt b/CMakeLists.txt index bd9d376e2..2f310d27c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,8 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.3) PROJECT(lmms) SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules" ${CMAKE_MODULE_PATH}) +SET(LMMS_BINARY_DIR ${CMAKE_BINARY_DIR}) +SET(LMMS_SOURCE_DIR ${CMAKE_SOURCE_DIR}) IF(COMMAND CMAKE_POLICY) CMAKE_POLICY(SET CMP0005 NEW) @@ -13,8 +15,10 @@ IF(COMMAND CMAKE_POLICY) CMAKE_POLICY(SET CMP0050 OLD) ENDIF() CMAKE_POLICY(SET CMP0020 NEW) + CMAKE_POLICY(SET CMP0057 NEW) ENDIF(COMMAND CMAKE_POLICY) +INCLUDE(PluginList) INCLUDE(CheckSubmodules) INCLUDE(AddFileDependencies) INCLUDE(CheckIncludeFiles) @@ -32,7 +36,7 @@ SET(PROJECT_DESCRIPTION "${PROJECT_NAME_UCASE} - Free music production software" SET(PROJECT_COPYRIGHT "2008-${PROJECT_YEAR} ${PROJECT_AUTHOR}") SET(VERSION_MAJOR "1") SET(VERSION_MINOR "2") -SET(VERSION_RELEASE "0") +SET(VERSION_RELEASE "1") SET(VERSION_STAGE "") SET(VERSION_BUILD "0") SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_RELEASE}") @@ -140,7 +144,7 @@ CHECK_INCLUDE_FILES(locale.h LMMS_HAVE_LOCALE_H) LIST(APPEND CMAKE_PREFIX_PATH "${CMAKE_INSTALL_PREFIX}") -FIND_PACKAGE(Qt5 COMPONENTS Core Gui Widgets Xml REQUIRED) +FIND_PACKAGE(Qt5 5.6.0 COMPONENTS Core Gui Widgets Xml REQUIRED) FIND_PACKAGE(Qt5 COMPONENTS LinguistTools QUIET) INCLUDE_DIRECTORIES( @@ -434,9 +438,9 @@ If(WANT_GIG) ENDIF(WANT_GIG) # check for pthreads -IF(LMMS_BUILD_LINUX OR LMMS_BUILD_APPLE OR LMMS_BUILD_OPENBSD) +IF(LMMS_BUILD_LINUX OR LMMS_BUILD_APPLE OR LMMS_BUILD_OPENBSD OR LMMS_BUILD_FREEBSD) FIND_PACKAGE(Threads) -ENDIF(LMMS_BUILD_LINUX OR LMMS_BUILD_APPLE OR LMMS_BUILD_OPENBSD) +ENDIF(LMMS_BUILD_LINUX OR LMMS_BUILD_APPLE OR LMMS_BUILD_OPENBSD OR LMMS_BUILD_FREEBSD) # check for sndio (roaraudio won't work yet) IF(WANT_SNDIO) @@ -565,8 +569,8 @@ ADD_SUBDIRECTORY(tests) ADD_SUBDIRECTORY(data) ADD_SUBDIRECTORY(doc) -# post-install tasks -ADD_SUBDIRECTORY(cmake/postinstall) +# install tasks +ADD_SUBDIRECTORY(cmake/install) ADD_CUSTOM_COMMAND(OUTPUT "${CMAKE_BINARY_DIR}/lmms.1.gz" COMMAND gzip -c ${CMAKE_SOURCE_DIR}/doc/lmms.1 > ${CMAKE_BINARY_DIR}/lmms.1.gz @@ -706,4 +710,9 @@ MESSAGE( "\n\n") SET(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION "${BIN_DIR}") +if(MSVC) + # We can't set this on the install time according to the configuration + SET(CMAKE_INSTALL_DEBUG_LIBRARIES TRUE) + SET(CMAKE_INSTALL_UCRT_LIBRARIES TRUE) +endif() INCLUDE(InstallRequiredSystemLibraries) diff --git a/cmake/install/CMakeLists.txt b/cmake/install/CMakeLists.txt new file mode 100644 index 000000000..a3a81beeb --- /dev/null +++ b/cmake/install/CMakeLists.txt @@ -0,0 +1,41 @@ +SET(PLUGIN_FILES "") +IF(LMMS_BUILD_WIN32) + INSTALL(FILES $ DESTINATION platforms) +ENDIF() + +IF(LMMS_BUILD_WIN32 OR LMMS_INSTALL_DEPENDENCIES) + include(InstallTargetDependencies) + + # Collect directories to search for DLLs + GET_FILENAME_COMPONENT(QTBIN_DIR "${QT_QMAKE_EXECUTABLE}" PATH) + set(LIB_DIRS "${QTBIN_DIR}") + + GET_PROPERTY(PLUGINS_BUILT GLOBAL PROPERTY PLUGINS_BUILT) + + IF(LMMS_BUILD_WIN32) + SET(LMMS_DEP_DESTINATION ${BIN_DIR}) + SET(PLUGIN_DEP_DESTINATION ${BIN_DIR}) + ELSE() + SET(LMMS_DEP_DESTINATION ${LIB_DIR}) + SET(PLUGIN_DEP_DESTINATION ${LIB_DIR}) + ENDIF() + + INSTALL_TARGET_DEPENDENCIES( + NAME "main_binary" + TARGETS lmms + DESTINATION "${LMMS_DEP_DESTINATION}" + LIB_DIRS ${LIB_DIRS} + ) + + INSTALL_TARGET_DEPENDENCIES( + NAME "plugins" + TARGETS ${PLUGINS_BUILT} + DESTINATION ${PLUGIN_DEP_DESTINATION} + LIB_DIRS ${LIB_DIRS} "${PLUGIN_DIR}" + ) +ENDIF() + +IF(LMMS_BUILD_APPLE) + INSTALL(CODE "EXECUTE_PROCESS(COMMAND chmod u+x ${CMAKE_BINARY_DIR}/install_apple.sh)") + INSTALL(CODE "EXECUTE_PROCESS(COMMAND ${CMAKE_BINARY_DIR}/install_apple.sh)") +ENDIF() diff --git a/cmake/install/excludelist-win b/cmake/install/excludelist-win new file mode 100644 index 000000000..17793a113 --- /dev/null +++ b/cmake/install/excludelist-win @@ -0,0 +1,23 @@ +# List of DLLs considered to be system libraries. +# This is needed when cross-compiling for Windows. +ADVAPI32.dll +COMCTL32.dll +comdlg32.dll +dwmapi.dll +GDI32.dll +IMM32.dll +KERNEL32.dll +MPR.DLL +msvcrt.dll +ole32.dll +OLEAUT32.dll +OPENGL32.DLL +SHELL32.dll +USER32.dll +UxTheme.dll +VERSION.dll +WINMM.DLL +WS2_32.dll +RPCRT4.dll +dsound.dll +SETUPAPI.dll diff --git a/cmake/linux/lmms.desktop b/cmake/linux/lmms.desktop index 72a82da17..d6a05d15f 100644 --- a/cmake/linux/lmms.desktop +++ b/cmake/linux/lmms.desktop @@ -3,11 +3,11 @@ Name=LMMS GenericName=Music production suite GenericName[ca]=Programari de producció musical GenericName[de]=Software zur Musik-Produktion -GenericName[fr]=Ensemble pour la production musicale +GenericName[fr]=Suite de production musicale GenericName[pl]=Narzędzia do produkcji muzyki Comment=Music sequencer and synthesizer Comment[ca]=Producció fàcil de música per a tothom! -Comment[fr]=Production facile de musique pour tout le monde ! +Comment[fr]=Séquenceur et synthétiseur de musique Comment[pl]=Prosta produkcja muzyki dla każdego! Icon=lmms Exec=lmms %f diff --git a/cmake/linux/package_linux.sh.in b/cmake/linux/package_linux.sh.in index 0dec715f4..9f233d401 100644 --- a/cmake/linux/package_linux.sh.in +++ b/cmake/linux/package_linux.sh.in @@ -103,7 +103,7 @@ mv "${APPDIR}usr/bin/lmms" "${APPDIR}usr/bin/lmms.real" cat >"${APPDIR}usr/bin/lmms" < /dev/null 2>&1; then CARLAPATH="\$(which carla)" CARLAPREFIX="\${CARLAPATH%/bin*}" @@ -175,10 +175,9 @@ executables="${executables} -executable=${APPDIR}usr/lib/lmms/ladspa/pitch_scale # Bundle both qt and non-qt dependencies into appimage format echo -e "\nBundling and relinking system dependencies..." echo -e ">>>>> linuxdeployqt" > "$LOGFILE" -# FIXME: -unsupported-allow-new-glibc may result in an AppImage which is unusable on old systems. # shellcheck disable=SC2086 -"$LINUXDEPLOYQT" "$DESKTOPFILE" $executables -unsupported-allow-new-glibc -bundle-non-qt-libs -verbose=$VERBOSITY $STRIP >> "$LOGFILE" 2>&1 +"$LINUXDEPLOYQT" "$DESKTOPFILE" $executables -bundle-non-qt-libs -verbose=$VERBOSITY $STRIP >> "$LOGFILE" 2>&1 success "Bundled and relinked dependencies" # Link to original location so lmms can find them diff --git a/cmake/modules/BuildPlugin.cmake b/cmake/modules/BuildPlugin.cmake index efa3e5b46..675433e63 100644 --- a/cmake/modules/BuildPlugin.cmake +++ b/cmake/modules/BuildPlugin.cmake @@ -62,7 +62,10 @@ MACRO(BUILD_PLUGIN PLUGIN_NAME) TARGET_LINK_LIBRARIES(${PLUGIN_NAME} lmms) ENDIF(LMMS_BUILD_WIN32) - INSTALL(TARGETS ${PLUGIN_NAME} DESTINATION "${PLUGIN_DIR}") + INSTALL(TARGETS ${PLUGIN_NAME} + LIBRARY DESTINATION "${PLUGIN_DIR}" + RUNTIME DESTINATION "${PLUGIN_DIR}" + ) IF(LMMS_BUILD_APPLE) IF ("${PLUGIN_LINK}" STREQUAL "SHARED") @@ -72,9 +75,11 @@ MACRO(BUILD_PLUGIN PLUGIN_NAME) ENDIF() ADD_DEPENDENCIES(${PLUGIN_NAME} lmms) ENDIF(LMMS_BUILD_APPLE) - IF(LMMS_BUILD_WIN32 AND STRIP) + IF(LMMS_BUILD_WIN32) + IF(STRIP) + ADD_CUSTOM_COMMAND(TARGET ${PLUGIN_NAME} POST_BUILD COMMAND ${STRIP} "$") + ENDIF() SET_TARGET_PROPERTIES(${PLUGIN_NAME} PROPERTIES PREFIX "") - ADD_CUSTOM_COMMAND(TARGET ${PLUGIN_NAME} POST_BUILD COMMAND ${STRIP} "$") ENDIF() SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${RCC_OUT} ${plugin_MOC_out}") @@ -89,5 +94,8 @@ MACRO(BUILD_PLUGIN PLUGIN_NAME) TARGET_INCLUDE_DIRECTORIES(${PLUGIN_NAME} PUBLIC $ ) + + SET_PROPERTY(GLOBAL APPEND PROPERTY PLUGINS_BUILT ${PLUGIN_NAME}) + GET_PROPERTY(PLUGINS_BUILT GLOBAL PROPERTY PLUGINS_BUILT) ENDMACRO(BUILD_PLUGIN) diff --git a/cmake/modules/CheckSubmodules.cmake b/cmake/modules/CheckSubmodules.cmake index 65e5be08b..32a2f9951 100644 --- a/cmake/modules/CheckSubmodules.cmake +++ b/cmake/modules/CheckSubmodules.cmake @@ -7,12 +7,12 @@ # INCLUDE(CheckSubmodules) # # Options: -# SET(SKIP_SUBMODULES "foo;bar") +# SET(PLUGIN_LIST "zynaddsubfx;...") # skips submodules for plugins not explicitely listed # # Or via command line: -# cmake -DSKIP_SUBMODULES=foo;bar +# cmake -PLUGIN_LIST=foo;bar # -# Copyright (c) 2017, Tres Finocchiaro, +# Copyright (c) 2019, Tres Finocchiaro, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. @@ -20,13 +20,15 @@ # Files which confirm a successful clone SET(VALID_CRUMBS "CMakeLists.txt;Makefile;Makefile.in;Makefile.am;configure.ac;configure.py;autogen.sh;.gitignore;LICENSE;Home.md") +OPTION(NO_SHALLOW_CLONE "Disable shallow cloning of submodules" OFF) + # Try and use the specified shallow clone on submodules, if supported SET(DEPTH_VALUE 100) # Number of times git commands will retry before failing SET(MAX_ATTEMPTS 2) -MESSAGE("\nValidating submodules...") +MESSAGE("\nChecking submodules...") IF(NOT EXISTS "${CMAKE_SOURCE_DIR}/.gitmodules") MESSAGE("Skipping the check because .gitmodules not detected." "Please make sure you have all submodules in the source tree!" @@ -41,74 +43,112 @@ SET(LANG_BACKUP "$ENV{LANG}") SET(ENV{LC_ALL} "C") SET(ENV{LANG} "en_US") -# Assume alpha-numeric paths -STRING(REGEX MATCHALL "path = [-0-9A-Za-z/]+" SUBMODULE_LIST ${SUBMODULE_DATA}) -STRING(REGEX MATCHALL "url = [.:%-0-9A-Za-z/]+" SUBMODULE_URL_LIST ${SUBMODULE_DATA}) +# Submodule list pairs, unparsed (WARNING: Assumes alpha-numeric paths) +STRING(REGEX MATCHALL "path = [-0-9A-Za-z/]+" SUBMODULE_LIST_RAW ${SUBMODULE_DATA}) +STRING(REGEX MATCHALL "url = [.:%-0-9A-Za-z/]+" SUBMODULE_URL_RAW ${SUBMODULE_DATA}) -FOREACH(_part ${SUBMODULE_LIST}) - STRING(REPLACE "path = " "" SUBMODULE_PATH ${_part}) +# Submodule list pairs, parsed +SET(SUBMODULE_LIST "") +SET(SUBMODULE_URL "") - LIST(FIND SUBMODULE_LIST ${_part} SUBMODULE_INDEX) - LIST(GET SUBMODULE_URL_LIST ${SUBMODULE_INDEX} _url) - STRING(REPLACE "url = " "" SUBMODULE_URL ${_url}) +FOREACH(_path ${SUBMODULE_LIST_RAW}) + # Parse SUBMODULE_PATH + STRING(REPLACE "path = " "" SUBMODULE_PATH "${_path}") + + # Grab index for matching SUBMODULE_URL + LIST(FIND SUBMODULE_LIST_RAW "${_path}" SUBMODULE_INDEX) + LIST(GET SUBMODULE_URL_RAW ${SUBMODULE_INDEX} _url) + + # Parse SUBMODULE_URL + STRING(REPLACE "url = " "" SUBMODULE_URL "${_url}") - # Remove submodules from validation as specified in -DSKIP_SUBMODULES=foo;bar SET(SKIP false) + + # Loop over skipped plugins, add to SKIP_SUBMODULES (e.g. -DPLUGIN_LIST=foo;bar) + IF(${SUBMODULE_PATH} MATCHES "^plugins/") + SET(REMOVE_PLUGIN true) + FOREACH(_plugin ${PLUGIN_LIST}) + IF(_plugin STREQUAL "") + CONTINUE() + ENDIF() + IF(${SUBMODULE_PATH} MATCHES "${_plugin}") + SET(REMOVE_PLUGIN false) + ENDIF() + ENDFOREACH() + + IF(REMOVE_PLUGIN) + LIST(APPEND SKIP_SUBMODULES "${SUBMODULE_PATH}") + ENDIF() + ENDIF() + + # Finally, loop and mark "SKIP" on match IF(SKIP_SUBMODULES) FOREACH(_skip ${SKIP_SUBMODULES}) - IF(${SUBMODULE_PATH} MATCHES ${_skip}) - MESSAGE("-- Skipping ${SUBMODULE_PATH} matches \"${_skip}\"") + IF("${SUBMODULE_PATH}" MATCHES "${_skip}") + MESSAGE("-- Skipping ${SUBMODULE_PATH} matches \"${_skip}\" (absent in PLUGIN_LIST)") SET(SKIP true) + BREAK() ENDIF() ENDFOREACH() ENDIF() - IF(NOT SKIP) - LIST(INSERT SUBMODULE_LIST ${SUBMODULE_INDEX} ${SUBMODULE_PATH}) - LIST(INSERT SUBMODULE_URL_LIST ${SUBMODULE_INDEX} ${SUBMODULE_URL}) - ENDIF() - LIST(REMOVE_ITEM SUBMODULE_LIST ${_part}) - LIST(REMOVE_ITEM SUBMODULE_URL_LIST ${_url}) -ENDFOREACH() + IF(NOT SKIP) + LIST(APPEND SUBMODULE_LIST "${SUBMODULE_PATH}") + LIST(APPEND SUBMODULE_URL "${SUBMODULE_URL}") + ENDIF() +ENDFOREACH() # Once called, status is stored in GIT_RESULT respectively. # Note: Git likes to write to stderr. Don't assume stderr is error; Check GIT_RESULT instead. -MACRO(GIT_SUBMODULE SUBMODULE_PATH FORCE_DEINIT FORCE_REMOTE) +MACRO(GIT_SUBMODULE SUBMODULE_PATH FORCE_DEINIT FORCE_REMOTE FULL_CLONE) FIND_PACKAGE(Git REQUIRED) # Handle missing commits SET(FORCE_REMOTE_FLAG "${FORCE_REMOTE}") + SET(FULL_CLONE_FLAG "${FULL_CLONE}") IF(FORCE_REMOTE_FLAG) MESSAGE("-- Adding remote submodulefix to ${SUBMODULE_PATH}") EXECUTE_PROCESS( - COMMAND ${GIT_EXECUTABLE} remote rm submodulefix - COMMAND ${GIT_EXECUTABLE} remote add submodulefix ${FORCE_REMOTE} - COMMAND ${GIT_EXECUTABLE} fetch submodulefix - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/${SUBMODULE_PATH} + COMMAND "${GIT_EXECUTABLE}" remote rm submodulefix + COMMAND "${GIT_EXECUTABLE}" remote add submodulefix ${FORCE_REMOTE} + COMMAND "${GIT_EXECUTABLE}" fetch submodulefix + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/${SUBMODULE_PATH}" OUTPUT_QUIET ERROR_QUIET ) # Recurse - GIT_SUBMODULE(${SUBMODULE_PATH} false false) + GIT_SUBMODULE(${SUBMODULE_PATH} false false ${FULL_CLONE_FLAG}) ELSEIF(${FORCE_DEINIT}) MESSAGE("-- Resetting ${SUBMODULE_PATH}") EXECUTE_PROCESS( - COMMAND ${GIT_EXECUTABLE} submodule deinit -f ${CMAKE_SOURCE_DIR}/${SUBMODULE_PATH} - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMAND "${GIT_EXECUTABLE}" submodule deinit -f "${CMAKE_SOURCE_DIR}/${SUBMODULE_PATH}" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" OUTPUT_QUIET ) + MESSAGE("-- Deleting ${CMAKE_SOURCE_DIR}/.git/${SUBMODULE_PATH}") + FILE(REMOVE_RECURSE "${CMAKE_SOURCE_DIR}/.git/modules/${SUBMODULE_PATH}") # Recurse - GIT_SUBMODULE(${SUBMODULE_PATH} false false) + GIT_SUBMODULE(${SUBMODULE_PATH} false false true) ELSE() # Try to use the depth switch - SET(DEPTH_CMD "") + IF(NO_SHALLOW_CLONE OR GIT_VERSION_STRING VERSION_LESS "1.8.4") + # Shallow submodules were introduced in 1.8.4 MESSAGE("-- Fetching ${SUBMODULE_PATH}") - IF(DEPTH_VALUE) - SET(DEPTH_CMD "--depth" ) + SET(DEPTH_CMD "") + SET(DEPTH_VAL "") + ELSEIF(FULL_CLONE_FLAG) + # Depth doesn't revert easily... It should be "--no-recommend-shallow" + # but it's ignored by nested submodules, use the highest value instead. + MESSAGE("-- Fetching ${SUBMODULE_PATH}") + SET(DEPTH_CMD "--depth") + SET(DEPTH_VAL "2147483647") + ELSE() MESSAGE("-- Fetching ${SUBMODULE_PATH} @ --depth ${DEPTH_VALUE}") + SET(DEPTH_CMD "--depth") + SET(DEPTH_VAL "${DEPTH_VALUE}") ENDIF() EXECUTE_PROCESS( - COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive ${DEPTH_CMD} ${DEPTH_VALUE} ${CMAKE_SOURCE_DIR}/${SUBMODULE_PATH} - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMAND "${GIT_EXECUTABLE}" submodule update --init --recursive ${DEPTH_CMD} ${DEPTH_VAL} "${CMAKE_SOURCE_DIR}/${SUBMODULE_PATH}" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" RESULT_VARIABLE GIT_RESULT OUTPUT_VARIABLE GIT_STDOUT ERROR_VARIABLE GIT_STDERR @@ -124,7 +164,7 @@ SET(RETRY_PHRASES "Failed to recurse;cannot create directory;already exists;${MI # Attempt to do lazy clone FOREACH(_submodule ${SUBMODULE_LIST}) - STRING(REPLACE "/" ";" PATH_PARTS ${_submodule}) + STRING(REPLACE "/" ";" PATH_PARTS "${_submodule}") LIST(REVERSE PATH_PARTS) LIST(GET PATH_PARTS 0 SUBMODULE_NAME) @@ -138,14 +178,12 @@ FOREACH(_submodule ${SUBMODULE_LIST}) ENDIF() ENDFOREACH() IF(NOT CRUMB_FOUND) - GIT_SUBMODULE(${_submodule} false false) + GIT_SUBMODULE("${_submodule}" false false false) SET(COUNTED 0) - SET(COUNTING "") # Handle edge-cases where submodule didn't clone properly or re-uses a non-empty directory WHILE(NOT GIT_RESULT EQUAL 0 AND COUNTED LESS MAX_ATTEMPTS) - LIST(APPEND COUNTING "x") - LIST(LENGTH COUNTING COUNTED) + MATH(EXPR COUNTED "${COUNTED}+1") SET(MISSING_COMMIT false) FOREACH(_phrase ${MISSING_COMMIT_PHRASES}) IF("${GIT_MESSAGE}" MATCHES "${_phrase}") @@ -154,25 +192,22 @@ FOREACH(_submodule ${SUBMODULE_LIST}) ENDIF() ENDFOREACH() FOREACH(_phrase ${RETRY_PHRASES}) - IF(${MISSING_COMMIT}) + IF(${MISSING_COMMIT} AND COUNTED LESS 2) LIST(FIND SUBMODULE_LIST ${_submodule} SUBMODULE_INDEX) LIST(GET SUBMODULE_URL_LIST ${SUBMODULE_INDEX} SUBMODULE_URL) MESSAGE("-- Retrying ${_submodule} using 'remote add submodulefix' (attempt ${COUNTED} of ${MAX_ATTEMPTS})...") - GIT_SUBMODULE(${_submodule} false "${SUBMODULE_URL}") + GIT_SUBMODULE("${_submodule}" false "${SUBMODULE_URL}" false) BREAK() ELSEIF("${GIT_MESSAGE}" MATCHES "${_phrase}") MESSAGE("-- Retrying ${_submodule} using 'deinit' (attempt ${COUNTED} of ${MAX_ATTEMPTS})...") - - # Shallow submodules were introduced in 1.8.4 - # Shallow commits can fail to clone from non-default branches, only try once - IF(GIT_VERSION_STRING VERSION_GREATER "1.8.3" AND COUNTED LESS 2) - # Try a shallow submodule clone + IF(COUNTED LESS 2) + SET(FULL_CLONE false) ELSE() - UNSET(DEPTH_VALUE) + SET(FULL_CLONE true) ENDIF() - GIT_SUBMODULE(${_submodule} true false) + GIT_SUBMODULE("${_submodule}" true false ${FULL_CLONE}) BREAK() ENDIF() ENDFOREACH() diff --git a/cmake/modules/CreateTempFile.cmake b/cmake/modules/CreateTempFile.cmake new file mode 100644 index 000000000..5210342ac --- /dev/null +++ b/cmake/modules/CreateTempFile.cmake @@ -0,0 +1,21 @@ +function(CreateTempFilePath) + set(options CONFIG_SUFFIX) + set(oneValueArgs OUTPUT_VAR TAG) + set(multiValueArgs CONTENT) + cmake_parse_arguments(TEMP "${options}" "${oneValueArgs}" + "${multiValueArgs}" ${ARGN} ) + + # Use hash to create a unique identifier + # for this file. + string(SHA1 hashed_content "${TEMP_CONTENT}") + + set(file_name "${CMAKE_BINARY_DIR}/${TEMP_TAG}_${hashed_content}") + set(${TEMP_OUTPUT_VAR} "${file_name}" PARENT_SCOPE) + if(CONFIG_SUFFIX) + set(file_name "${file_name}_$") + endif() + + file(GENERATE OUTPUT "${file_name}" + CONTENT "${TEMP_CONTENT}") + +endfunction() diff --git a/cmake/modules/DefineInstallVar.cmake b/cmake/modules/DefineInstallVar.cmake new file mode 100644 index 000000000..b13cb1d52 --- /dev/null +++ b/cmake/modules/DefineInstallVar.cmake @@ -0,0 +1,31 @@ +# This functions forwards a variable to +# the install stage. +# Parameters: +# CONTENT: Variable content. +# NAME: Variable name. +# Options: +# GENERATOR_EXPRESSION: Support generator expression for CONTENT. +function(DEFINE_INSTALL_VAR) + set(options GENERATOR_EXPRESSION) + set(oneValueArgs NAME ) + set(multiValueArgs CONTENT) + cmake_parse_arguments(VAR "${options}" "${oneValueArgs}" + "${multiValueArgs}" ${ARGN} ) + + # install(CODE) does not support generator expression in ver<3.14 + if(VAR_GENERATOR_EXPRESSION AND ${CMAKE_VERSION} VERSION_LESS "3.14.0") + include(CreateTempFile) + if(CMAKE_CONFIGURATION_TYPES) # in case of multi-config generators like MSVC generators + CreateTempFilePath(OUTPUT_VAR file_path TAG "${VAR_NAME}" CONTENT "${VAR_CONTENT}" CONFIG_SUFFIX) + install(CODE "file(READ \"${file_path}_\${CMAKE_INSTALL_CONFIG_NAME}\" \"${VAR_NAME}\")") + else() + CreateTempFilePath(OUTPUT_VAR file_path TAG "${VAR_NAME}" CONTENT "${VAR_CONTENT}") + install(CODE "file(READ \"${file_path}\" \"${VAR_NAME}\")") + endif() + else() + if(VAR_GENERATOR_EXPRESSION) + cmake_policy(SET CMP0087 NEW) + endif() + install(CODE "set(\"${VAR_NAME}\" \"${VAR_CONTENT}\")") + endif() +endfunction() diff --git a/cmake/modules/DetectMachine.cmake b/cmake/modules/DetectMachine.cmake index f3458165b..86807b757 100644 --- a/cmake/modules/DetectMachine.cmake +++ b/cmake/modules/DetectMachine.cmake @@ -4,6 +4,8 @@ ELSEIF(APPLE) SET(LMMS_BUILD_APPLE 1) ELSEIF(${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD") SET(LMMS_BUILD_OPENBSD 1) +ELSEIF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") + SET(LMMS_BUILD_FREEBSD 1) ELSEIF(HAIKU) SET(LMMS_BUILD_HAIKU 1) ELSE() @@ -30,6 +32,25 @@ IF(WIN32) ELSE(WIN64) SET(IS_X86 TRUE) ENDIF(WIN64) + + if(MSVC) + SET(MSVC_VER ${CMAKE_CXX_COMPILER_VERSION}) + + IF(MSVC_VER VERSION_GREATER 19.20 OR MSVC_VER VERSION_EQUAL 19.20) + SET(LMMS_MSVC_GENERATOR "Visual Studio 16 2019") + SET(LMMS_MSVC_YEAR 2019) # Qt only provides binaries for MSVC 2017, but 2019 is binary compatible + ELSEIF(MSVC_VER VERSION_GREATER 19.10 OR MSVC_VER VERSION_EQUAL 19.10) + SET(LMMS_MSVC_GENERATOR "Visual Studio 15 2017") + SET(LMMS_MSVC_YEAR 2017) + ELSEIF(MSVC_VER VERSION_GREATER 19.0 OR MSVC_VER VERSION_EQUAL 19.0) + SET(LMMS_MSVC_GENERATOR "Visual Studio 14 2015") + SET(LMMS_MSVC_YEAR 2015) + ELSE() + MESSAGE(SEND_WARNING "Can't detect MSVC version: ${MSVC_VER}") + ENDIF() + + unset(MSVC_VER) + endif() ELSE(WIN32) EXEC_PROGRAM( ${CMAKE_C_COMPILER} ARGS "-dumpmachine ${CMAKE_C_FLAGS}" OUTPUT_VARIABLE Machine ) MESSAGE("Machine: ${Machine}") diff --git a/cmake/modules/InstallDependencies.cmake b/cmake/modules/InstallDependencies.cmake new file mode 100644 index 000000000..791041bb2 --- /dev/null +++ b/cmake/modules/InstallDependencies.cmake @@ -0,0 +1,184 @@ +include(GetPrerequisites) +include(CMakeParseArguments) + +CMAKE_POLICY(SET CMP0011 NEW) +CMAKE_POLICY(SET CMP0057 NEW) + +function(make_absolute var) + get_filename_component(abs "${${var}}" ABSOLUTE BASE_DIR "${CMAKE_INSTALL_PREFIX}") + set(${var} ${abs} PARENT_SCOPE) +endfunction() + +# Reads lines of a file into a list, skipping '#' comment lines +function(READ_LIST_FILE FILE VAR) + file(STRINGS "${FILE}" list) + + set(result "") + foreach(item ${list}) + string(STRIP "${item}" item) + if(item STREQUAL "" OR item MATCHES "^\#") + continue() + endif() + list(APPEND result "${item}") + endforeach() + + set(${VAR} ${result} PARENT_SCOPE) +endfunction() + +function(make_all_absolute list_var) + set(result "") + foreach(file ${${list_var}}) + make_absolute(file) + list(APPEND result ${file}) + endforeach() + set(${list_var} ${result} PARENT_SCOPE) +endfunction() + +if(CMAKE_BINARY_DIR) + set(tmp_lib_dir "${CMAKE_BINARY_DIR}/bundled-libraries") +elseif(CMAKE_HOST_UNIX) + set(tmp_lib_dir "/tmp/bundled-libraries") +elseif(DEFINED ENV{TEMP}) + set(tmp_lib_dir "$ENV{TMP}/bundled-libraries") +else() + message(FATAL_ERROR "Can't find a temp dir for libraries") +endif() + +# Like file(INSTALL), but resolves symlinks +function(install_file_resolved file destination) + + get_filename_component(file_name "${file}" NAME) + if(IS_SYMLINK "${file}") + get_filename_component(real_path "${file}" REALPATH) + get_filename_component(real_name "${real_path}" NAME) + file(COPY "${real_path}" DESTINATION "${tmp_lib_dir}") + file(RENAME "${tmp_lib_dir}/${real_name}" "${tmp_lib_dir}/${file_name}") + set(file_path "${tmp_lib_dir}/${file_name}") + else() + set(file_path "${file}") + endif() + + file(INSTALL "${file_path}" DESTINATION "${destination}") +endfunction() + +function(install_resolved) + cmake_parse_arguments("" "" "DESTINATION" "FILES" ${ARGN}) + foreach(file ${_FILES}) + install_file_resolved("${file}" "${_DESTINATION}") + endforeach() +endfunction() + +if(CMAKE_CROSSCOMPILING) + # If we're cross-compiling, GetPrerequisites may not be able to find system libraries such as kernel32.dll because + # they're supplied by the toolchain. To suppress thousands of lines of warnings being printed to the console, we + # override gp_resolved_file_type to return "system" for any library in ${IGNORE_LIBS} without trying to resolve the + # file first. + # GetPrerequisites supports using an override function called gp_resolved_file_type_override, but it's not suited + # for our purpose because it's only called by gp_resolved_file_type *after* trying to resolve the file. + function(gp_resolved_file_type original_file file exepath dirs type_var) + set(file_find "${file}") + if(_IGNORE_CASE) + # On case-insensitive systems, convert to upper characters to respect it + string(TOUPPER "${file_find}" file_find) + endif() + SET(IGNORE_LIBS ${_IGNORE_LIBS} CACHE INTERNAL "Ignored library names" FORCE) + if(IGNORE_LIBS AND ${file_find} IN_LIST IGNORE_LIBS) + set(${type_var} system PARENT_SCOPE) + else() + #_gp_resolved_file_type(${ARGV}) + _gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "${dirs}" "${type_var}" ${ARGN}) + endif() + endfunction() +endif() + +function(INSTALL_DEPENDENCIES) + cmake_parse_arguments("" "INCLUDE_SYSTEM;IGNORE_CASE" "GP_TOOL;DESTINATION;IGNORE_LIBS_FILE" "FILES;LIB_DIRS;SEARCH_PATHS;IGNORE_LIBS" ${ARGN}) + + # Make paths absolute + make_absolute(_DESTINATION) + make_all_absolute(_FILES) + make_all_absolute(_LIB_DIRS) + make_all_absolute(_SEARCH_PATHS) + + if(_INCLUDE_SYSTEM) + set(EXCLUDE_SYSTEM 0) + else() + set(EXCLUDE_SYSTEM 1) + endif() + + if(_IGNORE_LIBS_FILE) + READ_LIST_FILE("${_IGNORE_LIBS_FILE}" _IGNORE_LIBS) + if(_IGNORE_CASE) + # On case-insensitive systems, convert to upper characters to respect it + string(TOUPPER "${_IGNORE_LIBS}" _IGNORE_LIBS) + endif() + SET(IGNORE_LIBS ${_IGNORE_LIBS} CACHE INTERNAL "Ignored library names" FORCE) + endif() + + if(_GP_TOOL) + set(gp_tool "${_GP_TOOL}") + endif() + + set(prereqs "") + foreach(file ${_FILES}) + get_filename_component(file_name "${file}" NAME) + message("-- Finding prerequisites of ${file_name}") + find_prerequisites("${file}" _prereqs + ${EXCLUDE_SYSTEM} # exclude system files + 1 # recurse + "" + "${_LIB_DIRS}" + "${_SEARCH_PATHS}" + "${_IGNORE_LIBS}" + ) + + list(APPEND prereqs ${_prereqs}) + endforeach() + + list(REMOVE_DUPLICATES prereqs) + + foreach(prereq ${prereqs}) + get_filename_component(prereq_name "${prereq}" NAME) + + foreach(rpath ${_SEARCH_PATHS}) + if(EXISTS "${rpath}/${prereq_name}") + list(REMOVE_ITEM prereqs "${prereq}") + break() + endif() + endforeach() + endforeach() + + #file(INSTALL ${prereqs} DESTINATION ${_DESTINATION}) + install_resolved(FILES ${prereqs} DESTINATION "${_DESTINATION}") +endfunction() + +# Like get_prerequisites, but returns full paths +function(FIND_PREREQUISITES target RESULT_VAR exclude_system recurse + exepath dirs rpaths) + set(RESULTS) + + get_prerequisites("${target}" _prereqs ${exclude_system} ${recurse} + "" "${dirs}" "${rpaths}") + + foreach(prereq ${_prereqs}) + get_filename_component(prereq_name "${prereq}" NAME) + if(_IGNORE_CASE) + # Windows is case insensitive. + # Use upper characters to respect it. + string(TOUPPER "${prereq_name}" prereq_name) + endif() + if("${prereq_name}" IN_LIST IGNORE_LIBS) + continue() + endif() + + gp_resolve_item("${LIB_DLL}" "${prereq}" "" "${dirs}" RESOLVED_PREREQ "${rpaths}") + + if(RESOLVED_PREREQ AND IS_ABSOLUTE ${RESOLVED_PREREQ} AND EXISTS ${RESOLVED_PREREQ}) + list(APPEND RESULTS ${RESOLVED_PREREQ}) + else() + message(FATAL_ERROR "Can't resolve dependency ${prereq}.") + endif() + endforeach() + + set(${RESULT_VAR} ${RESULTS} PARENT_SCOPE) +endfunction() diff --git a/cmake/modules/InstallTargetDependencies.cmake b/cmake/modules/InstallTargetDependencies.cmake new file mode 100644 index 000000000..9665a0b87 --- /dev/null +++ b/cmake/modules/InstallTargetDependencies.cmake @@ -0,0 +1,89 @@ +include(DefineInstallVar) + +SET(DEFAULT_SEARCH_DIRECTORIES "${BIN_DIR}" "${LIB_DIR}" "${CMAKE_FIND_ROOT_PATH}" "${CMAKE_PREFIX_PATH}") +SET(DEFAULT_SEARCH_SUFFIXES "bin" "lib" "../bin") + +# Like INSTALL_DEPENDENCIES but can be called from regular cmake code +# (instead of install(CODE)), takes targets instead of files, +# takes care of configuring search paths, and other platform-specific tweaks. +# Arguments: +# TARGETS: list of cmake targets to install. +# NAME: unique string for this install. +# DESTINATION: directory path to install the binaries to. +# LIB_DIRS: list of paths for looking up dependencies. +# LIB_DIRS_SUFFIXES: list of possible suffixes for LIB_DIRS entries. +# NO_DEFAULT_PATHS: supply this value to avoid adding DEFAULT_SEARCH_DIRECTORIES +# to LIB_DIRS and DEFAULT_SEARCH_SUFFIXES to LIB_DIRS_SUFFIXES. +FUNCTION(INSTALL_TARGET_DEPENDENCIES) + set(options NO_DEFAULT_PATHS) + set(oneValueArgs NAME) + set(multiValueArgs TARGETS DESTINATION LIB_DIRS_SUFFIXES LIB_DIRS) + cmake_parse_arguments(DEPS "${options}" "${oneValueArgs}" + "${multiValueArgs}" ${ARGN} ) + + if(NOT DEPS_LIB_DIRS) + set(DEPS_LIB_DIRS "") + endif() + + # Set default values. + if(NOT DEPS_NO_DEFAULT_PATHS) + list(APPEND DEPS_LIB_DIRS ${DEFAULT_SEARCH_DIRECTORIES}) + set(DEPS_LIB_DIRS_SUFFIXES "${DEPS_LIB_DIRS_SUFFIXES}" ${DEFAULT_SEARCH_SUFFIXES}) + endif() + + FOREACH(TARGET ${DEPS_TARGETS}) + IF(NOT TARGET ${TARGET}) + message(FATAL_ERROR "Not a target: ${TARGET}") + ENDIF() + + # Collect target output files. + LIST(APPEND DEPLOY_TARGETS "$") + + # Collect target link directories + get_target_property(target_libs ${TARGET} LINK_LIBRARIES) + + foreach(lib ${target_libs}) + if(TARGET ${lib} OR NOT IS_ABSOLUTE ${lib}) + continue() + endif() + + get_filename_component(lib_dir ${lib} PATH) + list(APPEND DEPS_LIB_DIRS ${lib_dir}) + endforeach() + ENDFOREACH() + + LIST(APPEND DEPS_LIB_DIRS ${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES}) + + FOREACH(LIB_PATH ${DEPS_LIB_DIRS}) + FOREACH(suffix ${DEPS_LIB_DIRS_SUFFIXES}) + list(APPEND DEPS_LIB_DIRS "${LIB_PATH}/${suffix}") + ENDFOREACH() + ENDFOREACH() + + DEFINE_INSTALL_VAR(NAME "DEPLOY_FILES" CONTENT "${DEPLOY_TARGETS}" GENERATOR_EXPRESSION) + + LIST(REMOVE_DUPLICATES DEPS_LIB_DIRS) + + IF(LMMS_BUILD_LINUX) + FILE(DOWNLOAD "https://raw.githubusercontent.com/AppImage/AppImages/master/excludelist" + "${CMAKE_BINARY_DIR}/excludelist") + SET(additional_args INCLUDE_SYSTEM IGNORE_LIBS_FILE ${CMAKE_BINARY_DIR}/excludelist) + ELSEIF(LMMS_BUILD_WIN32) + SET(additional_args IGNORE_CASE IGNORE_LIBS_FILE "${LMMS_SOURCE_DIR}/cmake/install/excludelist-win") + IF(CMAKE_CROSSCOMPILING) + SET(additional_args "${additional_args}" GP_TOOL objdump) + ENDIF() + ENDIF() + + INSTALL(CODE " + INCLUDE(\"${LMMS_SOURCE_DIR}/cmake/modules/InstallDependencies.cmake\") + + INSTALL_DEPENDENCIES( + FILES \"\${DEPLOY_FILES}\" + DESTINATION \"${DEPS_DESTINATION}\" + LIB_DIRS \"${DEPS_LIB_DIRS}\" + SEARCH_PATHS \"${DEPS_SEARCH_PATHS}\" + ${additional_args} + ) + ") +ENDFUNCTION() diff --git a/cmake/modules/PluginList.cmake b/cmake/modules/PluginList.cmake new file mode 100644 index 000000000..c82bba329 --- /dev/null +++ b/cmake/modules/PluginList.cmake @@ -0,0 +1,104 @@ +# Provides a fast mechanism for filtering the plugins used at build-time +SET(PLUGIN_LIST "" CACHE STRING "List of plug-ins to build") +STRING(REPLACE " " ";" PLUGIN_LIST "${PLUGIN_LIST}") +OPTION(LMMS_MINIMAL "Build a minimal list of plug-ins" OFF) +OPTION(LIST_PLUGINS "Lists the available plugins for building" OFF) + +SET(MINIMAL_LIST + audio_file_processor + kicker + triple_oscillator +) + +IF(LMMS_MINIMAL) + IF("${PLUGIN_LIST}" STREQUAL "") + STRING(REPLACE ";" " " MINIMAL_LIST_STRING "${MINIMAL_LIST}") + MESSAGE( +"-- Using minimal plug-ins: ${MINIMAL_LIST_STRING}\n" +" Note: You can specify specific plug-ins using -DPLUGIN_LIST=\"foo bar\"" + ) + ENDIF() + SET(PLUGIN_LIST ${MINIMAL_LIST} ${PLUGIN_LIST}) +ENDIF() + +SET(LMMS_PLUGIN_LIST + ${MINIMAL_LIST} + Amplifier + BassBooster + bit_invader + Bitcrush + carlabase + carlapatchbay + carlarack + CrossoverEQ + Delay + DualFilter + dynamics_processor + Eq + Flanger + HydrogenImport + ladspa_browser + LadspaEffect + lb302 + MidiImport + MidiExport + MultitapEcho + monstro + nes + OpulenZ + organic + FreeBoy + patman + peak_controller_effect + GigPlayer + ReverbSC + sf2_player + sfxr + sid + SpectrumAnalyzer + stereo_enhancer + stereo_matrix + stk + vst_base + vestige + VstEffect + watsyn + waveshaper + vibed + Xpressive + zynaddsubfx +) + +IF("${PLUGIN_LIST}" STREQUAL "") + SET(PLUGIN_LIST ${LMMS_PLUGIN_LIST}) +ENDIF() + +MACRO(LIST_ALL_PLUGINS) + MESSAGE("\n\nAll possible -DPLUGIN_LIST values") + MESSAGE("\n KEYWORD:") + MESSAGE(" -DLMMS_MINIMAL=True") + FOREACH(item IN LISTS MINIMAL_LIST) + MESSAGE(" ${item}") + ENDFOREACH() + MESSAGE("\n NAME:") + FOREACH(item IN LISTS LMMS_PLUGIN_LIST) + MESSAGE(" ${item}") + ENDFOREACH() + MESSAGE("\nNote: This value also impacts the fetching of git submodules.\n") + MESSAGE(FATAL_ERROR "Information was requested, aborting build!") +ENDMACRO() + +IF(LIST_PLUGINS) + UNSET(LIST_PLUGINS CACHE) + LIST_ALL_PLUGINS() +ENDIF() + +IF(MSVC) + SET(MSVC_INCOMPATIBLE_PLUGINS + LadspaEffect + zynaddsubfx + ) + message(WARNING "Compiling with MSVC. The following plugins are not available: ${MSVC_INCOMPATIBLE_PLUGINS}") + LIST(REMOVE_ITEM PLUGIN_LIST ${MSVC_INCOMPATIBLE_PLUGINS}) +ENDIF() + diff --git a/cmake/modules/winegcc_wrapper.in b/cmake/modules/winegcc_wrapper.in index d32aec664..7677e4c37 100755 --- a/cmake/modules/winegcc_wrapper.in +++ b/cmake/modules/winegcc_wrapper.in @@ -58,6 +58,9 @@ if [ "$win64" = true ] && [ "$no_link" != true ]; then extra_args="$extra_args @WINE_64_FLAGS@" fi +# Work around https://bugs.winehq.org/show_bug.cgi?id=47710 +extra_args="$extra_args -D__WIDL_objidl_generated_name_0000000C=" + # Run winegcc export WINEBUILD=@WINE_BUILD@ @WINE_CXX@ $extra_args $args diff --git a/cmake/nsis/CMakeLists.txt b/cmake/nsis/CMakeLists.txt index ac628d549..3fcb4b2f3 100644 --- a/cmake/nsis/CMakeLists.txt +++ b/cmake/nsis/CMakeLists.txt @@ -1,3 +1,8 @@ +SET(WIN_PLATFORM mingw) +if(LMMS_MSVC_YEAR) + SET(WIN_PLATFORM "msvc${LMMS_MSVC_YEAR}") +endif() + SET(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/cmake/nsis/nsis_branding.bmp") IF(MSVC) STRING(REPLACE "/" "\\\\" CPACK_PACKAGE_ICON ${CPACK_PACKAGE_ICON}) @@ -15,7 +20,7 @@ SET(CPACK_NSIS_DEFINES " !include FileAssociation.nsh !include LogicLib.nsh !include WinVer.nsh") -SET(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${VERSION}-win32") +SET(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${VERSION}-${WIN_PLATFORM}-win32") SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS " \\\${registerExtension} \\\"$INSTDIR\\\\${CMAKE_PROJECT_NAME}.exe\\\" \\\".mmp\\\" \\\"${PROJECT_NAME_UCASE} Project\\\" \\\${registerExtension} \\\"$INSTDIR\\\\${CMAKE_PROJECT_NAME}.exe\\\" \\\".mmpz\\\" \\\"${PROJECT_NAME_UCASE} Project (compressed)\\\" @@ -31,7 +36,7 @@ SET(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS " " PARENT_SCOPE) IF(WIN64) - SET(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${VERSION}-win64") + SET(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${VERSION}-${WIN_PLATFORM}-win64") SET(CPACK_INSTALL_FIX "$PROGRAMFILES64\\\\${CPACK_PACKAGE_INSTALL_DIRECTORY}\\\\") SET(CPACK_NSIS_DEFINES " ${CPACK_NSIS_DEFINES} diff --git a/cmake/postinstall/CMakeLists.txt b/cmake/postinstall/CMakeLists.txt deleted file mode 100644 index 434d1c54e..000000000 --- a/cmake/postinstall/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -IF(LMMS_BUILD_APPLE) - INSTALL(CODE "EXECUTE_PROCESS(COMMAND chmod u+x ${CMAKE_BINARY_DIR}/install_apple.sh)") - INSTALL(CODE "EXECUTE_PROCESS(COMMAND ${CMAKE_BINARY_DIR}/install_apple.sh)") -ENDIF() \ No newline at end of file diff --git a/data/locale/pl.ts b/data/locale/pl.ts index 5d9cc51cd..4214718af 100644 --- a/data/locale/pl.ts +++ b/data/locale/pl.ts @@ -3108,7 +3108,7 @@ Możesz usunąć i przenieść kanały FX w menu kontekstowym, które jest dost VELOCITY - GŁOŚNOŚĆ UDERZENIA + PRĘDKOŚĆ ENABLE MIDI OUTPUT @@ -10321,4 +10321,4 @@ Kontrolka LED w prawym dolnym rogu edytora kształtu fali pokazuje, czy wybrana Wzmocnienie wyścia - \ No newline at end of file + diff --git a/data/locale/ru.ts b/data/locale/ru.ts index c7ec3a328..f717d598d 100644 --- a/data/locale/ru.ts +++ b/data/locale/ru.ts @@ -1664,7 +1664,7 @@ Oe Ai <oeai/at/symbiants/dot/com> W/D - НАСЫЩ + @@ -1679,7 +1679,7 @@ Oe Ai <oeai/at/symbiants/dot/com> DECAY - ЗАТУХАНИЕ + diff --git a/data/locale/sv.ts b/data/locale/sv.ts index eb51c9082..56cf1a0af 100644 --- a/data/locale/sv.ts +++ b/data/locale/sv.ts @@ -1658,7 +1658,7 @@ If you're interested in translating LMMS in another language or want to imp W/D - B/T + @@ -1673,7 +1673,7 @@ If you're interested in translating LMMS in another language or want to imp DECAY - FÖRFALL + diff --git a/data/locale/uk.ts b/data/locale/uk.ts index 7271c4946..c088f401c 100644 --- a/data/locale/uk.ts +++ b/data/locale/uk.ts @@ -1678,7 +1678,7 @@ If you're interested in translating LMMS in another language or want to imp DECAY - ЗГАСАННЯ + diff --git a/data/presets/X-Pressive/Ambition.xpf b/data/presets/X-Pressive/Ambition.xpf deleted file mode 100644 index 2d93f7c05..000000000 --- a/data/presets/X-Pressive/Ambition.xpf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/data/presets/X-Pressive/Baby Violin.xpf b/data/presets/X-Pressive/Baby Violin.xpf deleted file mode 100644 index 2e887d3d2..000000000 --- a/data/presets/X-Pressive/Baby Violin.xpf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/data/presets/X-Pressive/Bad Singer.xpf b/data/presets/X-Pressive/Bad Singer.xpf deleted file mode 100644 index ca9cfd5a3..000000000 --- a/data/presets/X-Pressive/Bad Singer.xpf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/data/presets/X-Pressive/Cloud Bass.xpf b/data/presets/X-Pressive/Cloud Bass.xpf deleted file mode 100644 index 4e444f22a..000000000 --- a/data/presets/X-Pressive/Cloud Bass.xpf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/data/presets/X-Pressive/Creature.xpf b/data/presets/X-Pressive/Creature.xpf deleted file mode 100644 index b667a9c7f..000000000 --- a/data/presets/X-Pressive/Creature.xpf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/data/presets/X-Pressive/Electric Shock.xpf b/data/presets/X-Pressive/Electric Shock.xpf deleted file mode 100644 index 7dea6fe4a..000000000 --- a/data/presets/X-Pressive/Electric Shock.xpf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/data/presets/X-Pressive/Faded Colors.xpf b/data/presets/X-Pressive/Faded Colors.xpf deleted file mode 100644 index 84a37826a..000000000 --- a/data/presets/X-Pressive/Faded Colors.xpf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/data/presets/X-Pressive/Fat Flute.xpf b/data/presets/X-Pressive/Fat Flute.xpf deleted file mode 100644 index 92242114e..000000000 --- a/data/presets/X-Pressive/Fat Flute.xpf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/data/presets/X-Pressive/Horn.xpf b/data/presets/X-Pressive/Horn.xpf deleted file mode 100644 index 099480569..000000000 --- a/data/presets/X-Pressive/Horn.xpf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/data/presets/X-Pressive/Piano-Gong.xpf b/data/presets/X-Pressive/Piano-Gong.xpf deleted file mode 100644 index 241f61a55..000000000 --- a/data/presets/X-Pressive/Piano-Gong.xpf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/data/presets/X-Pressive/Rubber Bass.xpf b/data/presets/X-Pressive/Rubber Bass.xpf deleted file mode 100644 index 73c3648ba..000000000 --- a/data/presets/X-Pressive/Rubber Bass.xpf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/data/presets/X-Pressive/Space Echoes.xpf b/data/presets/X-Pressive/Space Echoes.xpf deleted file mode 100644 index 1d4d2b543..000000000 --- a/data/presets/X-Pressive/Space Echoes.xpf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/data/presets/X-Pressive/Speaker Swapper.xpf b/data/presets/X-Pressive/Speaker Swapper.xpf deleted file mode 100644 index cf80b9304..000000000 --- a/data/presets/X-Pressive/Speaker Swapper.xpf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/data/presets/X-Pressive/Toss.xpf b/data/presets/X-Pressive/Toss.xpf deleted file mode 100644 index 27a0b3f96..000000000 --- a/data/presets/X-Pressive/Toss.xpf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/data/presets/X-Pressive/Untuned Bell.xpf b/data/presets/X-Pressive/Untuned Bell.xpf deleted file mode 100644 index 744927063..000000000 --- a/data/presets/X-Pressive/Untuned Bell.xpf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/data/presets/X-Pressive/Vibrato.xpf b/data/presets/X-Pressive/Vibrato.xpf deleted file mode 100644 index 34795de11..000000000 --- a/data/presets/X-Pressive/Vibrato.xpf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/data/presets/X-Pressive/X-Distorted.xpf b/data/presets/X-Pressive/X-Distorted.xpf deleted file mode 100644 index cbe3742a5..000000000 --- a/data/presets/X-Pressive/X-Distorted.xpf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/data/presets/X-Pressive/Accordion.xpf b/data/presets/Xpressive/Accordion.xpf similarity index 100% rename from data/presets/X-Pressive/Accordion.xpf rename to data/presets/Xpressive/Accordion.xpf diff --git a/data/presets/Xpressive/Ambition.xpf b/data/presets/Xpressive/Ambition.xpf new file mode 100644 index 000000000..dd6448977 --- /dev/null +++ b/data/presets/Xpressive/Ambition.xpf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/presets/Xpressive/Baby Violin.xpf b/data/presets/Xpressive/Baby Violin.xpf new file mode 100644 index 000000000..45e407fc8 --- /dev/null +++ b/data/presets/Xpressive/Baby Violin.xpf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/presets/Xpressive/Bad Singer.xpf b/data/presets/Xpressive/Bad Singer.xpf new file mode 100644 index 000000000..10fe3b308 --- /dev/null +++ b/data/presets/Xpressive/Bad Singer.xpf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/presets/Xpressive/Cloud Bass.xpf b/data/presets/Xpressive/Cloud Bass.xpf new file mode 100644 index 000000000..15bf4188d --- /dev/null +++ b/data/presets/Xpressive/Cloud Bass.xpf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/presets/Xpressive/Creature.xpf b/data/presets/Xpressive/Creature.xpf new file mode 100644 index 000000000..bee39f224 --- /dev/null +++ b/data/presets/Xpressive/Creature.xpf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/presets/X-Pressive/Dream.xpf b/data/presets/Xpressive/Dream.xpf similarity index 100% rename from data/presets/X-Pressive/Dream.xpf rename to data/presets/Xpressive/Dream.xpf diff --git a/data/presets/Xpressive/Electric Shock.xpf b/data/presets/Xpressive/Electric Shock.xpf new file mode 100644 index 000000000..3f9aef104 --- /dev/null +++ b/data/presets/Xpressive/Electric Shock.xpf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/presets/Xpressive/Faded Colors - notes test.xpf b/data/presets/Xpressive/Faded Colors - notes test.xpf new file mode 100644 index 000000000..de4938f4d --- /dev/null +++ b/data/presets/Xpressive/Faded Colors - notes test.xpf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/presets/Xpressive/Faded Colors.xpf b/data/presets/Xpressive/Faded Colors.xpf new file mode 100644 index 000000000..a514ee438 --- /dev/null +++ b/data/presets/Xpressive/Faded Colors.xpf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/presets/Xpressive/Fat Flute.xpf b/data/presets/Xpressive/Fat Flute.xpf new file mode 100644 index 000000000..76d9e2f84 --- /dev/null +++ b/data/presets/Xpressive/Fat Flute.xpf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/presets/X-Pressive/Frog.xpf b/data/presets/Xpressive/Frog.xpf similarity index 100% rename from data/presets/X-Pressive/Frog.xpf rename to data/presets/Xpressive/Frog.xpf diff --git a/data/presets/Xpressive/Horn.xpf b/data/presets/Xpressive/Horn.xpf new file mode 100644 index 000000000..d44b332b2 --- /dev/null +++ b/data/presets/Xpressive/Horn.xpf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/presets/X-Pressive/Low Battery.xpf b/data/presets/Xpressive/Low Battery.xpf similarity index 64% rename from data/presets/X-Pressive/Low Battery.xpf rename to data/presets/Xpressive/Low Battery.xpf index c0e648ac9..78f1fc78f 100644 --- a/data/presets/X-Pressive/Low Battery.xpf +++ b/data/presets/Xpressive/Low Battery.xpf @@ -1,20 +1,21 @@ - + - - + + - + + + - - - - + + + + - - - + + diff --git a/data/presets/Xpressive/Piano-Gong.xpf b/data/presets/Xpressive/Piano-Gong.xpf new file mode 100644 index 000000000..a8244b799 --- /dev/null +++ b/data/presets/Xpressive/Piano-Gong.xpf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/presets/Xpressive/Rubber Bass.xpf b/data/presets/Xpressive/Rubber Bass.xpf new file mode 100644 index 000000000..4b1409e22 --- /dev/null +++ b/data/presets/Xpressive/Rubber Bass.xpf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/presets/Xpressive/Space Echoes.xpf b/data/presets/Xpressive/Space Echoes.xpf new file mode 100644 index 000000000..be6de3653 --- /dev/null +++ b/data/presets/Xpressive/Space Echoes.xpf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/presets/Xpressive/Speaker Swapper.xpf b/data/presets/Xpressive/Speaker Swapper.xpf new file mode 100644 index 000000000..d4da5aa2f --- /dev/null +++ b/data/presets/Xpressive/Speaker Swapper.xpf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/presets/Xpressive/Toss.xpf b/data/presets/Xpressive/Toss.xpf new file mode 100644 index 000000000..387e78fd9 --- /dev/null +++ b/data/presets/Xpressive/Toss.xpf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/presets/Xpressive/Untuned Bell.xpf b/data/presets/Xpressive/Untuned Bell.xpf new file mode 100644 index 000000000..5dd61ec18 --- /dev/null +++ b/data/presets/Xpressive/Untuned Bell.xpf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/presets/Xpressive/Vibrato.xpf b/data/presets/Xpressive/Vibrato.xpf new file mode 100644 index 000000000..a7dda25e9 --- /dev/null +++ b/data/presets/Xpressive/Vibrato.xpf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/presets/Xpressive/X-Distorted.xpf b/data/presets/Xpressive/X-Distorted.xpf new file mode 100644 index 000000000..b42495d75 --- /dev/null +++ b/data/presets/Xpressive/X-Distorted.xpf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/projects/demos/CapDan/CapDan-TwilightArea-OriginalByAlf42red.mmpz b/data/projects/demos/CapDan/CapDan-TwilightArea-OriginalByAlf42red.mmpz index 1687e8c34..b4a00e1ea 100644 Binary files a/data/projects/demos/CapDan/CapDan-TwilightArea-OriginalByAlf42red.mmpz and b/data/projects/demos/CapDan/CapDan-TwilightArea-OriginalByAlf42red.mmpz differ diff --git a/data/projects/demos/CapDan/CapDan-ZeroSumGame-OriginalByZakarra.mmpz b/data/projects/demos/CapDan/CapDan-ZeroSumGame-OriginalByZakarra.mmpz index 95a29daff..578c4f926 100644 Binary files a/data/projects/demos/CapDan/CapDan-ZeroSumGame-OriginalByZakarra.mmpz and b/data/projects/demos/CapDan/CapDan-ZeroSumGame-OriginalByZakarra.mmpz differ diff --git a/data/projects/demos/EsoXLB-CPU.mmpz b/data/projects/demos/EsoXLB-CPU.mmpz index 1c2549027..bc2445e87 100644 Binary files a/data/projects/demos/EsoXLB-CPU.mmpz and b/data/projects/demos/EsoXLB-CPU.mmpz differ diff --git a/data/projects/demos/Greippi - Krem Kaakkuja (Second Flight Remix).mmpz b/data/projects/demos/Greippi - Krem Kaakkuja (Second Flight Remix).mmpz index 2f862dd51..6c9f34369 100644 Binary files a/data/projects/demos/Greippi - Krem Kaakkuja (Second Flight Remix).mmpz and b/data/projects/demos/Greippi - Krem Kaakkuja (Second Flight Remix).mmpz differ diff --git a/data/projects/demos/Impulslogik-Zen.mmpz b/data/projects/demos/Impulslogik-Zen.mmpz index 05fa375c4..774ce89e3 100644 Binary files a/data/projects/demos/Impulslogik-Zen.mmpz and b/data/projects/demos/Impulslogik-Zen.mmpz differ diff --git a/data/projects/demos/Jousboxx-BuzzerBeater.mmpz b/data/projects/demos/Jousboxx-BuzzerBeater.mmpz index 60795608c..59f0d63f6 100644 Binary files a/data/projects/demos/Jousboxx-BuzzerBeater.mmpz and b/data/projects/demos/Jousboxx-BuzzerBeater.mmpz differ diff --git a/data/projects/demos/Momo64-esp.mmpz b/data/projects/demos/Momo64-esp.mmpz index 68ae6822c..37d1a52b5 100644 Binary files a/data/projects/demos/Momo64-esp.mmpz and b/data/projects/demos/Momo64-esp.mmpz differ diff --git a/data/projects/demos/Namitryus-K-Project.mmpz b/data/projects/demos/Namitryus-K-Project.mmpz index 6d463cbb9..4d62826c9 100644 Binary files a/data/projects/demos/Namitryus-K-Project.mmpz and b/data/projects/demos/Namitryus-K-Project.mmpz differ diff --git a/data/projects/demos/Oglsdl-Dr8v2.mmpz b/data/projects/demos/Oglsdl-Dr8v2.mmpz index eb9d7559a..14b1b0e85 100644 Binary files a/data/projects/demos/Oglsdl-Dr8v2.mmpz and b/data/projects/demos/Oglsdl-Dr8v2.mmpz differ diff --git a/data/projects/demos/Oglsdl-PpTrip.mmpz b/data/projects/demos/Oglsdl-PpTrip.mmpz index d1baceeba..776aeea2b 100644 Binary files a/data/projects/demos/Oglsdl-PpTrip.mmpz and b/data/projects/demos/Oglsdl-PpTrip.mmpz differ diff --git a/data/projects/demos/Popsip-Electric Dancer.mmpz b/data/projects/demos/Popsip-Electric Dancer.mmpz index fc93dd64a..1c935dbe1 100644 Binary files a/data/projects/demos/Popsip-Electric Dancer.mmpz and b/data/projects/demos/Popsip-Electric Dancer.mmpz differ diff --git a/data/projects/demos/Root84-Initialize.mmpz b/data/projects/demos/Root84-Initialize.mmpz index 349fcb88f..05200823a 100644 Binary files a/data/projects/demos/Root84-Initialize.mmpz and b/data/projects/demos/Root84-Initialize.mmpz differ diff --git a/data/projects/demos/Saber-FinalStep.mmpz b/data/projects/demos/Saber-FinalStep.mmpz index 5e3d1d1ff..05a5022a7 100644 Binary files a/data/projects/demos/Saber-FinalStep.mmpz and b/data/projects/demos/Saber-FinalStep.mmpz differ diff --git a/data/projects/demos/Settel-InnerRecreation.mmpz b/data/projects/demos/Settel-InnerRecreation.mmpz index aaa01e0bc..78e1d611d 100644 Binary files a/data/projects/demos/Settel-InnerRecreation.mmpz and b/data/projects/demos/Settel-InnerRecreation.mmpz differ diff --git a/data/projects/demos/Shovon-ProgressiveHousePluckDemo.mmpz b/data/projects/demos/Shovon-ProgressiveHousePluckDemo.mmpz index 2d31bd7bd..3ec6a2cff 100644 Binary files a/data/projects/demos/Shovon-ProgressiveHousePluckDemo.mmpz and b/data/projects/demos/Shovon-ProgressiveHousePluckDemo.mmpz differ diff --git a/data/projects/demos/Skiessi/Skiessi-C64.mmpz b/data/projects/demos/Skiessi/Skiessi-C64.mmpz index f0b3f5cdb..a9756453b 100644 Binary files a/data/projects/demos/Skiessi/Skiessi-C64.mmpz and b/data/projects/demos/Skiessi/Skiessi-C64.mmpz differ diff --git a/data/projects/demos/Skiessi/Skiessi-Onion.mmpz b/data/projects/demos/Skiessi/Skiessi-Onion.mmpz index 0c40fb60a..23a1ddc48 100644 Binary files a/data/projects/demos/Skiessi/Skiessi-Onion.mmpz and b/data/projects/demos/Skiessi/Skiessi-Onion.mmpz differ diff --git a/data/projects/demos/Skiessi/Skiessi-RandomProjectNumber14253.mmpz b/data/projects/demos/Skiessi/Skiessi-RandomProjectNumber14253.mmpz index d3c6e0f8d..bc2810567 100644 Binary files a/data/projects/demos/Skiessi/Skiessi-RandomProjectNumber14253.mmpz and b/data/projects/demos/Skiessi/Skiessi-RandomProjectNumber14253.mmpz differ diff --git a/data/projects/demos/Skiessi/Skiessi-TurningPoint.mmpz b/data/projects/demos/Skiessi/Skiessi-TurningPoint.mmpz index ee5be4b55..47a0a3672 100644 Binary files a/data/projects/demos/Skiessi/Skiessi-TurningPoint.mmpz and b/data/projects/demos/Skiessi/Skiessi-TurningPoint.mmpz differ diff --git a/data/projects/demos/Socceroos-Progress.mmpz b/data/projects/demos/Socceroos-Progress.mmpz index 74ff5774c..854663787 100644 Binary files a/data/projects/demos/Socceroos-Progress.mmpz and b/data/projects/demos/Socceroos-Progress.mmpz differ diff --git a/data/projects/demos/TameAnderson-MakeMe.mmpz b/data/projects/demos/TameAnderson-MakeMe.mmpz index de0152818..b69a64e3a 100644 Binary files a/data/projects/demos/TameAnderson-MakeMe.mmpz and b/data/projects/demos/TameAnderson-MakeMe.mmpz differ diff --git a/data/projects/demos/Thaledric-Armageddon.mmpz b/data/projects/demos/Thaledric-Armageddon.mmpz index 0e9d5f83f..731ea55f7 100644 Binary files a/data/projects/demos/Thaledric-Armageddon.mmpz and b/data/projects/demos/Thaledric-Armageddon.mmpz differ diff --git a/data/projects/demos/Thomasso-AxeFromThe80s.mmpz b/data/projects/demos/Thomasso-AxeFromThe80s.mmpz index af68b8b8b..f7056d38c 100644 Binary files a/data/projects/demos/Thomasso-AxeFromThe80s.mmpz and b/data/projects/demos/Thomasso-AxeFromThe80s.mmpz differ diff --git a/data/projects/demos/TobyDox-Psycho.mmpz b/data/projects/demos/TobyDox-Psycho.mmpz index 09ec6b6a6..c4fe7a1c4 100644 Binary files a/data/projects/demos/TobyDox-Psycho.mmpz and b/data/projects/demos/TobyDox-Psycho.mmpz differ diff --git a/data/projects/demos/unfa-Spoken.mmpz b/data/projects/demos/unfa-Spoken.mmpz index 659afa03a..66b7589d1 100644 Binary files a/data/projects/demos/unfa-Spoken.mmpz and b/data/projects/demos/unfa-Spoken.mmpz differ diff --git a/data/projects/shorties/DirtyLove.mmpz b/data/projects/shorties/DirtyLove.mmpz index 177c05ce5..37b766f4d 100644 Binary files a/data/projects/shorties/DirtyLove.mmpz and b/data/projects/shorties/DirtyLove.mmpz differ diff --git a/data/projects/shorties/Root84-TrancyLoop.mmpz b/data/projects/shorties/Root84-TrancyLoop.mmpz index 22bd5f2fa..f5eb032ac 100644 Binary files a/data/projects/shorties/Root84-TrancyLoop.mmpz and b/data/projects/shorties/Root84-TrancyLoop.mmpz differ diff --git a/data/projects/shorties/Skiessi-222.mmpz b/data/projects/shorties/Skiessi-222.mmpz index a56833645..a7076949c 100644 Binary files a/data/projects/shorties/Skiessi-222.mmpz and b/data/projects/shorties/Skiessi-222.mmpz differ diff --git a/data/projects/shorties/Surrender-Main.mmpz b/data/projects/shorties/Surrender-Main.mmpz index a94df2497..556581170 100644 Binary files a/data/projects/shorties/Surrender-Main.mmpz and b/data/projects/shorties/Surrender-Main.mmpz differ diff --git a/data/projects/shorties/sv-DnB-Startup.mmpz b/data/projects/shorties/sv-DnB-Startup.mmpz index c9d8d5970..db32d3452 100644 Binary files a/data/projects/shorties/sv-DnB-Startup.mmpz and b/data/projects/shorties/sv-DnB-Startup.mmpz differ diff --git a/data/projects/shorties/sv-Trance-Startup.mmpz b/data/projects/shorties/sv-Trance-Startup.mmpz index c508b1500..bea731461 100644 Binary files a/data/projects/shorties/sv-Trance-Startup.mmpz and b/data/projects/shorties/sv-Trance-Startup.mmpz differ diff --git a/data/themes/classic/style.css b/data/themes/classic/style.css index 12d90981d..97d68f6e3 100644 --- a/data/themes/classic/style.css +++ b/data/themes/classic/style.css @@ -897,7 +897,4 @@ LmmsPalette { qproperty-brightText: #4afd85; qproperty-highlight: #202020; qproperty-highlightedText: #ffffff; - /* the next two are used for whatsthis dialogs */ - qproperty-toolTipText: #000; - qproperty-toolTipBase: #c9c9c9; } diff --git a/data/themes/default/style.css b/data/themes/default/style.css index 5d889295c..f95469201 100644 --- a/data/themes/default/style.css +++ b/data/themes/default/style.css @@ -9,16 +9,23 @@ QLabel, QTreeWidget, QListWidget, QGroupBox, QMenuBar { QTreeView { outline: none; + font-size: 12px; +} + +QTreeWidget::item { + padding: 1px; } QTreeWidget::item:hover, QTreeWidget::branch:hover { background-color: #3C444E; + padding-left: 0px; } QTreeWidget::item:selected, QTreeWidget::branch:selected { background-color: #17793b; + padding-left: 0px; } QTreeView::branch:has-children:open { @@ -81,6 +88,12 @@ TextFloat { } +/* splash screen text */ +QSplashScreen QLabel { + color: white; +} + + QMenu { border-top: 2px solid #08993E; background-color: #15191c; @@ -920,7 +933,4 @@ LmmsPalette { qproperty-brightText: #d1d8e4; qproperty-highlight: #262b30; qproperty-highlightedText: #d1d8e4; - /* the next two are used for whatsthis dialogs */ - qproperty-toolTipText: #d1d8e4; - qproperty-toolTipBase: #101213; } diff --git a/debian/control b/debian/control index 463353df0..880e0d89a 100644 --- a/debian/control +++ b/debian/control @@ -37,18 +37,28 @@ Build-Depends: qttools5-dev, wine64-tools [amd64] | wine32-tools [i386] Standards-Version: 4.2.1.4 -Homepage: http://lmms.io/ +Homepage: https://lmms.io/ Vcs-Browser: https://salsa.debian.org/debian-edu-pkg-team/lmms.git Package: lmms-bin Architecture: any -Depends: lmms-common (>= ${source:Version}), ${shlibs:Depends}, ${misc:Depends}, - stk -Recommends: tap-plugins, caps, +Depends: + lmms-common (>= ${source:Version}), + ${shlibs:Depends}, + ${misc:Depends}, + stk, +Recommends: + caps, lmms-vst-server:i386 (>= ${source:Version}), - lmms-vst-server:amd64 (>= ${source:Version}) -Suggests: fil-plugins, mcp-plugins, omins, freepats, fluid-soundfont-gm, - ladspa-plugin + lmms-vst-server:amd64 (>= ${source:Version}), + tap-plugins, +Suggests: + fil-plugins, + fluid-soundfont-gm, + freepats, + ladspa-plugin, + mcp-plugins, + omins, Replaces: lmms-common (<< 1.0.0-1) Breaks: lmms-common (<< 1.0.0-1) Multi-Arch: allowed @@ -67,7 +77,9 @@ Description: Linux Multimedia Studio - minimal installation Package: lmms Architecture: any -Depends: lmms-bin, ${misc:Depends} +Depends: + lmms-bin, + ${misc:Depends}, Description: Linux Multimedia Studio LMMS aims to be a free alternative to popular (but commercial and closed- source) programs like FruityLoops, Cubase and Logic giving you the ability of @@ -83,7 +95,10 @@ Description: Linux Multimedia Studio Package: lmms-common Architecture: all -Depends: zynaddsubfx-data, ${shlibs:Depends}, ${misc:Depends} +Depends: + ${shlibs:Depends}, + ${misc:Depends}, + zynaddsubfx-data, Pre-Depends: ${misc:Pre-Depends} Description: Linux Multimedia Studio - common files LMMS aims to be a free alternative to popular (but commercial and closed- @@ -101,7 +116,10 @@ Description: Linux Multimedia Studio - common files Package: lmms-vst-server Architecture: amd64 i386 -Depends: wine64 [amd64] | wine64-development [amd64] | wine32 [i386] | wine32-development [i386], ${shlibs:Depends}, ${misc:Depends} +Depends: + wine64 [amd64] | wine64-development [amd64] | wine32 [i386] | wine32-development [i386], + ${shlibs:Depends}, + ${misc:Depends}, Recommends: lmms-bin:any Description: Linux Multimedia Studio - VST server This package contains a helper application that loads VST plugins. diff --git a/debian/copyright b/debian/copyright index 3fbf0917e..01b30459e 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,4 +1,4 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: LMMS Upstream-Contact: https://github.com/LMMS/lmms Source: https://github.com/LMMS/lmms/tags @@ -1367,7 +1367,7 @@ License: WOL documentation for any purpose is hereby granted without fee, provided that the above copyright notice and this license appear in all source copies. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF - ANY KIND. See http://www.dspguru.com/wol.htm for more information. + ANY KIND. See https://www.dspguru.com/wol.htm for more information. License: non-free This license does not comply with Debian Free Software Guidelines. diff --git a/debian/patches/contributors.patch b/debian/patches/contributors.patch deleted file mode 100644 index d2b55fd9a..000000000 --- a/debian/patches/contributors.patch +++ /dev/null @@ -1,89 +0,0 @@ -Description: Add contributors - The list of contributors is missing from the source tarball. This list is - generated from upstream repository, running: - git shortlog -sne v1.1.3 | cut -c8- - See https://github.com/LMMS/lmms/issues/2914 for more information. -Author: Javier Serrano Polo - -Index: lmms-1.1.3/doc/CONTRIBUTORS -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ lmms-1.1.3/doc/CONTRIBUTORS 2016-07-12 00:41:47.000000000 +0200 -@@ -0,0 +1,77 @@ -+Tobias Doerffel -+Vesa -+Javier Serrano Polo -+Paul Giblock -+Tres Finocchiaro -+Lukas W -+Raine M. Ekman -+Wong Cho Ching -+Hannu Haahti -+Danny McRae -+Dave French -+Daniel Winzen -+Andreas Brandmaier -+Andrew Kelley -+Oskar Wallgren -+Mike Choi -+Alexandre Almeida -+NoiseByNorthwest -+Johannes Lorenz -+Stian Jørgensrud -+falkTX -+Csaba Hruska -+StakeoutPunch -+ma2moto -+mikobuntu -+8tab <8tab@wp.pl> -+Matthew Krafczyk -+Spekular -+Umcaruje -+DeRobyJ -+Jonathan Aquilina -+ra -+wongcc966422 -+Gurjot Singh -+Janne Sinisalo -+Krzysztof Foltman -+Lou Herard -+Paul Wayper -+Rüdiger Ranft -+Yann Collette -+grindhold -+midi-pascal -+unfa -+Ian Sannar -+Jaroslav Petrnoušek -+LYF610400210 -+Rafael Ruggiero -+psyomn -+quadro -+sarahkeefe -+Achim Settelmeier -+André Hentschel -+Armin Kazmi -+Attila Herman -+Christopher A. Oliver -+Devin Venable -+Fastigium -+Frank Mather -+Frederik -+Hexasoft -+Jens Lang -+Jesse Dubay -+Joel Muzzerall -+Kristi -+Markus Elfring -+Nikos Chantziaras -+Paul Nasca -+Peter Nelson -+Ra -+Steffen Baranowsky -+Thorsten Müller -+TonyChyi -+devin -+dnl-music -+fundamental -+groboclown -+zm1990s diff --git a/debian/patches/series b/debian/patches/series index aba1af044..94ae11454 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,3 +1,2 @@ -contributors.patch clang.patch build-amd64-20181013.patch diff --git a/include/AudioAlsa.h b/include/AudioAlsa.h index 77938e164..b1aa9647a 100644 --- a/include/AudioAlsa.h +++ b/include/AudioAlsa.h @@ -80,10 +80,10 @@ public: static DeviceInfoCollection getAvailableDevices(); private: - virtual void startProcessing(); - virtual void stopProcessing(); - virtual void applyQualitySettings(); - virtual void run(); + void startProcessing() override; + void stopProcessing() override; + void applyQualitySettings() override; + void run() override; int setHWParams( const ch_cnt_t _channels, snd_pcm_access_t _access ); int setSWParams(); diff --git a/include/AudioAlsaSetupWidget.h b/include/AudioAlsaSetupWidget.h index f087d2fd7..db88558a7 100644 --- a/include/AudioAlsaSetupWidget.h +++ b/include/AudioAlsaSetupWidget.h @@ -46,7 +46,7 @@ public: AudioAlsaSetupWidget( QWidget * _parent ); virtual ~AudioAlsaSetupWidget(); - virtual void saveSettings(); + void saveSettings() override; public slots: void onCurrentIndexChanged(int index); diff --git a/include/AudioDummy.h b/include/AudioDummy.h index 5094caddc..0772c69eb 100644 --- a/include/AudioDummy.h +++ b/include/AudioDummy.h @@ -64,11 +64,11 @@ public: { } - virtual void saveSettings() + void saveSettings() override { } - virtual void show() + void show() override { parentWidget()->hide(); QWidget::show(); @@ -78,17 +78,17 @@ public: private: - virtual void startProcessing() + void startProcessing() override { start(); } - virtual void stopProcessing() + void stopProcessing() override { stopProcessingThread( this ); } - virtual void run() + void run() override { MicroTimer timer; while( true ) diff --git a/include/AudioFileMP3.h b/include/AudioFileMP3.h index 497208e20..057fd13a4 100644 --- a/include/AudioFileMP3.h +++ b/include/AudioFileMP3.h @@ -58,7 +58,7 @@ public: protected: virtual void writeBuffer( const surroundSampleFrame * /* _buf*/, const fpp_t /*_frames*/, - const float /*_master_gain*/ ); + const float /*_master_gain*/ ) override; private: void flushRemainingBuffers(); diff --git a/include/AudioFileOgg.h b/include/AudioFileOgg.h index 656a7174e..8082f3767 100644 --- a/include/AudioFileOgg.h +++ b/include/AudioFileOgg.h @@ -59,7 +59,7 @@ public: private: virtual void writeBuffer( const surroundSampleFrame * _ab, const fpp_t _frames, - const float _master_gain ); + const float _master_gain ) override; bool startEncoding(); void finishEncoding(); diff --git a/include/AudioFileWave.h b/include/AudioFileWave.h index 4d2778bad..7c8d54964 100644 --- a/include/AudioFileWave.h +++ b/include/AudioFileWave.h @@ -56,7 +56,7 @@ public: private: virtual void writeBuffer( const surroundSampleFrame * _ab, const fpp_t _frames, - float _master_gain ); + float _master_gain ) override; bool startEncoding(); void finishEncoding(); diff --git a/include/AudioOss.h b/include/AudioOss.h index bacfd9597..9e4787ff2 100644 --- a/include/AudioOss.h +++ b/include/AudioOss.h @@ -60,7 +60,7 @@ public: setupWidget( QWidget * _parent ); virtual ~setupWidget(); - virtual void saveSettings(); + void saveSettings() override; private: QLineEdit * m_device; @@ -70,10 +70,10 @@ public: private: - virtual void startProcessing(); - virtual void stopProcessing(); - virtual void applyQualitySettings(); - virtual void run(); + void startProcessing() override; + void stopProcessing() override; + void applyQualitySettings() override; + void run() override; int m_audioFD; diff --git a/include/AudioPort.h b/include/AudioPort.h index 2842c6a17..146bbd192 100644 --- a/include/AudioPort.h +++ b/include/AudioPort.h @@ -100,8 +100,8 @@ public: bool processEffects(); // ThreadableJob stuff - virtual void doProcessing(); - virtual bool requiresProcessing() const + void doProcessing() override; + bool requiresProcessing() const override { return true; } diff --git a/include/AudioPulseAudio.h b/include/AudioPulseAudio.h index 496746691..e65180a74 100644 --- a/include/AudioPulseAudio.h +++ b/include/AudioPulseAudio.h @@ -62,7 +62,7 @@ public: setupWidget( QWidget * _parent ); virtual ~setupWidget(); - virtual void saveSettings(); + void saveSettings() override; private: QLineEdit * m_device; @@ -80,10 +80,10 @@ public: private: - virtual void startProcessing(); - virtual void stopProcessing(); - virtual void applyQualitySettings(); - virtual void run(); + void startProcessing() override; + void stopProcessing() override; + void applyQualitySettings() override; + void run() override; volatile bool m_quit; diff --git a/include/AudioSampleRecorder.h b/include/AudioSampleRecorder.h index 69ac19490..0a82d2d96 100644 --- a/include/AudioSampleRecorder.h +++ b/include/AudioSampleRecorder.h @@ -48,7 +48,7 @@ public: private: virtual void writeBuffer( const surroundSampleFrame * _ab, const fpp_t _frames, - const float _master_gain ); + const float _master_gain ) override; typedef QList > BufferList; BufferList m_buffers; diff --git a/include/AudioSdl.h b/include/AudioSdl.h index fd8c544c2..93f23abed 100644 --- a/include/AudioSdl.h +++ b/include/AudioSdl.h @@ -60,9 +60,9 @@ public: { public: setupWidget( QWidget * _parent ); - virtual ~setupWidget(); + ~setupWidget() override; - virtual void saveSettings(); + void saveSettings() override; private: QLineEdit * m_device; @@ -71,9 +71,9 @@ public: private: - virtual void startProcessing(); - virtual void stopProcessing(); - virtual void applyQualitySettings(); + void startProcessing() override; + void stopProcessing() override; + void applyQualitySettings() override; static void sdlAudioCallback( void * _udata, Uint8 * _buf, int _len ); void sdlAudioCallback( Uint8 * _buf, int _len ); diff --git a/include/AudioSndio.h b/include/AudioSndio.h index d2bc5c074..f8cf56848 100644 --- a/include/AudioSndio.h +++ b/include/AudioSndio.h @@ -58,7 +58,7 @@ public: setupWidget( QWidget * _parent ); virtual ~setupWidget(); - virtual void saveSettings( void ); + void saveSettings( void ) override; private: QLineEdit * m_device; @@ -66,10 +66,10 @@ public: } ; private: - virtual void startProcessing( void ); - virtual void stopProcessing( void ); - virtual void applyQualitySettings( void ); - virtual void run( void ); + void startProcessing( void ) override; + void stopProcessing( void ) override; + void applyQualitySettings( void ) override; + void run( void ) override; struct sio_hdl *m_hdl; struct sio_par m_par; diff --git a/include/AutomatableButton.h b/include/AutomatableButton.h index 4b5065542..d7859a10c 100644 --- a/include/AutomatableButton.h +++ b/include/AutomatableButton.h @@ -48,7 +48,7 @@ public: model()->setJournalling( _on ); } - virtual void modelChanged(); + void modelChanged() override; public slots: @@ -62,9 +62,9 @@ public slots: protected: - virtual void contextMenuEvent( QContextMenuEvent * _me ); - virtual void mousePressEvent( QMouseEvent * _me ); - virtual void mouseReleaseEvent( QMouseEvent * _me ); + void contextMenuEvent( QContextMenuEvent * _me ) override; + void mousePressEvent( QMouseEvent * _me ) override; + void mouseReleaseEvent( QMouseEvent * _me ) override; private: @@ -92,7 +92,7 @@ public: void activateButton( AutomatableButton * _btn ); - virtual void modelChanged(); + void modelChanged() override; private slots: diff --git a/include/AutomatableModel.h b/include/AutomatableModel.h index 3e0b6143d..6d8000804 100644 --- a/include/AutomatableModel.h +++ b/include/AutomatableModel.h @@ -255,7 +255,7 @@ public: specified DOM element using as attribute/node name */ virtual void loadSettings( const QDomElement& element, const QString& name ); - virtual QString nodeName() const + QString nodeName() const override { return "automatablemodel"; } @@ -337,12 +337,12 @@ private: static bool mustQuoteName(const QString &name); - virtual void saveSettings( QDomDocument& doc, QDomElement& element ) + void saveSettings( QDomDocument& doc, QDomElement& element ) override { saveSettings( doc, element, "value" ); } - virtual void loadSettings( const QDomElement& element ) + void loadSettings( const QDomElement& element ) override { loadSettings( element, "value" ); } diff --git a/include/AutomatableModelView.h b/include/AutomatableModelView.h index 964ffdc5d..1bcbd97d6 100644 --- a/include/AutomatableModelView.h +++ b/include/AutomatableModelView.h @@ -49,7 +49,7 @@ public: return castModel(); } - virtual void setModel( Model* model, bool isOldModelValid = true ); + void setModel( Model* model, bool isOldModelValid = true ) override; template inline T value() const diff --git a/include/AutomatableSlider.h b/include/AutomatableSlider.h index f58d4a059..b51ef1e3f 100644 --- a/include/AutomatableSlider.h +++ b/include/AutomatableSlider.h @@ -51,12 +51,12 @@ signals: protected: - virtual void contextMenuEvent( QContextMenuEvent * _me ); - virtual void mousePressEvent( QMouseEvent * _me ); - virtual void mouseReleaseEvent( QMouseEvent * _me ); - virtual void wheelEvent( QWheelEvent * _me ); + void contextMenuEvent( QContextMenuEvent * _me ) override; + void mousePressEvent( QMouseEvent * _me ) override; + void mouseReleaseEvent( QMouseEvent * _me ) override; + void wheelEvent( QWheelEvent * _me ) override; - virtual void modelChanged(); + void modelChanged() override; private: diff --git a/include/AutomationEditor.h b/include/AutomationEditor.h index 9705c5efa..60b894f1f 100644 --- a/include/AutomationEditor.h +++ b/include/AutomationEditor.h @@ -73,9 +73,9 @@ public: return m_pattern != nullptr; } - virtual void saveSettings(QDomDocument & doc, QDomElement & parent); - virtual void loadSettings(const QDomElement & parent); - QString nodeName() const + void saveSettings(QDomDocument & doc, QDomElement & parent) override; + void loadSettings(const QDomElement & parent) override; + QString nodeName() const override { return "automationeditor"; } @@ -114,14 +114,14 @@ public slots: protected: typedef AutomationPattern::timeMap timeMap; - virtual void keyPressEvent(QKeyEvent * ke); - virtual void leaveEvent(QEvent * e); - virtual void mousePressEvent(QMouseEvent * mouseEvent); - virtual void mouseReleaseEvent(QMouseEvent * mouseEvent); - virtual void mouseMoveEvent(QMouseEvent * mouseEvent); - virtual void paintEvent(QPaintEvent * pe); - virtual void resizeEvent(QResizeEvent * re); - virtual void wheelEvent(QWheelEvent * we); + void keyPressEvent(QKeyEvent * ke) override; + void leaveEvent(QEvent * e) override; + void mousePressEvent(QMouseEvent * mouseEvent) override; + void mouseReleaseEvent(QMouseEvent * mouseEvent) override; + void mouseMoveEvent(QMouseEvent * mouseEvent) override; + void paintEvent(QPaintEvent * pe) override; + void resizeEvent(QResizeEvent * re) override; + void wheelEvent(QWheelEvent * we) override; float getLevel( int y ); int xCoordOfTick( int tick ); @@ -176,8 +176,8 @@ private: static const int TOP_MARGIN = 16; static const int DEFAULT_Y_DELTA = 6; - static const int DEFAULT_STEPS_PER_TACT = 16; - static const int DEFAULT_PPT = 12 * DEFAULT_STEPS_PER_TACT; + static const int DEFAULT_STEPS_PER_BAR = 16; + static const int DEFAULT_PPB = 12 * DEFAULT_STEPS_PER_BAR; static const int VALUES_WIDTH = 64; @@ -230,7 +230,7 @@ private: float m_drawLastLevel; tick_t m_drawLastTick; - int m_ppt; + int m_ppb; int m_y_delta; bool m_y_auto; @@ -282,14 +282,14 @@ public: void setCurrentPattern(AutomationPattern* pattern); const AutomationPattern* currentPattern(); - virtual void dropEvent( QDropEvent * _de ); - virtual void dragEnterEvent( QDragEnterEvent * _dee ); + void dropEvent( QDropEvent * _de ) override; + void dragEnterEvent( QDragEnterEvent * _dee ) override; void open(AutomationPattern* pattern); AutomationEditor* m_editor; - QSize sizeHint() const; + QSize sizeHint() const override; public slots: void clearCurrentPattern(); @@ -297,9 +297,12 @@ public slots: signals: void currentPatternChanged(); +protected: + void focusInEvent(QFocusEvent * event) override; + protected slots: - void play(); - void stop(); + void play() override; + void stop() override; private slots: void updateWindowTitle(); diff --git a/include/AutomationPattern.h b/include/AutomationPattern.h index 070b6c669..cad9d0a1d 100644 --- a/include/AutomationPattern.h +++ b/include/AutomationPattern.h @@ -140,13 +140,13 @@ public: const QString name() const; // settings-management - virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void loadSettings( const QDomElement & _this ); + void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; + void loadSettings( const QDomElement & _this ) override; static const QString classNodeName() { return "automationpattern"; } - QString nodeName() const { return classNodeName(); } + QString nodeName() const override { return classNodeName(); } - virtual TrackContentObjectView * createView( TrackView * _tv ); + TrackContentObjectView * createView( TrackView * _tv ) override; static bool isAutomated( const AutomatableModel * _m ); diff --git a/include/AutomationPatternView.h b/include/AutomationPatternView.h index 45aa9ef2a..3f019483a 100644 --- a/include/AutomationPatternView.h +++ b/include/AutomationPatternView.h @@ -44,7 +44,7 @@ public: public slots: /// Opens this view's pattern in the global automation editor void openInAutomationEditor(); - virtual void update(); + void update() override; protected slots: @@ -56,11 +56,11 @@ protected slots: void flipX(); protected: - virtual void constructContextMenu( QMenu * ); - virtual void mouseDoubleClickEvent(QMouseEvent * me ); - virtual void paintEvent( QPaintEvent * pe ); - virtual void dragEnterEvent( QDragEnterEvent * _dee ); - virtual void dropEvent( QDropEvent * _de ); + void constructContextMenu( QMenu * ) override; + void mouseDoubleClickEvent(QMouseEvent * me ) override; + void paintEvent( QPaintEvent * pe ) override; + void dragEnterEvent( QDragEnterEvent * _dee ) override; + void dropEvent( QDropEvent * _de ) override; private: diff --git a/include/AutomationTrack.h b/include/AutomationTrack.h index 195c21e9d..92a50dd04 100644 --- a/include/AutomationTrack.h +++ b/include/AutomationTrack.h @@ -38,19 +38,19 @@ public: virtual ~AutomationTrack() = default; virtual bool play( const MidiTime & _start, const fpp_t _frames, - const f_cnt_t _frame_base, int _tco_num = -1 ); + const f_cnt_t _frame_base, int _tco_num = -1 ) override; - virtual QString nodeName() const + QString nodeName() const override { return "automationtrack"; } - virtual TrackView * createView( TrackContainerView* ); - virtual TrackContentObject * createTCO( const MidiTime & _pos ); + TrackView * createView( TrackContainerView* ) override; + TrackContentObject * createTCO( const MidiTime & _pos ) override; virtual void saveTrackSpecificSettings( QDomDocument & _doc, - QDomElement & _parent ); - virtual void loadTrackSpecificSettings( const QDomElement & _this ); + QDomElement & _parent ) override; + void loadTrackSpecificSettings( const QDomElement & _this ) override; private: friend class AutomationTrackView; @@ -65,8 +65,8 @@ public: AutomationTrackView( AutomationTrack* at, TrackContainerView* tcv ); virtual ~AutomationTrackView() = default; - virtual void dragEnterEvent( QDragEnterEvent * _dee ); - virtual void dropEvent( QDropEvent * _de ); + void dragEnterEvent( QDragEnterEvent * _dee ) override; + void dropEvent( QDropEvent * _de ) override; } ; diff --git a/include/BBEditor.h b/include/BBEditor.h index 59b7142f4..ed54beaf1 100644 --- a/include/BBEditor.h +++ b/include/BBEditor.h @@ -42,7 +42,7 @@ public: BBEditor( BBTrackContainer * _tc ); ~BBEditor(); - QSize sizeHint() const; + QSize sizeHint() const override; const BBTrackContainerView* trackContainerView() const { return m_trackContainerView; @@ -54,8 +54,8 @@ public: void removeBBView( int bb ); public slots: - void play(); - void stop(); + void play() override; + void stop() override; private: BBTrackContainerView* m_trackContainerView; @@ -70,15 +70,15 @@ class BBTrackContainerView : public TrackContainerView public: BBTrackContainerView(BBTrackContainer* tc); - bool fixedTCOs() const + bool fixedTCOs() const override { return true; } void removeBBView(int bb); - void saveSettings(QDomDocument& doc, QDomElement& element); - void loadSettings(const QDomElement& element); + void saveSettings(QDomDocument& doc, QDomElement& element) override; + void loadSettings(const QDomElement& element) override; public slots: void addSteps(); @@ -88,7 +88,7 @@ public slots: void addAutomationTrack(); protected slots: - void dropEvent(QDropEvent * de ); + void dropEvent(QDropEvent * de ) override; void updatePosition(); private: diff --git a/include/BBTrack.h b/include/BBTrack.h index a906b54d2..70195f28d 100644 --- a/include/BBTrack.h +++ b/include/BBTrack.h @@ -43,9 +43,9 @@ public: BBTCO( Track * _track ); virtual ~BBTCO() = default; - virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void loadSettings( const QDomElement & _this ); - inline virtual QString nodeName() const + void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; + void loadSettings( const QDomElement & _this ) override; + inline QString nodeName() const override { return( "bbtco" ); } @@ -72,7 +72,7 @@ public: int bbTrackIndex(); - virtual TrackContentObjectView * createView( TrackView * _tv ); + TrackContentObjectView * createView( TrackView * _tv ) override; private: QColor m_color; @@ -99,7 +99,7 @@ public: void setColor( QColor _new_color ); public slots: - virtual void update(); + void update() override; protected slots: void openInBBEditor(); @@ -110,9 +110,9 @@ protected slots: protected: - virtual void paintEvent( QPaintEvent * pe ); - virtual void mouseDoubleClickEvent( QMouseEvent * _me ); - virtual void constructContextMenu( QMenu * ); + void paintEvent( QPaintEvent * pe ) override; + void mouseDoubleClickEvent( QMouseEvent * _me ) override; + void constructContextMenu( QMenu * ) override; private: @@ -133,13 +133,13 @@ public: virtual ~BBTrack(); virtual bool play( const MidiTime & _start, const fpp_t _frames, - const f_cnt_t _frame_base, int _tco_num = -1 ); - virtual TrackView * createView( TrackContainerView* tcv ); - virtual TrackContentObject * createTCO( const MidiTime & _pos ); + const f_cnt_t _frame_base, int _tco_num = -1 ) override; + TrackView * createView( TrackContainerView* tcv ) override; + TrackContentObject * createTCO( const MidiTime & _pos ) override; virtual void saveTrackSpecificSettings( QDomDocument & _doc, - QDomElement & _parent ); - virtual void loadTrackSpecificSettings( const QDomElement & _this ); + QDomElement & _parent ) override; + void loadTrackSpecificSettings( const QDomElement & _this ) override; static BBTrack * findBBTrack( int _bb_num ); static void swapBBTracks( Track * _track1, Track * _track2 ); @@ -184,7 +184,7 @@ public: } protected: - inline virtual QString nodeName() const + inline QString nodeName() const override { return( "bbtrack" ); } @@ -211,7 +211,7 @@ public: BBTrackView( BBTrack* bbt, TrackContainerView* tcv ); virtual ~BBTrackView(); - virtual bool close(); + bool close() override; const BBTrack * getBBTrack() const { diff --git a/include/BBTrackContainer.h b/include/BBTrackContainer.h index 236325157..17d6eb5fe 100644 --- a/include/BBTrackContainer.h +++ b/include/BBTrackContainer.h @@ -41,15 +41,15 @@ public: virtual bool play( MidiTime _start, const fpp_t _frames, const f_cnt_t _frame_base, int _tco_num = -1 ); - virtual void updateAfterTrackAdd() override; + void updateAfterTrackAdd() override; - inline virtual QString nodeName() const override + inline QString nodeName() const override { return "bbtrackcontainer"; } - tact_t lengthOfBB( int _bb ) const; - inline tact_t lengthOfCurrentBB() + bar_t lengthOfBB( int _bb ) const; + inline bar_t lengthOfCurrentBB() { return lengthOfBB( currentBB() ); } diff --git a/include/CPULoadWidget.h b/include/CPULoadWidget.h index 610403f57..2bc41283b 100644 --- a/include/CPULoadWidget.h +++ b/include/CPULoadWidget.h @@ -43,7 +43,7 @@ public: protected: - virtual void paintEvent( QPaintEvent * _ev ); + void paintEvent( QPaintEvent * _ev ) override; protected slots: diff --git a/include/ComboBox.h b/include/ComboBox.h index 927c87620..d530c9d92 100644 --- a/include/ComboBox.h +++ b/include/ComboBox.h @@ -57,10 +57,10 @@ public slots: protected: - virtual void contextMenuEvent( QContextMenuEvent* event ); - virtual void mousePressEvent( QMouseEvent* event ); - virtual void paintEvent( QPaintEvent* event ); - virtual void wheelEvent( QWheelEvent* event ); + void contextMenuEvent( QContextMenuEvent* event ) override; + void mousePressEvent( QMouseEvent* event ) override; + void paintEvent( QPaintEvent* event ) override; + void wheelEvent( QWheelEvent* event ) override; private: diff --git a/include/ConfigManager.h b/include/ConfigManager.h index dc5b9f485..556c455a0 100644 --- a/include/ConfigManager.h +++ b/include/ConfigManager.h @@ -36,6 +36,7 @@ #include "lmms_export.h" + class LmmsCore; @@ -57,61 +58,22 @@ class LMMS_EXPORT ConfigManager : public QObject public: static inline ConfigManager * inst() { - if( s_instanceOfMe == NULL ) + if(s_instanceOfMe == NULL ) { s_instanceOfMe = new ConfigManager(); } return s_instanceOfMe; } - const QString & dataDir() const - { - return m_dataDir; - } const QString & workingDir() const { return m_workingDir; } - QString userProjectsDir() const + const QString & dataDir() const { - return workingDir() + PROJECTS_PATH; - } - - QString userTemplateDir() const - { - return workingDir() + TEMPLATE_PATH; - } - - QString userPresetsDir() const - { - return workingDir() + PRESETS_PATH; - } - - QString userSamplesDir() const - { - return workingDir() + SAMPLES_PATH; - } - - QString userGigDir() const - { - return workingDir() + GIG_PATH; - } - - QString userSf2Dir() const - { - return workingDir() + SF2_PATH; - } - - QString userLadspaDir() const - { - return workingDir() + LADSPA_PATH; - } - - QString userVstDir() const - { - return m_vstDir; + return m_dataDir; } QString factoryProjectsDir() const @@ -134,37 +96,27 @@ public: return dataDir() + SAMPLES_PATH; } - QString defaultVersion() const; - QString defaultArtworkDir() const + QString userProjectsDir() const { - return m_dataDir + DEFAULT_THEME_PATH; + return workingDir() + PROJECTS_PATH; } - QString artworkDir() const + QString userTemplateDir() const { - return m_artworkDir; + return workingDir() + TEMPLATE_PATH; } - QString trackIconsDir() const + QString userPresetsDir() const { - return m_dataDir + TRACK_ICON_PATH; + return workingDir() + PRESETS_PATH; } - QString localeDir() const + QString userSamplesDir() const { - return m_dataDir + LOCALE_PATH; + return workingDir() + SAMPLES_PATH; } - const QString & gigDir() const - { - return m_gigDir; - } - - const QString & sf2Dir() const - { - return m_sf2Dir; - } const QString & vstDir() const { @@ -173,18 +125,20 @@ public: const QString & ladspaDir() const { - return m_ladDir; + return m_ladspaDir; } - const QString recoveryFile() const + const QString & sf2Dir() const { - return m_workingDir + "recover.mmp"; + return m_sf2Dir; } - - const QString & version() const + +#ifdef LMMS_HAVE_FLUIDSYNTH + const QString & sf2File() const { - return m_version; + return m_sf2File; } +#endif #ifdef LMMS_HAVE_STK const QString & stkDir() const @@ -193,16 +147,55 @@ public: } #endif -#ifdef LMMS_HAVE_FLUIDSYNTH - const QString & defaultSoundfont() const + const QString & gigDir() const { - return m_defaultSoundfont; + return m_gigDir; } -#endif - const QString & backgroundArtwork() const + + QString userVstDir() const { - return m_backgroundArtwork; + return m_vstDir; + } + + QString userLadspaDir() const + { + return workingDir() + LADSPA_PATH; + } + + QString userSf2Dir() const + { + return workingDir() + SF2_PATH; + } + + QString userGigDir() const + { + return workingDir() + GIG_PATH; + } + + QString defaultThemeDir() const + { + return m_dataDir + DEFAULT_THEME_PATH; + } + + QString themeDir() const + { + return m_themeDir; + } + + const QString & backgroundPicFile() const + { + return m_backgroundPicFile; + } + + QString trackIconsDir() const + { + return m_dataDir + TRACK_ICON_PATH; + } + + const QString recoveryFile() const + { + return m_workingDir + "recover.mmp"; } inline const QStringList & recentlyOpenedProjects() const @@ -210,39 +203,51 @@ public: return m_recentlyOpenedProjects; } + QString localeDir() const + { + return m_dataDir + LOCALE_PATH; + } + + const QString & version() const + { + return m_version; + } + + QString defaultVersion() const; + + static QStringList availabeVstEmbedMethods(); QString vstEmbedMethod() const; - // returns true if the working dir (e.g. ~/lmms) exists on disk + // Returns true if the working dir (e.g. ~/lmms) exists on disk. bool hasWorkingDir() const; - void addRecentlyOpenedProject( const QString & _file ); + void addRecentlyOpenedProject(const QString & _file); - const QString & value( const QString & cls, - const QString & attribute ) const; - const QString & value( const QString & cls, + const QString & value(const QString & cls, + const QString & attribute) const; + const QString & value(const QString & cls, const QString & attribute, - const QString & defaultVal ) const; - void setValue( const QString & cls, const QString & attribute, - const QString & value ); - void deleteValue( const QString & cls, const QString & attribute); + const QString & defaultVal) const; + void setValue(const QString & cls, const QString & attribute, + const QString & value); + void deleteValue(const QString & cls, const QString & attribute); - void loadConfigFile( const QString & configFile = "" ); + void loadConfigFile(const QString & configFile = ""); void saveConfigFile(); - void setWorkingDir( const QString & _wd ); - void setVSTDir( const QString & _vd ); - void setArtworkDir( const QString & _ad ); - void setLADSPADir( const QString & _fd ); - void setVersion( const QString & _cv ); - void setSTKDir( const QString & _fd ); - void setDefaultSoundfont( const QString & _sf ); - void setBackgroundArtwork( const QString & _ba ); - void setGIGDir( const QString & gd ); - void setSF2Dir( const QString & sfd ); + void setWorkingDir(const QString & workingDir); + void setVSTDir(const QString & vstDir); + void setLADSPADir(const QString & ladspaDir); + void setSF2Dir(const QString & sf2Dir); + void setSF2File(const QString & sf2File); + void setSTKDir(const QString & stkDir); + void setGIGDir(const QString & gigDir); + void setThemeDir(const QString & themeDir); + void setBackgroundPicFile(const QString & backgroundPicFile); - // creates the working directory & subdirectories on disk. + // Creates the working directory & subdirectories on disk. void createWorkingDir(); signals: @@ -252,29 +257,29 @@ private: static ConfigManager * s_instanceOfMe; ConfigManager(); - ConfigManager( const ConfigManager & _c ); + ConfigManager(const ConfigManager & _c); ~ConfigManager(); void upgrade_1_1_90(); void upgrade_1_1_91(); void upgrade(); - QString m_lmmsRcFile; QString m_workingDir; QString m_dataDir; - QString m_artworkDir; QString m_vstDir; - QString m_ladDir; - QString m_gigDir; + QString m_ladspaDir; QString m_sf2Dir; - QString m_version; +#ifdef LMMS_HAVE_FLUIDSYNTH + QString m_sf2File; +#endif #ifdef LMMS_HAVE_STK QString m_stkDir; #endif -#ifdef LMMS_HAVE_FLUIDSYNTH - QString m_defaultSoundfont; -#endif - QString m_backgroundArtwork; + QString m_gigDir; + QString m_themeDir; + QString m_backgroundPicFile; + QString m_lmmsRcFile; + QString m_version; QStringList m_recentlyOpenedProjects; typedef QVector > stringPairVector; @@ -283,7 +288,5 @@ private: friend class LmmsCore; - -} ; - +}; #endif diff --git a/include/Controller.h b/include/Controller.h index f1e71ad8f..b60349463 100644 --- a/include/Controller.h +++ b/include/Controller.h @@ -101,9 +101,9 @@ public: } - virtual void saveSettings( QDomDocument & _doc, QDomElement & _this ); - virtual void loadSettings( const QDomElement & _this ); - virtual QString nodeName() const; + void saveSettings( QDomDocument & _doc, QDomElement & _this ) override; + void loadSettings( const QDomElement & _this ) override; + QString nodeName() const override; static Controller * create( ControllerTypes _tt, Model * _parent ); static Controller * create( const QDomElement & _this, diff --git a/include/ControllerConnection.h b/include/ControllerConnection.h index 5c4d5f20e..e57cd4db2 100644 --- a/include/ControllerConnection.h +++ b/include/ControllerConnection.h @@ -85,15 +85,15 @@ public: static void finalizeConnections(); - virtual void saveSettings( QDomDocument & _doc, QDomElement & _this ); - virtual void loadSettings( const QDomElement & _this ); + void saveSettings( QDomDocument & _doc, QDomElement & _this ) override; + void loadSettings( const QDomElement & _this ) override; static inline const QString classNodeName() { return "connection"; } - virtual QString nodeName() const + QString nodeName() const override { return classNodeName(); } diff --git a/include/ControllerDialog.h b/include/ControllerDialog.h index 58a0a94b2..05e8f3bfe 100644 --- a/include/ControllerDialog.h +++ b/include/ControllerDialog.h @@ -47,7 +47,7 @@ signals: protected: - virtual void closeEvent( QCloseEvent * _ce ); + void closeEvent( QCloseEvent * _ce ) override; } ; diff --git a/include/ControllerRackView.h b/include/ControllerRackView.h index cb393f5ca..9ef2d9b7f 100644 --- a/include/ControllerRackView.h +++ b/include/ControllerRackView.h @@ -47,10 +47,10 @@ public: ControllerRackView(); virtual ~ControllerRackView(); - virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void loadSettings( const QDomElement & _this ); + void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; + void loadSettings( const QDomElement & _this ) override; - inline virtual QString nodeName() const + inline QString nodeName() const override { return "ControllerRackView"; } @@ -62,7 +62,7 @@ public slots: void onControllerRemoved( Controller * ); protected: - virtual void closeEvent( QCloseEvent * _ce ); + void closeEvent( QCloseEvent * _ce ) override; private slots: void addController(); diff --git a/include/ControllerView.h b/include/ControllerView.h index 4b215feca..d1284845e 100644 --- a/include/ControllerView.h +++ b/include/ControllerView.h @@ -68,9 +68,9 @@ signals: protected: - virtual void contextMenuEvent( QContextMenuEvent * _me ); - virtual void modelChanged(); - virtual void mouseDoubleClickEvent( QMouseEvent * event ); + void contextMenuEvent( QContextMenuEvent * _me ) override; + void modelChanged() override; + void mouseDoubleClickEvent( QMouseEvent * event ) override; private: diff --git a/include/DetuningHelper.h b/include/DetuningHelper.h index de0acc826..2157b6ba8 100644 --- a/include/DetuningHelper.h +++ b/include/DetuningHelper.h @@ -43,17 +43,17 @@ public: { } - virtual float defaultValue() const + float defaultValue() const override { return 0; } - virtual QString displayName() const + QString displayName() const override { return tr( "Note detuning" ); } - inline virtual QString nodeName() const + inline QString nodeName() const override { return "detuning"; } diff --git a/include/DummyEffect.h b/include/DummyEffect.h index 4f770af3c..5509131be 100644 --- a/include/DummyEffect.h +++ b/include/DummyEffect.h @@ -53,25 +53,25 @@ public: { } - virtual int controlCount() + int controlCount() override { return 0; } - virtual void saveSettings( QDomDocument &, QDomElement & ) + void saveSettings( QDomDocument &, QDomElement & ) override { } - virtual void loadSettings( const QDomElement & ) + void loadSettings( const QDomElement & ) override { } - virtual QString nodeName() const + QString nodeName() const override { return "DummyControls"; } - virtual EffectControlDialog * createView() + EffectControlDialog * createView() override { return new DummyEffectControlDialog( this ); } @@ -95,12 +95,12 @@ public: { } - virtual EffectControls * controls() + EffectControls * controls() override { return &m_controls; } - bool processAudioBuffer( sampleFrame *, const fpp_t ) + bool processAudioBuffer( sampleFrame *, const fpp_t ) override { return false; } diff --git a/include/DummyInstrument.h b/include/DummyInstrument.h index 87083f262..a37b089ae 100644 --- a/include/DummyInstrument.h +++ b/include/DummyInstrument.h @@ -47,26 +47,26 @@ public: { } - virtual void playNote( NotePlayHandle *, sampleFrame * buffer ) + void playNote( NotePlayHandle *, sampleFrame * buffer ) override { memset( buffer, 0, sizeof( sampleFrame ) * Engine::mixer()->framesPerPeriod() ); } - virtual void saveSettings( QDomDocument &, QDomElement & ) + void saveSettings( QDomDocument &, QDomElement & ) override { } - virtual void loadSettings( const QDomElement & ) + void loadSettings( const QDomElement & ) override { } - virtual QString nodeName() const + QString nodeName() const override { return "dummyinstrument"; } - virtual PluginView * instantiateView( QWidget * _parent ) + PluginView * instantiateView( QWidget * _parent ) override { return new InstrumentViewFixedSize( this, _parent ); } diff --git a/include/DummyPlugin.h b/include/DummyPlugin.h index 49475a2ac..ec26da0a3 100644 --- a/include/DummyPlugin.h +++ b/include/DummyPlugin.h @@ -42,22 +42,22 @@ public: { } - virtual void saveSettings( QDomDocument &, QDomElement & ) + void saveSettings( QDomDocument &, QDomElement & ) override { } - virtual void loadSettings( const QDomElement & ) + void loadSettings( const QDomElement & ) override { } - virtual QString nodeName() const + QString nodeName() const override { return "DummyPlugin"; } protected: - virtual PluginView * instantiateView( QWidget * _parent ) + PluginView * instantiateView( QWidget * _parent ) override { return new PluginView( this, _parent ); } diff --git a/include/Editor.h b/include/Editor.h index 26b70ec87..1c80e9f2f 100644 --- a/include/Editor.h +++ b/include/Editor.h @@ -47,7 +47,7 @@ protected: DropToolBar * addDropToolBar(Qt::ToolBarArea whereToAdd, QString const & windowTitle); DropToolBar * addDropToolBar(QWidget * parent, Qt::ToolBarArea whereToAdd, QString const & windowTitle); - virtual void closeEvent( QCloseEvent * _ce ); + void closeEvent( QCloseEvent * _ce ) override; protected slots: virtual void play() {} virtual void record() {} @@ -92,8 +92,8 @@ signals: void dropped(QDropEvent* event); protected: - void dragEnterEvent(QDragEnterEvent* event); - void dropEvent(QDropEvent* event); + void dragEnterEvent(QDragEnterEvent* event) override; + void dropEvent(QDropEvent* event) override; }; diff --git a/include/Effect.h b/include/Effect.h index 4dc50e8a4..3874aa602 100644 --- a/include/Effect.h +++ b/include/Effect.h @@ -47,10 +47,10 @@ public: const Descriptor::SubPluginFeatures::Key * _key ); virtual ~Effect(); - virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void loadSettings( const QDomElement & _this ); + void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; + void loadSettings( const QDomElement & _this ) override; - inline virtual QString nodeName() const + inline QString nodeName() const override { return "effect"; } @@ -170,7 +170,7 @@ protected: */ void checkGate( double _out_sum ); - virtual PluginView * instantiateView( QWidget * ); + PluginView * instantiateView( QWidget * ) override; // some effects might not be capable of higher sample-rates so they can // sample it down before processing and back after processing diff --git a/include/EffectChain.h b/include/EffectChain.h index bc1e7df8c..9ebc4d534 100644 --- a/include/EffectChain.h +++ b/include/EffectChain.h @@ -40,10 +40,10 @@ public: EffectChain( Model * _parent ); virtual ~EffectChain(); - virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void loadSettings( const QDomElement & _this ); + void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; + void loadSettings( const QDomElement & _this ) override; - inline virtual QString nodeName() const + inline QString nodeName() const override { return "fxchain"; } diff --git a/include/EffectControlDialog.h b/include/EffectControlDialog.h index c0a60cfa6..4a59489da 100644 --- a/include/EffectControlDialog.h +++ b/include/EffectControlDialog.h @@ -48,7 +48,7 @@ signals: protected: - virtual void closeEvent( QCloseEvent * _ce ); + void closeEvent( QCloseEvent * _ce ) override; EffectControls * m_effectControls; diff --git a/include/EffectRackView.h b/include/EffectRackView.h index 0cfc04e15..698bad7fb 100644 --- a/include/EffectRackView.h +++ b/include/EffectRackView.h @@ -60,7 +60,7 @@ private slots: private: - virtual void modelChanged(); + void modelChanged() override; inline EffectChain* fxChain() { diff --git a/include/EffectView.h b/include/EffectView.h index 71a0e7128..6e994dd7e 100644 --- a/include/EffectView.h +++ b/include/EffectView.h @@ -73,9 +73,9 @@ signals: protected: - virtual void contextMenuEvent( QContextMenuEvent * _me ); - virtual void paintEvent( QPaintEvent * _pe ); - virtual void modelChanged(); + void contextMenuEvent( QContextMenuEvent * _me ) override; + void paintEvent( QPaintEvent * _pe ) override; + void modelChanged() override; private: diff --git a/include/EnvelopeAndLfoParameters.h b/include/EnvelopeAndLfoParameters.h index 4824062f3..0f691adb0 100644 --- a/include/EnvelopeAndLfoParameters.h +++ b/include/EnvelopeAndLfoParameters.h @@ -91,9 +91,9 @@ public: } - virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void loadSettings( const QDomElement & _this ); - virtual QString nodeName() const + void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; + void loadSettings( const QDomElement & _this ) override; + QString nodeName() const override { return "el"; } diff --git a/include/EnvelopeAndLfoView.h b/include/EnvelopeAndLfoView.h index 817b0a6ee..f6d4fd0a8 100644 --- a/include/EnvelopeAndLfoView.h +++ b/include/EnvelopeAndLfoView.h @@ -52,12 +52,12 @@ public: protected: - virtual void modelChanged(); + void modelChanged() override; - virtual void dragEnterEvent( QDragEnterEvent * _dee ); - virtual void dropEvent( QDropEvent * _de ); - virtual void mousePressEvent( QMouseEvent * _me ); - virtual void paintEvent( QPaintEvent * _pe ); + void dragEnterEvent( QDragEnterEvent * _dee ) override; + void dropEvent( QDropEvent * _de ) override; + void mousePressEvent( QMouseEvent * _me ) override; + void paintEvent( QPaintEvent * _pe ) override; protected slots: diff --git a/include/ExportFilter.h b/include/ExportFilter.h index 950bacbcd..3124b477b 100644 --- a/include/ExportFilter.h +++ b/include/ExportFilter.h @@ -44,15 +44,15 @@ public: int tempo, int masterPitch, const QString &filename ) = 0; protected: - virtual void saveSettings( QDomDocument &, QDomElement & ) + void saveSettings( QDomDocument &, QDomElement & ) override { } - virtual void loadSettings( const QDomElement & ) + void loadSettings( const QDomElement & ) override { } - virtual QString nodeName() const + QString nodeName() const override { return "import_filter"; } diff --git a/include/ExportProjectDialog.h b/include/ExportProjectDialog.h index 0eedb9722..06c1e3011 100644 --- a/include/ExportProjectDialog.h +++ b/include/ExportProjectDialog.h @@ -41,14 +41,14 @@ public: ExportProjectDialog( const QString & _file_name, QWidget * _parent, bool multi_export ); protected: - virtual void reject( void ); - virtual void closeEvent( QCloseEvent * _ce ); + void reject( void ) override; + void closeEvent( QCloseEvent * _ce ) override; private slots: void startBtnClicked( void ); void updateTitleBar( int ); - void accept(); + void accept() override; void startExport(); void onFileFormatChanged(int); diff --git a/include/FadeButton.h b/include/FadeButton.h index 8f56a77b2..09a4c6457 100644 --- a/include/FadeButton.h +++ b/include/FadeButton.h @@ -50,8 +50,8 @@ public slots: protected: - virtual void customEvent( QEvent * ); - virtual void paintEvent( QPaintEvent * _pe ); + void customEvent( QEvent * ) override; + void paintEvent( QPaintEvent * _pe ) override; private: diff --git a/include/Fader.h b/include/Fader.h index 018f66e0c..207215445 100644 --- a/include/Fader.h +++ b/include/Fader.h @@ -109,13 +109,13 @@ public: } private: - virtual void contextMenuEvent( QContextMenuEvent * _me ); - virtual void mousePressEvent( QMouseEvent *ev ); - virtual void mouseDoubleClickEvent( QMouseEvent* mouseEvent ); - virtual void mouseMoveEvent( QMouseEvent *ev ); - virtual void mouseReleaseEvent( QMouseEvent * _me ); - virtual void wheelEvent( QWheelEvent *ev ); - virtual void paintEvent( QPaintEvent *ev ); + void contextMenuEvent( QContextMenuEvent * _me ) override; + void mousePressEvent( QMouseEvent *ev ) override; + void mouseDoubleClickEvent( QMouseEvent* mouseEvent ) override; + void mouseMoveEvent( QMouseEvent *ev ) override; + void mouseReleaseEvent( QMouseEvent * _me ) override; + void wheelEvent( QWheelEvent *ev ) override; + void paintEvent( QPaintEvent *ev ) override; inline bool clips(float const & value) const { return value >= 1.0f; } diff --git a/include/FileBrowser.h b/include/FileBrowser.h index 4b92dd549..9b56a8dbd 100644 --- a/include/FileBrowser.h +++ b/include/FileBrowser.h @@ -61,7 +61,7 @@ private slots: void giveFocusToFilter(); private: - virtual void keyPressEvent( QKeyEvent * ke ); + void keyPressEvent( QKeyEvent * ke ) override; void addItems( const QString & path ); @@ -93,10 +93,10 @@ public: protected: - virtual void contextMenuEvent( QContextMenuEvent * e ); - virtual void mousePressEvent( QMouseEvent * me ); - virtual void mouseMoveEvent( QMouseEvent * me ); - virtual void mouseReleaseEvent( QMouseEvent * me ); + void contextMenuEvent( QContextMenuEvent * e ) override; + void mousePressEvent( QMouseEvent * me ) override; + void mouseMoveEvent( QMouseEvent * me ) override; + void mouseReleaseEvent( QMouseEvent * me ) override; private: diff --git a/include/FxLine.h b/include/FxLine.h index ef8313e74..c16dcd5f5 100644 --- a/include/FxLine.h +++ b/include/FxLine.h @@ -51,10 +51,10 @@ public: FxLine( QWidget * _parent, FxMixerView * _mv, int _channelIndex); ~FxLine(); - virtual void paintEvent( QPaintEvent * ); - virtual void mousePressEvent( QMouseEvent * ); - virtual void mouseDoubleClickEvent( QMouseEvent * ); - virtual void contextMenuEvent( QContextMenuEvent * ); + void paintEvent( QPaintEvent * ) override; + void mousePressEvent( QMouseEvent * ) override; + void mouseDoubleClickEvent( QMouseEvent * ) override; + void contextMenuEvent( QContextMenuEvent * ) override; inline int channelIndex() { return m_channelIndex; } void setChannelIndex(int index); @@ -79,7 +79,7 @@ public: static const int FxLineHeight; - bool eventFilter (QObject *dist, QEvent *event); + bool eventFilter (QObject *dist, QEvent *event) override; private: void drawFxLine( QPainter* p, const FxLine *fxLine, bool isActive, bool sendToThis, bool receiveFromThis ); diff --git a/include/FxLineLcdSpinBox.h b/include/FxLineLcdSpinBox.h index fa001b2bb..eeb104c5c 100644 --- a/include/FxLineLcdSpinBox.h +++ b/include/FxLineLcdSpinBox.h @@ -42,8 +42,8 @@ public: void setTrackView(TrackView * tv); protected: - virtual void mouseDoubleClickEvent(QMouseEvent* event); - virtual void contextMenuEvent(QContextMenuEvent* event); + void mouseDoubleClickEvent(QMouseEvent* event) override; + void contextMenuEvent(QContextMenuEvent* event) override; private: TrackView * m_tv; diff --git a/include/FxMixer.h b/include/FxMixer.h index 2c7ef3c5a..68b69d9bc 100644 --- a/include/FxMixer.h +++ b/include/FxMixer.h @@ -67,7 +67,7 @@ class FxChannel : public ThreadableJob // pointers to other channels that send to this one FxRouteVector m_receives; - virtual bool requiresProcessing() const { return true; } + bool requiresProcessing() const override { return true; } void unmuteForSolo(); @@ -76,7 +76,7 @@ class FxChannel : public ThreadableJob void processed(); private: - virtual void doProcessing(); + void doProcessing() override; }; @@ -133,10 +133,10 @@ public: void prepareMasterMix(); void masterMix( sampleFrame * _buf ); - virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void loadSettings( const QDomElement & _this ); + void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; + void loadSettings( const QDomElement & _this ) override; - virtual QString nodeName() const + QString nodeName() const override { return "fxmixer"; } diff --git a/include/FxMixerView.h b/include/FxMixerView.h index 9b07637ed..a7662321a 100644 --- a/include/FxMixerView.h +++ b/include/FxMixerView.h @@ -64,10 +64,10 @@ public: FxMixerView(); virtual ~FxMixerView(); - virtual void keyPressEvent(QKeyEvent * e); + void keyPressEvent(QKeyEvent * e) override; - virtual void saveSettings( QDomDocument & _doc, QDomElement & _this ); - virtual void loadSettings( const QDomElement & _this ); + void saveSettings( QDomDocument & _doc, QDomElement & _this ) override; + void loadSettings( const QDomElement & _this ) override; inline FxLine * currentFxLine() { @@ -110,7 +110,7 @@ public slots: int addNewChannel(); protected: - virtual void closeEvent( QCloseEvent * _ce ); + void closeEvent( QCloseEvent * _ce ) override; private slots: void updateFaders(); diff --git a/include/Graph.h b/include/Graph.h index 1bee05c41..2a6fc4f8a 100644 --- a/include/Graph.h +++ b/include/Graph.h @@ -87,19 +87,19 @@ public: signals: void drawn(); protected: - virtual void paintEvent( QPaintEvent * _pe ); - virtual void dropEvent( QDropEvent * _de ); - virtual void dragEnterEvent( QDragEnterEvent * _dee ); - virtual void mousePressEvent( QMouseEvent * _me ); - virtual void mouseMoveEvent( QMouseEvent * _me ); - virtual void mouseReleaseEvent( QMouseEvent * _me ); + void paintEvent( QPaintEvent * _pe ) override; + void dropEvent( QDropEvent * _de ) override; + void dragEnterEvent( QDragEnterEvent * _dee ) override; + void mousePressEvent( QMouseEvent * _me ) override; + void mouseMoveEvent( QMouseEvent * _me ) override; + void mouseReleaseEvent( QMouseEvent * _me ) override; protected slots: void updateGraph( int _startPos, int _endPos ); void updateGraph(); private: - virtual void modelChanged(); + void modelChanged() override; void changeSampleAt( int _x, int _y ); void drawLineAt( int _x, int _y, int _lastx ); diff --git a/include/GroupBox.h b/include/GroupBox.h index 8a857199f..88428b1aa 100644 --- a/include/GroupBox.h +++ b/include/GroupBox.h @@ -42,7 +42,7 @@ public: GroupBox( const QString & _caption, QWidget * _parent = NULL ); virtual ~GroupBox(); - virtual void modelChanged(); + void modelChanged() override; PixmapButton * ledButton() { @@ -56,8 +56,8 @@ public: protected: - virtual void mousePressEvent( QMouseEvent * _me ); - virtual void paintEvent( QPaintEvent * _pe ); + void mousePressEvent( QMouseEvent * _me ) override; + void paintEvent( QPaintEvent * _pe ) override; private: diff --git a/include/ImportFilter.h b/include/ImportFilter.h index 166c1bfda..ccefd3db2 100644 --- a/include/ImportFilter.h +++ b/include/ImportFilter.h @@ -89,15 +89,15 @@ protected: m_file.ungetChar( _ch ); } - virtual void saveSettings( QDomDocument &, QDomElement & ) + void saveSettings( QDomDocument &, QDomElement & ) override { } - virtual void loadSettings( const QDomElement & ) + void loadSettings( const QDomElement & ) override { } - virtual QString nodeName() const + QString nodeName() const override { return "import_filter"; } diff --git a/include/InlineAutomation.h b/include/InlineAutomation.h index d70121a45..431ecbc81 100644 --- a/include/InlineAutomation.h +++ b/include/InlineAutomation.h @@ -79,8 +79,8 @@ public: return m_autoPattern; } - virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void loadSettings( const QDomElement & _this ); + void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; + void loadSettings( const QDomElement & _this ) override; private: diff --git a/include/Instrument.h b/include/Instrument.h index 2179a1f72..438197cd8 100644 --- a/include/Instrument.h +++ b/include/Instrument.h @@ -110,7 +110,7 @@ public: return true; } - virtual QString fullDisplayName() const; + QString fullDisplayName() const override; // -------------------------------------------------------------------- // provided functions: diff --git a/include/InstrumentFunctionViews.h b/include/InstrumentFunctionViews.h index 8ac13e1b9..58f915b15 100644 --- a/include/InstrumentFunctionViews.h +++ b/include/InstrumentFunctionViews.h @@ -49,7 +49,7 @@ public: private: - virtual void modelChanged(); + void modelChanged() override; InstrumentFunctionNoteStacking * m_cc; @@ -72,7 +72,7 @@ public: private: - virtual void modelChanged(); + void modelChanged() override; InstrumentFunctionArpeggio * m_a; GroupBox * m_arpGroupBox; diff --git a/include/InstrumentFunctions.h b/include/InstrumentFunctions.h index 0055c6c97..b45484e71 100644 --- a/include/InstrumentFunctions.h +++ b/include/InstrumentFunctions.h @@ -54,10 +54,10 @@ public: void processNote( NotePlayHandle* n ); - virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void loadSettings( const QDomElement & _this ); + void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; + void loadSettings( const QDomElement & _this ) override; - inline virtual QString nodeName() const + inline QString nodeName() const override { return "chordcreator"; } @@ -176,10 +176,10 @@ public: void processNote( NotePlayHandle* n ); - virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void loadSettings( const QDomElement & _this ); + void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; + void loadSettings( const QDomElement & _this ) override; - inline virtual QString nodeName() const + inline QString nodeName() const override { return "arpeggiator"; } diff --git a/include/InstrumentMidiIOView.h b/include/InstrumentMidiIOView.h index 38f441942..e63b48425 100644 --- a/include/InstrumentMidiIOView.h +++ b/include/InstrumentMidiIOView.h @@ -47,7 +47,7 @@ public: private: - virtual void modelChanged(); + void modelChanged() override; GroupBox * m_midiInputGroupBox; LcdSpinBox * m_inputChannelSpinBox; diff --git a/include/InstrumentPlayHandle.h b/include/InstrumentPlayHandle.h index 426b413ce..ac5fc3222 100644 --- a/include/InstrumentPlayHandle.h +++ b/include/InstrumentPlayHandle.h @@ -40,7 +40,7 @@ public: } - virtual void play( sampleFrame * _working_buffer ) + void play( sampleFrame * _working_buffer ) override { // ensure that all our nph's have been processed first ConstNotePlayHandleList nphv = NotePlayHandle::nphsOfInstrumentTrack( m_instrument->instrumentTrack(), true ); @@ -65,12 +65,12 @@ public: m_instrument->play( _working_buffer ); } - virtual bool isFinished() const + bool isFinished() const override { return false; } - virtual bool isFromTrack( const Track* _track ) const + bool isFromTrack( const Track* _track ) const override { return m_instrument->isFromTrack( _track ); } diff --git a/include/InstrumentSoundShaping.h b/include/InstrumentSoundShaping.h index a159f8380..1b8df38d3 100644 --- a/include/InstrumentSoundShaping.h +++ b/include/InstrumentSoundShaping.h @@ -57,9 +57,9 @@ public: float volumeLevel( NotePlayHandle * _n, const f_cnt_t _frame ); - virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void loadSettings( const QDomElement & _this ); - inline virtual QString nodeName() const + void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; + void loadSettings( const QDomElement & _this ) override; + inline QString nodeName() const override { return "eldata"; } diff --git a/include/InstrumentSoundShapingView.h b/include/InstrumentSoundShapingView.h index a409e8446..06d53232c 100644 --- a/include/InstrumentSoundShapingView.h +++ b/include/InstrumentSoundShapingView.h @@ -50,7 +50,7 @@ public: private: - virtual void modelChanged(); + void modelChanged() override; InstrumentSoundShaping * m_ss; diff --git a/include/InstrumentTrack.h b/include/InstrumentTrack.h index 72e0d04cc..d72331e52 100644 --- a/include/InstrumentTrack.h +++ b/include/InstrumentTrack.h @@ -80,8 +80,8 @@ public: MidiEvent applyMasterKey( const MidiEvent& event ); - virtual void processInEvent( const MidiEvent& event, const MidiTime& time = MidiTime(), f_cnt_t offset = 0 ); - virtual void processOutEvent( const MidiEvent& event, const MidiTime& time = MidiTime(), f_cnt_t offset = 0 ); + void processInEvent( const MidiEvent& event, const MidiTime& time = MidiTime(), f_cnt_t offset = 0 ) override; + void processOutEvent( const MidiEvent& event, const MidiTime& time = MidiTime(), f_cnt_t offset = 0 ) override; // silence all running notes played by this track void silenceAllNotes( bool removeIPH = false ); @@ -111,7 +111,7 @@ public: void deleteNotePluginData( NotePlayHandle * _n ); // name-stuff - virtual void setName( const QString & _new_name ); + void setName( const QString & _new_name ) override; // translate given key of a note-event to absolute key (i.e. // add global master-pitch and base-note of this instrument track) @@ -131,18 +131,18 @@ public: // play everything in given frame-range - creates note-play-handles virtual bool play( const MidiTime & _start, const fpp_t _frames, - const f_cnt_t _frame_base, int _tco_num = -1 ); + const f_cnt_t _frame_base, int _tco_num = -1 ) override; // create new view for me - virtual TrackView * createView( TrackContainerView* tcv ); + TrackView * createView( TrackContainerView* tcv ) override; // create new track-content-object = pattern - virtual TrackContentObject * createTCO( const MidiTime & _pos ); + TrackContentObject * createTCO( const MidiTime & _pos ) override; // called by track virtual void saveTrackSpecificSettings( QDomDocument & _doc, - QDomElement & _parent ); - virtual void loadTrackSpecificSettings( const QDomElement & _this ); + QDomElement & _parent ) override; + void loadTrackSpecificSettings( const QDomElement & _this ) override; using Track::setJournalling; @@ -225,7 +225,7 @@ signals: protected: - virtual QString nodeName() const + QString nodeName() const override { return "instrumenttrack"; } @@ -317,12 +317,12 @@ public: static void cleanupWindowCache(); // Create a menu for assigning/creating channels for this track - QMenu * createFxMenu( QString title, QString newFxLabel ); + QMenu * createFxMenu( QString title, QString newFxLabel ) override; protected: - virtual void dragEnterEvent( QDragEnterEvent * _dee ); - virtual void dropEvent( QDropEvent * _de ); + void dragEnterEvent( QDragEnterEvent * _dee ) override; + void dropEvent( QDropEvent * _de ) override; private slots: @@ -404,8 +404,8 @@ public: static void dragEnterEventGeneric( QDragEnterEvent * _dee ); - virtual void dragEnterEvent( QDragEnterEvent * _dee ); - virtual void dropEvent( QDropEvent * _de ); + void dragEnterEvent( QDragEnterEvent * _dee ) override; + void dropEvent( QDropEvent * _de ) override; public slots: @@ -417,11 +417,11 @@ public slots: protected: // capture close-events for toggling instrument-track-button - virtual void closeEvent( QCloseEvent * _ce ); - virtual void focusInEvent( QFocusEvent * _fe ); + void closeEvent( QCloseEvent * _ce ) override; + void focusInEvent( QFocusEvent * _fe ) override; - virtual void saveSettings( QDomDocument & _doc, QDomElement & _this ); - virtual void loadSettings( const QDomElement & _this ); + void saveSettings( QDomDocument & _doc, QDomElement & _this ) override; + void loadSettings( const QDomElement & _this ) override; protected slots: @@ -430,7 +430,7 @@ protected slots: void viewPrevInstrument(); private: - virtual void modelChanged(); + void modelChanged() override; void viewInstrumentInDirection(int d); //! adjust size of any child widget of the main tab //! required to keep the old look when using a variable sized tab widget diff --git a/include/JournallingObject.h b/include/JournallingObject.h index 6974bef84..f4755994b 100644 --- a/include/JournallingObject.h +++ b/include/JournallingObject.h @@ -59,9 +59,9 @@ public: void addJournalCheckPoint(); virtual QDomElement saveState( QDomDocument & _doc, - QDomElement & _parent ); + QDomElement & _parent ) override; - virtual void restoreState( const QDomElement & _this ); + void restoreState( const QDomElement & _this ) override; inline bool isJournalling() const { diff --git a/include/Knob.h b/include/Knob.h index b8d460f45..4f8064731 100644 --- a/include/Knob.h +++ b/include/Knob.h @@ -124,16 +124,16 @@ signals: protected: - virtual void contextMenuEvent( QContextMenuEvent * _me ); - virtual void dragEnterEvent( QDragEnterEvent * _dee ); - virtual void dropEvent( QDropEvent * _de ); - virtual void focusOutEvent( QFocusEvent * _fe ); - virtual void mousePressEvent( QMouseEvent * _me ); - virtual void mouseReleaseEvent( QMouseEvent * _me ); - virtual void mouseMoveEvent( QMouseEvent * _me ); - virtual void mouseDoubleClickEvent( QMouseEvent * _me ); - virtual void paintEvent( QPaintEvent * _me ); - virtual void wheelEvent( QWheelEvent * _me ); + void contextMenuEvent( QContextMenuEvent * _me ) override; + void dragEnterEvent( QDragEnterEvent * _dee ) override; + void dropEvent( QDropEvent * _de ) override; + void focusOutEvent( QFocusEvent * _fe ) override; + void mousePressEvent( QMouseEvent * _me ) override; + void mouseReleaseEvent( QMouseEvent * _me ) override; + void mouseMoveEvent( QMouseEvent * _me ) override; + void mouseDoubleClickEvent( QMouseEvent * _me ) override; + void paintEvent( QPaintEvent * _me ) override; + void wheelEvent( QWheelEvent * _me ) override; virtual float getValue( const QPoint & _p ); @@ -145,7 +145,7 @@ private slots: private: QString displayValue() const; - virtual void doConnections(); + void doConnections() override; QLineF calculateLine( const QPointF & _mid, float _radius, float _innerRadius = 1) const; diff --git a/include/LadspaControl.h b/include/LadspaControl.h index 2ad895b3f..34f6c9ae2 100644 --- a/include/LadspaControl.h +++ b/include/LadspaControl.h @@ -74,7 +74,7 @@ public: virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent, const QString & _name ); virtual void loadSettings( const QDomElement & _this, const QString & _name ); - inline virtual QString nodeName() const + inline QString nodeName() const override { return "port"; } @@ -92,13 +92,13 @@ protected slots: void linkStateChanged(); protected: - virtual void saveSettings( QDomDocument& doc, QDomElement& element ) + void saveSettings( QDomDocument& doc, QDomElement& element ) override { Q_UNUSED(doc) Q_UNUSED(element) } - virtual void loadSettings( const QDomElement& element ) + void loadSettings( const QDomElement& element ) override { Q_UNUSED(element) } diff --git a/include/LcdSpinBox.h b/include/LcdSpinBox.h index b63dfaa40..379b743ac 100644 --- a/include/LcdSpinBox.h +++ b/include/LcdSpinBox.h @@ -40,7 +40,7 @@ public: virtual ~LcdSpinBox() = default; - virtual void modelChanged() + void modelChanged() override { ModelView::modelChanged(); update(); @@ -65,12 +65,12 @@ public slots: protected: - virtual void contextMenuEvent( QContextMenuEvent * _me ); - virtual void mousePressEvent( QMouseEvent * _me ); - virtual void mouseMoveEvent( QMouseEvent * _me ); - virtual void mouseReleaseEvent( QMouseEvent * _me ); - virtual void wheelEvent( QWheelEvent * _we ); - virtual void mouseDoubleClickEvent( QMouseEvent * _me ); + void contextMenuEvent( QContextMenuEvent * _me ) override; + void mousePressEvent( QMouseEvent * _me ) override; + void mouseMoveEvent( QMouseEvent * _me ) override; + void mouseReleaseEvent( QMouseEvent * _me ) override; + void wheelEvent( QWheelEvent * _we ) override; + void mouseDoubleClickEvent( QMouseEvent * _me ) override; private: bool m_mouseMoving; diff --git a/include/LcdWidget.h b/include/LcdWidget.h index db969dd33..f4c7d1579 100644 --- a/include/LcdWidget.h +++ b/include/LcdWidget.h @@ -71,7 +71,7 @@ public slots: protected: - virtual void paintEvent( QPaintEvent * pe ); + void paintEvent( QPaintEvent * pe ) override; virtual void updateSize(); diff --git a/include/LedCheckbox.h b/include/LedCheckbox.h index 723bae6a9..66d7ce07e 100644 --- a/include/LedCheckbox.h +++ b/include/LedCheckbox.h @@ -64,7 +64,7 @@ public: Q_PROPERTY( QString text READ text WRITE setText ) protected: - virtual void paintEvent( QPaintEvent * _pe ); + void paintEvent( QPaintEvent * _pe ) override; private: diff --git a/include/LfoController.h b/include/LfoController.h index 9dfbba671..8fc35fd09 100644 --- a/include/LfoController.h +++ b/include/LfoController.h @@ -49,18 +49,18 @@ public: virtual ~LfoController(); - virtual void saveSettings( QDomDocument & _doc, QDomElement & _this ); - virtual void loadSettings( const QDomElement & _this ); - virtual QString nodeName() const; + void saveSettings( QDomDocument & _doc, QDomElement & _this ) override; + void loadSettings( const QDomElement & _this ) override; + QString nodeName() const override; public slots: - virtual ControllerDialog * createDialog( QWidget * _parent ); + ControllerDialog * createDialog( QWidget * _parent ) override; protected: // The internal per-controller value updating function - virtual void updateValueBuffer(); + void updateValueBuffer() override; FloatModel m_baseModel; TempoSyncKnobModel m_speedModel; @@ -98,8 +98,8 @@ public: protected: - virtual void contextMenuEvent( QContextMenuEvent * _me ); - virtual void modelChanged(); + void contextMenuEvent( QContextMenuEvent * _me ) override; + void modelChanged() override; LfoController * m_lfo; diff --git a/include/LmmsPalette.h b/include/LmmsPalette.h index 49b831346..a8ee5d1c8 100644 --- a/include/LmmsPalette.h +++ b/include/LmmsPalette.h @@ -43,8 +43,6 @@ class LMMS_EXPORT LmmsPalette : public QWidget Q_PROPERTY( QColor brightText READ brightText WRITE setBrightText ) Q_PROPERTY( QColor highlight READ highlight WRITE setHighlight ) Q_PROPERTY( QColor highlightedText READ highlightedText WRITE setHighlightedText ) - Q_PROPERTY( QColor toolTipText READ toolTipText WRITE setToolTipText ) - Q_PROPERTY( QColor toolTipBase READ toolTipBase WRITE setToolTipBase ) public: LmmsPalette( QWidget * parent, QStyle * stylearg ); @@ -65,8 +63,6 @@ public: ACCESSMET( brightText, setBrightText ) ACCESSMET( highlight, setHighlight ) ACCESSMET( highlightedText, setHighlightedText ) - ACCESSMET( toolTipText, setToolTipText ) - ACCESSMET( toolTipBase, setToolTipBase ) #undef ACCESSMET @@ -83,8 +79,6 @@ private: QColor m_brightText; QColor m_highlight; QColor m_highlightedText; - QColor m_toolTipText; - QColor m_toolTipBase; }; diff --git a/include/LmmsStyle.h b/include/LmmsStyle.h index 88b8a2112..ccf14396c 100644 --- a/include/LmmsStyle.h +++ b/include/LmmsStyle.h @@ -67,21 +67,21 @@ public: { } - virtual QPalette standardPalette( void ) const; + QPalette standardPalette( void ) const override; virtual void drawComplexControl( ComplexControl control, const QStyleOptionComplex * option, QPainter *painter, - const QWidget *widget ) const; + const QWidget *widget ) const override; virtual void drawPrimitive( PrimitiveElement element, const QStyleOption *option, QPainter *painter, - const QWidget *widget = 0 ) const; + const QWidget *widget = 0 ) const override; virtual int pixelMetric( PixelMetric metric, const QStyleOption * option = 0, - const QWidget * widget = 0 ) const; + const QWidget * widget = 0 ) const override; static QPalette * s_palette; diff --git a/include/LocklessRingBuffer.h b/include/LocklessRingBuffer.h new file mode 100644 index 000000000..3b18dd475 --- /dev/null +++ b/include/LocklessRingBuffer.h @@ -0,0 +1,132 @@ +/* + * LocklessRingBuffer.h - LMMS wrapper for a lockless ringbuffer library + * + * Copyright (c) 2019 Martin Pavelek + * + * This file is part of LMMS - https://lmms.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#ifndef LOCKLESSRINGBUFFER_H +#define LOCKLESSRINGBUFFER_H + +#include +#include + +#include "lmms_basics.h" +#include "lmms_export.h" +#include "../src/3rdparty/ringbuffer/include/ringbuffer/ringbuffer.h" + + +//! A convenience layer for a realtime-safe and thread-safe multi-reader ring buffer library. +template +class LocklessRingBufferBase +{ + template + friend class LocklessRingBufferReader; +public: + LocklessRingBufferBase(std::size_t sz) : m_buffer(sz) + { + m_buffer.touch(); // reserve storage space before realtime operation starts + } + ~LocklessRingBufferBase() {}; + + std::size_t capacity() const {return m_buffer.maximum_eventual_write_space();} + std::size_t free() const {return m_buffer.write_space();} + void wakeAll() {m_notifier.wakeAll();} + +protected: + ringbuffer_t m_buffer; + QWaitCondition m_notifier; +}; + + +// The SampleFrameCopier is required because sampleFrame is just a two-element +// array and therefore does not have a copy constructor needed by std::copy. +class SampleFrameCopier +{ + const sampleFrame* m_src; +public: + SampleFrameCopier(const sampleFrame* src) : m_src(src) {} + void operator()(std::size_t src_offset, std::size_t count, sampleFrame* dest) + { + for (std::size_t i = src_offset; i < src_offset + count; i++, dest++) + { + (*dest)[0] = m_src[i][0]; + (*dest)[1] = m_src[i][1]; + } + } +}; + + +//! Standard ring buffer template for data types with copy constructor. +template +class LocklessRingBuffer : public LocklessRingBufferBase +{ +public: + LocklessRingBuffer(std::size_t sz) : LocklessRingBufferBase(sz) {}; + + std::size_t write(const sampleFrame *src, std::size_t cnt, bool notify = false) + { + std::size_t written = LocklessRingBufferBase::m_buffer.write(src, cnt); + // Let all waiting readers know new data are available. + if (notify) {LocklessRingBufferBase::m_notifier.wakeAll();} + return written; + } +}; + + +//! Specialized ring buffer template with write function modified to support sampleFrame. +template <> +class LocklessRingBuffer : public LocklessRingBufferBase +{ +public: + LocklessRingBuffer(std::size_t sz) : LocklessRingBufferBase(sz) {}; + + std::size_t write(const sampleFrame *src, std::size_t cnt, bool notify = false) + { + SampleFrameCopier copier(src); + std::size_t written = LocklessRingBufferBase::m_buffer.write_func(copier, cnt); + // Let all waiting readers know new data are available. + if (notify) {LocklessRingBufferBase::m_notifier.wakeAll();} + return written; + } +}; + + +//! Wrapper for lockless ringbuffer reader +template +class LocklessRingBufferReader : public ringbuffer_reader_t +{ +public: + LocklessRingBufferReader(LocklessRingBuffer &rb) : + ringbuffer_reader_t(rb.m_buffer), + m_notifier(&rb.m_notifier) {}; + + bool empty() const {return !this->read_space();} + void waitForData() + { + QMutex useless_lock; + m_notifier->wait(&useless_lock); + useless_lock.unlock(); + } +private: + QWaitCondition *m_notifier; +}; + +#endif //LOCKLESSRINGBUFFER_H diff --git a/include/MainApplication.h b/include/MainApplication.h index 41d670419..d28900213 100644 --- a/include/MainApplication.h +++ b/include/MainApplication.h @@ -42,7 +42,7 @@ class MainApplication : public QApplication { public: MainApplication(int& argc, char** argv); - bool event(QEvent* event); + bool event(QEvent* event) override; #ifdef LMMS_BUILD_WIN32 bool winEventFilter(MSG* msg, long* result); bool nativeEventFilter(const QByteArray& eventType, void* message, diff --git a/include/MainWindow.h b/include/MainWindow.h index 74e569653..5dc102321 100644 --- a/include/MainWindow.h +++ b/include/MainWindow.h @@ -176,11 +176,11 @@ private slots: void onExportProjectMidi(); protected: - virtual void closeEvent( QCloseEvent * _ce ); - virtual void focusOutEvent( QFocusEvent * _fe ); - virtual void keyPressEvent( QKeyEvent * _ke ); - virtual void keyReleaseEvent( QKeyEvent * _ke ); - virtual void timerEvent( QTimerEvent * _ev ); + void closeEvent( QCloseEvent * _ce ) override; + void focusOutEvent( QFocusEvent * _fe ) override; + void keyPressEvent( QKeyEvent * _ke ) override; + void keyReleaseEvent( QKeyEvent * _ke ) override; + void timerEvent( QTimerEvent * _ev ) override; private: diff --git a/include/MeterDialog.h b/include/MeterDialog.h index 5399c4a9a..da254c7c7 100644 --- a/include/MeterDialog.h +++ b/include/MeterDialog.h @@ -40,7 +40,7 @@ public: MeterDialog( QWidget * _parent, bool _simple = false ); virtual ~MeterDialog(); - virtual void modelChanged(); + void modelChanged() override; private: diff --git a/include/MidiAlsaRaw.h b/include/MidiAlsaRaw.h index 81f288c22..69f9366f1 100644 --- a/include/MidiAlsaRaw.h +++ b/include/MidiAlsaRaw.h @@ -62,8 +62,8 @@ public: protected: - virtual void sendByte( const unsigned char c ); - virtual void run(); + void sendByte( const unsigned char c ) override; + void run() override; private: diff --git a/include/MidiAlsaSeq.h b/include/MidiAlsaSeq.h index 0406b42b9..b6e498721 100644 --- a/include/MidiAlsaSeq.h +++ b/include/MidiAlsaSeq.h @@ -67,44 +67,44 @@ public: virtual void processOutEvent( const MidiEvent & _me, const MidiTime & _time, - const MidiPort * _port ); + const MidiPort * _port ) override; - virtual void applyPortMode( MidiPort * _port ); - virtual void applyPortName( MidiPort * _port ); + void applyPortMode( MidiPort * _port ) override; + void applyPortName( MidiPort * _port ) override; - virtual void removePort( MidiPort * _port ); + void removePort( MidiPort * _port ) override; // list seq-ports from ALSA - virtual QStringList readablePorts() const + QStringList readablePorts() const override { return m_readablePorts; } - virtual QStringList writablePorts() const + QStringList writablePorts() const override { return m_writablePorts; } // return name of port which specified MIDI event came from - virtual QString sourcePortName( const MidiEvent & ) const; + QString sourcePortName( const MidiEvent & ) const override; // (un)subscribe given MidiPort to/from destination-port virtual void subscribeReadablePort( MidiPort * _port, const QString & _dest, - bool _subscribe = true ); + bool _subscribe = true ) override; virtual void subscribeWritablePort( MidiPort * _port, const QString & _dest, - bool _subscribe = true ); + bool _subscribe = true ) override; virtual void connectRPChanged( QObject * _receiver, - const char * _member ) + const char * _member ) override { connect( this, SIGNAL( readablePortsChanged() ), _receiver, _member ); } virtual void connectWPChanged( QObject * _receiver, - const char * _member ) + const char * _member ) override { connect( this, SIGNAL( writablePortsChanged() ), _receiver, _member ); @@ -117,7 +117,7 @@ private slots: private: - virtual void run(); + void run() override; #ifdef LMMS_HAVE_ALSA QMutex m_seqMutex; diff --git a/include/MidiClient.h b/include/MidiClient.h index 293f2b3da..f06cac893 100644 --- a/include/MidiClient.h +++ b/include/MidiClient.h @@ -124,7 +124,7 @@ public: virtual ~MidiClientRaw(); // we are raw-clients for sure! - virtual bool isRaw() const + bool isRaw() const override { return true; } @@ -141,7 +141,7 @@ protected: private: // this does MIDI-event-process void processParsedEvent(); - virtual void processOutEvent( const MidiEvent& event, const MidiTime& time, const MidiPort* port ); + void processOutEvent( const MidiEvent& event, const MidiTime& time, const MidiPort* port ) override; // small helper function returning length of a certain event - this // is necessary for parsing raw-MIDI-data diff --git a/include/MidiController.h b/include/MidiController.h index d661b8d0f..43f928a25 100644 --- a/include/MidiController.h +++ b/include/MidiController.h @@ -44,30 +44,30 @@ public: virtual ~MidiController(); virtual void processInEvent( const MidiEvent & _me, - const MidiTime & _time, f_cnt_t offset = 0 ); + const MidiTime & _time, f_cnt_t offset = 0 ) override; virtual void processOutEvent( const MidiEvent& _me, - const MidiTime & _time, f_cnt_t offset = 0 ) + const MidiTime & _time, f_cnt_t offset = 0 ) override { // No output yet } - virtual void saveSettings( QDomDocument & _doc, QDomElement & _this ); - virtual void loadSettings( const QDomElement & _this ); - virtual QString nodeName() const; + void saveSettings( QDomDocument & _doc, QDomElement & _this ) override; + void loadSettings( const QDomElement & _this ) override; + QString nodeName() const override; // Used by controllerConnectionDialog to copy void subscribeReadablePorts( const MidiPort::Map & _map ); public slots: - virtual ControllerDialog * createDialog( QWidget * _parent ); + ControllerDialog * createDialog( QWidget * _parent ) override; void updateName(); protected: // The internal per-controller get-value function - virtual void updateValueBuffer(); + void updateValueBuffer() override; MidiPort m_midiPort; diff --git a/include/MidiDummy.h b/include/MidiDummy.h index dffd1ce51..f809d3c36 100644 --- a/include/MidiDummy.h +++ b/include/MidiDummy.h @@ -56,7 +56,7 @@ public: protected: - virtual void sendByte( const unsigned char ) + void sendByte( const unsigned char ) override { } diff --git a/include/MidiOss.h b/include/MidiOss.h index 27ebf0771..7e1f179ef 100644 --- a/include/MidiOss.h +++ b/include/MidiOss.h @@ -58,8 +58,8 @@ public: } protected: - virtual void sendByte( const unsigned char c ); - virtual void run(); + void sendByte( const unsigned char c ) override; + void run() override; private: diff --git a/include/MidiPort.h b/include/MidiPort.h index 07c61d788..e9cba39ed 100644 --- a/include/MidiPort.h +++ b/include/MidiPort.h @@ -103,10 +103,10 @@ public: void processOutEvent( const MidiEvent& event, const MidiTime& time = MidiTime() ); - virtual void saveSettings( QDomDocument& doc, QDomElement& thisElement ); - virtual void loadSettings( const QDomElement& thisElement ); + void saveSettings( QDomDocument& doc, QDomElement& thisElement ) override; + void loadSettings( const QDomElement& thisElement ) override; - virtual QString nodeName() const + QString nodeName() const override { return "midiport"; } diff --git a/include/MidiPortMenu.h b/include/MidiPortMenu.h index b963a7bd9..ce39c4aac 100644 --- a/include/MidiPortMenu.h +++ b/include/MidiPortMenu.h @@ -51,7 +51,7 @@ protected slots: private: - virtual void modelChanged(); + void modelChanged() override; MidiPort::Modes m_mode; diff --git a/include/MidiSndio.h b/include/MidiSndio.h index d115993fe..14ecfa0e9 100644 --- a/include/MidiSndio.h +++ b/include/MidiSndio.h @@ -59,8 +59,8 @@ public: protected: - virtual void sendByte(const unsigned char c); - virtual void run(void); + void sendByte(const unsigned char c) override; + void run(void) override; private: struct mio_hdl *m_hdl; diff --git a/include/MidiTime.h b/include/MidiTime.h index 0e8015e04..952b4b6d5 100644 --- a/include/MidiTime.h +++ b/include/MidiTime.h @@ -32,10 +32,10 @@ #include "lmms_export.h" #include "lmms_basics.h" -// note: 1 "Tact" = 1 Measure -const int DefaultTicksPerTact = 192; -const int DefaultStepsPerTact = 16; -const int DefaultBeatsPerTact = DefaultTicksPerTact / DefaultStepsPerTact; +// note: a bar was erroneously called "tact" in older versions of LMMS +const int DefaultTicksPerBar = 192; +const int DefaultStepsPerBar = 16; +const int DefaultBeatsPerBar = DefaultTicksPerBar / DefaultStepsPerBar; class MeterModel; @@ -60,19 +60,19 @@ private: class LMMS_EXPORT MidiTime { public: - MidiTime( const tact_t tact, const tick_t ticks ); + MidiTime( const bar_t bar, const tick_t ticks ); MidiTime( const tick_t ticks = 0 ); MidiTime quantize(float) const; - MidiTime toAbsoluteTact() const; + MidiTime toAbsoluteBar() const; MidiTime& operator+=( const MidiTime& time ); MidiTime& operator-=( const MidiTime& time ); - // return the tact, rounded down and 0-based - tact_t getTact() const; - // return the tact, rounded up and 0-based - tact_t nextFullTact() const; + // return the bar, rounded down and 0-based + bar_t getBar() const; + // return the bar, rounded up and 0-based + bar_t nextFullBar() const; void setTicks( tick_t ticks ); tick_t getTicks() const; @@ -90,21 +90,21 @@ public: // calculate number of frame that are needed this time f_cnt_t frames( const float framesPerTick ) const; - double getTimeInMilliseconds(bpm_t beatsPerMinute) const; + double getTimeInMilliseconds( bpm_t beatsPerMinute ) const; static MidiTime fromFrames( const f_cnt_t frames, const float framesPerTick ); - static tick_t ticksPerTact(); - static tick_t ticksPerTact( const TimeSig &sig ); - static int stepsPerTact(); - static void setTicksPerTact( tick_t tpt ); + static tick_t ticksPerBar(); + static tick_t ticksPerBar( const TimeSig &sig ); + static int stepsPerBar(); + static void setTicksPerBar( tick_t tpt ); static MidiTime stepPosition( int step ); - static double ticksToMilliseconds(tick_t ticks, bpm_t beatsPerMinute); - static double ticksToMilliseconds(double ticks, bpm_t beatsPerMinute); + static double ticksToMilliseconds( tick_t ticks, bpm_t beatsPerMinute ); + static double ticksToMilliseconds( double ticks, bpm_t beatsPerMinute ); private: tick_t m_ticks; - static tick_t s_ticksPerTact; + static tick_t s_ticksPerBar; } ; diff --git a/include/Mixer.h b/include/Mixer.h index 69ea0d12d..32eeb8977 100644 --- a/include/Mixer.h +++ b/include/Mixer.h @@ -345,7 +345,7 @@ private: fifo * m_fifo; volatile bool m_writing; - virtual void run(); + void run() override; void write( surroundSampleFrame * buffer ); diff --git a/include/MixerWorkerThread.h b/include/MixerWorkerThread.h index 7c3792392..2d49dce09 100644 --- a/include/MixerWorkerThread.h +++ b/include/MixerWorkerThread.h @@ -106,7 +106,7 @@ public: private: - virtual void run(); + void run() override; static JobQueue globalJobQueue; static QWaitCondition * queueReadyWaitCond; diff --git a/include/NStateButton.h b/include/NStateButton.h index d9e56b892..95d36c253 100644 --- a/include/NStateButton.h +++ b/include/NStateButton.h @@ -61,7 +61,7 @@ signals: protected: - virtual void mousePressEvent( QMouseEvent * _me ); + void mousePressEvent( QMouseEvent * _me ) override; private: diff --git a/include/Note.h b/include/Note.h index 0eae8f6b0..30969b4c8 100644 --- a/include/Note.h +++ b/include/Note.h @@ -200,7 +200,7 @@ public: return "note"; } - inline virtual QString nodeName() const + inline QString nodeName() const override { return classNodeName(); } @@ -218,8 +218,8 @@ public: protected: - virtual void saveSettings( QDomDocument & doc, QDomElement & parent ); - virtual void loadSettings( const QDomElement & _this ); + void saveSettings( QDomDocument & doc, QDomElement & parent ) override; + void loadSettings( const QDomElement & _this ) override; private: diff --git a/include/NotePlayHandle.h b/include/NotePlayHandle.h index ae55c9ebb..3dba0f277 100644 --- a/include/NotePlayHandle.h +++ b/include/NotePlayHandle.h @@ -74,8 +74,8 @@ public: return p; } - virtual void setVolume( volume_t volume ); - virtual void setPanning( panning_t panning ); + void setVolume( volume_t volume ) override; + void setPanning( panning_t panning ) override; int midiKey() const; int midiChannel() const @@ -105,10 +105,10 @@ public: } /*! Renders one chunk using the attached instrument into the buffer */ - virtual void play( sampleFrame* buffer ); + void play( sampleFrame* buffer ) override; /*! Returns whether playback of note is finished and thus handle can be deleted */ - virtual bool isFinished() const + bool isFinished() const override { return m_released && framesLeft() <= 0; } @@ -120,7 +120,7 @@ public: fpp_t framesLeftForCurrentPeriod() const; /*! Returns whether the play handle plays on a certain track */ - virtual bool isFromTrack( const Track* _track ) const; + bool isFromTrack( const Track* _track ) const override; /*! Releases the note (and plays release frames */ void noteOff( const f_cnt_t offset = 0 ); diff --git a/include/Pattern.h b/include/Pattern.h index 3a1cc941c..5192da9fa 100644 --- a/include/Pattern.h +++ b/include/Pattern.h @@ -94,9 +94,9 @@ public: Pattern * nextPattern() const; // settings-management - virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void loadSettings( const QDomElement & _this ); - inline virtual QString nodeName() const + void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; + void loadSettings( const QDomElement & _this ) override; + inline QString nodeName() const override { return "pattern"; } @@ -109,7 +109,7 @@ public: bool empty(); - virtual TrackContentObjectView * createView( TrackView * _tv ); + TrackContentObjectView * createView( TrackView * _tv ) override; using Model::dataChanged; @@ -182,7 +182,7 @@ public: void setMutedNoteBorderColor(QColor const & color) { m_mutedNoteBorderColor = color; } public slots: - virtual void update(); + void update() override; protected slots: @@ -194,11 +194,11 @@ protected slots: protected: - virtual void constructContextMenu( QMenu * ); - virtual void mousePressEvent( QMouseEvent * _me ); - virtual void mouseDoubleClickEvent( QMouseEvent * _me ); - virtual void paintEvent( QPaintEvent * pe ); - virtual void wheelEvent( QWheelEvent * _we ); + void constructContextMenu( QMenu * ) override; + void mousePressEvent( QMouseEvent * _me ) override; + void mouseDoubleClickEvent( QMouseEvent * _me ) override; + void paintEvent( QPaintEvent * pe ) override; + void wheelEvent( QWheelEvent * _we ) override; private: diff --git a/include/PeakController.h b/include/PeakController.h index b2824f0ac..74a3aab59 100644 --- a/include/PeakController.h +++ b/include/PeakController.h @@ -46,9 +46,9 @@ public: virtual ~PeakController(); - virtual void saveSettings( QDomDocument & _doc, QDomElement & _this ); - virtual void loadSettings( const QDomElement & _this ); - virtual QString nodeName() const; + void saveSettings( QDomDocument & _doc, QDomElement & _this ) override; + void loadSettings( const QDomElement & _this ) override; + QString nodeName() const override; static void initGetControllerBySetting(); static PeakController * getControllerBySetting( const QDomElement & _this ); @@ -57,13 +57,13 @@ public: public slots: - virtual ControllerDialog * createDialog( QWidget * _parent ); + ControllerDialog * createDialog( QWidget * _parent ) override; void handleDestroyedEffect( ); void updateCoeffs(); protected: // The internal per-controller get-value function - virtual void updateValueBuffer(); + void updateValueBuffer() override; PeakControllerEffect * m_peakEffect; @@ -91,9 +91,9 @@ public: virtual ~PeakControllerDialog(); protected: - virtual void contextMenuEvent( QContextMenuEvent * _me ); - virtual void paintEvent( QPaintEvent * _pe ); - virtual void modelChanged(); + void contextMenuEvent( QContextMenuEvent * _me ) override; + void paintEvent( QPaintEvent * _pe ) override; + void modelChanged() override; PeakController * m_peakController; diff --git a/include/PianoRoll.h b/include/PianoRoll.h index 4451a07c5..27a15149e 100644 --- a/include/PianoRoll.h +++ b/include/PianoRoll.h @@ -46,7 +46,6 @@ class QPixmap; class QScrollBar; class QString; class QMenu; -class QSignalMapper; class ComboBox; class NotePlayHandle; @@ -95,6 +94,7 @@ public: void setCurrentPattern( Pattern* newPattern ); void setGhostPattern( Pattern* newPattern ); void loadGhostNotes( const QDomElement & de ); + void loadMarkedSemiTones(const QDomElement & de); inline void stopRecording() { @@ -167,17 +167,17 @@ public: protected: - virtual void keyPressEvent( QKeyEvent * ke ); - virtual void keyReleaseEvent( QKeyEvent * ke ); - virtual void leaveEvent( QEvent * e ); - virtual void mousePressEvent( QMouseEvent * me ); - virtual void mouseDoubleClickEvent( QMouseEvent * me ); - virtual void mouseReleaseEvent( QMouseEvent * me ); - virtual void mouseMoveEvent( QMouseEvent * me ); - virtual void paintEvent( QPaintEvent * pe ); - virtual void resizeEvent( QResizeEvent * re ); - virtual void wheelEvent( QWheelEvent * we ); - virtual void focusOutEvent( QFocusEvent * ); + void keyPressEvent( QKeyEvent * ke ) override; + void keyReleaseEvent( QKeyEvent * ke ) override; + void leaveEvent( QEvent * e ) override; + void mousePressEvent( QMouseEvent * me ) override; + void mouseDoubleClickEvent( QMouseEvent * me ) override; + void mouseReleaseEvent( QMouseEvent * me ) override; + void mouseMoveEvent( QMouseEvent * me ) override; + void paintEvent( QPaintEvent * pe ) override; + void resizeEvent( QResizeEvent * re ) override; + void wheelEvent( QWheelEvent * we ) override; + void focusOutEvent( QFocusEvent * ) override; int getKey( int y ) const; static void drawNoteRect( QPainter & p, int x, int y, @@ -382,7 +382,7 @@ private: int m_oldNotesEditHeight; int m_notesEditHeight; - int m_ppt; // pixels per tact + int m_ppb; // pixels per bar int m_totalKeysToScroll; // remember these values to use them @@ -460,11 +460,11 @@ public: int quantization() const; - void play(); - void stop(); - void record(); - void recordAccompany(); - void toggleStepRecording(); + void play() override; + void stop() override; + void record() override; + void recordAccompany() override; + void toggleStepRecording() override; void stopRecording(); bool isRecording() const; @@ -474,15 +474,15 @@ public: using SerializingObject::saveState; using SerializingObject::restoreState; - virtual void saveSettings(QDomDocument & doc, QDomElement & de ); - virtual void loadSettings( const QDomElement & de ); + void saveSettings(QDomDocument & doc, QDomElement & de ) override; + void loadSettings( const QDomElement & de ) override; - inline virtual QString nodeName() const + inline QString nodeName() const override { return "pianoroll"; } - QSize sizeHint() const; + QSize sizeHint() const override; signals: void currentPatternChanged(); @@ -494,7 +494,7 @@ private slots: private: void patternRenamed(); - void focusInEvent(QFocusEvent * event); + void focusInEvent(QFocusEvent * event) override; void stopStepRecording(); void updateStepRecordingIcon(); diff --git a/include/PianoView.h b/include/PianoView.h index 2a362c584..b793ee768 100644 --- a/include/PianoView.h +++ b/include/PianoView.h @@ -44,19 +44,19 @@ public: public: - virtual void keyPressEvent( QKeyEvent * ke ); - virtual void keyReleaseEvent( QKeyEvent * ke ); + void keyPressEvent( QKeyEvent * ke ) override; + void keyReleaseEvent( QKeyEvent * ke ) override; protected: - virtual void modelChanged(); - virtual void contextMenuEvent( QContextMenuEvent * _me ); - virtual void paintEvent( QPaintEvent * ); - virtual void mousePressEvent( QMouseEvent * me ); - virtual void mouseReleaseEvent( QMouseEvent * me ); - virtual void mouseMoveEvent( QMouseEvent * me ); - virtual void focusOutEvent( QFocusEvent * _fe ); - virtual void resizeEvent( QResizeEvent * _event ); + void modelChanged() override; + void contextMenuEvent( QContextMenuEvent * _me ) override; + void paintEvent( QPaintEvent * ) override; + void mousePressEvent( QMouseEvent * me ) override; + void mouseReleaseEvent( QMouseEvent * me ) override; + void mouseMoveEvent( QMouseEvent * me ) override; + void focusOutEvent( QFocusEvent * _fe ) override; + void resizeEvent( QResizeEvent * _event ) override; private: diff --git a/include/Pitch.h b/include/Pitch.h index 5ef1c3d62..2f866a1c5 100644 --- a/include/Pitch.h +++ b/include/Pitch.h @@ -25,8 +25,7 @@ #ifndef PITCH_H #define PITCH_H -#include "lmms_basics.h" -#include "Midi.h" +#include typedef int16_t pitch_t; diff --git a/include/PixmapButton.h b/include/PixmapButton.h index 6ee7bcdc8..e2fb58885 100644 --- a/include/PixmapButton.h +++ b/include/PixmapButton.h @@ -42,17 +42,17 @@ public: void setActiveGraphic( const QPixmap & _pm ); void setInactiveGraphic( const QPixmap & _pm, bool _update = true ); - QSize sizeHint() const; + QSize sizeHint() const override; signals: void doubleClicked(); protected: - virtual void paintEvent( QPaintEvent * _pe ); - virtual void mousePressEvent( QMouseEvent * _me ); - virtual void mouseReleaseEvent( QMouseEvent * _me ); - virtual void mouseDoubleClickEvent( QMouseEvent * _me ); + void paintEvent( QPaintEvent * _pe ) override; + void mousePressEvent( QMouseEvent * _me ) override; + void mouseReleaseEvent( QMouseEvent * _me ) override; + void mouseDoubleClickEvent( QMouseEvent * _me ) override; private: diff --git a/include/PlayHandle.h b/include/PlayHandle.h index 1760e1ec7..1ddd632d1 100644 --- a/include/PlayHandle.h +++ b/include/PlayHandle.h @@ -87,9 +87,9 @@ public: } // required for ThreadableJob - virtual void doProcessing(); + void doProcessing() override; - virtual bool requiresProcessing() const + bool requiresProcessing() const override { return !isFinished(); } diff --git a/include/Plugin.h b/include/Plugin.h index af42b0f10..cb8995bf2 100644 --- a/include/Plugin.h +++ b/include/Plugin.h @@ -239,7 +239,7 @@ public: virtual ~Plugin(); //! Return display-name out of sub plugin or descriptor - virtual QString displayName() const; + QString displayName() const override; //! Return logo out of sub plugin or descriptor const PixmapLoader *logo() const; diff --git a/include/PresetPreviewPlayHandle.h b/include/PresetPreviewPlayHandle.h index 57996fa17..a95b680ab 100644 --- a/include/PresetPreviewPlayHandle.h +++ b/include/PresetPreviewPlayHandle.h @@ -38,15 +38,15 @@ public: PresetPreviewPlayHandle( const QString& presetFile, bool loadByPlugin = false, DataFile *dataFile = 0 ); virtual ~PresetPreviewPlayHandle(); - virtual inline bool affinityMatters() const + inline bool affinityMatters() const override { return true; } - virtual void play( sampleFrame* buffer ); - virtual bool isFinished() const; + void play( sampleFrame* buffer ) override; + bool isFinished() const override; - virtual bool isFromTrack( const Track * _track ) const; + bool isFromTrack( const Track * _track ) const override; static void init(); static void cleanup(); diff --git a/include/ProjectNotes.h b/include/ProjectNotes.h index ab82e4eeb..fc97a8844 100644 --- a/include/ProjectNotes.h +++ b/include/ProjectNotes.h @@ -47,17 +47,17 @@ public: void clear(); void setText( const QString & _text ); - virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void loadSettings( const QDomElement & _this ); + void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; + void loadSettings( const QDomElement & _this ) override; - inline virtual QString nodeName() const + inline QString nodeName() const override { return "projectnotes"; } protected: - virtual void closeEvent( QCloseEvent * _ce ); + void closeEvent( QCloseEvent * _ce ) override; void setupActions(); diff --git a/include/ProjectRenderer.h b/include/ProjectRenderer.h index 4f932ad34..1af9d422d 100644 --- a/include/ProjectRenderer.h +++ b/include/ProjectRenderer.h @@ -86,7 +86,7 @@ signals: private: - virtual void run(); + void run() override; AudioFileDevice * m_fileDev; Mixer::qualitySettings m_qualitySettings; diff --git a/include/RemotePlugin.h b/include/RemotePlugin.h index 27c658a3d..862370d1f 100644 --- a/include/RemotePlugin.h +++ b/include/RemotePlugin.h @@ -766,7 +766,7 @@ public: } private: - virtual void run(); + void run() override; RemotePlugin * m_plugin; volatile bool m_quit; @@ -803,7 +803,7 @@ public: m_failed = waitForMessage( IdInitDone, _busyWaiting ).id != IdInitDone; } - virtual bool processMessage( const message & _m ); + bool processMessage( const message & _m ) override; bool process( const sampleFrame * _in_buf, sampleFrame * _out_buf ); diff --git a/include/RenameDialog.h b/include/RenameDialog.h index c1d24a8a9..8f526badd 100644 --- a/include/RenameDialog.h +++ b/include/RenameDialog.h @@ -42,8 +42,8 @@ public: protected: - void keyPressEvent( QKeyEvent * _ke ); - virtual void resizeEvent(QResizeEvent * event); + void keyPressEvent( QKeyEvent * _ke ) override; + void resizeEvent(QResizeEvent * event) override; protected slots: diff --git a/include/RingBuffer.h b/include/RingBuffer.h index c761616bd..c7e91bd33 100644 --- a/include/RingBuffer.h +++ b/include/RingBuffer.h @@ -32,6 +32,8 @@ #include "lmms_math.h" #include "MemoryManager.h" +/** \brief A basic LMMS ring buffer for single-thread use. For thread and realtime safe alternative see LocklessRingBuffer. +*/ class LMMS_EXPORT RingBuffer : public QObject { Q_OBJECT diff --git a/include/RowTableView.h b/include/RowTableView.h index 537792a05..a7b07c2c8 100644 --- a/include/RowTableView.h +++ b/include/RowTableView.h @@ -38,11 +38,11 @@ public: RowTableView( QWidget * parent = 0 ); virtual ~RowTableView(); - virtual void setModel( QAbstractItemModel * model ); + void setModel( QAbstractItemModel * model ) override; protected: - virtual void keyPressEvent( QKeyEvent * event ); + void keyPressEvent( QKeyEvent * event ) override; private: diff --git a/include/Rubberband.h b/include/Rubberband.h index bc9f3c6a2..eeb3c7e5b 100644 --- a/include/Rubberband.h +++ b/include/Rubberband.h @@ -83,7 +83,7 @@ public: protected: - virtual void resizeEvent( QResizeEvent * _re ); + void resizeEvent( QResizeEvent * _re ) override; private: diff --git a/include/SamplePlayHandle.h b/include/SamplePlayHandle.h index d10c44837..33f5ebe52 100644 --- a/include/SamplePlayHandle.h +++ b/include/SamplePlayHandle.h @@ -44,16 +44,16 @@ public: SamplePlayHandle( SampleTCO* tco ); virtual ~SamplePlayHandle(); - virtual inline bool affinityMatters() const + inline bool affinityMatters() const override { return true; } - virtual void play( sampleFrame * buffer ); - virtual bool isFinished() const; + void play( sampleFrame * buffer ) override; + bool isFinished() const override; - virtual bool isFromTrack( const Track * _track ) const; + bool isFromTrack( const Track * _track ) const override; f_cnt_t totalFrames() const; inline f_cnt_t framesDone() const diff --git a/include/SampleRecordHandle.h b/include/SampleRecordHandle.h index 22d9bf315..fc40d0622 100644 --- a/include/SampleRecordHandle.h +++ b/include/SampleRecordHandle.h @@ -44,10 +44,10 @@ public: SampleRecordHandle( SampleTCO* tco ); virtual ~SampleRecordHandle(); - virtual void play( sampleFrame * _working_buffer ); - virtual bool isFinished() const; + void play( sampleFrame * _working_buffer ) override; + bool isFinished() const override; - virtual bool isFromTrack( const Track * _track ) const; + bool isFromTrack( const Track * _track ) const override; f_cnt_t framesRecorded() const; void createSampleBuffer( SampleBuffer * * _sample_buf ); diff --git a/include/SampleTrack.h b/include/SampleTrack.h index 9469669a1..2bad4d910 100644 --- a/include/SampleTrack.h +++ b/include/SampleTrack.h @@ -49,12 +49,12 @@ public: SampleTCO( Track * _track ); virtual ~SampleTCO(); - virtual void changeLength( const MidiTime & _length ); + void changeLength( const MidiTime & _length ) override; const QString & sampleFile() const; - virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void loadSettings( const QDomElement & _this ); - inline virtual QString nodeName() const + void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; + void loadSettings( const QDomElement & _this ) override; + inline QString nodeName() const override { return "sampletco"; } @@ -67,7 +67,7 @@ public: MidiTime sampleLength() const; void setSampleStartFrame( f_cnt_t startFrame ); void setSamplePlayLength( f_cnt_t length ); - virtual TrackContentObjectView * createView( TrackView * _tv ); + TrackContentObjectView * createView( TrackView * _tv ) override; bool isPlaying() const; @@ -112,13 +112,13 @@ public slots: protected: - virtual void contextMenuEvent( QContextMenuEvent * _cme ); - virtual void mousePressEvent( QMouseEvent * _me ); - virtual void mouseReleaseEvent( QMouseEvent * _me ); - virtual void dragEnterEvent( QDragEnterEvent * _dee ); - virtual void dropEvent( QDropEvent * _de ); - virtual void mouseDoubleClickEvent( QMouseEvent * ); - virtual void paintEvent( QPaintEvent * ); + void contextMenuEvent( QContextMenuEvent * _cme ) override; + void mousePressEvent( QMouseEvent * _me ) override; + void mouseReleaseEvent( QMouseEvent * _me ) override; + void dragEnterEvent( QDragEnterEvent * _dee ) override; + void dropEvent( QDropEvent * _de ) override; + void mouseDoubleClickEvent( QMouseEvent * ) override; + void paintEvent( QPaintEvent * ) override; private: @@ -137,14 +137,14 @@ public: virtual ~SampleTrack(); virtual bool play( const MidiTime & _start, const fpp_t _frames, - const f_cnt_t _frame_base, int _tco_num = -1 ); - virtual TrackView * createView( TrackContainerView* tcv ); - virtual TrackContentObject * createTCO(const MidiTime & pos); + const f_cnt_t _frame_base, int _tco_num = -1 ) override; + TrackView * createView( TrackContainerView* tcv ) override; + TrackContentObject * createTCO( const MidiTime & _pos ) override; virtual void saveTrackSpecificSettings( QDomDocument & _doc, - QDomElement & _parent ); - virtual void loadTrackSpecificSettings( const QDomElement & _this ); + QDomElement & _parent ) override; + void loadTrackSpecificSettings( const QDomElement & _this ) override; inline IntModel * effectChannelModel() { @@ -156,7 +156,7 @@ public: return &m_audioPort; } - virtual QString nodeName() const + QString nodeName() const override { return "sampletrack"; } @@ -204,7 +204,7 @@ public: } - virtual QMenu * createFxMenu( QString title, QString newFxLabel ); + QMenu * createFxMenu( QString title, QString newFxLabel ) override; public slots: @@ -212,14 +212,14 @@ public slots: protected: - void modelChanged(); - virtual QString nodeName() const + void modelChanged() override; + QString nodeName() const override { return "SampleTrackView"; } - void dragEnterEvent(QDragEnterEvent *dee); - void dropEvent(QDropEvent *de); + void dragEnterEvent(QDragEnterEvent *dee) override; + void dropEvent(QDropEvent *de) override; private slots: void assignFxLine( int channelIndex ); @@ -273,13 +273,13 @@ public slots: protected: // capture close-events for toggling sample-track-button - virtual void closeEvent(QCloseEvent * ce); + void closeEvent(QCloseEvent * ce) override; - virtual void saveSettings(QDomDocument & doc, QDomElement & element); - virtual void loadSettings(const QDomElement & element); + void saveSettings(QDomDocument & doc, QDomElement & element) override; + void loadSettings(const QDomElement & element) override; private: - virtual void modelChanged(); + void modelChanged() override; SampleTrack * m_track; SampleTrackView * m_stv; diff --git a/include/SendButtonIndicator.h b/include/SendButtonIndicator.h index 97acde1ba..b60113758 100644 --- a/include/SendButtonIndicator.h +++ b/include/SendButtonIndicator.h @@ -17,7 +17,7 @@ public: SendButtonIndicator( QWidget * _parent, FxLine * _owner, FxMixerView * _mv); - virtual void mousePressEvent( QMouseEvent * e ); + void mousePressEvent( QMouseEvent * e ) override; void updateLightStatus(); private: diff --git a/include/SetupDialog.h b/include/SetupDialog.h index 272ba7b09..9f9ae1b3f 100644 --- a/include/SetupDialog.h +++ b/include/SetupDialog.h @@ -1,4 +1,3 @@ - /* * SetupDialog.h - dialog for setting up LMMS * @@ -23,20 +22,20 @@ * */ + #ifndef SETUP_DIALOG_H #define SETUP_DIALOG_H #include #include +#include "AudioDevice.h" +#include "AudioDeviceSetupWidget.h" #include "LedCheckbox.h" #include "lmmsconfig.h" -#include "AudioDevice.h" #include "MidiClient.h" #include "MidiSetupWidget.h" -#include "AudioDeviceSetupWidget.h" - class QComboBox; class QLabel; @@ -48,167 +47,156 @@ class TabBar; class SetupDialog : public QDialog { Q_OBJECT + public: enum ConfigTabs { GeneralSettings, - PathSettings, PerformanceSettings, AudioSettings, - MidiSettings - } ; + MidiSettings, + PathsSettings + }; - SetupDialog( ConfigTabs _tab_to_open = GeneralSettings ); + SetupDialog(ConfigTabs tab_to_open = GeneralSettings); virtual ~SetupDialog(); protected slots: - virtual void accept(); + void accept() override; private slots: - // general settings widget - void setBufferSize( int _value ); - void resetBufSize(); + // General settings widget. + void toggleDisplaydBFS(bool enabled); + void toggleTooltips(bool enabled); + void toggleDisplayWaveform(bool enabled); + void toggleNoteLabels(bool enabled); + void toggleCompactTrackButtons(bool enabled); + void toggleOneInstrumentTrackWindow(bool enabled); + void toggleMMPZ(bool enabled); + void toggleDisableBackup(bool enabled); + void toggleOpenLastProject(bool enabled); + void setLanguage(int lang); - // path settings widget - void setWorkingDir( const QString & _wd ); - void setVSTDir( const QString & _vd ); - void setGIGDir( const QString & _gd ); - void setSF2Dir( const QString & _sfd ); - void setArtworkDir( const QString & _ad ); - void setLADSPADir( const QString & _ld ); - void setSTKDir( const QString & _sd ); - void setDefaultSoundfont( const QString & _sf ); - void setBackgroundArtwork( const QString & _ba ); - - // performance settings widget - void setAutoSaveInterval( int time ); + // Performance settings widget. + void setAutoSaveInterval(int time); void resetAutoSave(); - - // audio settings widget - void audioInterfaceChanged( const QString & _driver ); - - // MIDI settings widget - void midiInterfaceChanged( const QString & _driver ); - - - void toggleToolTips( bool _enabled ); - void toggleWarnAfterSetup( bool _enabled ); - void toggleDisplaydBFS( bool _enabled ); - void toggleMMPZ( bool _enabled ); - void toggleDisableBackup( bool _enabled ); - void toggleOpenLastProject( bool _enabled ); - void toggleHQAudioDev( bool _enabled ); - - void openWorkingDir(); - void openVSTDir(); - void openGIGDir(); - void openSF2Dir(); - void openArtworkDir(); - void openLADSPADir(); - void openSTKDir(); - void openDefaultSoundfont(); - void openBackgroundArtwork(); - - void toggleSmoothScroll( bool _enabled ); - void toggleAutoSave( bool _enabled ); - void toggleRunningAutoSave( bool _enabled ); - void toggleOneInstrumentTrackWindow( bool _enabled ); - void toggleCompactTrackButtons( bool _enabled ); - void toggleSyncVSTPlugins( bool _enabled ); - void toggleAnimateAFP( bool _enabled ); - void toggleNoteLabels( bool en ); - void toggleDisplayWaveform( bool en ); - void toggleDisableAutoquit( bool en ); - + void toggleAutoSave(bool enabled); + void toggleRunningAutoSave(bool enabled); + void toggleSmoothScroll(bool enabled); + void toggleAnimateAFP(bool enabled); + void toggleSyncVSTPlugins(bool enabled); void vstEmbedMethodChanged(); - void toggleVSTAlwaysOnTop( bool en ); + void toggleVSTAlwaysOnTop(bool en); + void toggleDisableAutoQuit(bool enabled); - void setLanguage( int lang ); + // Audio settings widget. + void audioInterfaceChanged(const QString & driver); + void toggleHQAudioDev(bool enabled); + void setBufferSize(int value); + void resetBufferSize(); + // MIDI settings widget. + void midiInterfaceChanged(const QString & driver); + + // Paths settings widget. + void openWorkingDir(); + void setWorkingDir(const QString & workingDir); + void openVSTDir(); + void setVSTDir(const QString & vstDir); + void openLADSPADir(); + void setLADSPADir(const QString & ladspaDir); + void openSF2Dir(); + void setSF2Dir(const QString & sf2Dir); + void openSF2File(); + void setSF2File(const QString & sf2File); + void openGIGDir(); + void setGIGDir(const QString & gigDir); + void openThemeDir(); + void setThemeDir(const QString & themeDir); + void openBackgroundPicFile(); + void setBackgroundPicFile(const QString & backgroundPicFile); + + void showRestartWarning(); private: TabBar * m_tabBar; - QSlider * m_bufSizeSlider; - QLabel * m_bufSizeLbl; - int m_bufferSize; - - bool m_toolTips; - bool m_warnAfterSetup; + // General settings widgets. bool m_displaydBFS; + bool m_tooltips; + bool m_displayWaveform; + bool m_printNoteLabels; + bool m_compactTrackButtons; + bool m_oneInstrumentTrackWindow; bool m_MMPZ; bool m_disableBackup; bool m_openLastProject; - bool m_NaNHandler; - bool m_hqAudioDev; QString m_lang; QStringList m_languages; - - QLineEdit * m_wdLineEdit; - QLineEdit * m_vdLineEdit; - QLineEdit * m_adLineEdit; - QLineEdit * m_ladLineEdit; - QLineEdit * m_gigLineEdit; - QLineEdit * m_sf2LineEdit; -#ifdef LMMS_HAVE_FLUIDSYNTH - QLineEdit * m_sfLineEdit; -#endif -#ifdef LMMS_HAVE_STK - QLineEdit * m_stkLineEdit; -#endif - QLineEdit * m_baLineEdit; - - QString m_workingDir; - QString m_vstDir; - QString m_artworkDir; - QString m_ladDir; - QString m_gigDir; - QString m_sf2Dir; -#ifdef LMMS_HAVE_FLUIDSYNTH - QString m_defaultSoundfont; -#endif -#ifdef LMMS_HAVE_STK - QString m_stkDir; -#endif - QString m_backgroundArtwork; - - bool m_smoothScroll; + // Performance settings widgets. + int m_saveInterval; bool m_enableAutoSave; bool m_enableRunningAutoSave; - int m_saveInterval; QSlider * m_saveIntervalSlider; QLabel * m_saveIntervalLbl; LedCheckBox * m_autoSave; LedCheckBox * m_runningAutoSave; - - bool m_oneInstrumentTrackWindow; - bool m_compactTrackButtons; - bool m_syncVSTPlugins; + bool m_smoothScroll; bool m_animateAFP; - bool m_printNoteLabels; - bool m_displayWaveform; + QLabel * m_vstEmbedLbl; + QComboBox* m_vstEmbedComboBox; + QString m_vstEmbedMethod; + LedCheckBox * m_vstAlwaysOnTopCheckBox; + bool m_vstAlwaysOnTop; + bool m_syncVSTPlugins; bool m_disableAutoQuit; + typedef QMap AswMap; typedef QMap MswMap; typedef QMap trMap; + // Audio settings widgets. QComboBox * m_audioInterfaces; AswMap m_audioIfaceSetupWidgets; trMap m_audioIfaceNames; + bool m_NaNHandler; + bool m_hqAudioDev; + int m_bufferSize; + QSlider * m_bufferSizeSlider; + QLabel * m_bufferSizeLbl; + // MIDI settings widgets. QComboBox * m_midiInterfaces; MswMap m_midiIfaceSetupWidgets; trMap m_midiIfaceNames; - QComboBox* m_vstEmbedComboBox; - QString m_vstEmbedMethod; - LedCheckBox * m_vstAlwaysOnTopCheckBox; - bool m_vstAlwaysOnTop; -} ; - - + // Paths settings widgets. + QString m_workingDir; + QString m_vstDir; + QString m_ladspaDir; + QString m_gigDir; + QString m_sf2Dir; +#ifdef LMMS_HAVE_FLUIDSYNTH + QString m_sf2File; +#endif + QString m_themeDir; + QString m_backgroundPicFile; + + QLineEdit * m_workingDirLineEdit; + QLineEdit * m_vstDirLineEdit; + QLineEdit * m_themeDirLineEdit; + QLineEdit * m_ladspaDirLineEdit; + QLineEdit * m_gigDirLineEdit; + QLineEdit * m_sf2DirLineEdit; +#ifdef LMMS_HAVE_FLUIDSYNTH + QLineEdit * m_sf2FileLineEdit; +#endif + QLineEdit * m_backgroundPicFileLineEdit; + + QLabel * restartWarningLbl; +}; #endif diff --git a/include/SideBarWidget.h b/include/SideBarWidget.h index 229f07df0..9972daa7c 100644 --- a/include/SideBarWidget.h +++ b/include/SideBarWidget.h @@ -28,6 +28,7 @@ #include #include #include +#include class SideBarWidget : public QWidget @@ -47,11 +48,13 @@ public: return m_title; } +signals: + void closeButtonClicked(); protected: - virtual void paintEvent( QPaintEvent * _pe ); - virtual void resizeEvent( QResizeEvent * _re ); - virtual void contextMenuEvent( QContextMenuEvent * ) + void paintEvent( QPaintEvent * _pe ) override; + void resizeEvent( QResizeEvent * _re ) override; + void contextMenuEvent( QContextMenuEvent * ) override { } @@ -75,6 +78,8 @@ private: QVBoxLayout * m_layout; QString m_title; QPixmap m_icon; + QPushButton * m_closeBtn; + const QSize m_buttonSize; } ; diff --git a/include/Song.h b/include/Song.h index 32ead7181..d398a168c 100644 --- a/include/Song.h +++ b/include/Song.h @@ -45,7 +45,7 @@ class TimeLineWidget; const bpm_t MinTempo = 10; const bpm_t DefaultTempo = 140; const bpm_t MaxTempo = 999; -const tick_t MaxSongLength = 9999 * DefaultTicksPerTact; +const tick_t MaxSongLength = 9999 * DefaultTicksPerBar; class LMMS_EXPORT Song : public TrackContainer @@ -155,14 +155,14 @@ public: m_playPos[playMode].setTicks(ticks); } - inline int getTacts() const + inline int getBars() const { - return currentTact(); + return currentBar(); } - inline int ticksPerTact() const + inline int ticksPerBar() const { - return MidiTime::ticksPerTact(m_timeSigModel); + return MidiTime::ticksPerBar(m_timeSigModel); } // Returns the beat position inside the bar, 0-based @@ -254,14 +254,14 @@ public: } void updateLength(); - tact_t length() const + bar_t length() const { return m_length; } bpm_t getTempo(); - virtual AutomationPattern * tempoAutomationPattern(); + AutomationPattern * tempoAutomationPattern() override; AutomationTrack * globalAutomationTrack() { @@ -269,7 +269,7 @@ public: } //TODO: Add Q_DECL_OVERRIDE when Qt4 is dropped - AutomatedValueMap automatedValuesAt(MidiTime time, int tcoNum = -1) const; + AutomatedValueMap automatedValuesAt(MidiTime time, int tcoNum = -1) const override; // file management void createNewProject(); @@ -305,7 +305,7 @@ public: return m_modified; } - virtual QString nodeName() const + QString nodeName() const override { return "song"; } @@ -382,9 +382,9 @@ private: virtual ~Song(); - inline tact_t currentTact() const + inline bar_t currentBar() const { - return m_playPos[m_playMode].getTact(); + return m_playPos[m_playMode].getBar(); } inline tick_t currentTick() const @@ -415,7 +415,7 @@ private: IntModel m_tempoModel; MeterModel m_timeSigModel; - int m_oldTicksPerTact; + int m_oldTicksPerBar; IntModel m_masterVolumeModel; IntModel m_masterPitchModel; @@ -445,14 +445,14 @@ private: PlayModes m_playMode; PlayPos m_playPos[Mode_Count]; - tact_t m_length; + bar_t m_length; const Pattern* m_patternToPlay; bool m_loopPattern; double m_elapsedMilliSeconds[Mode_Count]; tick_t m_elapsedTicks; - tact_t m_elapsedTacts; + bar_t m_elapsedBars; VstSyncController m_vstSyncController; @@ -473,9 +473,9 @@ signals: void projectLoaded(); void playbackStateChanged(); void playbackPositionChanged(); - void lengthChanged( int tacts ); + void lengthChanged( int bars ); void tempoChanged( bpm_t newBPM ); - void timeSignatureChanged( int oldTicksPerTact, int ticksPerTact ); + void timeSignatureChanged( int oldTicksPerBar, int ticksPerBar ); void controllerAdded( Controller * ); void controllerRemoved( Controller * ); void updateSampleTracks(); diff --git a/include/SongEditor.h b/include/SongEditor.h index 8a02d5691..9621bcc23 100644 --- a/include/SongEditor.h +++ b/include/SongEditor.h @@ -51,7 +51,7 @@ public: positionLine( QWidget * parent ); private: - virtual void paintEvent( QPaintEvent * pe ); + void paintEvent( QPaintEvent * pe ) override; } ; @@ -69,8 +69,8 @@ public: SongEditor( Song * song ); ~SongEditor(); - void saveSettings( QDomDocument& doc, QDomElement& element ); - void loadSettings( const QDomElement& element ); + void saveSettings( QDomDocument& doc, QDomElement& element ) override; + void loadSettings( const QDomElement& element ) override; ComboBoxModel *zoomingModel() const; ComboBoxModel *snappingModel() const; @@ -79,6 +79,9 @@ public: public slots: void scrolled( int new_pos ); + void selectRegionFromPixels(int xStart, int xEnd); + void stopSelectRegion(); + void updateRubberband(); void setEditMode( EditMode mode ); void setEditModeDraw(); @@ -90,7 +93,10 @@ public slots: void selectAllTcos( bool select ); protected: - virtual void closeEvent( QCloseEvent * ce ); + void closeEvent( QCloseEvent * ce ) override; + void mousePressEvent(QMouseEvent * me) override; + void mouseMoveEvent(QMouseEvent * me) override; + void mouseReleaseEvent(QMouseEvent * me) override; private slots: void setHighQuality( bool ); @@ -110,10 +116,13 @@ private slots: void zoomingChanged(); private: - virtual void keyPressEvent( QKeyEvent * ke ); - virtual void wheelEvent( QWheelEvent * we ); + void keyPressEvent( QKeyEvent * ke ) override; + void wheelEvent( QWheelEvent * we ) override; - virtual bool allowRubberband() const; + bool allowRubberband() const override; + + int trackIndexFromSelectionPoint(int yPos); + int indexOfTrackView(const TrackView* tv); Song * m_song; @@ -141,11 +150,19 @@ private: bool m_scrollBack; bool m_smoothScroll; - int m_widgetWidthTotal; EditMode m_mode; EditMode m_ctrlMode; // mode they were in before they hit ctrl + QPoint m_origin; + QPoint m_scrollPos; + QPoint m_mousePos; + int m_rubberBandStartTrackview; + MidiTime m_rubberbandStartMidipos; + int m_currentZoomingValue; + int m_trackHeadWidth; + bool m_selectRegion; + friend class SongEditorWindow; } ; @@ -158,19 +175,19 @@ class SongEditorWindow : public Editor public: SongEditorWindow( Song* song ); - QSize sizeHint() const; + QSize sizeHint() const override; SongEditor* m_editor; protected: - virtual void resizeEvent( QResizeEvent * event ); - virtual void changeEvent( QEvent * ); + void resizeEvent( QResizeEvent * event ) override; + void changeEvent( QEvent * ) override; protected slots: - void play(); - void record(); - void recordAccompany(); - void stop(); + void play() override; + void record() override; + void recordAccompany() override; + void stop() override; void lostFocus(); void adjustUiAfterProjectLoad(); @@ -182,8 +199,8 @@ signals: void resized(); private: - virtual void keyPressEvent( QKeyEvent * ke ); - virtual void keyReleaseEvent( QKeyEvent * ke ); + void keyPressEvent( QKeyEvent * ke ) override; + void keyReleaseEvent( QKeyEvent * ke ) override; QAction* m_addBBTrackAction; QAction* m_addSampleTrackAction; diff --git a/include/StepRecorderWidget.h b/include/StepRecorderWidget.h index 0e4512169..14cfc2eed 100644 --- a/include/StepRecorderWidget.h +++ b/include/StepRecorderWidget.h @@ -36,14 +36,14 @@ class StepRecorderWidget : public QWidget public: StepRecorderWidget( QWidget * parent, - const int ppt, + const int ppb, const int marginTop, const int marginBottom, const int marginLeft, const int marginRight); //API used by PianoRoll - void setPixelsPerTact(int ppt); + void setPixelsPerBar(int ppb); void setCurrentPosition(MidiTime currentPosition); void setBottomMargin(const int marginBottom); @@ -55,7 +55,7 @@ public: void showHint(); private: - virtual void paintEvent(QPaintEvent * pe); + void paintEvent(QPaintEvent * pe) override; int xCoordOfTick(int tick); @@ -68,7 +68,7 @@ private: MidiTime m_curStepStartPos; MidiTime m_curStepEndPos; - int m_ppt; // pixels per tact + int m_ppb; // pixels per bar MidiTime m_currentPosition; // current position showed by on PianoRoll QColor m_colorLineStart; diff --git a/include/SubWindow.h b/include/SubWindow.h index 5d7a810c2..148cf2c99 100644 --- a/include/SubWindow.h +++ b/include/SubWindow.h @@ -67,10 +67,10 @@ public: protected: // hook the QWidget move/resize events to update the tracked geometry - virtual void moveEvent( QMoveEvent * event ); - virtual void resizeEvent( QResizeEvent * event ); - virtual void paintEvent( QPaintEvent * pe ); - virtual void changeEvent( QEvent * event ); + void moveEvent( QMoveEvent * event ) override; + void resizeEvent( QResizeEvent * event ) override; + void paintEvent( QPaintEvent * pe ) override; + void changeEvent( QEvent * event ) override; signals: void focusLost(); diff --git a/include/TabWidget.h b/include/TabWidget.h index 88ecf9034..0cf15155b 100644 --- a/include/TabWidget.h +++ b/include/TabWidget.h @@ -72,13 +72,13 @@ public: void setTabBorder( const QColor & c ); protected: - virtual bool event( QEvent * event ); - virtual void mousePressEvent( QMouseEvent * _me ); - virtual void paintEvent( QPaintEvent * _pe ); - virtual void resizeEvent( QResizeEvent * _re ); - virtual void wheelEvent( QWheelEvent * _we ); - virtual QSize minimumSizeHint() const; - virtual QSize sizeHint() const; + bool event( QEvent * event ) override; + void mousePressEvent( QMouseEvent * _me ) override; + void paintEvent( QPaintEvent * _pe ) override; + void resizeEvent( QResizeEvent * _re ) override; + void wheelEvent( QWheelEvent * _we ) override; + QSize minimumSizeHint() const override; + QSize sizeHint() const override; private: struct widgetDesc diff --git a/include/TempoSyncKnob.h b/include/TempoSyncKnob.h index 034e2b8f4..416abe1fc 100644 --- a/include/TempoSyncKnob.h +++ b/include/TempoSyncKnob.h @@ -52,7 +52,7 @@ public: return castModel(); } - virtual void modelChanged(); + void modelChanged() override; signals: @@ -61,7 +61,7 @@ signals: protected: - virtual void contextMenuEvent( QContextMenuEvent * _me ); + void contextMenuEvent( QContextMenuEvent * _me ) override; protected slots: diff --git a/include/TempoSyncKnobModel.h b/include/TempoSyncKnobModel.h index 9aaf48fea..b9512aa1a 100644 --- a/include/TempoSyncKnobModel.h +++ b/include/TempoSyncKnobModel.h @@ -52,7 +52,7 @@ public: const float _max, const float _step, const float _scale, Model * _parent, const QString & _display_name = QString() ); - virtual ~TempoSyncKnobModel() override; + ~TempoSyncKnobModel() override; void saveSettings( QDomDocument & _doc, QDomElement & _this, const QString& name ) override; void loadSettings( const QDomElement & _this, const QString& name ) override; diff --git a/include/TextFloat.h b/include/TextFloat.h index ed10516b5..8f940c591 100644 --- a/include/TextFloat.h +++ b/include/TextFloat.h @@ -66,8 +66,8 @@ public: protected: - virtual void paintEvent( QPaintEvent * _me ); - virtual void mousePressEvent( QMouseEvent * _me ); + void paintEvent( QPaintEvent * _me ) override; + void mousePressEvent( QMouseEvent * _me ) override; private: diff --git a/include/TimeDisplayWidget.h b/include/TimeDisplayWidget.h index 175f159c9..e7e5cb210 100644 --- a/include/TimeDisplayWidget.h +++ b/include/TimeDisplayWidget.h @@ -41,7 +41,7 @@ public: protected: - virtual void mousePressEvent( QMouseEvent* mouseEvent ); + void mousePressEvent( QMouseEvent* mouseEvent ) override; private slots: diff --git a/include/TimeLineWidget.h b/include/TimeLineWidget.h index 7629694ca..bc0881f82 100644 --- a/include/TimeLineWidget.h +++ b/include/TimeLineWidget.h @@ -72,15 +72,15 @@ public: } ; - TimeLineWidget(int xoff, int yoff, float ppt, Song::PlayPos & pos, + TimeLineWidget(int xoff, int yoff, float ppb, Song::PlayPos & pos, const MidiTime & begin, Song::PlayModes mode, QWidget * parent); virtual ~TimeLineWidget(); inline QColor const & getBarLineColor() const { return m_barLineColor; } - inline void setBarLineColor(QColor const & tactLineColor) { m_barLineColor = tactLineColor; } + inline void setBarLineColor(QColor const & barLineColor) { m_barLineColor = barLineColor; } inline QColor const & getBarNumberColor() const { return m_barNumberColor; } - inline void setBarNumberColor(QColor const & tactNumberColor) { m_barNumberColor = tactNumberColor; } + inline void setBarNumberColor(QColor const & barNumberColor) { m_barNumberColor = barNumberColor; } inline QColor const & getInactiveLoopColor() const { return m_inactiveLoopColor; } inline void setInactiveLoopColor(QColor const & inactiveLoopColor) { m_inactiveLoopColor = inactiveLoopColor; } @@ -135,27 +135,27 @@ public: m_loopPos[0] : m_loopPos[1]; } - inline void savePos( const MidiTime & _pos ) + inline void savePos( const MidiTime & pos ) { - m_savedPos = _pos; + m_savedPos = pos; } inline const MidiTime & savedPos() const { return m_savedPos; } - inline void setPixelsPerTact( float _ppt ) + inline void setPixelsPerBar( float ppb ) { - m_ppt = _ppt; + m_ppb = ppb; update(); } void addToolButtons(QToolBar* _tool_bar ); - virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void loadSettings( const QDomElement & _this ); - inline virtual QString nodeName() const + void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; + void loadSettings( const QDomElement & _this ) override; + inline QString nodeName() const override { return "timeline"; } @@ -163,7 +163,7 @@ public: inline int markerX( const MidiTime & _t ) const { return m_xOffset + static_cast( ( _t - m_begin ) * - m_ppt / MidiTime::ticksPerTact() ); + m_ppb / MidiTime::ticksPerBar() ); } signals: @@ -184,10 +184,10 @@ public slots: protected: - virtual void paintEvent( QPaintEvent * _pe ); - virtual void mousePressEvent( QMouseEvent * _me ); - virtual void mouseMoveEvent( QMouseEvent * _me ); - virtual void mouseReleaseEvent( QMouseEvent * _me ); + void paintEvent( QPaintEvent * _pe ) override; + void mousePressEvent( QMouseEvent * _me ) override; + void mouseMoveEvent( QMouseEvent * _me ) override; + void mouseReleaseEvent( QMouseEvent * _me ) override; private: @@ -214,7 +214,7 @@ private: int m_xOffset; int m_posMarkerX; - float m_ppt; + float m_ppb; Song::PlayPos & m_pos; const MidiTime & m_begin; const Song::PlayModes m_mode; diff --git a/include/Track.h b/include/Track.h index b00c50248..70e49a1c6 100644 --- a/include/Track.h +++ b/include/Track.h @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -73,7 +72,7 @@ const int DEFAULT_TRACK_HEIGHT = 32; const int TCO_BORDER_WIDTH = 2; -class TrackContentObject : public Model, public JournallingObject +class LMMS_EXPORT TrackContentObject : public Model, public JournallingObject { Q_OBJECT MM_OPERATORS @@ -99,7 +98,7 @@ public: emit dataChanged(); } - virtual QString displayName() const + QString displayName() const override { return name(); } @@ -215,6 +214,12 @@ public: { return m_tco; } + + inline TrackView * getTrackView() + { + return m_trackView; + } + // qproperty access func QColor mutedColor() const; QColor mutedBackgroundColor() const; @@ -241,32 +246,28 @@ public slots: virtual bool close(); void cut(); void remove(); - virtual void update(); + void update() override; protected: virtual void constructContextMenu( QMenu * ) { } - virtual void contextMenuEvent( QContextMenuEvent * cme ); - virtual void dragEnterEvent( QDragEnterEvent * dee ); - virtual void dropEvent( QDropEvent * de ); - virtual void leaveEvent( QEvent * e ); - virtual void mousePressEvent( QMouseEvent * me ); - virtual void mouseMoveEvent( QMouseEvent * me ); - virtual void mouseReleaseEvent( QMouseEvent * me ); - virtual void resizeEvent( QResizeEvent * re ) + void contextMenuEvent( QContextMenuEvent * cme ) override; + void dragEnterEvent( QDragEnterEvent * dee ) override; + void dropEvent( QDropEvent * de ) override; + void leaveEvent( QEvent * e ) override; + void mousePressEvent( QMouseEvent * me ) override; + void mouseMoveEvent( QMouseEvent * me ) override; + void mouseReleaseEvent( QMouseEvent * me ) override; + void resizeEvent( QResizeEvent * re ) override { m_needsUpdate = true; selectableObject::resizeEvent( re ); } - float pixelsPerTact(); + float pixelsPerBar(); - inline TrackView * getTrackView() - { - return m_trackView; - } DataFile createTCODataFiles(const QVector & tcos) const; @@ -380,24 +381,24 @@ public slots: void changePosition( const MidiTime & newPos = MidiTime( -1 ) ); protected: - virtual void dragEnterEvent( QDragEnterEvent * dee ); - virtual void dropEvent( QDropEvent * de ); - virtual void mousePressEvent( QMouseEvent * me ); - virtual void paintEvent( QPaintEvent * pe ); - virtual void resizeEvent( QResizeEvent * re ); + void dragEnterEvent( QDragEnterEvent * dee ) override; + void dropEvent( QDropEvent * de ) override; + void mousePressEvent( QMouseEvent * me ) override; + void paintEvent( QPaintEvent * pe ) override; + void resizeEvent( QResizeEvent * re ) override; - virtual QString nodeName() const + QString nodeName() const override { return "trackcontentwidget"; } - virtual void saveSettings( QDomDocument& doc, QDomElement& element ) + void saveSettings( QDomDocument& doc, QDomElement& element ) override { Q_UNUSED(doc) Q_UNUSED(element) } - virtual void loadSettings( const QDomElement& element ) + void loadSettings( const QDomElement& element ) override { Q_UNUSED(element) } @@ -434,8 +435,8 @@ public: protected: - virtual void mousePressEvent( QMouseEvent * me ); - virtual void paintEvent( QPaintEvent * pe ); + void mousePressEvent( QMouseEvent * me ) override; + void paintEvent( QPaintEvent * pe ) override; private slots: @@ -517,8 +518,8 @@ public: virtual void loadTrackSpecificSettings( const QDomElement & element ) = 0; - virtual void saveSettings( QDomDocument & doc, QDomElement & element ); - virtual void loadSettings( const QDomElement & element ); + void saveSettings( QDomDocument & doc, QDomElement & element ) override; + void loadSettings( const QDomElement & element ) override; void setSimpleSerializing() { @@ -546,10 +547,10 @@ public: void createTCOsForBB( int bb ); - void insertTact( const MidiTime & pos ); - void removeTact( const MidiTime & pos ); + void insertBar( const MidiTime & pos ); + void removeBar( const MidiTime & pos ); - tact_t length() const; + bar_t length() const; inline TrackContainer* trackContainer() const @@ -563,7 +564,7 @@ public: return m_name; } - virtual QString displayName() const + QString displayName() const override { return name(); } @@ -691,32 +692,32 @@ public slots: protected: - virtual void modelChanged(); + void modelChanged() override; - virtual void saveSettings( QDomDocument& doc, QDomElement& element ) + void saveSettings( QDomDocument& doc, QDomElement& element ) override { Q_UNUSED(doc) Q_UNUSED(element) } - virtual void loadSettings( const QDomElement& element ) + void loadSettings( const QDomElement& element ) override { Q_UNUSED(element) } - virtual QString nodeName() const + QString nodeName() const override { return "trackview"; } - virtual void dragEnterEvent( QDragEnterEvent * dee ); - virtual void dropEvent( QDropEvent * de ); - virtual void mousePressEvent( QMouseEvent * me ); - virtual void mouseMoveEvent( QMouseEvent * me ); - virtual void mouseReleaseEvent( QMouseEvent * me ); - virtual void paintEvent( QPaintEvent * pe ); - virtual void resizeEvent( QResizeEvent * re ); + void dragEnterEvent( QDragEnterEvent * dee ) override; + void dropEvent( QDropEvent * de ) override; + void mousePressEvent( QMouseEvent * me ) override; + void mouseMoveEvent( QMouseEvent * me ) override; + void mouseReleaseEvent( QMouseEvent * me ) override; + void paintEvent( QPaintEvent * pe ) override; + void resizeEvent( QResizeEvent * re ) override; private: diff --git a/include/TrackContainer.h b/include/TrackContainer.h index 1caca922e..fd853a73c 100644 --- a/include/TrackContainer.h +++ b/include/TrackContainer.h @@ -51,9 +51,9 @@ public: TrackContainer(); virtual ~TrackContainer(); - virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); + void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; - virtual void loadSettings( const QDomElement & _this ); + void loadSettings( const QDomElement & _this ) override; virtual AutomationPattern * tempoAutomationPattern() @@ -124,7 +124,7 @@ public: { } - virtual QString nodeName() const + QString nodeName() const override { return "DummyTrackContainer"; } diff --git a/include/TrackContainerView.h b/include/TrackContainerView.h index 67575583b..6e952189b 100644 --- a/include/TrackContainerView.h +++ b/include/TrackContainerView.h @@ -49,30 +49,30 @@ public: TrackContainerView( TrackContainer* tc ); virtual ~TrackContainerView(); - virtual void saveSettings( QDomDocument & _doc, QDomElement & _this ); - virtual void loadSettings( const QDomElement & _this ); + void saveSettings( QDomDocument & _doc, QDomElement & _this ) override; + void loadSettings( const QDomElement & _this ) override; QScrollArea * contentWidget() { - return( m_scrollArea ); + return m_scrollArea; } inline const MidiTime & currentPosition() const { - return( m_currentPosition ); + return m_currentPosition; } virtual bool fixedTCOs() const { - return( false ); + return false; } - inline float pixelsPerTact() const + inline float pixelsPerBar() const { - return( m_ppt ); + return m_ppb; } - void setPixelsPerTact( int _ppt ); + void setPixelsPerBar( int ppb ); const TrackView * trackViewAt( const int _y ) const; @@ -80,12 +80,12 @@ public: inline bool rubberBandActive() const { - return( m_rubberBand->isEnabled() && m_rubberBand->isVisible() ); + return m_rubberBand->isEnabled() && m_rubberBand->isVisible(); } inline QVector selectedObjects() { - return( m_rubberBand->selectedObjects() ); + return m_rubberBand->selectedObjects(); } @@ -116,9 +116,9 @@ public: void clearAllTracks(); - virtual QString nodeName() const + QString nodeName() const override { - return( "trackcontainerview" ); + return "trackcontainerview"; } @@ -129,27 +129,19 @@ public slots: TrackView * createTrackView( Track * _t ); void deleteTrackView( TrackView * _tv ); - virtual void dropEvent( QDropEvent * _de ); - virtual void dragEnterEvent( QDragEnterEvent * _dee ); - /// - /// \brief selectRegionFromPixels - /// \param x - /// \param y - /// Use the rubber band to select TCO from all tracks using x, y pixels - void selectRegionFromPixels(int xStart, int xEnd); + void dropEvent( QDropEvent * _de ) override; + void dragEnterEvent( QDragEnterEvent * _dee ) override; /// /// \brief stopRubberBand /// Removes the rubber band from display when finished with. void stopRubberBand(); -protected: - static const int DEFAULT_PIXELS_PER_TACT = 16; - virtual void mousePressEvent( QMouseEvent * _me ); - virtual void mouseMoveEvent( QMouseEvent * _me ); - virtual void mouseReleaseEvent( QMouseEvent * _me ); - virtual void resizeEvent( QResizeEvent * ); +protected: + static const int DEFAULT_PIXELS_PER_BAR = 16; + + void resizeEvent( QResizeEvent * ) override; MidiTime m_currentPosition; @@ -168,7 +160,7 @@ private: virtual ~scrollArea(); protected: - virtual void wheelEvent( QWheelEvent * _we ); + void wheelEvent( QWheelEvent * _we ) override; private: TrackContainerView* m_trackContainerView; @@ -183,10 +175,10 @@ private: scrollArea * m_scrollArea; QVBoxLayout * m_scrollLayout; - float m_ppt; + float m_ppb; RubberBand * m_rubberBand; - QPoint m_origin; + signals: @@ -202,7 +194,7 @@ public: InstrumentLoaderThread( QObject *parent = 0, InstrumentTrack *it = 0, QString name = "" ); - void run(); + void run() override; private: InstrumentTrack *m_it; diff --git a/include/TrackLabelButton.h b/include/TrackLabelButton.h index f1059bdbf..7d9726feb 100644 --- a/include/TrackLabelButton.h +++ b/include/TrackLabelButton.h @@ -49,13 +49,13 @@ public slots: protected: - virtual void dragEnterEvent( QDragEnterEvent * _dee ); - virtual void dropEvent( QDropEvent * _de ); - virtual void mousePressEvent( QMouseEvent * _me ); - virtual void mouseDoubleClickEvent( QMouseEvent * _me ); - virtual void mouseReleaseEvent( QMouseEvent * _me ); - virtual void paintEvent( QPaintEvent * _pe ); - virtual void resizeEvent( QResizeEvent * _re ); + void dragEnterEvent( QDragEnterEvent * _dee ) override; + void dropEvent( QDropEvent * _de ) override; + void mousePressEvent( QMouseEvent * _me ) override; + void mouseDoubleClickEvent( QMouseEvent * _me ) override; + void mouseReleaseEvent( QMouseEvent * _me ) override; + void paintEvent( QPaintEvent * _pe ) override; + void resizeEvent( QResizeEvent * _re ) override; private: diff --git a/include/TrackRenameLineEdit.h b/include/TrackRenameLineEdit.h index 6883b9b05..e681a2d21 100644 --- a/include/TrackRenameLineEdit.h +++ b/include/TrackRenameLineEdit.h @@ -37,7 +37,7 @@ public: void show(); protected: - virtual void keyPressEvent( QKeyEvent * ke ); + void keyPressEvent( QKeyEvent * ke ) override; private: QString m_oldName; diff --git a/include/VisualizationWidget.h b/include/VisualizationWidget.h index a178b1ad8..85825975a 100644 --- a/include/VisualizationWidget.h +++ b/include/VisualizationWidget.h @@ -61,8 +61,8 @@ public: protected: - virtual void paintEvent( QPaintEvent * _pe ); - virtual void mousePressEvent( QMouseEvent * _me ); + void paintEvent( QPaintEvent * _pe ) override; + void mousePressEvent( QMouseEvent * _me ) override; protected slots: diff --git a/include/lmms_basics.h b/include/lmms_basics.h index cca04e97d..961810856 100644 --- a/include/lmms_basics.h +++ b/include/lmms_basics.h @@ -35,7 +35,7 @@ #endif -typedef int32_t tact_t; +typedef int32_t bar_t; typedef int32_t tick_t; typedef uint8_t volume_t; typedef int8_t panning_t; diff --git a/include/lmms_constants.h b/include/lmms_constants.h index befa789dd..ae6d3d277 100644 --- a/include/lmms_constants.h +++ b/include/lmms_constants.h @@ -49,4 +49,47 @@ const float F_PI_SQR = (float) LD_PI_SQR; const float F_E = (float) LD_E; const float F_E_R = (float) LD_E_R; +// Frequency ranges (in Hz). +// Arbitrary low limit for logarithmic frequency scale; >1 Hz. +const int LOWEST_LOG_FREQ = 10; + +// Full range is defined by LOWEST_LOG_FREQ and current sample rate. +enum FREQUENCY_RANGES +{ + FRANGE_FULL = 0, + FRANGE_AUDIBLE, + FRANGE_BASS, + FRANGE_MIDS, + FRANGE_HIGH +}; + +const int FRANGE_AUDIBLE_START = 20; +const int FRANGE_AUDIBLE_END = 20000; +const int FRANGE_BASS_START = 20; +const int FRANGE_BASS_END = 300; +const int FRANGE_MIDS_START = 200; +const int FRANGE_MIDS_END = 5000; +const int FRANGE_HIGH_START = 4000; +const int FRANGE_HIGH_END = 20000; + +// Amplitude ranges (in dBFS). +// Reference: full scale sine wave (-1.0 to 1.0) is 0 dB. +// Doubling or halving the amplitude produces 3 dB difference. +enum AMPLITUDE_RANGES +{ + ARANGE_EXTENDED = 0, + ARANGE_AUDIBLE, + ARANGE_LOUD, + ARANGE_SILENT +}; + +const int ARANGE_EXTENDED_START = -80; +const int ARANGE_EXTENDED_END = 20; +const int ARANGE_AUDIBLE_START = -50; +const int ARANGE_AUDIBLE_END = 0; +const int ARANGE_LOUD_START = -30; +const int ARANGE_LOUD_END = 0; +const int ARANGE_SILENT_START = -60; +const int ARANGE_SILENT_END = -10; + #endif diff --git a/include/panning.h b/include/panning.h index 8668ddf88..c043adf5c 100644 --- a/include/panning.h +++ b/include/panning.h @@ -27,9 +27,9 @@ #define PANNING_H #include "lmms_basics.h" -#include "volume.h" #include "panning_constants.h" #include "Midi.h" +#include "volume.h" inline stereoVolumeVector panningToVolumeVector( panning_t _p, float _scale = 1.0f ) diff --git a/include/versioninfo.h b/include/versioninfo.h index b34936d57..a5d3d64c6 100644 --- a/include/versioninfo.h +++ b/include/versioninfo.h @@ -32,6 +32,10 @@ #define PLATFORM "OpenBSD" #endif +#ifdef LMMS_BUILD_FREEBSD +#define PLATFORM "FreeBSD" +#endif + #ifdef LMMS_BUILD_WIN32 #define PLATFORM "win32" #endif diff --git a/include/volume.h b/include/volume.h index f0f7708ad..9172395d6 100644 --- a/include/volume.h +++ b/include/volume.h @@ -26,10 +26,7 @@ #ifndef VOLUME_H #define VOLUME_H -#include "lmmsconfig.h" - #include "lmms_basics.h" -#include "Midi.h" const volume_t MinVolume = 0; const volume_t MaxVolume = 200; diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index e12783bab..77f7aa223 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -14,90 +14,8 @@ INCLUDE_DIRECTORIES( "${CMAKE_BINARY_DIR}/src" ) -SET(PLUGIN_LIST "" CACHE STRING "List of plug-ins to build") - -STRING(REPLACE " " ";" PLUGIN_LIST "${PLUGIN_LIST}") - -OPTION(LMMS_MINIMAL "Build a minimal list of plug-ins" OFF) - -SET(MINIMAL_LIST - audio_file_processor - kicker - triple_oscillator -) - -IF(LMMS_MINIMAL) - IF("${PLUGIN_LIST}" STREQUAL "") - STRING(REPLACE ";" " " MINIMAL_LIST_STRING "${MINIMAL_LIST}") - MESSAGE( -"-- Using minimal plug-ins: ${MINIMAL_LIST_STRING}\n" -" Note: You can specify specific plug-ins using -DPLUGIN_LIST=\"foo bar\"" - ) - ENDIF() - SET(PLUGIN_LIST ${MINIMAL_LIST} ${PLUGIN_LIST}) -ENDIF() - -IF("${PLUGIN_LIST}" STREQUAL "") - SET(PLUGIN_LIST - ${MINIMAL_LIST} - Amplifier - BassBooster - bit_invader - Bitcrush - carlabase - carlapatchbay - carlarack - CrossoverEQ - Delay - Disintegrator - DualFilter - dynamics_processor - Eq - Flanger - HydrogenImport - ladspa_browser - LadspaEffect - lb302 - MidiImport - MidiExport - MultitapEcho - monstro - nes - OpulenZ - organic - FreeBoy - patman - peak_controller_effect - GigPlayer - ReverbSC - sf2_player - sfxr - sid - SpectrumAnalyzer - stereo_enhancer - stereo_matrix - stk - vst_base - vestige - VstEffect - watsyn - waveshaper - vibed - Xpressive - zynaddsubfx - ) - -ENDIF("${PLUGIN_LIST}" STREQUAL "") - -IF(MSVC) - SET(MSVC_INCOMPATIBLE_PLUGINS - LadspaEffect - zynaddsubfx - ) - message(WARNING "Compiling with MSVC. The following plugins are not available: ${MSVC_INCOMPATIBLE_PLUGINS}") - LIST(REMOVE_ITEM PLUGIN_LIST ${MSVC_INCOMPATIBLE_PLUGINS}) -ENDIF() +# See cmake/modules/PluginList.cmake FOREACH(PLUGIN ${PLUGIN_LIST}) ADD_SUBDIRECTORY(${PLUGIN}) ENDFOREACH() diff --git a/plugins/MidiImport/MidiImport.cpp b/plugins/MidiImport/MidiImport.cpp index e31c24508..b3d01e790 100644 --- a/plugins/MidiImport/MidiImport.cpp +++ b/plugins/MidiImport/MidiImport.cpp @@ -103,7 +103,7 @@ bool MidiImport::tryImport( TrackContainer* tc ) #ifdef LMMS_HAVE_FLUIDSYNTH if( gui != NULL && - ConfigManager::inst()->defaultSoundfont().isEmpty() ) + ConfigManager::inst()->sf2File().isEmpty() ) { QMessageBox::information( gui->mainWindow(), tr( "Setup incomplete" ), @@ -188,9 +188,9 @@ public: smfMidiCC & putValue( MidiTime time, AutomatableModel * objModel, float value ) { - if( !ap || time > lastPos + DefaultTicksPerTact ) + if( !ap || time > lastPos + DefaultTicksPerBar ) { - MidiTime pPos = MidiTime( time.getTact(), 0 ); + MidiTime pPos = MidiTime( time.getBar(), 0 ); ap = dynamic_cast( at->createTCO(0) ); ap->movePosition( pPos ); @@ -200,7 +200,7 @@ public: lastPos = time; time = time - ap->startPosition(); ap->putValue( time, value, false ); - ap->changeLength( MidiTime( time.getTact() + 1, 0 ) ); + ap->changeLength( MidiTime( time.getBar() + 1, 0 ) ); return *this; } @@ -242,7 +242,7 @@ public: if( it_inst ) { isSF2 = true; - it_inst->loadFile( ConfigManager::inst()->defaultSoundfont() ); + it_inst->loadFile( ConfigManager::inst()->sf2File() ); it_inst->childModel( "bank" )->setValue( 0 ); it_inst->childModel( "patch" )->setValue( 0 ); } @@ -267,9 +267,9 @@ public: void addNote( Note & n ) { - if( !p || n.pos() > lastEnd + DefaultTicksPerTact ) + if( !p || n.pos() > lastEnd + DefaultTicksPerBar ) { - MidiTime pPos = MidiTime( n.pos().getTact(), 0 ); + MidiTime pPos = MidiTime( n.pos().getBar(), 0 ); p = dynamic_cast( it->createTCO( 0 ) ); p->movePosition( pPos ); } @@ -309,33 +309,36 @@ bool MidiImport::readSMF( TrackContainer* tc ) smfMidiChannel chs[256]; MeterModel & timeSigMM = Engine::getSong()->getTimeSigModel(); - AutomationPattern * timeSigNumeratorPat = - AutomationPattern::globalAutomationPattern( &timeSigMM.numeratorModel() ); - AutomationPattern * timeSigDenominatorPat = - AutomationPattern::globalAutomationPattern( &timeSigMM.denominatorModel() ); + AutomationTrack * nt = dynamic_cast( + Track::create(Track::AutomationTrack, Engine::getSong())); + nt->setName(tr("MIDI Time Signature Numerator")); + AutomationTrack * dt = dynamic_cast( + Track::create(Track::AutomationTrack, Engine::getSong())); + dt->setName(tr("MIDI Time Signature Denominator")); + AutomationPattern * timeSigNumeratorPat = + new AutomationPattern(nt); + timeSigNumeratorPat->setDisplayName(tr("Numerator")); + timeSigNumeratorPat->addObject(&timeSigMM.numeratorModel()); + AutomationPattern * timeSigDenominatorPat = + new AutomationPattern(dt); + timeSigDenominatorPat->setDisplayName(tr("Denominator")); + timeSigDenominatorPat->addObject(&timeSigMM.denominatorModel()); // TODO: adjust these to Time.Sig changes - double beatsPerTact = 4; - double ticksPerBeat = DefaultTicksPerTact / beatsPerTact; + double beatsPerBar = 4; + double ticksPerBeat = DefaultTicksPerBar / beatsPerBar; // Time-sig changes Alg_time_sigs * timeSigs = &seq->time_sig; for( int s = 0; s < timeSigs->length(); ++s ) { Alg_time_sig timeSig = (*timeSigs)[s]; - // Initial timeSig, set song-default value - if(/* timeSig.beat == 0*/ true ) - { - // TODO set song-global default value - printf("Another timesig at %f\n", timeSig.beat); - timeSigNumeratorPat->putValue( timeSig.beat*ticksPerBeat, timeSig.num ); - timeSigDenominatorPat->putValue( timeSig.beat*ticksPerBeat, timeSig.den ); - } - else - { - } - + timeSigNumeratorPat->putValue(timeSig.beat * ticksPerBeat, timeSig.num); + timeSigDenominatorPat->putValue(timeSig.beat * ticksPerBeat, timeSig.den); } + // manually call otherwise the pattern shows being 1 bar + timeSigNumeratorPat->updateLength(); + timeSigDenominatorPat->updateLength(); pd.setValue( 2 ); diff --git a/plugins/SpectrumAnalyzer/Analyzer.cpp b/plugins/SpectrumAnalyzer/Analyzer.cpp index 9c3fe0814..656d18bd4 100644 --- a/plugins/SpectrumAnalyzer/Analyzer.cpp +++ b/plugins/SpectrumAnalyzer/Analyzer.cpp @@ -27,7 +27,13 @@ #include "Analyzer.h" +#ifdef SA_DEBUG + #include + #include +#endif + #include "embed.h" +#include "lmms_basics.h" #include "plugin_export.h" @@ -38,7 +44,7 @@ extern "C" { "Spectrum Analyzer", QT_TRANSLATE_NOOP("pluginBrowser", "A graphical spectrum analyzer."), "Martin Pavelek ", - 0x0100, + 0x0112, Plugin::Effect, new PluginPixmapLoader("logo"), NULL, @@ -50,17 +56,54 @@ extern "C" { Analyzer::Analyzer(Model *parent, const Plugin::Descriptor::SubPluginFeatures::Key *key) : Effect(&analyzer_plugin_descriptor, parent, key), m_processor(&m_controls), - m_controls(this) + m_controls(this), + m_processorThread(m_processor, m_inputBuffer), + // Buffer is sized to cover 4* the current maximum LMMS audio buffer size, + // so that it has some reserve space in case data processor is busy. + m_inputBuffer(4 * m_maxBufferSize) { + m_processorThread.start(); } +Analyzer::~Analyzer() +{ + m_processor.terminate(); + m_inputBuffer.wakeAll(); + m_processorThread.wait(); +} + // Take audio data and pass them to the spectrum processor. -// Skip processing if the controls dialog isn't visible, it would only waste CPU cycles. bool Analyzer::processAudioBuffer(sampleFrame *buffer, const fpp_t frame_count) { + // Measure time spent in audio thread; both average and peak should be well under 1 ms. + #ifdef SA_DEBUG + unsigned int audio_time = std::chrono::high_resolution_clock::now().time_since_epoch().count(); + if (audio_time - m_last_dump_time > 5000000000) // print every 5 seconds + { + std::cout << "Analyzer audio thread: " << m_sum_execution / m_dump_count << " ms avg / " + << m_max_execution << " ms peak." << std::endl; + m_last_dump_time = audio_time; + m_sum_execution = m_max_execution = m_dump_count = 0; + } + #endif + if (!isEnabled() || !isRunning ()) {return false;} - if (m_controls.isViewVisible()) {m_processor.analyse(buffer, frame_count);} + + // Skip processing if the controls dialog isn't visible, it would only waste CPU cycles. + if (m_controls.isViewVisible()) + { + // To avoid processing spikes on audio thread, data are stored in + // a lockless ringbuffer and processed in a separate thread. + m_inputBuffer.write(buffer, frame_count, true); + } + #ifdef SA_DEBUG + audio_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - audio_time; + m_dump_count++; + m_sum_execution += audio_time / 1000000.0; + if (audio_time / 1000000.0 > m_max_execution) {m_max_execution = audio_time / 1000000.0;} + #endif + return isRunning(); } diff --git a/plugins/SpectrumAnalyzer/Analyzer.h b/plugins/SpectrumAnalyzer/Analyzer.h index 157cc1eae..304777c9a 100644 --- a/plugins/SpectrumAnalyzer/Analyzer.h +++ b/plugins/SpectrumAnalyzer/Analyzer.h @@ -27,7 +27,11 @@ #ifndef ANALYZER_H #define ANALYZER_H +#include + +#include "DataprocLauncher.h" #include "Effect.h" +#include "LocklessRingBuffer.h" #include "SaControls.h" #include "SaProcessor.h" @@ -37,7 +41,7 @@ class Analyzer : public Effect { public: Analyzer(Model *parent, const Descriptor::SubPluginFeatures::Key *key); - virtual ~Analyzer() {}; + virtual ~Analyzer(); bool processAudioBuffer(sampleFrame *buffer, const fpp_t frame_count) override; EffectControls *controls() override {return &m_controls;} @@ -47,6 +51,24 @@ public: private: SaProcessor m_processor; SaControls m_controls; + + // Maximum LMMS buffer size (hard coded, the actual constant is hard to get) + const unsigned int m_maxBufferSize = 4096; + + // QThread::create() workaround + // Replace DataprocLauncher by QThread and replace initializer in constructor + // with the following commented line when LMMS CI starts using Qt > 5.9 + //m_processorThread = QThread::create([=]{m_processor.analyze(m_inputBuffer);}); + DataprocLauncher m_processorThread; + + LocklessRingBuffer m_inputBuffer; + + #ifdef SA_DEBUG + int m_last_dump_time; + int m_dump_count; + float m_sum_execution; + float m_max_execution; + #endif }; #endif // ANALYZER_H diff --git a/plugins/SpectrumAnalyzer/CMakeLists.txt b/plugins/SpectrumAnalyzer/CMakeLists.txt index 630fbf1be..488495a9e 100644 --- a/plugins/SpectrumAnalyzer/CMakeLists.txt +++ b/plugins/SpectrumAnalyzer/CMakeLists.txt @@ -1,5 +1,7 @@ INCLUDE(BuildPlugin) INCLUDE_DIRECTORIES(${FFTW3F_INCLUDE_DIRS}) + LINK_LIBRARIES(${FFTW3F_LIBRARIES}) + BUILD_PLUGIN(analyzer Analyzer.cpp SaProcessor.cpp SaControls.cpp SaControlsDialog.cpp SaSpectrumView.cpp SaWaterfallView.cpp -MOCFILES SaProcessor.h SaControls.h SaControlsDialog.h SaSpectrumView.h SaWaterfallView.h EMBEDDED_RESOURCES *.svg logo.png) +MOCFILES SaProcessor.h SaControls.h SaControlsDialog.h SaSpectrumView.h SaWaterfallView.h DataprocLauncher.h EMBEDDED_RESOURCES *.svg logo.png) diff --git a/plugins/SpectrumAnalyzer/DataprocLauncher.h b/plugins/SpectrumAnalyzer/DataprocLauncher.h new file mode 100644 index 000000000..d91e0bedf --- /dev/null +++ b/plugins/SpectrumAnalyzer/DataprocLauncher.h @@ -0,0 +1,52 @@ +/* + * DataprocLauncher.h - QThread::create workaround for older Qt version + * + * Copyright (c) 2019 Martin Pavelek + * + * This file is part of LMMS - https://lmms.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#ifndef DATAPROCLAUNCHER_H +#define DATAPROCLAUNCHER_H + +#include + +#include "SaProcessor.h" +#include "LocklessRingBuffer.h" + +class DataprocLauncher : public QThread +{ +public: + explicit DataprocLauncher(SaProcessor &proc, LocklessRingBuffer &buffer) + : m_processor(&proc), + m_inputBuffer(&buffer) + { + } + +private: + void run() override + { + m_processor->analyze(*m_inputBuffer); + } + + SaProcessor *m_processor; + LocklessRingBuffer *m_inputBuffer; +}; + +#endif // DATAPROCLAUNCHER_H diff --git a/plugins/SpectrumAnalyzer/README.md b/plugins/SpectrumAnalyzer/README.md index 3d3506d65..473083da8 100644 --- a/plugins/SpectrumAnalyzer/README.md +++ b/plugins/SpectrumAnalyzer/README.md @@ -4,13 +4,41 @@ This plugin consists of three widgets and back-end code to provide them with required data. -The top-level widget is SaControlDialog. It populates a configuration widget (created dynamically) and instantiates spectrum display widgets. Its main back-end class is SaControls, which holds all configuration values and globally valid constants (e.g. range definitions). +The top-level widget is `SaControlDialog`. It populates configuration widgets (created dynamically) and instantiates spectrum display widgets. Its main back-end class is `SaControls`, which holds all configuration values. -SaSpectrumDisplay and SaWaterfallDisplay show the result of spectrum analysis. Their main back-end class is SaProcessor, which performs FFT analysis on data received from the Analyzer class, which in turn handles the interface with LMMS. +`SaSpectrumView` and `SaWaterfallView` widgets show the result of spectrum analysis. Their main back-end class is `SaProcessor`, which performs FFT analysis on data received from the `Analyzer` class, which in turn handles the interface with LMMS. + +## Threads + +The Spectrum Analyzer is involved in three different threads: + - **Effect mixer thread**: periodically calls `Analyzer::processAudioBuffer()` to provide the plugin with more data. This thread is real-time sensitive -- any latency spikes can potentially cause interruptions in the audio stream. For this reason, `Analyzer::processAudioBuffer()` must finish as fast as possible and must not call any functions that could cause it to be delayed for unpredictable amount of time. A lock-less ring buffer is used to safely feed data to the FFT analysis thread without risking any latency spikes due to a shared mutex being unavailable at the time of writing. + - **FFT analysis thread**: a standalone thread formed by the `SaProcessor::analyze()` function. Takes in data from the ring buffer, performs FFT analysis and prepares results for display. This thread is not real-time sensitive but excessive locking is discouraged to maintain good performance. + - **GUI thread**: periodically triggers `paintEvent()` of all Qt widgets, including `SaSpectrumView` and `SaWaterfallView`. While it is not as sensitive to latency spikes as the effect mixer thread, the `paintEvent()`s appear to be called sequentially and the execution time of each widget therefore adds to the total time needed to complete one full refresh cycle. This means the maximum frame rate of the Qt GUI will be limited to `1 / total_execution_time`. Good performance of the `paintEvent()` functions should be therefore kept in mind. ## Changelog - + 1.1.2 2019-11-18 + - waterfall is no longer cut short when width limit is reached + - various small tweaks based on final review + 1.1.1 2019-10-13 + - improved interface for accessing SaProcessor private data + - readme file update + - other small improvements based on reviews + 1.1.0 2019-08-29 + - advanced config: expose hidden constants to user + - advanced config: add support for FFT window overlapping + - waterfall: display at native resolution on high-DPI screens + - waterfall: add cursor and improve label density + - FFT: fix normalization so that 0 dBFS matches full-scale sinewave + - FFT: decouple data acquisition from processing and display + - FFT: separate lock for reallocation (to avoid some needless waiting) + - moved ranges and other constants to a separate file + - debug: better performance measurements + - various performance optimizations + 1.0.3 2019-07-25 + - rename and tweak amplitude ranges based on feedback + 1.0.2 2019-07-12 + - variety of small changes based on code review 1.0.1 2019-06-02 - code style changes - added tool-tips diff --git a/plugins/SpectrumAnalyzer/SaControls.cpp b/plugins/SpectrumAnalyzer/SaControls.cpp index 5691c0ae4..6be298e27 100644 --- a/plugins/SpectrumAnalyzer/SaControls.cpp +++ b/plugins/SpectrumAnalyzer/SaControls.cpp @@ -50,7 +50,17 @@ SaControls::SaControls(Analyzer *effect) : m_freqRangeModel(this, tr("Frequency range")), m_ampRangeModel(this, tr("Amplitude range")), m_blockSizeModel(this, tr("FFT block size")), - m_windowModel(this, tr("FFT window type")) + m_windowModel(this, tr("FFT window type")), + + // Advanced settings knobs + m_envelopeResolutionModel(0.25f, 0.1f, 3.0f, 0.05f, this, tr("Peak envelope resolution")), + m_spectrumResolutionModel(1.5f, 0.1f, 3.0f, 0.05f, this, tr("Spectrum display resolution")), + m_peakDecayFactorModel(0.992f, 0.95f, 0.999f, 0.001f, this, tr("Peak decay multiplier")), + m_averagingWeightModel(0.15f, 0.01f, 0.5f, 0.01f, this, tr("Averaging weight")), + m_waterfallHeightModel(300.0f, 50.0f, 1000.0f, 50.0f, this, tr("Waterfall history size")), + m_waterfallGammaModel(0.30f, 0.10f, 1.00f, 0.05f, this, tr("Waterfall gamma correction")), + m_windowOverlapModel(2.0f, 1.0f, 4.0f, 1.0f, this, tr("FFT window overlap")), + m_zeroPaddingModel(2.0f, 0.0f, 4.0f, 1.0f, this, tr("FFT zero padding")) { // Frequency and amplitude ranges; order must match // FREQUENCY_RANGES and AMPLITUDE_RANGES defined in SaControls.h @@ -62,10 +72,10 @@ SaControls::SaControls(Analyzer *effect) : m_freqRangeModel.setValue(m_freqRangeModel.findText(tr("Full (auto)"))); m_ampRangeModel.addItem(tr("Extended")); - m_ampRangeModel.addItem(tr("Default")); m_ampRangeModel.addItem(tr("Audible")); - m_ampRangeModel.addItem(tr("Noise")); - m_ampRangeModel.setValue(m_ampRangeModel.findText(tr("Default"))); + m_ampRangeModel.addItem(tr("Loud")); + m_ampRangeModel.addItem(tr("Silent")); + m_ampRangeModel.setValue(m_ampRangeModel.findText(tr("Audible"))); // FFT block size labels are generated automatically, based on // FFT_BLOCK_SIZES vector defined in fft_helpers.h @@ -95,12 +105,15 @@ SaControls::SaControls(Analyzer *effect) : // Colors // Background color is defined by Qt / theme. - // Make sure the sum of colors for L and R channel stays lower or equal - // to 255. Otherwise the Waterfall pixels may overflow back to 0 even when - // the input signal isn't clipping (over 1.0). + // Make sure the sum of colors for L and R channel results into a neutral + // color that has at least one component equal to 255 (i.e. ideally white). + // This means the color overflows to zero exactly when signal reaches + // clipping threshold, indicating the problematic frequency to user. + // Mono waterfall color should have similarly at least one component at 255. m_colorL = QColor(51, 148, 204, 135); m_colorR = QColor(204, 107, 51, 135); m_colorMono = QColor(51, 148, 204, 204); + m_colorMonoW = QColor(64, 185, 255, 255); m_colorBG = QColor(7, 7, 7, 255); // ~20 % gray (after gamma correction) m_colorGrid = QColor(30, 34, 38, 255); // ~40 % gray (slightly cold / blue) m_colorLabels = QColor(192, 202, 212, 255); // ~90 % gray (slightly cold / blue) @@ -126,6 +139,15 @@ void SaControls::loadSettings(const QDomElement &_this) m_ampRangeModel.loadSettings(_this, "RangeY"); m_blockSizeModel.loadSettings(_this, "BlockSize"); m_windowModel.loadSettings(_this, "WindowType"); + + m_envelopeResolutionModel.loadSettings(_this, "EnvelopeRes"); + m_spectrumResolutionModel.loadSettings(_this, "SpectrumRes"); + m_peakDecayFactorModel.loadSettings(_this, "PeakDecayFactor"); + m_averagingWeightModel.loadSettings(_this, "AverageWeight"); + m_waterfallHeightModel.loadSettings(_this, "WaterfallHeight"); + m_waterfallGammaModel.loadSettings(_this, "WaterfallGamma"); + m_windowOverlapModel.loadSettings(_this, "WindowOverlap"); + m_zeroPaddingModel.loadSettings(_this, "ZeroPadding"); } @@ -141,4 +163,14 @@ void SaControls::saveSettings(QDomDocument &doc, QDomElement &parent) m_ampRangeModel.saveSettings(doc, parent, "RangeY"); m_blockSizeModel.saveSettings(doc, parent, "BlockSize"); m_windowModel.saveSettings(doc, parent, "WindowType"); + + m_envelopeResolutionModel.saveSettings(doc, parent, "EnvelopeRes"); + m_spectrumResolutionModel.saveSettings(doc, parent, "SpectrumRes"); + m_peakDecayFactorModel.saveSettings(doc, parent, "PeakDecayFactor"); + m_averagingWeightModel.saveSettings(doc, parent, "AverageWeight"); + m_waterfallHeightModel.saveSettings(doc, parent, "WaterfallHeight"); + m_waterfallGammaModel.saveSettings(doc, parent, "WaterfallGamma"); + m_windowOverlapModel.saveSettings(doc, parent, "WindowOverlap"); + m_zeroPaddingModel.saveSettings(doc, parent, "ZeroPadding"); + } diff --git a/plugins/SpectrumAnalyzer/SaControls.h b/plugins/SpectrumAnalyzer/SaControls.h index e0b54e6a2..4673416bc 100644 --- a/plugins/SpectrumAnalyzer/SaControls.h +++ b/plugins/SpectrumAnalyzer/SaControls.h @@ -27,52 +27,10 @@ #include "ComboBoxModel.h" #include "EffectControls.h" +#include "lmms_constants.h" //#define SA_DEBUG 1 // define SA_DEBUG to enable performance measurements -// Frequency ranges (in Hz). -// Full range is defined by LOWEST_LOG_FREQ and current sample rate. -const int LOWEST_LOG_FREQ = 10; // arbitrary low limit for log. scale, >1 - -enum FREQUENCY_RANGES -{ - FRANGE_FULL = 0, - FRANGE_AUDIBLE, - FRANGE_BASS, - FRANGE_MIDS, - FRANGE_HIGH -}; - -const int FRANGE_AUDIBLE_START = 20; -const int FRANGE_AUDIBLE_END = 20000; -const int FRANGE_BASS_START = 20; -const int FRANGE_BASS_END = 300; -const int FRANGE_MIDS_START = 200; -const int FRANGE_MIDS_END = 5000; -const int FRANGE_HIGH_START = 4000; -const int FRANGE_HIGH_END = 20000; - -// Amplitude ranges. -// Reference: sine wave from -1.0 to 1.0 = 0 dB. -// I.e. if master volume is 100 %, positive values signify clipping. -// Doubling or halving the amplitude produces 3 dB difference. -enum AMPLITUDE_RANGES -{ - ARANGE_EXTENDED = 0, - ARANGE_DEFAULT, - ARANGE_AUDIBLE, - ARANGE_NOISE -}; - -const int ARANGE_EXTENDED_START = -80; -const int ARANGE_EXTENDED_END = 20; -const int ARANGE_DEFAULT_START = -30; -const int ARANGE_DEFAULT_END = 0; -const int ARANGE_AUDIBLE_START = -50; -const int ARANGE_AUDIBLE_END = 10; -const int ARANGE_NOISE_START = -60; -const int ARANGE_NOISE_END = -20; - class Analyzer; @@ -90,11 +48,12 @@ public: void loadSettings (const QDomElement &_this) override; QString nodeName() const override {return "Analyzer";} - int controlCount() override {return 12;} + int controlCount() override {return 20;} private: Analyzer *m_effect; + // basic settings BoolModel m_pauseModel; BoolModel m_refFreezeModel; @@ -111,12 +70,24 @@ private: ComboBoxModel m_blockSizeModel; ComboBoxModel m_windowModel; - QColor m_colorL; - QColor m_colorR; - QColor m_colorMono; - QColor m_colorBG; - QColor m_colorGrid; - QColor m_colorLabels; + // advanced settings + FloatModel m_envelopeResolutionModel; + FloatModel m_spectrumResolutionModel; + FloatModel m_peakDecayFactorModel; + FloatModel m_averagingWeightModel; + FloatModel m_waterfallHeightModel; + FloatModel m_waterfallGammaModel; + FloatModel m_windowOverlapModel; + FloatModel m_zeroPaddingModel; + + // colors (hard-coded, values must add up to specific numbers) + QColor m_colorL; //!< color of the left channel + QColor m_colorR; //!< color of the right channel + QColor m_colorMono; //!< mono color for spectrum display + QColor m_colorMonoW; //!< mono color for waterfall display + QColor m_colorBG; //!< spectrum display background color + QColor m_colorGrid; //!< color of grid lines + QColor m_colorLabels; //!< color of axis labels friend class SaControlsDialog; friend class SaSpectrumView; diff --git a/plugins/SpectrumAnalyzer/SaControlsDialog.cpp b/plugins/SpectrumAnalyzer/SaControlsDialog.cpp index 4ba307a4d..d89cc1093 100644 --- a/plugins/SpectrumAnalyzer/SaControlsDialog.cpp +++ b/plugins/SpectrumAnalyzer/SaControlsDialog.cpp @@ -34,6 +34,7 @@ #include "ComboBoxModel.h" #include "embed.h" #include "Engine.h" +#include "Knob.h" #include "LedCheckbox.h" #include "PixmapButton.h" #include "SaControls.h" @@ -53,13 +54,24 @@ SaControlsDialog::SaControlsDialog(SaControls *controls, SaProcessor *processor) master_layout->setContentsMargins(2, 6, 2, 8); setLayout(master_layout); - // QSplitter top: configuration section + // Display splitter top: controls section + QWidget *controls_widget = new QWidget; + QHBoxLayout *controls_layout = new QHBoxLayout; + controls_layout->setContentsMargins(0, 0, 0, 0); + controls_widget->setLayout(controls_layout); + controls_widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding); + controls_widget->setMaximumHeight(m_configHeight); + display_splitter->addWidget(controls_widget); + + + // Basic configuration QWidget *config_widget = new QWidget; QGridLayout *config_layout = new QGridLayout; config_widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); config_widget->setMaximumHeight(m_configHeight); config_widget->setLayout(config_layout); - display_splitter->addWidget(config_widget); + controls_layout->addWidget(config_widget); + controls_layout->setStretchFactor(config_widget, 10); // Pre-compute target pixmap size based on monitor DPI. // Using setDevicePixelRatio() on pixmap allows the SVG image to be razor @@ -67,6 +79,8 @@ SaControlsDialog::SaControlsDialog(SaControls *controls, SaProcessor *processor) // enlarged. No idea how to make Qt do it in a more reasonable way. QSize iconSize = QSize(22.0 * devicePixelRatio(), 22.0 * devicePixelRatio()); QSize buttonSize = 1.2 * iconSize; + QSize advButtonSize = QSize((m_configHeight * devicePixelRatio()) / 3, m_configHeight * devicePixelRatio()); + // pause and freeze buttons PixmapButton *pauseButton = new PixmapButton(this, tr("Pause")); @@ -79,7 +93,7 @@ SaControlsDialog::SaControlsDialog(SaControls *controls, SaProcessor *processor) pauseButton->setInactiveGraphic(*pauseOffPixmap); pauseButton->setCheckable(true); pauseButton->setModel(&controls->m_pauseModel); - config_layout->addWidget(pauseButton, 0, 0, 2, 1); + config_layout->addWidget(pauseButton, 0, 0, 2, 1, Qt::AlignHCenter); PixmapButton *refFreezeButton = new PixmapButton(this, tr("Reference freeze")); refFreezeButton->setToolTip(tr("Freeze current input as a reference / disable falloff in peak-hold mode.")); @@ -91,7 +105,7 @@ SaControlsDialog::SaControlsDialog(SaControls *controls, SaProcessor *processor) refFreezeButton->setInactiveGraphic(*freezeOffPixmap); refFreezeButton->setCheckable(true); refFreezeButton->setModel(&controls->m_refFreezeModel); - config_layout->addWidget(refFreezeButton, 2, 0, 2, 1); + config_layout->addWidget(refFreezeButton, 2, 0, 2, 1, Qt::AlignHCenter); // misc configuration switches LedCheckBox *waterfallButton = new LedCheckBox(tr("Waterfall"), this); @@ -194,6 +208,117 @@ SaControlsDialog::SaControlsDialog(SaControls *controls, SaProcessor *processor) processor->rebuildWindow(); connect(&controls->m_windowModel, &ComboBoxModel::dataChanged, [=] {processor->rebuildWindow();}); + // set stretch factors so that combo boxes expand first + config_layout->setColumnStretch(3, 2); + config_layout->setColumnStretch(5, 3); + + + // Advanced configuration + QWidget *advanced_widget = new QWidget; + QGridLayout *advanced_layout = new QGridLayout; + advanced_widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + advanced_widget->setMaximumHeight(m_configHeight); + advanced_widget->setLayout(advanced_layout); + advanced_widget->hide(); + controls_layout->addWidget(advanced_widget); + controls_layout->setStretchFactor(advanced_widget, 10); + + // Peak envelope resolution + Knob *envelopeResolutionKnob = new Knob(knobSmall_17, this); + envelopeResolutionKnob->setModel(&controls->m_envelopeResolutionModel); + envelopeResolutionKnob->setLabel(tr("Envelope res.")); + envelopeResolutionKnob->setToolTip(tr("Increase envelope resolution for better details, decrease for better GUI performance.")); + envelopeResolutionKnob->setHintText(tr("Draw at most"), tr(" envelope points per pixel")); + advanced_layout->addWidget(envelopeResolutionKnob, 0, 0, 1, 1, Qt::AlignCenter); + + // Spectrum graph resolution + Knob *spectrumResolutionKnob = new Knob(knobSmall_17, this); + spectrumResolutionKnob->setModel(&controls->m_spectrumResolutionModel); + spectrumResolutionKnob->setLabel(tr("Spectrum res.")); + spectrumResolutionKnob->setToolTip(tr("Increase spectrum resolution for better details, decrease for better GUI performance.")); + spectrumResolutionKnob->setHintText(tr("Draw at most"), tr(" spectrum points per pixel")); + advanced_layout->addWidget(spectrumResolutionKnob, 1, 0, 1, 1, Qt::AlignCenter); + + // Peak falloff speed + Knob *peakDecayFactorKnob = new Knob(knobSmall_17, this); + peakDecayFactorKnob->setModel(&controls->m_peakDecayFactorModel); + peakDecayFactorKnob->setLabel(tr("Falloff factor")); + peakDecayFactorKnob->setToolTip(tr("Decrease to make peaks fall faster.")); + peakDecayFactorKnob->setHintText(tr("Multiply buffered value by"), ""); + advanced_layout->addWidget(peakDecayFactorKnob, 0, 1, 1, 1, Qt::AlignCenter); + + // Averaging weight + Knob *averagingWeightKnob = new Knob(knobSmall_17, this); + averagingWeightKnob->setModel(&controls->m_averagingWeightModel); + averagingWeightKnob->setLabel(tr("Averaging weight")); + averagingWeightKnob->setToolTip(tr("Decrease to make averaging slower and smoother.")); + averagingWeightKnob->setHintText(tr("New sample contributes"), ""); + advanced_layout->addWidget(averagingWeightKnob, 1, 1, 1, 1, Qt::AlignCenter); + + // Waterfall history size + Knob *waterfallHeightKnob = new Knob(knobSmall_17, this); + waterfallHeightKnob->setModel(&controls->m_waterfallHeightModel); + waterfallHeightKnob->setLabel(tr("Waterfall height")); + waterfallHeightKnob->setToolTip(tr("Increase to get slower scrolling, decrease to see fast transitions better. Warning: medium CPU usage.")); + waterfallHeightKnob->setHintText(tr("Keep"), tr(" lines")); + advanced_layout->addWidget(waterfallHeightKnob, 0, 2, 1, 1, Qt::AlignCenter); + processor->reallocateBuffers(); + connect(&controls->m_waterfallHeightModel, &FloatModel::dataChanged, [=] {processor->reallocateBuffers();}); + + // Waterfall gamma correction + Knob *waterfallGammaKnob = new Knob(knobSmall_17, this); + waterfallGammaKnob->setModel(&controls->m_waterfallGammaModel); + waterfallGammaKnob->setLabel(tr("Waterfall gamma")); + waterfallGammaKnob->setToolTip(tr("Decrease to see very weak signals, increase to get better contrast.")); + waterfallGammaKnob->setHintText(tr("Gamma value:"), ""); + advanced_layout->addWidget(waterfallGammaKnob, 1, 2, 1, 1, Qt::AlignCenter); + + // FFT window overlap + Knob *windowOverlapKnob = new Knob(knobSmall_17, this); + windowOverlapKnob->setModel(&controls->m_windowOverlapModel); + windowOverlapKnob->setLabel(tr("Window overlap")); + windowOverlapKnob->setToolTip(tr("Increase to prevent missing fast transitions arriving near FFT window edges. Warning: high CPU usage.")); + windowOverlapKnob->setHintText(tr("Each sample processed"), tr(" times")); + advanced_layout->addWidget(windowOverlapKnob, 0, 3, 1, 1, Qt::AlignCenter); + + // FFT zero padding + Knob *zeroPaddingKnob = new Knob(knobSmall_17, this); + zeroPaddingKnob->setModel(&controls->m_zeroPaddingModel); + zeroPaddingKnob->setLabel(tr("Zero padding")); + zeroPaddingKnob->setToolTip(tr("Increase to get smoother-looking spectrum. Warning: high CPU usage.")); + zeroPaddingKnob->setHintText(tr("Processing buffer is"), tr(" steps larger than input block")); + advanced_layout->addWidget(zeroPaddingKnob, 1, 3, 1, 1, Qt::AlignCenter); + processor->reallocateBuffers(); + connect(&controls->m_zeroPaddingModel, &FloatModel::dataChanged, [=] {processor->reallocateBuffers();}); + + + // Advanced settings button + PixmapButton *advancedButton = new PixmapButton(this, tr("Advanced settings")); + advancedButton->setToolTip(tr("Access advanced settings")); + QPixmap *advancedOnPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("advanced_on").scaled(advButtonSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + QPixmap *advancedOffPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("advanced_off").scaled(advButtonSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + advancedOnPixmap->setDevicePixelRatio(devicePixelRatio()); + advancedOffPixmap->setDevicePixelRatio(devicePixelRatio()); + advancedButton->setActiveGraphic(*advancedOnPixmap); + advancedButton->setInactiveGraphic(*advancedOffPixmap); + advancedButton->setCheckable(true); + controls_layout->addStretch(0); + controls_layout->addWidget(advancedButton); + + connect(advancedButton, &PixmapButton::toggled, [=](bool checked) + { + if (checked) + { + config_widget->hide(); + advanced_widget->show(); + } + else + { + config_widget->show(); + advanced_widget->hide(); + } + } + ); // QSplitter middle and bottom: spectrum display widgets m_spectrum = new SaSpectrumView(controls, processor, this); diff --git a/plugins/SpectrumAnalyzer/SaProcessor.cpp b/plugins/SpectrumAnalyzer/SaProcessor.cpp index 9261658aa..9d83f2916 100644 --- a/plugins/SpectrumAnalyzer/SaProcessor.cpp +++ b/plugins/SpectrumAnalyzer/SaProcessor.cpp @@ -26,15 +26,23 @@ #include "SaProcessor.h" #include +#ifdef SA_DEBUG + #include +#endif #include -#include +#ifdef SA_DEBUG + #include + #include +#endif #include #include "lmms_math.h" +#include "LocklessRingBuffer.h" -SaProcessor::SaProcessor(SaControls *controls) : +SaProcessor::SaProcessor(const SaControls *controls) : m_controls(controls), + m_terminate(false), m_inBlockSize(FFT_BLOCK_SIZES[0]), m_fftBlockSize(FFT_BLOCK_SIZES[0]), m_sampleRate(Engine::mixer()->processingSampleRate()), @@ -47,21 +55,23 @@ SaProcessor::SaProcessor(SaControls *controls) : m_fftWindow.resize(m_inBlockSize, 1.0); precomputeWindow(m_fftWindow.data(), m_inBlockSize, BLACKMAN_HARRIS); - m_bufferL.resize(m_fftBlockSize, 0); - m_bufferR.resize(m_fftBlockSize, 0); + m_bufferL.resize(m_inBlockSize, 0); + m_bufferR.resize(m_inBlockSize, 0); + m_filteredBufferL.resize(m_fftBlockSize, 0); + m_filteredBufferR.resize(m_fftBlockSize, 0); m_spectrumL = (fftwf_complex *) fftwf_malloc(binCount() * sizeof (fftwf_complex)); m_spectrumR = (fftwf_complex *) fftwf_malloc(binCount() * sizeof (fftwf_complex)); - m_fftPlanL = fftwf_plan_dft_r2c_1d(m_fftBlockSize, m_bufferL.data(), m_spectrumL, FFTW_MEASURE); - m_fftPlanR = fftwf_plan_dft_r2c_1d(m_fftBlockSize, m_bufferR.data(), m_spectrumR, FFTW_MEASURE); + m_fftPlanL = fftwf_plan_dft_r2c_1d(m_fftBlockSize, m_filteredBufferL.data(), m_spectrumL, FFTW_MEASURE); + m_fftPlanR = fftwf_plan_dft_r2c_1d(m_fftBlockSize, m_filteredBufferR.data(), m_spectrumR, FFTW_MEASURE); m_absSpectrumL.resize(binCount(), 0); m_absSpectrumR.resize(binCount(), 0); m_normSpectrumL.resize(binCount(), 0); m_normSpectrumR.resize(binCount(), 0); - m_history.resize(binCount() * m_waterfallHeight * sizeof qRgb(0,0,0), 0); - - clear(); + m_waterfallHeight = 100; // a small safe value + m_history_work.resize(waterfallWidth() * m_waterfallHeight * sizeof qRgb(0,0,0), 0); + m_history.resize(waterfallWidth() * m_waterfallHeight * sizeof qRgb(0,0,0), 0); } @@ -79,169 +89,229 @@ SaProcessor::~SaProcessor() } -// Load a batch of data from LMMS; run FFT analysis if buffer is full enough. -void SaProcessor::analyse(sampleFrame *in_buffer, const fpp_t frame_count) +// Load data from audio thread ringbuffer and run FFT analysis if buffer is full enough. +void SaProcessor::analyze(LocklessRingBuffer &ring_buffer) { - #ifdef SA_DEBUG - int start_time = std::chrono::high_resolution_clock::now().time_since_epoch().count(); - #endif - // only take in data if any view is visible and not paused - if ((m_spectrumActive || m_waterfallActive) && !m_controls->m_pauseModel.value()) + LocklessRingBufferReader reader(ring_buffer); + + // Processing thread loop + while (!m_terminate) { - const bool stereo = m_controls->m_stereoModel.value(); - fpp_t in_frame = 0; - while (in_frame < frame_count) + // If there is nothing to read, wait for notification from the writing side. + if (reader.empty()) {reader.waitForData();} + + // skip waterfall render if processing can't keep up with input + bool overload = ring_buffer.free() < ring_buffer.capacity() / 2; + + auto in_buffer = reader.read_max(ring_buffer.capacity() / 4); + std::size_t frame_count = in_buffer.size(); + + // Process received data only if any view is visible and not paused. + // Also, to prevent a momentary GUI freeze under high load (due to lock + // starvation), skip analysis when buffer reallocation is requested. + if ((m_spectrumActive || m_waterfallActive) && !m_controls->m_pauseModel.value() && !m_reallocating) { - // fill sample buffers and check for zero input - bool block_empty = true; - for (; in_frame < frame_count && m_framesFilledUp < m_inBlockSize; in_frame++, m_framesFilledUp++) + const bool stereo = m_controls->m_stereoModel.value(); + fpp_t in_frame = 0; + while (in_frame < frame_count) { + // Lock data access to prevent reallocation from changing + // buffers and control variables. + QMutexLocker data_lock(&m_dataAccess); + + // Fill sample buffers and check for zero input. + bool block_empty = true; + for (; in_frame < frame_count && m_framesFilledUp < m_inBlockSize; in_frame++, m_framesFilledUp++) + { + if (stereo) + { + m_bufferL[m_framesFilledUp] = in_buffer[in_frame][0]; + m_bufferR[m_framesFilledUp] = in_buffer[in_frame][1]; + } + else + { + m_bufferL[m_framesFilledUp] = + m_bufferR[m_framesFilledUp] = (in_buffer[in_frame][0] + in_buffer[in_frame][1]) * 0.5f; + } + if (in_buffer[in_frame][0] != 0.f || in_buffer[in_frame][1] != 0.f) + { + block_empty = false; + } + } + + // Run analysis only if buffers contain enough data. + if (m_framesFilledUp < m_inBlockSize) {break;} + + // Print performance analysis once per 2 seconds if debug is enabled + #ifdef SA_DEBUG + unsigned int total_time = std::chrono::high_resolution_clock::now().time_since_epoch().count(); + if (total_time - m_last_dump_time > 2000000000) + { + std::cout << "FFT analysis: " << std::fixed << std::setprecision(2) + << m_sum_execution / m_dump_count << " ms avg / " + << m_max_execution << " ms peak, executing " + << m_dump_count << " times per second (" + << m_sum_execution / 20.0 << " % CPU usage)." << std::endl; + m_last_dump_time = total_time; + m_sum_execution = m_max_execution = m_dump_count = 0; + } + #endif + + // update sample rate + m_sampleRate = Engine::mixer()->processingSampleRate(); + + // apply FFT window + for (unsigned int i = 0; i < m_inBlockSize; i++) + { + m_filteredBufferL[i] = m_bufferL[i] * m_fftWindow[i]; + m_filteredBufferR[i] = m_bufferR[i] * m_fftWindow[i]; + } + + // Run FFT on left channel, convert the result to absolute magnitude + // spectrum and normalize it. + fftwf_execute(m_fftPlanL); + absspec(m_spectrumL, m_absSpectrumL.data(), binCount()); + normalize(m_absSpectrumL, m_normSpectrumL, m_inBlockSize); + + // repeat analysis for right channel if stereo processing is enabled if (stereo) { - m_bufferL[m_framesFilledUp] = in_buffer[in_frame][0]; - m_bufferR[m_framesFilledUp] = in_buffer[in_frame][1]; + fftwf_execute(m_fftPlanR); + absspec(m_spectrumR, m_absSpectrumR.data(), binCount()); + normalize(m_absSpectrumR, m_normSpectrumR, m_inBlockSize); } - else + + // count empty lines so that empty history does not have to update + if (block_empty && m_waterfallNotEmpty) { - m_bufferL[m_framesFilledUp] = - m_bufferR[m_framesFilledUp] = (in_buffer[in_frame][0] + in_buffer[in_frame][1]) * 0.5f; + m_waterfallNotEmpty -= 1; } - if (in_buffer[in_frame][0] != 0.f || in_buffer[in_frame][1] != 0.f) + else if (!block_empty) { - block_empty = false; + m_waterfallNotEmpty = m_waterfallHeight + 2; } - } - - // Run analysis only if buffers contain enough data. - // Also, to prevent audio interruption and a momentary GUI freeze, - // skip analysis if buffers are being reallocated. - if (m_framesFilledUp < m_inBlockSize || m_reallocating) {return;} - // update sample rate - m_sampleRate = Engine::mixer()->processingSampleRate(); - - // apply FFT window - for (unsigned int i = 0; i < m_inBlockSize; i++) - { - m_bufferL[i] = m_bufferL[i] * m_fftWindow[i]; - m_bufferR[i] = m_bufferR[i] * m_fftWindow[i]; - } - - // lock data shared with SaSpectrumView and SaWaterfallView - QMutexLocker lock(&m_dataAccess); - - // Run FFT on left channel, convert the result to absolute magnitude - // spectrum and normalize it. - fftwf_execute(m_fftPlanL); - absspec(m_spectrumL, m_absSpectrumL.data(), binCount()); - normalize(m_absSpectrumL, m_normSpectrumL, m_inBlockSize); - - // repeat analysis for right channel if stereo processing is enabled - if (stereo) - { - fftwf_execute(m_fftPlanR); - absspec(m_spectrumR, m_absSpectrumR.data(), binCount()); - normalize(m_absSpectrumR, m_normSpectrumR, m_inBlockSize); - } - - // count empty lines so that empty history does not have to update - if (block_empty && m_waterfallNotEmpty) - { - m_waterfallNotEmpty -= 1; - } - else if (!block_empty) - { - m_waterfallNotEmpty = m_waterfallHeight + 2; - } - - if (m_waterfallActive && m_waterfallNotEmpty) - { - // move waterfall history one line down and clear the top line - QRgb *pixel = (QRgb *)m_history.data(); - std::copy(pixel, - pixel + binCount() * m_waterfallHeight - binCount(), - pixel + binCount()); - memset(pixel, 0, binCount() * sizeof (QRgb)); - - // add newest result on top - int target; // pixel being constructed - float accL = 0; // accumulators for merging multiple bins - float accR = 0; - - for (unsigned int i = 0; i < binCount(); i++) + if (m_waterfallActive && m_waterfallNotEmpty) { - // Every frequency bin spans a frequency range that must be - // partially or fully mapped to a pixel. Any inconsistency - // may be seen in the spectrogram as dark or white lines -- - // play white noise to confirm your change did not break it. - float band_start = freqToXPixel(binToFreq(i) - binBandwidth() / 2.0, binCount()); - float band_end = freqToXPixel(binToFreq(i + 1) - binBandwidth() / 2.0, binCount()); - if (m_controls->m_logXModel.value()) + // move waterfall history one line down and clear the top line + QRgb *pixel = (QRgb *)m_history_work.data(); + std::copy(pixel, + pixel + waterfallWidth() * m_waterfallHeight - waterfallWidth(), + pixel + waterfallWidth()); + memset(pixel, 0, waterfallWidth() * sizeof (QRgb)); + + // add newest result on top + int target; // pixel being constructed + float accL = 0; // accumulators for merging multiple bins + float accR = 0; + for (unsigned int i = 0; i < binCount(); i++) { - // Logarithmic scale - if (band_end - band_start > 1.0) + // fill line with red color to indicate lost data if CPU cannot keep up + if (overload && i < waterfallWidth()) { - // band spans multiple pixels: draw all pixels it covers - for (target = (int)band_start; target < (int)band_end; target++) + pixel[i] = qRgb(42, 0, 0); + continue; + } + + // Every frequency bin spans a frequency range that must be + // partially or fully mapped to a pixel. Any inconsistency + // may be seen in the spectrogram as dark or white lines -- + // play white noise to confirm your change did not break it. + float band_start = freqToXPixel(binToFreq(i) - binBandwidth() / 2.0, waterfallWidth()); + float band_end = freqToXPixel(binToFreq(i + 1) - binBandwidth() / 2.0, waterfallWidth()); + if (m_controls->m_logXModel.value()) + { + // Logarithmic scale + if (band_end - band_start > 1.0) { - if (target >= 0 && target < binCount()) + // band spans multiple pixels: draw all pixels it covers + for (target = (int)band_start; target < (int)band_end; target++) + { + if (target >= 0 && target < waterfallWidth()) + { + pixel[target] = makePixel(m_normSpectrumL[i], m_normSpectrumR[i]); + } + } + // save remaining portion of the band for the following band / pixel + // (in case the next band uses sub-pixel drawing) + accL = (band_end - (int)band_end) * m_normSpectrumL[i]; + accR = (band_end - (int)band_end) * m_normSpectrumR[i]; + } + else + { + // sub-pixel drawing; add contribution of current band + target = (int)band_start; + if ((int)band_start == (int)band_end) + { + // band ends within current target pixel, accumulate + accL += (band_end - band_start) * m_normSpectrumL[i]; + accR += (band_end - band_start) * m_normSpectrumR[i]; + } + else + { + // Band ends in the next pixel -- finalize the current pixel. + // Make sure contribution is split correctly on pixel boundary. + accL += ((int)band_end - band_start) * m_normSpectrumL[i]; + accR += ((int)band_end - band_start) * m_normSpectrumR[i]; + + if (target >= 0 && target < waterfallWidth()) {pixel[target] = makePixel(accL, accR);} + + // save remaining portion of the band for the following band / pixel + accL = (band_end - (int)band_end) * m_normSpectrumL[i]; + accR = (band_end - (int)band_end) * m_normSpectrumR[i]; + } + } + } + else + { + // Linear: always draws one or more pixels per band + for (target = (int)band_start; target < band_end; target++) + { + if (target >= 0 && target < waterfallWidth()) { pixel[target] = makePixel(m_normSpectrumL[i], m_normSpectrumR[i]); } } - // save remaining portion of the band for the following band / pixel - // (in case the next band uses sub-pixel drawing) - accL = (band_end - (int)band_end) * m_normSpectrumL[i]; - accR = (band_end - (int)band_end) * m_normSpectrumR[i]; - } - else - { - // sub-pixel drawing; add contribution of current band - target = (int)band_start; - if ((int)band_start == (int)band_end) - { - // band ends within current target pixel, accumulate - accL += (band_end - band_start) * m_normSpectrumL[i]; - accR += (band_end - band_start) * m_normSpectrumR[i]; - } - else - { - // Band ends in the next pixel -- finalize the current pixel. - // Make sure contribution is split correctly on pixel boundary. - accL += ((int)band_end - band_start) * m_normSpectrumL[i]; - accR += ((int)band_end - band_start) * m_normSpectrumR[i]; - - if (target >= 0 && target < binCount()) {pixel[target] = makePixel(accL, accR);} - - // save remaining portion of the band for the following band / pixel - accL = (band_end - (int)band_end) * m_normSpectrumL[i]; - accR = (band_end - (int)band_end) * m_normSpectrumR[i]; - } } } - else + + // Copy work buffer to result buffer. Done only if requested, so + // that time isn't wasted on updating faster than display FPS. + // (The copy is about as expensive as the movement.) + if (m_flipRequest) { - // Linear: always draws one or more pixels per band - for (target = (int)band_start; target < band_end; target++) - { - if (target >= 0 && target < binCount()) - { - pixel[target] = makePixel(m_normSpectrumL[i], m_normSpectrumR[i]); - } - } + m_history = m_history_work; + m_flipRequest = false; } } - } - #ifdef SA_DEBUG - // report FFT processing speed - start_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - start_time; - std::cout << "Processed " << m_framesFilledUp << " samples in " << start_time / 1000000.0 << " ms" << std::endl; - #endif + // clean up before checking for more data from input buffer + const unsigned int overlaps = m_controls->m_windowOverlapModel.value(); + if (overlaps == 1) // Discard buffer, each sample used only once + { + m_framesFilledUp = 0; + } + else + { + // Drop only a part of the buffer from the beginning, so that new + // data can be added to the end. This means the older samples will + // be analyzed again, but in a different position in the window, + // making short transient signals show up better in the waterfall. + const unsigned int drop = m_inBlockSize / overlaps; + std::move(m_bufferL.begin() + drop, m_bufferL.end(), m_bufferL.begin()); + std::move(m_bufferR.begin() + drop, m_bufferR.end(), m_bufferR.begin()); + m_framesFilledUp -= drop; + } - // clean up before checking for more data from input buffer - m_framesFilledUp = 0; - } - } + #ifdef SA_DEBUG + // measure overall FFT processing speed + total_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - total_time; + m_dump_count++; + m_sum_execution += total_time / 1000000.0; + if (total_time / 1000000.0 > m_max_execution) {m_max_execution = total_time / 1000000.0;} + #endif + } // frame filler and processing + } // process if active + } // thread loop end } @@ -251,8 +321,9 @@ void SaProcessor::analyse(sampleFrame *in_buffer, const fpp_t frame_count) // Gamma correction is applied to make small values more visible and to make // a linear gradient actually appear roughly linear. The correction should be // around 0.42 to 0.45 for sRGB displays (or lower for bigger visibility boost). -QRgb SaProcessor::makePixel(float left, float right, float gamma_correction) const +QRgb SaProcessor::makePixel(float left, float right) const { + const float gamma_correction = m_controls->m_waterfallGammaModel.value(); if (m_controls->m_stereoModel.value()) { float ampL = pow(left, gamma_correction); @@ -265,9 +336,9 @@ QRgb SaProcessor::makePixel(float left, float right, float gamma_correction) con { float ampL = pow(left, gamma_correction); // make mono color brighter to compensate for the fact it is not summed - return qRgb(m_controls->m_colorMono.lighter().red() * ampL, - m_controls->m_colorMono.lighter().green() * ampL, - m_controls->m_colorMono.lighter().blue() * ampL); + return qRgb(m_controls->m_colorMonoW.red() * ampL, + m_controls->m_colorMonoW.green() * ampL, + m_controls->m_colorMonoW.blue() * ampL); } } @@ -301,6 +372,7 @@ void SaProcessor::reallocateBuffers() { new_in_size = FFT_BLOCK_SIZES.back(); } + m_zeroPadFactor = m_controls->m_zeroPaddingModel.value(); if (new_size_index + m_zeroPadFactor < FFT_BLOCK_SIZES.size()) { new_fft_size = FFT_BLOCK_SIZES[new_size_index + m_zeroPadFactor]; @@ -312,12 +384,16 @@ void SaProcessor::reallocateBuffers() new_bins = new_fft_size / 2 +1; - // Lock data shared with SaSpectrumView and SaWaterfallView. - // The m_reallocating is here to tell analyse() to avoid asking for the - // lock, since fftw3 can take a while to find the fastest FFT algorithm - // for given machine, which would produce interruption in the audio stream. + // Use m_reallocating to tell analyze() to avoid asking for the lock. This + // is needed because under heavy load the FFT thread requests data lock so + // often that this routine could end up waiting even for several seconds. m_reallocating = true; - QMutexLocker lock(&m_dataAccess); + + // Lock data shared with SaSpectrumView and SaWaterfallView. + // Reallocation lock must be acquired first to avoid deadlock (a view class + // may already have it and request the "stronger" data lock on top of that). + QMutexLocker reloc_lock(&m_reallocationAccess); + QMutexLocker data_lock(&m_dataAccess); // destroy old FFT plan and free the result buffer if (m_fftPlanL != NULL) {fftwf_destroy_plan(m_fftPlanL);} @@ -328,30 +404,42 @@ void SaProcessor::reallocateBuffers() // allocate new space, create new plan and resize containers m_fftWindow.resize(new_in_size, 1.0); precomputeWindow(m_fftWindow.data(), new_in_size, (FFT_WINDOWS) m_controls->m_windowModel.value()); - m_bufferL.resize(new_fft_size, 0); - m_bufferR.resize(new_fft_size, 0); + m_bufferL.resize(new_in_size, 0); + m_bufferR.resize(new_in_size, 0); + m_filteredBufferL.resize(new_fft_size, 0); + m_filteredBufferR.resize(new_fft_size, 0); m_spectrumL = (fftwf_complex *) fftwf_malloc(new_bins * sizeof (fftwf_complex)); m_spectrumR = (fftwf_complex *) fftwf_malloc(new_bins * sizeof (fftwf_complex)); - m_fftPlanL = fftwf_plan_dft_r2c_1d(new_fft_size, m_bufferL.data(), m_spectrumL, FFTW_MEASURE); - m_fftPlanR = fftwf_plan_dft_r2c_1d(new_fft_size, m_bufferR.data(), m_spectrumR, FFTW_MEASURE); + m_fftPlanL = fftwf_plan_dft_r2c_1d(new_fft_size, m_filteredBufferL.data(), m_spectrumL, FFTW_MEASURE); + m_fftPlanR = fftwf_plan_dft_r2c_1d(new_fft_size, m_filteredBufferR.data(), m_spectrumR, FFTW_MEASURE); if (m_fftPlanL == NULL || m_fftPlanR == NULL) { - std::cerr << "Failed to create new FFT plan!" << std::endl; + #ifdef SA_DEBUG + std::cerr << "Analyzer: failed to create new FFT plan!" << std::endl; + #endif } m_absSpectrumL.resize(new_bins, 0); m_absSpectrumR.resize(new_bins, 0); m_normSpectrumL.resize(new_bins, 0); m_normSpectrumR.resize(new_bins, 0); - m_history.resize(new_bins * m_waterfallHeight * sizeof qRgb(0,0,0), 0); + m_waterfallHeight = m_controls->m_waterfallHeightModel.value(); + m_history_work.resize((new_bins < m_waterfallMaxWidth ? new_bins : m_waterfallMaxWidth) + * m_waterfallHeight + * sizeof qRgb(0,0,0), 0); + m_history.resize((new_bins < m_waterfallMaxWidth ? new_bins : m_waterfallMaxWidth) + * m_waterfallHeight + * sizeof qRgb(0,0,0), 0); // done; publish new sizes and clean up m_inBlockSize = new_in_size; m_fftBlockSize = new_fft_size; - lock.unlock(); + data_lock.unlock(); + reloc_lock.unlock(); m_reallocating = false; + clear(); } @@ -369,17 +457,39 @@ void SaProcessor::rebuildWindow() // Note: may take a few milliseconds, do not call in a loop! void SaProcessor::clear() { + const unsigned int overlaps = m_controls->m_windowOverlapModel.value(); QMutexLocker lock(&m_dataAccess); - m_framesFilledUp = 0; + // If there is any window overlap, leave space only for the new samples + // and treat the rest at initialized with zeros. Prevents missing + // transients at the start of the very first block. + m_framesFilledUp = m_inBlockSize - m_inBlockSize / overlaps; std::fill(m_bufferL.begin(), m_bufferL.end(), 0); std::fill(m_bufferR.begin(), m_bufferR.end(), 0); + std::fill(m_filteredBufferL.begin(), m_filteredBufferL.end(), 0); + std::fill(m_filteredBufferR.begin(), m_filteredBufferR.end(), 0); std::fill(m_absSpectrumL.begin(), m_absSpectrumL.end(), 0); std::fill(m_absSpectrumR.begin(), m_absSpectrumR.end(), 0); std::fill(m_normSpectrumL.begin(), m_normSpectrumL.end(), 0); std::fill(m_normSpectrumR.begin(), m_normSpectrumR.end(), 0); + std::fill(m_history_work.begin(), m_history_work.end(), 0); std::fill(m_history.begin(), m_history.end(), 0); } +// Clear only history work buffer. Used to flush old data when waterfall +// is shown after a period of inactivity. +void SaProcessor::clearHistory() +{ + QMutexLocker lock(&m_dataAccess); + std::fill(m_history_work.begin(), m_history_work.end(), 0); +} + +// Check if result buffers contain any non-zero values +bool SaProcessor::spectrumNotEmpty() +{ + QMutexLocker lock(&m_reallocationAccess); + return notEmpty(m_normSpectrumL) || notEmpty(m_normSpectrumR); +} + // -------------------------------------- // Frequency conversion helpers @@ -407,6 +517,17 @@ unsigned int SaProcessor::binCount() const } +// Return the final width of waterfall display buffer. +// Normally the waterfall width equals the number of frequency bins, but the +// FFT transform can easily produce more bins than can be reasonably useful for +// currently used display resolutions. This function limits width of the final +// image to a given size, which is then used during waterfall render and display. +unsigned int SaProcessor::waterfallWidth() const +{ + return binCount() < m_waterfallMaxWidth ? binCount() : m_waterfallMaxWidth; +} + + // Return the center frequency of given frequency bin. float SaProcessor::binToFreq(unsigned int bin_index) const { @@ -499,10 +620,10 @@ float SaProcessor::getAmpRangeMin(bool linear) const switch (m_controls->m_ampRangeModel.value()) { case ARANGE_EXTENDED: return ARANGE_EXTENDED_START; - case ARANGE_AUDIBLE: return ARANGE_AUDIBLE_START; - case ARANGE_NOISE: return ARANGE_NOISE_START; + case ARANGE_SILENT: return ARANGE_SILENT_START; + case ARANGE_LOUD: return ARANGE_LOUD_START; default: - case ARANGE_DEFAULT: return ARANGE_DEFAULT_START; + case ARANGE_AUDIBLE: return ARANGE_AUDIBLE_START; } } @@ -512,10 +633,10 @@ float SaProcessor::getAmpRangeMax() const switch (m_controls->m_ampRangeModel.value()) { case ARANGE_EXTENDED: return ARANGE_EXTENDED_END; - case ARANGE_AUDIBLE: return ARANGE_AUDIBLE_END; - case ARANGE_NOISE: return ARANGE_NOISE_END; + case ARANGE_SILENT: return ARANGE_SILENT_END; + case ARANGE_LOUD: return ARANGE_LOUD_END; default: - case ARANGE_DEFAULT: return ARANGE_DEFAULT_END; + case ARANGE_AUDIBLE: return ARANGE_AUDIBLE_END; } } diff --git a/plugins/SpectrumAnalyzer/SaProcessor.h b/plugins/SpectrumAnalyzer/SaProcessor.h index ae2df16f8..0c396b3c0 100644 --- a/plugins/SpectrumAnalyzer/SaProcessor.h +++ b/plugins/SpectrumAnalyzer/SaProcessor.h @@ -27,6 +27,7 @@ #ifndef SAPROCESSOR_H #define SAPROCESSOR_H +#include #include #include #include @@ -34,27 +35,45 @@ #include "fft_helpers.h" #include "SaControls.h" +template +class LocklessRingBuffer; //! Receives audio data, runs FFT analysis and stores the result. class SaProcessor { public: - explicit SaProcessor(SaControls *controls); + explicit SaProcessor(const SaControls *controls); virtual ~SaProcessor(); - void analyse(sampleFrame *in_buffer, const fpp_t frame_count); + // analysis thread and a method to terminate it + void analyze(LocklessRingBuffer &ring_buffer); + void terminate() {m_terminate = true;} // inform processor if any processing is actually required void setSpectrumActive(bool active); void setWaterfallActive(bool active); + void flipRequest() {m_flipRequest = true;} // request refresh of history buffer // configuration is taken from models in SaControls; some changes require // an exlicit update request (reallocation and window rebuild) void reallocateBuffers(); void rebuildWindow(); void clear(); + void clearHistory(); + + const float *getSpectrumL() const {return m_normSpectrumL.data();} + const float *getSpectrumR() const {return m_normSpectrumR.data();} + const uchar *getHistory() const {return m_history.data();} // information about results and unit conversion helpers + unsigned int inBlockSize() const {return m_inBlockSize;} + unsigned int binCount() const; //!< size of output (frequency domain) data block + bool spectrumNotEmpty(); //!< check if result buffers contain any non-zero values + + unsigned int waterfallWidth() const; //!< binCount value capped at 3840 (for display) + unsigned int waterfallHeight() const {return m_waterfallHeight;} + bool waterfallNotEmpty() const {return m_waterfallNotEmpty;} + float binToFreq(unsigned int bin_index) const; float binBandwidth() const; @@ -72,26 +91,38 @@ public: float getAmpRangeMin(bool linear = false) const; float getAmpRangeMax() const; - // data access lock must be acquired by any friendly class that touches - // the results, mainly to prevent unexpected mid-way reallocation + // Reallocation lock prevents the processor from changing size of its buffers. + // It is used to keep consistent bin-to-frequency mapping while drawing the + // spectrum and to make sure reading side does not find itself out of bounds. + // The processor is meanwhile free to work on another block. + QMutex m_reallocationAccess; + // Data access lock prevents the processor from changing both size and content + // of its buffers. It is used when writing to a result buffer, or when a friendly + // class reads them and needs guaranteed data consistency. + // It causes FFT analysis to be paused, so this lock should be used sparingly. + // If using both locks at the same time, reallocation lock MUST be acquired first. QMutex m_dataAccess; + private: - SaControls *m_controls; + const SaControls *m_controls; + + // thread communication and control + bool m_terminate; // currently valid configuration - const unsigned int m_zeroPadFactor = 2; //!< use n-steps bigger FFT for given block size - unsigned int m_inBlockSize; //!< size of input (time domain) data block + unsigned int m_zeroPadFactor = 2; //!< use n-steps bigger FFT for given block size + std::atomic m_inBlockSize;//!< size of input (time domain) data block unsigned int m_fftBlockSize; //!< size of padded block for FFT processing unsigned int m_sampleRate; - unsigned int binCount() const; //!< size of output (frequency domain) data block - // data buffers (roughly in the order of processing, from input to output) unsigned int m_framesFilledUp; std::vector m_bufferL; //!< time domain samples (left) std::vector m_bufferR; //!< time domain samples (right) std::vector m_fftWindow; //!< precomputed window function coefficients + std::vector m_filteredBufferL; //!< time domain samples with window function applied (left) + std::vector m_filteredBufferR; //!< time domain samples with window function applied (right) fftwf_plan m_fftPlanL; fftwf_plan m_fftPlanR; fftwf_complex *m_spectrumL; //!< frequency domain samples (complex) (left) @@ -102,21 +133,28 @@ private: std::vector m_normSpectrumR; //!< frequency domain samples (normalized) (right) // spectrum history for waterfall: new normSpectrum lines are added on top - std::vector m_history; - const unsigned int m_waterfallHeight = 200; // Number of stored lines. - // Note: high values may make it harder to see transients. + std::vector m_history_work; //!< local history buffer for render + std::vector m_history; //!< public buffer for reading + bool m_flipRequest; //!< update public buffer only when requested + std::atomic m_waterfallHeight; //!< number of stored lines in history buffer + // Note: high values may make it harder to see transients. + const unsigned int m_waterfallMaxWidth = 3840; // book keeping bool m_spectrumActive; bool m_waterfallActive; - unsigned int m_waterfallNotEmpty; + std::atomic m_waterfallNotEmpty; //!< number of lines remaining visible on display bool m_reallocating; // merge L and R channels and apply gamma correction to make a spectrogram pixel - QRgb makePixel(float left, float right, float gamma_correction = 0.30) const; + QRgb makePixel(float left, float right) const; - friend class SaSpectrumView; - friend class SaWaterfallView; + #ifdef SA_DEBUG + unsigned int m_last_dump_time; + unsigned int m_dump_count; + float m_sum_execution; + float m_max_execution; + #endif }; #endif // SAPROCESSOR_H diff --git a/plugins/SpectrumAnalyzer/SaSpectrumView.cpp b/plugins/SpectrumAnalyzer/SaSpectrumView.cpp index 746d52cfd..13aaeb724 100644 --- a/plugins/SpectrumAnalyzer/SaSpectrumView.cpp +++ b/plugins/SpectrumAnalyzer/SaSpectrumView.cpp @@ -39,7 +39,6 @@ #ifdef SA_DEBUG #include - #include #endif @@ -68,7 +67,11 @@ SaSpectrumView::SaSpectrumView(SaControls *controls, SaProcessor *processor, QWi m_logAmpTics = makeLogAmpTics(m_processor->getAmpRangeMin(), m_processor->getAmpRangeMax()); m_linearAmpTics = makeLinearAmpTics(m_processor->getAmpRangeMin(), m_processor->getAmpRangeMax()); - m_cursor = QPoint(0, 0); + m_cursor = QPointF(0, 0); + + #ifdef SA_DEBUG + m_execution_avg = m_path_avg = m_draw_avg = 0; + #endif } @@ -134,12 +137,20 @@ void SaSpectrumView::paintEvent(QPaintEvent *event) 2.0, 2.0); #ifdef SA_DEBUG - // display what FPS would be achieved if spectrum display ran in a loop + // display performance measurements if enabled total_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - total_time; + m_execution_avg = 0.95 * m_execution_avg + 0.05 * total_time / 1000000.0; painter.setPen(QPen(m_controls->m_colorLabels, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin)); - painter.drawText(m_displayRight -100, 70, 100, 16, Qt::AlignLeft, - QString(std::string("Max FPS: " + std::to_string(1000000000.0 / total_time)).c_str())); + painter.drawText(m_displayRight -150, 10, 130, 16, Qt::AlignLeft, + QString("Exec avg.: ").append(std::to_string(m_execution_avg).substr(0, 5).c_str()).append(" ms")); + painter.drawText(m_displayRight -150, 30, 130, 16, Qt::AlignLeft, + QString("Buff. upd. avg: ").append(std::to_string(m_refresh_avg).substr(0, 5).c_str()).append(" ms")); + painter.drawText(m_displayRight -150, 50, 130, 16, Qt::AlignLeft, + QString("Path build avg: ").append(std::to_string(m_path_avg).substr(0, 5).c_str()).append(" ms")); + painter.drawText(m_displayRight -150, 70, 130, 16, Qt::AlignLeft, + QString("Path draw avg: ").append(std::to_string(m_draw_avg).substr(0, 5).c_str()).append(" ms")); + #endif } @@ -148,22 +159,14 @@ void SaSpectrumView::paintEvent(QPaintEvent *event) void SaSpectrumView::drawSpectrum(QPainter &painter) { #ifdef SA_DEBUG - int path_time = 0, draw_time = 0; + int draw_time = 0; #endif // draw the graph only if there is any input, averaging residue or peaks - QMutexLocker lock(&m_processor->m_dataAccess); - if (m_decaySum > 0 || notEmpty(m_processor->m_normSpectrumL) || notEmpty(m_processor->m_normSpectrumR)) + if (m_decaySum > 0 || m_processor->spectrumNotEmpty()) { - lock.unlock(); - #ifdef SA_DEBUG - path_time = std::chrono::high_resolution_clock::now().time_since_epoch().count(); - #endif // update data buffers and reconstruct paths refreshPaths(); - #ifdef SA_DEBUG - path_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - path_time; - #endif // draw stored paths #ifdef SA_DEBUG @@ -199,17 +202,10 @@ void SaSpectrumView::drawSpectrum(QPainter &painter) draw_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - draw_time; #endif } - else - { - lock.unlock(); - } #ifdef SA_DEBUG - // display measurement results - painter.drawText(m_displayRight -100, 90, 100, 16, Qt::AlignLeft, - QString(std::string("Path ms: " + std::to_string(path_time / 1000000.0)).c_str())); - painter.drawText(m_displayRight -100, 110, 100, 16, Qt::AlignLeft, - QString(std::string("Draw ms: " + std::to_string(draw_time / 1000000.0)).c_str())); + // save performance measurement result + m_draw_avg = 0.95 * m_draw_avg + 0.05 * draw_time / 1000000.0; #endif } @@ -218,9 +214,9 @@ void SaSpectrumView::drawSpectrum(QPainter &painter) // and build QPainter paths. void SaSpectrumView::refreshPaths() { - // Lock is required for the entire function, mainly to prevent block size - // changes from causing reallocation of data structures mid-way. - QMutexLocker lock(&m_processor->m_dataAccess); + // Reallocation lock is required for the entire function, to keep display + // buffer size consistent with block size. + QMutexLocker reloc_lock(&m_processor->m_reallocationAccess); // check if bin count changed and reallocate display buffers accordingly if (m_processor->binCount() != m_displayBufferL.size()) @@ -240,8 +236,8 @@ void SaSpectrumView::refreshPaths() int refresh_time = std::chrono::high_resolution_clock::now().time_since_epoch().count(); #endif m_decaySum = 0; - updateBuffers(m_processor->m_normSpectrumL.data(), m_displayBufferL.data(), m_peakBufferL.data()); - updateBuffers(m_processor->m_normSpectrumR.data(), m_displayBufferR.data(), m_peakBufferR.data()); + updateBuffers(m_processor->getSpectrumL(), m_displayBufferL.data(), m_peakBufferL.data()); + updateBuffers(m_processor->getSpectrumR(), m_displayBufferR.data(), m_peakBufferR.data()); #ifdef SA_DEBUG refresh_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - refresh_time; #endif @@ -254,41 +250,43 @@ void SaSpectrumView::refreshPaths() } #ifdef SA_DEBUG - int make_time = std::chrono::high_resolution_clock::now().time_since_epoch().count(); + int path_time = std::chrono::high_resolution_clock::now().time_since_epoch().count(); #endif // Use updated display buffers to prepare new paths for QPainter. // This is the second slowest action (first is the subsequent drawing); use // the resolution parameter to balance display quality and performance. - m_pathL = makePath(m_displayBufferL, 1.5); + m_pathL = makePath(m_displayBufferL, m_controls->m_spectrumResolutionModel.value()); if (m_controls->m_stereoModel.value()) { - m_pathR = makePath(m_displayBufferR, 1.5); + m_pathR = makePath(m_displayBufferR, m_controls->m_spectrumResolutionModel.value()); } if (m_controls->m_peakHoldModel.value() || m_controls->m_refFreezeModel.value()) { - m_pathPeakL = makePath(m_peakBufferL, 0.25); + m_pathPeakL = makePath(m_peakBufferL, m_controls->m_envelopeResolutionModel.value()); if (m_controls->m_stereoModel.value()) { - m_pathPeakR = makePath(m_peakBufferR, 0.25); + m_pathPeakR = makePath(m_peakBufferR, m_controls->m_envelopeResolutionModel.value()); } } #ifdef SA_DEBUG - make_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - make_time; + path_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - path_time; #endif #ifdef SA_DEBUG - // print measurement results - std::cout << "Buffer update ms: " << std::to_string(refresh_time / 1000000.0) << ", "; - std::cout << "Path-make ms: " << std::to_string(make_time / 1000000.0) << std::endl; + // save performance measurement results + m_refresh_avg = 0.95 * m_refresh_avg + 0.05 * refresh_time / 1000000.0; + m_path_avg = .95f * m_path_avg + .05f * path_time / 1000000.f; #endif } // Update display buffers: add new data, update average and peaks / reference. // Output the sum of all displayed values -- draw only if it is non-zero. -// NOTE: The calling function is responsible for acquiring SaProcessor data -// access lock! -void SaSpectrumView::updateBuffers(float *spectrum, float *displayBuffer, float *peakBuffer) +// NOTE: The calling function is responsible for acquiring SaProcessor +// reallocation access lock! Data access lock is not needed: the final result +// buffer is updated very quickly and the worst case is that one frame will be +// part new, part old. At reasonable frame rate, such difference is invisible.. +void SaSpectrumView::updateBuffers(const float *spectrum, float *displayBuffer, float *peakBuffer) { for (int n = 0; n < m_processor->binCount(); n++) { @@ -297,7 +295,8 @@ void SaSpectrumView::updateBuffers(float *spectrum, float *displayBuffer, float { if (m_controls->m_smoothModel.value()) { - displayBuffer[n] = spectrum[n] * m_smoothFactor + displayBuffer[n] * (1 - m_smoothFactor); + const float smoothFactor = m_controls->m_averagingWeightModel.value(); + displayBuffer[n] = spectrum[n] * smoothFactor + displayBuffer[n] * (1 - smoothFactor); } else { @@ -319,7 +318,7 @@ void SaSpectrumView::updateBuffers(float *spectrum, float *displayBuffer, float } else if (!m_controls->m_refFreezeModel.value()) { - peakBuffer[n] = peakBuffer[n] * m_peakDecayFactor; + peakBuffer[n] = peakBuffer[n] * m_controls->m_peakDecayFactorModel.value(); } } else if (!m_controls->m_refFreezeModel.value() && !m_controls->m_peakHoldModel.value()) @@ -539,38 +538,52 @@ void SaSpectrumView::drawGrid(QPainter &painter) // Draw cursor and its coordinates if it is within display bounds. void SaSpectrumView::drawCursor(QPainter &painter) { - if( m_cursor.x() >= m_displayLeft + if ( m_cursor.x() >= m_displayLeft && m_cursor.x() <= m_displayRight && m_cursor.y() >= m_displayTop && m_cursor.y() <= m_displayBottom) { // cursor lines painter.setPen(QPen(m_controls->m_colorGrid.lighter(), 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin)); - painter.drawLine(m_cursor.x(), m_displayTop, m_cursor.x(), m_displayBottom); - painter.drawLine(m_displayLeft, m_cursor.y(), m_displayRight, m_cursor.y()); + painter.drawLine(QPointF(m_cursor.x(), m_displayTop), QPointF(m_cursor.x(), m_displayBottom)); + painter.drawLine(QPointF(m_displayLeft, m_cursor.y()), QPointF(m_displayRight, m_cursor.y())); - // coordinates + // coordinates: background box + QFontMetrics fontMetrics = painter.fontMetrics(); + unsigned int const box_left = 5; + unsigned int const box_top = 5; + unsigned int const box_margin = 3; + unsigned int const box_height = 2*(fontMetrics.size(Qt::TextSingleLine, "0 HzdBFS").height() + box_margin); + unsigned int const box_width = fontMetrics.size(Qt::TextSingleLine, "-99.9 dBFS").width() + 2*box_margin; painter.setPen(QPen(m_controls->m_colorLabels.darker(), 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin)); - painter.drawText(m_displayRight -60, 5, 100, 16, Qt::AlignLeft, "Cursor"); + painter.fillRect(m_displayLeft + box_left, m_displayTop + box_top, + box_width, box_height, QColor(0, 0, 0, 64)); + // coordinates: text + painter.setPen(QPen(m_controls->m_colorLabels, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin)); QString tmps; + // frequency int xFreq = (int)m_processor->xPixelToFreq(m_cursor.x() - m_displayLeft, m_displayWidth); - tmps = QString(std::string(std::to_string(xFreq) + " Hz").c_str()); - painter.drawText(m_displayRight -60, 18, 100, 16, Qt::AlignLeft, tmps); + tmps = QString("%1 Hz").arg(xFreq); + painter.drawText(m_displayLeft + box_left + box_margin, + m_displayTop + box_top + box_margin, + box_width, box_height / 2, Qt::AlignLeft, tmps); // amplitude float yAmp = m_processor->yPixelToAmp(m_cursor.y(), m_displayBottom); if (m_controls->m_logYModel.value()) { - tmps = QString(std::string(std::to_string(yAmp).substr(0, 5) + " dB").c_str()); + tmps = QString(std::to_string(yAmp).substr(0, 5).c_str()).append(" dBFS"); } else { // add 0.0005 to get proper rounding to 3 decimal places - tmps = QString(std::string(std::to_string(0.0005f + yAmp)).substr(0, 5).c_str()); + tmps = QString(std::to_string(0.0005f + yAmp).substr(0, 5).c_str()); } - painter.drawText(m_displayRight -60, 30, 100, 16, Qt::AlignLeft, tmps); + painter.drawText(m_displayLeft + box_left + box_margin, + m_displayTop + box_top + box_height / 2, + box_width, box_height / 2, Qt::AlignLeft, tmps); } } @@ -774,14 +787,18 @@ void SaSpectrumView::periodicUpdate() // Handle mouse input: set new cursor position. +// For some reason (a bug?), localPos() only returns integers. As a workaround +// the fractional part is taken from windowPos() (which works correctly). void SaSpectrumView::mouseMoveEvent(QMouseEvent *event) { - m_cursor = event->pos(); + m_cursor = QPointF( event->localPos().x() - (event->windowPos().x() - (long)event->windowPos().x()), + event->localPos().y() - (event->windowPos().y() - (long)event->windowPos().y())); } void SaSpectrumView::mousePressEvent(QMouseEvent *event) { - m_cursor = event->pos(); + m_cursor = QPointF( event->localPos().x() - (event->windowPos().x() - (long)event->windowPos().x()), + event->localPos().y() - (event->windowPos().y() - (long)event->windowPos().y())); } diff --git a/plugins/SpectrumAnalyzer/SaSpectrumView.h b/plugins/SpectrumAnalyzer/SaSpectrumView.h index 0db5852e1..b59264d9c 100644 --- a/plugins/SpectrumAnalyzer/SaSpectrumView.h +++ b/plugins/SpectrumAnalyzer/SaSpectrumView.h @@ -27,6 +27,8 @@ #ifndef SASPECTRUMVIEW_H #define SASPECTRUMVIEW_H +#include "SaControls.h" + #include #include #include @@ -34,7 +36,6 @@ class QMouseEvent; class QPainter; -class SaControls; class SaProcessor; //! Widget that displays a spectrum curve and frequency / amplitude grid @@ -84,7 +85,7 @@ private: std::vector m_displayBufferR; std::vector m_peakBufferL; std::vector m_peakBufferR; - void updateBuffers(float *spectrum, float *displayBuffer, float *peakBuffer); + void updateBuffers(const float *spectrum, float *displayBuffer, float *peakBuffer); // final paths to be drawn by QPainter and methods to build them QPainterPath m_pathL; @@ -99,14 +100,11 @@ private: bool m_freezeRequest; // new reference should be acquired bool m_frozen; // a reference is currently stored in the peakBuffer - const float m_smoothFactor = 0.15; // alpha for exponential smoothing - const float m_peakDecayFactor = 0.992; // multiplier for gradual peak decay - // top level: refresh buffers, make paths and draw the spectrum void drawSpectrum(QPainter &painter); // current cursor location and a method to draw it - QPoint m_cursor; + QPointF m_cursor; void drawCursor(QPainter &painter); // wrappers for most used SaProcessor conversion helpers @@ -121,6 +119,13 @@ private: unsigned int m_displayLeft; unsigned int m_displayRight; unsigned int m_displayWidth; + + #ifdef SA_DEBUG + float m_execution_avg; + float m_refresh_avg; + float m_path_avg; + float m_draw_avg; + #endif }; #endif // SASPECTRUMVIEW_H diff --git a/plugins/SpectrumAnalyzer/SaWaterfallView.cpp b/plugins/SpectrumAnalyzer/SaWaterfallView.cpp index 617e80b2c..e015d31ef 100644 --- a/plugins/SpectrumAnalyzer/SaWaterfallView.cpp +++ b/plugins/SpectrumAnalyzer/SaWaterfallView.cpp @@ -23,8 +23,12 @@ #include "SaWaterfallView.h" #include +#ifdef SA_DEBUG + #include +#endif #include #include +#include #include #include #include @@ -47,8 +51,22 @@ SaWaterfallView::SaWaterfallView(SaControls *controls, SaProcessor *processor, Q connect(gui->mainWindow(), SIGNAL(periodicUpdate()), this, SLOT(periodicUpdate())); + m_displayTop = 1; + m_displayBottom = height() -2; + m_displayLeft = 26; + m_displayRight = width() -26; + m_displayWidth = m_displayRight - m_displayLeft; + m_displayHeight = m_displayBottom - m_displayTop; + m_timeTics = makeTimeTics(); - m_oldTimePerLine = (float)m_processor->m_inBlockSize / m_processor->getSampleRate(); + m_oldSecondsPerLine = 0; + m_oldHeight = 0; + + m_cursor = QPointF(0, 0); + + #ifdef SA_DEBUG + m_execution_avg = 0; + #endif } @@ -58,15 +76,14 @@ SaWaterfallView::SaWaterfallView(SaControls *controls, SaProcessor *processor, Q void SaWaterfallView::paintEvent(QPaintEvent *event) { #ifdef SA_DEBUG - int start_time = std::chrono::high_resolution_clock::now().time_since_epoch().count(); + unsigned int draw_time = std::chrono::high_resolution_clock::now().time_since_epoch().count(); #endif - // all drawing done here, local variables are sufficient for the boundary - const int displayTop = 1; - const int displayBottom = height() -2; - const int displayLeft = 26; - const int displayRight = width() -26; - const int displayWidth = displayRight - displayLeft; + // update boundary + m_displayBottom = height() -2; + m_displayRight = width() -26; + m_displayWidth = m_displayRight - m_displayLeft; + m_displayHeight = m_displayBottom - m_displayTop; float label_width = 20; float label_height = 16; float margin = 2; @@ -75,10 +92,11 @@ void SaWaterfallView::paintEvent(QPaintEvent *event) painter.setRenderHint(QPainter::Antialiasing, true); // check if time labels need to be rebuilt - if ((float)m_processor->m_inBlockSize / m_processor->getSampleRate() != m_oldTimePerLine) + if (secondsPerLine() != m_oldSecondsPerLine || m_processor->waterfallHeight() != m_oldHeight) { m_timeTics = makeTimeTics(); - m_oldTimePerLine = (float)m_processor->m_inBlockSize / m_processor->getSampleRate(); + m_oldSecondsPerLine = secondsPerLine(); + m_oldHeight = m_processor->waterfallHeight(); } // print time labels @@ -86,78 +104,104 @@ void SaWaterfallView::paintEvent(QPaintEvent *event) painter.setPen(QPen(m_controls->m_colorLabels, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin)); for (auto & line: m_timeTics) { - pos = timeToYPixel(line.first, displayBottom); + pos = timeToYPixel(line.first, m_displayHeight); // align first and last label to the edge if needed, otherwise center them if (line == m_timeTics.front() && pos < label_height / 2) { - painter.drawText(displayLeft - label_width - margin, displayTop - 1, + painter.drawText(m_displayLeft - label_width - margin, m_displayTop - 1, label_width, label_height, Qt::AlignRight | Qt::AlignTop | Qt::TextDontClip, QString(line.second.c_str())); - painter.drawText(displayRight + margin, displayTop - 1, + painter.drawText(m_displayRight + margin, m_displayTop - 1, label_width, label_height, Qt::AlignLeft | Qt::AlignTop | Qt::TextDontClip, QString(line.second.c_str())); } - else if (line == m_timeTics.back() && pos > displayBottom - label_height + 2) + else if (line == m_timeTics.back() && pos > m_displayBottom - label_height + 2) { - painter.drawText(displayLeft - label_width - margin, displayBottom - label_height, + painter.drawText(m_displayLeft - label_width - margin, m_displayBottom - label_height, label_width, label_height, Qt::AlignRight | Qt::AlignBottom | Qt::TextDontClip, QString(line.second.c_str())); - painter.drawText(displayRight + margin, displayBottom - label_height + 2, + painter.drawText(m_displayRight + margin, m_displayBottom - label_height + 2, label_width, label_height, Qt::AlignLeft | Qt::AlignBottom | Qt::TextDontClip, QString(line.second.c_str())); } else { - painter.drawText(displayLeft - label_width - margin, pos - label_height / 2, + painter.drawText(m_displayLeft - label_width - margin, pos - label_height / 2, label_width, label_height, Qt::AlignRight | Qt::AlignVCenter | Qt::TextDontClip, QString(line.second.c_str())); - painter.drawText(displayRight + margin, pos - label_height / 2, + painter.drawText(m_displayRight + margin, pos - label_height / 2, label_width, label_height, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip, QString(line.second.c_str())); } } // draw the spectrogram precomputed in SaProcessor - if (m_processor->m_waterfallNotEmpty) + if (m_processor->waterfallNotEmpty()) { - QMutexLocker lock(&m_processor->m_dataAccess); - painter.drawImage(displayLeft, displayTop, // top left corner coordinates - QImage(m_processor->m_history.data(), // raw pixel data to display - m_processor->binCount(), // width = number of frequency bins - m_processor->m_waterfallHeight, // height = number of history lines - QImage::Format_RGB32 - ).scaled(displayWidth, // scale to fit view.. - displayBottom, - Qt::IgnoreAspectRatio, - Qt::SmoothTransformation)); + QMutexLocker lock(&m_processor->m_reallocationAccess); + QImage temp = QImage(m_processor->getHistory(), // raw pixel data to display + m_processor->waterfallWidth(), // width = number of frequency bins + m_processor->waterfallHeight(), // height = number of history lines + QImage::Format_RGB32); lock.unlock(); + temp.setDevicePixelRatio(devicePixelRatio()); // display at native resolution + painter.drawImage(m_displayLeft, m_displayTop, + temp.scaled(m_displayWidth * devicePixelRatio(), + m_displayHeight * devicePixelRatio(), + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation)); + m_processor->flipRequest(); } else { - painter.fillRect(displayLeft, displayTop, displayWidth, displayBottom, QColor(0,0,0)); + painter.fillRect(m_displayLeft, m_displayTop, m_displayWidth, m_displayHeight, QColor(0,0,0)); } + // draw cursor (if it is within bounds) + drawCursor(painter); + // always draw the outline painter.setPen(QPen(m_controls->m_colorGrid, 2, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin)); - painter.drawRoundedRect(displayLeft, displayTop, displayWidth, displayBottom, 2.0, 2.0); + painter.drawRoundedRect(m_displayLeft, m_displayTop, m_displayWidth, m_displayHeight, 2.0, 2.0); #ifdef SA_DEBUG - // display what FPS would be achieved if waterfall ran in a loop - start_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - start_time; + draw_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - draw_time; + m_execution_avg = 0.95 * m_execution_avg + 0.05 * draw_time / 1000000.0; painter.setPen(QPen(m_controls->m_colorLabels, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin)); - painter.drawText(displayRight -100, 10, 100, 16, Qt::AlignLeft, - QString(std::string("Max FPS: " + std::to_string(1000000000.0 / start_time)).c_str())); + painter.drawText(m_displayRight -150, 10, 100, 16, Qt::AlignLeft, + QString("Exec avg.: ").append(std::to_string(m_execution_avg).substr(0, 5).c_str()).append(" ms")); #endif } +// Helper functions for time conversion +float SaWaterfallView::samplesPerLine() +{ + return (float)m_processor->inBlockSize() / m_controls->m_windowOverlapModel.value(); +} + +float SaWaterfallView::secondsPerLine() +{ + return samplesPerLine() / m_processor->getSampleRate(); +} + + // Convert time value to Y coordinate for display of given height. float SaWaterfallView::timeToYPixel(float time, int height) { - float pixels_per_line = (float)height / m_processor->m_waterfallHeight; - float seconds_per_line = ((float)m_processor->m_inBlockSize / m_processor->getSampleRate()); + float pixels_per_line = (float)height / m_processor->waterfallHeight(); - return pixels_per_line * time / seconds_per_line; + return pixels_per_line * time / secondsPerLine(); +} + + +// Convert Y coordinate on display of given height back to time value. +float SaWaterfallView::yPixelToTime(float position, int height) +{ + if (height == 0) {height = 1;} + float pixels_per_line = (float)height / m_processor->waterfallHeight(); + + return (position / pixels_per_line) * secondsPerLine(); } @@ -167,16 +211,21 @@ std::vector> SaWaterfallView::makeTimeTics() std::vector> result; float i; - // upper limit defined by number of lines * time per line - float limit = m_processor->m_waterfallHeight * ((float)m_processor->m_inBlockSize / m_processor->getSampleRate()); + // get time value of the last line + float limit = yPixelToTime(m_displayBottom, m_displayHeight); - // set increment so that about 8 tics are generated - float increment = std::round(10 * limit / 7) / 10; + // set increment to about 30 pixels (but min. 0.1 s) + float increment = std::round(10 * limit / (m_displayHeight / 30)) / 10; + if (increment < 0.1) {increment = 0.1;} // NOTE: labels positions are rounded to match the (rounded) label value for (i = 0; i <= limit; i += increment) { - if (i < 10) + if (i > 99) + { + result.emplace_back(std::round(i), std::to_string(std::round(i)).substr(0, 3)); + } + else if (i < 10) { result.emplace_back(std::round(i * 10) / 10, std::to_string(std::round(i * 10) / 10).substr(0, 3)); } @@ -208,10 +257,7 @@ void SaWaterfallView::updateVisibility() if (m_controls->m_waterfallModel.value()) { // clear old data before showing the waterfall - QMutexLocker lock(&m_processor->m_dataAccess); - std::fill(m_processor->m_history.begin(), m_processor->m_history.end(), 0); - lock.unlock(); - + m_processor->clearHistory(); setVisible(true); // increase window size if it is too small @@ -228,3 +274,70 @@ void SaWaterfallView::updateVisibility() } } + +// Draw cursor and its coordinates if it is within display bounds. +void SaWaterfallView::drawCursor(QPainter &painter) +{ + if ( m_cursor.x() >= m_displayLeft + && m_cursor.x() <= m_displayRight + && m_cursor.y() >= m_displayTop + && m_cursor.y() <= m_displayBottom) + { + // cursor lines + painter.setPen(QPen(m_controls->m_colorGrid.lighter(), 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin)); + painter.drawLine(QPointF(m_cursor.x(), m_displayTop), QPointF(m_cursor.x(), m_displayBottom)); + painter.drawLine(QPointF(m_displayLeft, m_cursor.y()), QPointF(m_displayRight, m_cursor.y())); + + // coordinates: background box + QFontMetrics fontMetrics = painter.fontMetrics(); + unsigned int const box_left = 5; + unsigned int const box_top = 5; + unsigned int const box_margin = 3; + unsigned int const box_height = 2*(fontMetrics.size(Qt::TextSingleLine, "0 Hz").height() + box_margin); + unsigned int const box_width = fontMetrics.size(Qt::TextSingleLine, "20000 Hz ").width() + 2*box_margin; + painter.setPen(QPen(m_controls->m_colorLabels.darker(), 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin)); + painter.fillRect(m_displayLeft + box_left, m_displayTop + box_top, + box_width, box_height, QColor(0, 0, 0, 64)); + + // coordinates: text + painter.setPen(QPen(m_controls->m_colorLabels, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin)); + QString tmps; + + // frequency + int freq = (int)m_processor->xPixelToFreq(m_cursor.x() - m_displayLeft, m_displayWidth); + tmps = QString("%1 Hz").arg(freq); + painter.drawText(m_displayLeft + box_left + box_margin, + m_displayTop + box_top + box_margin, + box_width, box_height / 2, Qt::AlignLeft, tmps); + + // time + float time = yPixelToTime(m_cursor.y(), m_displayBottom); + tmps = QString(std::to_string(time).substr(0, 5).c_str()).append(" s"); + painter.drawText(m_displayLeft + box_left + box_margin, + m_displayTop + box_top + box_height / 2, + box_width, box_height / 2, Qt::AlignLeft, tmps); + } +} + + +// Handle mouse input: set new cursor position. +// For some reason (a bug?), localPos() only returns integers. As a workaround +// the fractional part is taken from windowPos() (which works correctly). +void SaWaterfallView::mouseMoveEvent(QMouseEvent *event) +{ + m_cursor = QPointF( event->localPos().x() - (event->windowPos().x() - (long)event->windowPos().x()), + event->localPos().y() - (event->windowPos().y() - (long)event->windowPos().y())); +} + +void SaWaterfallView::mousePressEvent(QMouseEvent *event) +{ + m_cursor = QPointF( event->localPos().x() - (event->windowPos().x() - (long)event->windowPos().x()), + event->localPos().y() - (event->windowPos().y() - (long)event->windowPos().y())); +} + + +// Handle resize event: rebuild time labels +void SaWaterfallView::resizeEvent(QResizeEvent *event) +{ + m_timeTics = makeTimeTics(); +} diff --git a/plugins/SpectrumAnalyzer/SaWaterfallView.h b/plugins/SpectrumAnalyzer/SaWaterfallView.h index 0e104c0a1..bd91d6d16 100644 --- a/plugins/SpectrumAnalyzer/SaWaterfallView.h +++ b/plugins/SpectrumAnalyzer/SaWaterfallView.h @@ -32,6 +32,7 @@ #include "SaControls.h" #include "SaProcessor.h" +class QMouseEvent; // Widget that displays a spectrum waterfall (spectrogram) and time labels. class SaWaterfallView : public QWidget @@ -48,6 +49,9 @@ public: protected: void paintEvent(QPaintEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void resizeEvent(QResizeEvent *event) override; private slots: void periodicUpdate(); @@ -58,9 +62,29 @@ private: const EffectControlDialog *m_controlDialog; // Methods and data used to make time labels - float m_oldTimePerLine; + float m_oldSecondsPerLine; + float m_oldHeight; + float samplesPerLine(); + float secondsPerLine(); float timeToYPixel(float time, int height); + float yPixelToTime(float position, int height); std::vector> makeTimeTics(); std::vector> m_timeTics; // 0..n (s) + + // current cursor location and a method to draw it + QPointF m_cursor; + void drawCursor(QPainter &painter); + + // current boundaries for drawing + unsigned int m_displayTop; + unsigned int m_displayBottom; + unsigned int m_displayLeft; + unsigned int m_displayRight; + unsigned int m_displayWidth; + unsigned int m_displayHeight; + + #ifdef SA_DEBUG + float m_execution_avg; + #endif }; #endif // SAWATERFALLVIEW_H diff --git a/plugins/SpectrumAnalyzer/advanced_off.svg b/plugins/SpectrumAnalyzer/advanced_off.svg new file mode 100644 index 000000000..6d3ed82b1 --- /dev/null +++ b/plugins/SpectrumAnalyzer/advanced_off.svg @@ -0,0 +1,243 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/plugins/SpectrumAnalyzer/advanced_on.svg b/plugins/SpectrumAnalyzer/advanced_on.svg new file mode 100644 index 000000000..9e6b1ca3f --- /dev/null +++ b/plugins/SpectrumAnalyzer/advanced_on.svg @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/plugins/SpectrumAnalyzer/advanced_src.svg b/plugins/SpectrumAnalyzer/advanced_src.svg new file mode 100644 index 000000000..ae201aad0 --- /dev/null +++ b/plugins/SpectrumAnalyzer/advanced_src.svg @@ -0,0 +1,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + ADV. + + + diff --git a/plugins/VstEffect/VstEffectControlDialog.h b/plugins/VstEffect/VstEffectControlDialog.h index 3cd9af360..930f514c9 100644 --- a/plugins/VstEffect/VstEffectControlDialog.h +++ b/plugins/VstEffect/VstEffectControlDialog.h @@ -49,8 +49,8 @@ public: virtual ~VstEffectControlDialog(); protected: - virtual void paintEvent( QPaintEvent * _pe ); - virtual void showEvent( QShowEvent* _se ) override; + void paintEvent( QPaintEvent * _pe ) override; + void showEvent( QShowEvent* _se ) override; private: QWidget * m_pluginWidget; diff --git a/plugins/Xpressive/Xpressive.cpp b/plugins/Xpressive/Xpressive.cpp index 018319c82..a80a0ae41 100644 --- a/plugins/Xpressive/Xpressive.cpp +++ b/plugins/Xpressive/Xpressive.cpp @@ -53,9 +53,9 @@ extern "C" { Plugin::Descriptor PLUGIN_EXPORT xpressive_plugin_descriptor = { STRINGIFY( - PLUGIN_NAME), "X-Pressive", QT_TRANSLATE_NOOP("pluginBrowser", - "Mathematical expression parser"), "Orr Dvori", 0x0100, - Plugin::Instrument, new PluginPixmapLoader("logo"), NULL, NULL }; + PLUGIN_NAME), "Xpressive", QT_TRANSLATE_NOOP("pluginBrowser", + "Mathematical expression parser"), "Orr Dvori", 0x0100, + Plugin::Instrument, new PluginPixmapLoader("logo"), NULL, NULL }; } @@ -257,7 +257,6 @@ public: setCenterPointY(14.5); setInnerRadius(4); setOuterRadius(9); - setOuterColor(QColor(0x519fff)); setTotalAngle(300.0); setLineWidth(3); } @@ -277,14 +276,18 @@ XpressiveView::XpressiveView(Instrument * _instrument, QWidget * _parent) : InstrumentViewFixedSize(_instrument, _parent) { - const int COL_KNOBS = 194; - const int ROW_KNOBSA1 = 26; - const int ROW_KNOBSA2 = 26 + 32; - const int ROW_KNOBSA3 = 26 + 64; - const int ROW_KNOBSP1 = 126; - const int ROW_KNOBSP2 = 126 + 32; - const int ROW_KNOBREL = 126 + 64; - const int ROW_WAVEBTN = 234; + const int COL_KNOBS = 191; + const int BASE_START = 2; + const int ROW_KNOBSA1 = BASE_START; + const int ROW_KNOBSA2 = BASE_START + 32; + const int ROW_KNOBSA3 = BASE_START + 64; + const int ROW_KNOBSP1 = BASE_START + 100; + const int ROW_KNOBSP2 = BASE_START + 100 + 32; + const int ROW_KNOBREL = BASE_START + 100 + 64; + const int ROW_BTN = BASE_START + 85; + const int ROW_WAVEBTN = BASE_START + 233 - 26; + const int EXPR_TEXT_Y = BASE_START + 102; + const int EXPR_TEXT_H = 90; setAutoFillBackground(true); QPalette pal; @@ -293,7 +296,7 @@ XpressiveView::XpressiveView(Instrument * _instrument, QWidget * _parent) : setPalette(pal); m_graph = new Graph(this, Graph::LinearStyle, 180, 81); - m_graph->move(9, 27); + m_graph->move(3, BASE_START + 1); m_graph->setAutoFillBackground(true); m_graph->setGraphColor(QColor(255, 255, 255)); m_graph->setEnabled(false); @@ -313,37 +316,37 @@ XpressiveView::XpressiveView(Instrument * _instrument, QWidget * _parent) : PixmapButton * m_helpBtn; m_w1Btn = new PixmapButton(this, NULL); - m_w1Btn->move(9, 111); + m_w1Btn->move(3, ROW_BTN); m_w1Btn->setActiveGraphic(PLUGIN_NAME::getIconPixmap("w1_active")); m_w1Btn->setInactiveGraphic(PLUGIN_NAME::getIconPixmap("w1_inactive")); ToolTip::add(m_w1Btn, tr("Select oscillator W1")); m_w2Btn = new PixmapButton(this, NULL); - m_w2Btn->move(32, 111); + m_w2Btn->move(26, ROW_BTN); m_w2Btn->setActiveGraphic(PLUGIN_NAME::getIconPixmap("w2_active")); m_w2Btn->setInactiveGraphic(PLUGIN_NAME::getIconPixmap("w2_inactive")); ToolTip::add(m_w2Btn, tr("Select oscillator W2")); m_w3Btn = new PixmapButton(this, NULL); - m_w3Btn->move(55, 111); + m_w3Btn->move(49, ROW_BTN); m_w3Btn->setActiveGraphic(PLUGIN_NAME::getIconPixmap("w3_active")); m_w3Btn->setInactiveGraphic(PLUGIN_NAME::getIconPixmap("w3_inactive")); ToolTip::add(m_w3Btn, tr("Select oscillator W3")); m_o1Btn = new PixmapButton(this, NULL); - m_o1Btn->move(85, 111); + m_o1Btn->move(79, ROW_BTN); m_o1Btn->setActiveGraphic(PLUGIN_NAME::getIconPixmap("o1_active")); m_o1Btn->setInactiveGraphic(PLUGIN_NAME::getIconPixmap("o1_inactive")); ToolTip::add(m_o1Btn, tr("Select output O1")); m_o2Btn = new PixmapButton(this, NULL); - m_o2Btn->move(107, 111); + m_o2Btn->move(101, ROW_BTN); m_o2Btn->setActiveGraphic(PLUGIN_NAME::getIconPixmap("o2_active")); m_o2Btn->setInactiveGraphic(PLUGIN_NAME::getIconPixmap("o2_inactive")); ToolTip::add(m_o2Btn, tr("Select output O2")); m_helpBtn = new PixmapButton(this, NULL); - m_helpBtn->move(139, 111); + m_helpBtn->move(133, ROW_BTN); m_helpBtn->setActiveGraphic(PLUGIN_NAME::getIconPixmap("help_active")); m_helpBtn->setInactiveGraphic(PLUGIN_NAME::getIconPixmap("help_inactive")); ToolTip::add(m_helpBtn, tr("Open help window")); @@ -359,38 +362,38 @@ XpressiveView::XpressiveView(Instrument * _instrument, QWidget * _parent) : m_selectedGraphGroup->setModel(&e->selectedGraph()); m_sinWaveBtn = new PixmapButton(this, tr("Sine wave")); - m_sinWaveBtn->move(10, ROW_WAVEBTN); + m_sinWaveBtn->move(4, ROW_WAVEBTN); m_sinWaveBtn->setActiveGraphic(embed::getIconPixmap("sin_wave_active")); m_sinWaveBtn->setInactiveGraphic(embed::getIconPixmap("sin_wave_inactive")); ToolTip::add(m_sinWaveBtn, tr("Sine wave")); m_moogWaveBtn = new PixmapButton(this, tr("Moog-saw wave")); - m_moogWaveBtn->move(10, ROW_WAVEBTN-14); + m_moogWaveBtn->move(4, ROW_WAVEBTN-14); m_moogWaveBtn->setActiveGraphic( embed::getIconPixmap( "moog_saw_wave_active" ) ); m_moogWaveBtn->setInactiveGraphic(embed::getIconPixmap("moog_saw_wave_inactive")); ToolTip::add(m_moogWaveBtn, tr("Moog-saw wave")); m_expWaveBtn = new PixmapButton(this, tr("Exponential wave")); - m_expWaveBtn->move(10 +14, ROW_WAVEBTN-14); + m_expWaveBtn->move(4 +14, ROW_WAVEBTN-14); m_expWaveBtn->setActiveGraphic(embed::getIconPixmap( "exp_wave_active" ) ); m_expWaveBtn->setInactiveGraphic(embed::getIconPixmap( "exp_wave_inactive" ) ); ToolTip::add(m_expWaveBtn, tr("Exponential wave")); m_sawWaveBtn = new PixmapButton(this, tr("Saw wave")); - m_sawWaveBtn->move(10 + 14 * 2, ROW_WAVEBTN-14); + m_sawWaveBtn->move(4 + 14 * 2, ROW_WAVEBTN-14); m_sawWaveBtn->setActiveGraphic(embed::getIconPixmap("saw_wave_active")); m_sawWaveBtn->setInactiveGraphic(embed::getIconPixmap("saw_wave_inactive")); ToolTip::add(m_sawWaveBtn, tr("Saw wave")); m_usrWaveBtn = new PixmapButton(this, tr("User-defined wave")); - m_usrWaveBtn->move(10 + 14 * 3, ROW_WAVEBTN-14); + m_usrWaveBtn->move(4 + 14 * 3, ROW_WAVEBTN-14); m_usrWaveBtn->setActiveGraphic(embed::getIconPixmap("usr_wave_active")); m_usrWaveBtn->setInactiveGraphic(embed::getIconPixmap("usr_wave_inactive")); ToolTip::add(m_usrWaveBtn, tr("User-defined wave")); m_triangleWaveBtn = new PixmapButton(this, tr("Triangle wave")); - m_triangleWaveBtn->move(10 + 14, ROW_WAVEBTN); + m_triangleWaveBtn->move(4 + 14, ROW_WAVEBTN); m_triangleWaveBtn->setActiveGraphic( embed::getIconPixmap("triangle_wave_active")); m_triangleWaveBtn->setInactiveGraphic( @@ -398,14 +401,14 @@ XpressiveView::XpressiveView(Instrument * _instrument, QWidget * _parent) : ToolTip::add(m_triangleWaveBtn, tr("Triangle wave")); m_sqrWaveBtn = new PixmapButton(this, tr("Square wave")); - m_sqrWaveBtn->move(10 + 14 * 2, ROW_WAVEBTN); + m_sqrWaveBtn->move(4 + 14 * 2, ROW_WAVEBTN); m_sqrWaveBtn->setActiveGraphic(embed::getIconPixmap("square_wave_active")); m_sqrWaveBtn->setInactiveGraphic( embed::getIconPixmap("square_wave_inactive")); ToolTip::add(m_sqrWaveBtn, tr("Square wave")); m_whiteNoiseWaveBtn = new PixmapButton(this, tr("White noise")); - m_whiteNoiseWaveBtn->move(10 + 14 * 3, ROW_WAVEBTN); + m_whiteNoiseWaveBtn->move(4 + 14 * 3, ROW_WAVEBTN); m_whiteNoiseWaveBtn->setActiveGraphic( embed::getIconPixmap("white_noise_wave_active")); m_whiteNoiseWaveBtn->setInactiveGraphic( @@ -415,16 +418,16 @@ XpressiveView::XpressiveView(Instrument * _instrument, QWidget * _parent) : m_waveInterpolate = new LedCheckBox("Interpolate", this, tr("WaveInterpolate"), LedCheckBox::Green); - m_waveInterpolate->move(120, 230); + m_waveInterpolate->move(2, 230); m_expressionValidToggle = new LedCheckBox("", this, tr("ExpressionValid"), LedCheckBox::Red); - m_expressionValidToggle->move(174, 216); + m_expressionValidToggle->move(168, EXPR_TEXT_Y+EXPR_TEXT_H-2); m_expressionValidToggle->setEnabled( false ); m_expressionEditor = new QPlainTextEdit(this); - m_expressionEditor->move(9, 128); - m_expressionEditor->resize(180, 90); + m_expressionEditor->move(3, EXPR_TEXT_Y); + m_expressionEditor->resize(180, EXPR_TEXT_H); m_generalPurposeKnob[0] = new XpressiveKnob(this,"A1"); m_generalPurposeKnob[0]->setHintText(tr("General purpose 1:"), ""); @@ -452,9 +455,16 @@ XpressiveView::XpressiveView(Instrument * _instrument, QWidget * _parent) : - m_smoothKnob=new Knob(this,"Smoothness"); + m_smoothKnob=new Knob(knobStyled, this, "Smoothness"); + m_smoothKnob->setFixedSize(25, 25); + m_smoothKnob->setCenterPointX(12.5); + m_smoothKnob->setCenterPointY(12.5); + m_smoothKnob->setInnerRadius(4); + m_smoothKnob->setOuterRadius(9); + m_smoothKnob->setTotalAngle(280.0); + m_smoothKnob->setLineWidth(3); m_smoothKnob->setHintText(tr("Smoothness"), ""); - m_smoothKnob->move(80, 220); + m_smoothKnob->move(66, EXPR_TEXT_Y + EXPR_TEXT_H + 4); connect(m_generalPurposeKnob[0], SIGNAL(sliderMoved(float)), this, SLOT(expressionChanged())); @@ -748,7 +758,7 @@ void XpressiveView::updateLayout() { void XpressiveView::sinWaveClicked() { if (m_output_expr) - m_expressionEditor->appendPlainText("sinew(t*f)"); + m_expressionEditor->appendPlainText("sinew(integrate(f))"); else m_expressionEditor->appendPlainText("sinew(t)"); Engine::getSong()->setModified(); @@ -756,7 +766,7 @@ void XpressiveView::sinWaveClicked() { void XpressiveView::triangleWaveClicked() { if (m_output_expr) - m_expressionEditor->appendPlainText("trianglew(t*f)"); + m_expressionEditor->appendPlainText("trianglew(integrate(f))"); else m_expressionEditor->appendPlainText("trianglew(t)"); Engine::getSong()->setModified(); @@ -764,7 +774,7 @@ void XpressiveView::triangleWaveClicked() { void XpressiveView::sawWaveClicked() { if (m_output_expr) - m_expressionEditor->appendPlainText("saww(t*f)"); + m_expressionEditor->appendPlainText("saww(integrate(f))"); else m_expressionEditor->appendPlainText("saww(t)"); Engine::getSong()->setModified(); @@ -772,7 +782,7 @@ void XpressiveView::sawWaveClicked() { void XpressiveView::sqrWaveClicked() { if (m_output_expr) - m_expressionEditor->appendPlainText("squarew(t*f)"); + m_expressionEditor->appendPlainText("squarew(integrate(f))"); else m_expressionEditor->appendPlainText("squarew(t)"); Engine::getSong()->setModified(); @@ -786,7 +796,7 @@ void XpressiveView::noiseWaveClicked() { void XpressiveView::moogSawWaveClicked() { if (m_output_expr) - m_expressionEditor->appendPlainText("moogsaww(t*f)"); + m_expressionEditor->appendPlainText("moogsaww(integrate(f))"); else m_expressionEditor->appendPlainText("moogsaww(t)"); Engine::getSong()->setModified(); @@ -794,7 +804,7 @@ void XpressiveView::moogSawWaveClicked() void XpressiveView::expWaveClicked() { if (m_output_expr) - m_expressionEditor->appendPlainText("expw(t*f)"); + m_expressionEditor->appendPlainText("expw(integrate(f))"); else m_expressionEditor->appendPlainText("expw(t)"); Engine::getSong()->setModified(); @@ -861,7 +871,7 @@ QString XpressiveHelpView::s_helpText= XpressiveHelpView::XpressiveHelpView():QTextEdit(s_helpText) { - setWindowTitle ( "X-Pressive Help" ); + setWindowTitle ( "Xpressive Help" ); setTextInteractionFlags ( Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse ); gui->mainWindow()->addWindowedWidget( this ); parentWidget()->setAttribute( Qt::WA_DeleteOnClose, false ); diff --git a/plugins/Xpressive/Xpressive.svg b/plugins/Xpressive/Xpressive.svg new file mode 100644 index 000000000..ef3029c0d --- /dev/null +++ b/plugins/Xpressive/Xpressive.svg @@ -0,0 +1,130 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/Xpressive/Xpressive_logo.svg b/plugins/Xpressive/Xpressive_logo.svg new file mode 100644 index 000000000..fca1f0d98 --- /dev/null +++ b/plugins/Xpressive/Xpressive_logo.svg @@ -0,0 +1,106 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/plugins/Xpressive/artwork.png b/plugins/Xpressive/artwork.png index d5b39acee..1f4e35ad5 100644 Binary files a/plugins/Xpressive/artwork.png and b/plugins/Xpressive/artwork.png differ diff --git a/plugins/Xpressive/help_active.png b/plugins/Xpressive/help_active.png index 4e991ad54..8d8b49d43 100644 Binary files a/plugins/Xpressive/help_active.png and b/plugins/Xpressive/help_active.png differ diff --git a/plugins/Xpressive/help_inactive.png b/plugins/Xpressive/help_inactive.png index 4b77af24f..d08f6d9a7 100644 Binary files a/plugins/Xpressive/help_inactive.png and b/plugins/Xpressive/help_inactive.png differ diff --git a/plugins/Xpressive/logo.png b/plugins/Xpressive/logo.png index 68b613176..555c3f13e 100644 Binary files a/plugins/Xpressive/logo.png and b/plugins/Xpressive/logo.png differ diff --git a/plugins/Xpressive/o1_active.png b/plugins/Xpressive/o1_active.png index 6370769dd..8e31a8322 100644 Binary files a/plugins/Xpressive/o1_active.png and b/plugins/Xpressive/o1_active.png differ diff --git a/plugins/Xpressive/o1_inactive.png b/plugins/Xpressive/o1_inactive.png index 0fd4f8b29..7a6b603e3 100644 Binary files a/plugins/Xpressive/o1_inactive.png and b/plugins/Xpressive/o1_inactive.png differ diff --git a/plugins/Xpressive/o2_active.png b/plugins/Xpressive/o2_active.png index 51897412d..4e3b5f214 100644 Binary files a/plugins/Xpressive/o2_active.png and b/plugins/Xpressive/o2_active.png differ diff --git a/plugins/Xpressive/o2_inactive.png b/plugins/Xpressive/o2_inactive.png index 20158d725..35851d553 100644 Binary files a/plugins/Xpressive/o2_inactive.png and b/plugins/Xpressive/o2_inactive.png differ diff --git a/plugins/Xpressive/w1_active.png b/plugins/Xpressive/w1_active.png index 49a3a2b6e..68d8e9ae0 100644 Binary files a/plugins/Xpressive/w1_active.png and b/plugins/Xpressive/w1_active.png differ diff --git a/plugins/Xpressive/w1_inactive.png b/plugins/Xpressive/w1_inactive.png index 266e4206f..7159b4979 100644 Binary files a/plugins/Xpressive/w1_inactive.png and b/plugins/Xpressive/w1_inactive.png differ diff --git a/plugins/Xpressive/w2_active.png b/plugins/Xpressive/w2_active.png index cd4729949..17d7b53d9 100644 Binary files a/plugins/Xpressive/w2_active.png and b/plugins/Xpressive/w2_active.png differ diff --git a/plugins/Xpressive/w2_inactive.png b/plugins/Xpressive/w2_inactive.png index 8d54929da..412482bb0 100644 Binary files a/plugins/Xpressive/w2_inactive.png and b/plugins/Xpressive/w2_inactive.png differ diff --git a/plugins/Xpressive/w3_active.png b/plugins/Xpressive/w3_active.png index 9e4facb2c..579b997dd 100644 Binary files a/plugins/Xpressive/w3_active.png and b/plugins/Xpressive/w3_active.png differ diff --git a/plugins/Xpressive/w3_inactive.png b/plugins/Xpressive/w3_inactive.png index e5b0bc7d9..d45d8b497 100644 Binary files a/plugins/Xpressive/w3_inactive.png and b/plugins/Xpressive/w3_inactive.png differ diff --git a/plugins/Xpressive/wavegraph.png b/plugins/Xpressive/wavegraph.png index 9d58e8fe7..ea7bc3761 100644 Binary files a/plugins/Xpressive/wavegraph.png and b/plugins/Xpressive/wavegraph.png differ diff --git a/plugins/bit_invader/bit_invader.cpp b/plugins/bit_invader/bit_invader.cpp index f8a8423ad..caa272fa7 100644 --- a/plugins/bit_invader/bit_invader.cpp +++ b/plugins/bit_invader/bit_invader.cpp @@ -64,17 +64,16 @@ Plugin::Descriptor PLUGIN_EXPORT bitinvader_plugin_descriptor = } -bSynth::bSynth( float * _shape, int _length, NotePlayHandle * _nph, bool _interpolation, +bSynth::bSynth( float * _shape, NotePlayHandle * _nph, bool _interpolation, float _factor, const sample_rate_t _sample_rate ) : sample_index( 0 ), sample_realindex( 0 ), nph( _nph ), - sample_length( _length ), sample_rate( _sample_rate ), interpolation( _interpolation) { - sample_shape = new float[sample_length]; - for (int i=0; i < _length; ++i) + sample_shape = new float[200]; + for (int i=0; i < 200; ++i) { sample_shape[i] = _shape[i] * _factor; } @@ -87,7 +86,7 @@ bSynth::~bSynth() } -sample_t bSynth::nextStringSample() +sample_t bSynth::nextStringSample( float sample_length ) { float sample_step = static_cast( sample_length / ( sample_rate / nph->frequency() ) ); @@ -140,10 +139,12 @@ sample_t bSynth::nextStringSample() bitInvader::bitInvader( InstrumentTrack * _instrument_track ) : Instrument( _instrument_track, &bitinvader_plugin_descriptor ), m_sampleLength( 128, 4, 200, 1, this, tr( "Sample length" ) ), - m_graph( -1.0f, 1.0f, 128, this ), + m_graph( -1.0f, 1.0f, 200, this ), m_interpolation( false, this ), m_normalize( false, this ) { + + lengthChanged(); m_graph.setWaveToSine(); @@ -278,7 +279,6 @@ void bitInvader::playNote( NotePlayHandle * _n, _n->m_pluginData = new bSynth( const_cast( m_graph.samples() ), - m_graph.length(), _n, m_interpolation.value(), factor, Engine::mixer()->processingSampleRate() ); @@ -290,7 +290,7 @@ void bitInvader::playNote( NotePlayHandle * _n, bSynth * ps = static_cast( _n->m_pluginData ); for( fpp_t frame = offset; frame < frames + offset; ++frame ) { - const sample_t cur = ps->nextStringSample(); + const sample_t cur = ps->nextStringSample( m_graph.length() ); for( ch_cnt_t chnl = 0; chnl < DEFAULT_CHANNELS; ++chnl ) { _working_buffer[frame][chnl] = cur; @@ -572,7 +572,3 @@ PLUGIN_EXPORT Plugin * lmms_plugin_main( Model *m, void * ) } - - - - diff --git a/plugins/bit_invader/bit_invader.h b/plugins/bit_invader/bit_invader.h index 793831e4a..ae9c92cb2 100644 --- a/plugins/bit_invader/bit_invader.h +++ b/plugins/bit_invader/bit_invader.h @@ -42,12 +42,12 @@ class bSynth { MM_OPERATORS public: - bSynth( float * sample, int length, NotePlayHandle * _nph, + bSynth( float * sample, NotePlayHandle * _nph, bool _interpolation, float factor, const sample_rate_t _sample_rate ); virtual ~bSynth(); - sample_t nextStringSample(); + sample_t nextStringSample( float sample_length ); private: @@ -55,7 +55,6 @@ private: float sample_realindex; float* sample_shape; NotePlayHandle* nph; - const int sample_length; const sample_rate_t sample_rate; bool interpolation; diff --git a/plugins/carlabase/carla.cpp b/plugins/carlabase/carla.cpp index 3df97ce40..ba2dd085c 100644 --- a/plugins/carlabase/carla.cpp +++ b/plugins/carlabase/carla.cpp @@ -324,10 +324,10 @@ void CarlaInstrument::play(sampleFrame* workingBuffer) fTimeInfo.playing = s->isPlaying(); fTimeInfo.frame = s->getPlayPos(s->playMode()).frames(Engine::framesPerTick()); fTimeInfo.usecs = s->getMilliseconds()*1000; - fTimeInfo.bbt.bar = s->getTacts() + 1; + fTimeInfo.bbt.bar = s->getBars() + 1; fTimeInfo.bbt.beat = s->getBeat() + 1; fTimeInfo.bbt.tick = s->getBeatTicks(); - fTimeInfo.bbt.barStartTick = ticksPerBeat*s->getTimeSigModel().getNumerator()*s->getTacts(); + fTimeInfo.bbt.barStartTick = ticksPerBeat*s->getTimeSigModel().getNumerator()*s->getBars(); fTimeInfo.bbt.beatsPerBar = s->getTimeSigModel().getNumerator(); fTimeInfo.bbt.beatType = s->getTimeSigModel().getDenominator(); fTimeInfo.bbt.ticksPerBeat = ticksPerBeat; diff --git a/plugins/organic/organic.cpp b/plugins/organic/organic.cpp index 7da4fc6f7..6eb933afa 100644 --- a/plugins/organic/organic.cpp +++ b/plugins/organic/organic.cpp @@ -306,7 +306,7 @@ void organicInstrument::playNote( NotePlayHandle * _n, // fxKnob is [0;1] float t = m_fx1Model.value(); - for (int i=0 ; i < frames ; i++) + for (int i=0 ; i < frames + offset ; i++) { _working_buffer[i][0] = waveshape( _working_buffer[i][0], t ) * m_volModel.value() / 100.0f; diff --git a/plugins/peak_controller_effect/peak_controller_effect.h b/plugins/peak_controller_effect/peak_controller_effect.h index 093b56437..a872e2b8b 100644 --- a/plugins/peak_controller_effect/peak_controller_effect.h +++ b/plugins/peak_controller_effect/peak_controller_effect.h @@ -36,9 +36,9 @@ public: const Descriptor::SubPluginFeatures::Key * _key ); virtual ~PeakControllerEffect(); virtual bool processAudioBuffer( sampleFrame * _buf, - const fpp_t _frames ); + const fpp_t _frames ) override; - virtual EffectControls * controls() + EffectControls * controls() override { return &m_peakControls; } diff --git a/plugins/peak_controller_effect/peak_controller_effect_controls.h b/plugins/peak_controller_effect/peak_controller_effect_controls.h index 784df4d8d..fe90eddca 100644 --- a/plugins/peak_controller_effect/peak_controller_effect_controls.h +++ b/plugins/peak_controller_effect/peak_controller_effect_controls.h @@ -41,18 +41,18 @@ public: { } - virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); - virtual void loadSettings( const QDomElement & _this ); - inline virtual QString nodeName() const + void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; + void loadSettings( const QDomElement & _this ) override; + inline QString nodeName() const override { return "peakcontrollereffectcontrols"; } - virtual int controlCount() + int controlCount() override { return 1; } - virtual EffectControlDialog * createView() + EffectControlDialog * createView() override { return new PeakControllerEffectControlDialog( this ); } diff --git a/plugins/sf2_player/sf2_player.cpp b/plugins/sf2_player/sf2_player.cpp index cc2575d2b..99af22781 100644 --- a/plugins/sf2_player/sf2_player.cpp +++ b/plugins/sf2_player/sf2_player.cpp @@ -151,7 +151,7 @@ sf2Instrument::sf2Instrument( InstrumentTrack * _instrument_track ) : m_chorusDepth.setInitValue(settingVal); #endif - loadFile( ConfigManager::inst()->defaultSoundfont() ); + loadFile( ConfigManager::inst()->sf2File() ); updateSampleRate(); updateReverbOn(); diff --git a/plugins/vst_base/CMakeLists.txt b/plugins/vst_base/CMakeLists.txt index 44ed0dcb3..873ed5f8e 100644 --- a/plugins/vst_base/CMakeLists.txt +++ b/plugins/vst_base/CMakeLists.txt @@ -11,23 +11,35 @@ SET(REMOTE_VST_PLUGIN_FILEPATH_64 "RemoteVstPlugin64" CACHE STRING "Relative fil ADD_SUBDIRECTORY(vstbase) -SET(LMMS_BINARY_DIR ${CMAKE_BINARY_DIR}) -SET(LMMS_SOURCE_DIR ${CMAKE_SOURCE_DIR}) - SET(EXTERNALPROJECT_ARGS SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/RemoteVstPlugin" - INSTALL_COMMAND "" + #INSTALL_COMMAND "" BUILD_ALWAYS ON + # Skip the install step. + INSTALL_COMMAND "" ) +set(export_variables + "LMMS_SOURCE_DIR" + "LMMS_BINARY_DIR" + "CMAKE_MODULE_PATH" + "CMAKE_RUNTIME_OUTPUT_DIRECTORY" + "CMAKE_BUILD_TYPE" + "LMMS_BUILD_LINUX" + "LMMS_BUILD_WIN32" + "PLUGIN_DIR") + SET(EXTERNALPROJECT_CMAKE_ARGS - "-DLMMS_SOURCE_DIR=${CMAKE_SOURCE_DIR}" - "-DLMMS_BINARY_DIR=${CMAKE_BINARY_DIR}" - "-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" - "-DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}" - "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" + "-DBUILD_WITH_EXTERNALPROJECT=ON" ) +macro(_export_var_to_external var_name) + list(APPEND EXTERNALPROJECT_CMAKE_ARGS "-D${var_name}=${${var_name}}") +endmacro() +foreach(var ${export_variables}) + _export_var_to_external(${var}) +endforeach() + # build 32 bit version of RemoteVstPlugin IF(WANT_VST_32) INCLUDE("${CMAKE_CURRENT_LIST_DIR}/RemoteVstPlugin32.cmake") diff --git a/plugins/vst_base/RemoteVstPlugin.cpp b/plugins/vst_base/RemoteVstPlugin.cpp index 48ab13743..5b4bbbd9b 100644 --- a/plugins/vst_base/RemoteVstPlugin.cpp +++ b/plugins/vst_base/RemoteVstPlugin.cpp @@ -734,6 +734,7 @@ void RemoteVstPlugin::init( const std::string & _plugin_file ) static void close_check( FILE* fp ) { + if (!fp) {return;} if( fclose( fp ) ) { perror( "fclose" ); @@ -1128,6 +1129,12 @@ void RemoteVstPlugin::saveChunkToFile( const std::string & _file ) if( len > 0 ) { FILE* fp = F_OPEN_UTF8( _file, "wb" ); + if (!fp) + { + fprintf( stderr, + "Error opening file for saving chunk.\n" ); + return; + } if ( fwrite( chunk, 1, len, fp ) != len ) { fprintf( stderr, @@ -1293,6 +1300,12 @@ void RemoteVstPlugin::savePreset( const std::string & _file ) pBank->numPrograms = endian_swap( uIntToFile ); FILE * stream = F_OPEN_UTF8( _file, "w" ); + if (!stream) + { + fprintf( stderr, + "Error opening file for saving preset.\n" ); + return; + } fwrite ( pBank, 1, 28, stream ); fwrite ( progName, 1, isPreset ? 28 : 128, stream ); if ( chunky ) { @@ -1345,6 +1358,12 @@ void RemoteVstPlugin::loadPresetFile( const std::string & _file ) unsigned int len = 0; sBank * pBank = (sBank*) new char[ sizeof( sBank ) ]; FILE * stream = F_OPEN_UTF8( _file, "r" ); + if (!stream) + { + fprintf( stderr, + "Error opening file for loading preset.\n" ); + return; + } if ( fread ( pBank, 1, 56, stream ) != 56 ) { fprintf( stderr, "Error loading preset file.\n" ); @@ -1446,6 +1465,12 @@ void RemoteVstPlugin::loadChunkFromFile( const std::string & _file, int _len ) char * chunk = new char[_len]; FILE* fp = F_OPEN_UTF8( _file, "rb" ); + if (!fp) + { + fprintf( stderr, + "Error opening file for loading chunk.\n" ); + return; + } if ( fread( chunk, 1, _len, fp ) != _len ) { fprintf( stderr, "Error loading chunk from file.\n" ); diff --git a/plugins/vst_base/RemoteVstPlugin/CMakeLists.txt b/plugins/vst_base/RemoteVstPlugin/CMakeLists.txt index 59dd19a0a..f4023fd42 100644 --- a/plugins/vst_base/RemoteVstPlugin/CMakeLists.txt +++ b/plugins/vst_base/RemoteVstPlugin/CMakeLists.txt @@ -76,3 +76,18 @@ endif() IF(STRIP) ADD_CUSTOM_COMMAND(TARGET ${EXE_NAME} POST_BUILD COMMAND "${STRIP}" "$") ENDIF() + +if(BITNESS EQUAL 32) + INSTALL(TARGETS ${EXE_NAME} RUNTIME DESTINATION "${PLUGIN_DIR}/32") +else() + INSTALL(TARGETS ${EXE_NAME} RUNTIME DESTINATION "${PLUGIN_DIR}") +endif() + +if(BUILD_WITH_EXTERNALPROJECT) + include(InstallTargetDependencies) + INSTALL_TARGET_DEPENDENCIES(TARGETS ${EXE_NAME} + DESTINATION "${PLUGIN_DIR}/32") +else() + # Needed to deploy dependencies of RemoteVstPlugin + SET_PROPERTY(GLOBAL APPEND PROPERTY PLUGINS_BUILT "${EXE_NAME}") +endif() diff --git a/plugins/vst_base/RemoteVstPlugin32.cmake b/plugins/vst_base/RemoteVstPlugin32.cmake index 9a8f04529..cba9a26c8 100644 --- a/plugins/vst_base/RemoteVstPlugin32.cmake +++ b/plugins/vst_base/RemoteVstPlugin32.cmake @@ -1,33 +1,31 @@ +# INSTALL_EXTERNAL_PROJECT: install a project created with ExternalProject_Add in the +# parent project's install time. +# +# Description: +# In a regular scenario, cmake will install external projects +# BEFORE actually building the parent project. Since the building +# process may use installed components from the project. +# We want to give the external project the ability to install +# files directly to the parent's install. Therefore, we have to +# manually trigger the install stage with the parent's INSTALL_PREFIX. +MACRO(INSTALL_EXTERNAL_PROJECT name) + ExternalProject_Get_Property(${name} BINARY_DIR) + + install(CODE "include(\"${BINARY_DIR}/cmake_install.cmake\")") +ENDMACRO() + IF(LMMS_BUILD_WIN32 AND NOT LMMS_BUILD_WIN64) ADD_SUBDIRECTORY(RemoteVstPlugin) - IF(MSVC) - SET(VCPKG_ROOT "${CMAKE_FIND_ROOT_PATH}") - INSTALL(FILES "${VCPKG_ROOT}/bin/Qt5Core.dll" DESTINATION "${PLUGIN_DIR}/32") - INSTALL(FILES "${VCPKG_ROOT}/bin/zlib1.dll" DESTINATION "${PLUGIN_DIR}/32") - ELSE(MSVC) - INSTALL(FILES "${MINGW_PREFIX}/bin/Qt5Core.dll" DESTINATION "${PLUGIN_DIR}/32") - INSTALL(FILES "${MINGW_PREFIX}/bin/zlib1.dll" DESTINATION "${PLUGIN_DIR}/32") - ENDIF(MSVC) - INSTALL(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/../32/RemoteVstPlugin32.exe" DESTINATION "${PLUGIN_DIR}/32") ELSEIF(LMMS_BUILD_WIN64 AND MSVC) - SET(MSVC_VER ${CMAKE_CXX_COMPILER_VERSION}) - - IF(NOT CMAKE_GENERATOR_32) - IF(MSVC_VER VERSION_GREATER 19.10 OR MSVC_VER VERSION_EQUAL 19.10) - SET(CMAKE_GENERATOR_32 "Visual Studio 15 2017") - SET(MSVC_YEAR 2017) - ELSEIF(MSVC_VER VERSION_GREATER 19.0 OR MSVC_VER VERSION_EQUAL 19.0) - SET(CMAKE_GENERATOR_32 "Visual Studio 14 2015") - SET(MSVC_YEAR 2015) - ELSE() - MESSAGE(SEND_WARNING "Can't build RemoteVstPlugin32, unknown MSVC version ${MSVC_VER} and no CMAKE_GENERATOR_32 set") - RETURN() - ENDIF() - ENDIF() - IF(NOT QT_32_PREFIX) + SET(LMMS_MSVC_YEAR_FOR_QT ${LMMS_MSVC_YEAR}) + + if(LMMS_MSVC_YEAR_FOR_QT EQUAL 2019) + SET(LMMS_MSVC_YEAR_FOR_QT 2017) # Qt only provides binaries for MSVC 2017, but 2019 is binary compatible + endif() + GET_FILENAME_COMPONENT(QT_BIN_DIR ${QT_QMAKE_EXECUTABLE} DIRECTORY) - SET(QT_32_PREFIX "${QT_BIN_DIR}/../../msvc${MSVC_YEAR}") + SET(QT_32_PREFIX "${QT_BIN_DIR}/../../msvc${LMMS_MSVC_YEAR_FOR_QT}") ENDIF() #TODO: qt5 installed using vcpkg: I don't know how to detect if the user built the x86 version of qt5 from here. At least not cleanly. @@ -38,7 +36,8 @@ ELSEIF(LMMS_BUILD_WIN64 AND MSVC) ExternalProject_Add(RemoteVstPlugin32 "${EXTERNALPROJECT_ARGS}" - CMAKE_GENERATOR "${CMAKE_GENERATOR_32}" + CMAKE_GENERATOR "${LMMS_MSVC_GENERATOR}" + CMAKE_GENERATOR_PLATFORM Win32 #CMAKE_GENERATOR_TOOLSET "${CMAKE_GENERATOR_TOOLSET}" CMAKE_ARGS "${EXTERNALPROJECT_CMAKE_ARGS}" @@ -46,16 +45,7 @@ ELSEIF(LMMS_BUILD_WIN64 AND MSVC) "-DCMAKE_PREFIX_PATH=${QT_32_PREFIX}" ) - INSTALL(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/../32/RemoteVstPlugin32.exe" DESTINATION "${PLUGIN_DIR}/32") - - #TODO: find a solution when not using vcpkg for qt - SET(VCPKG_ROOT_32 "${CMAKE_FIND_ROOT_PATH}/../x86-windows") - - INSTALL(FILES "${VCPKG_ROOT_32}/bin/zlib1.dll" DESTINATION "${PLUGIN_DIR}/32") - INSTALL(FILES "${VCPKG_ROOT_32}/bin/pcre2-16.dll" DESTINATION "${PLUGIN_DIR}/32") - INSTALL(FILES "${VCPKG_ROOT_32}/bin/double-conversion.dll" DESTINATION "${PLUGIN_DIR}/32") - INSTALL(FILES "${VCPKG_ROOT_32}/bin/qt5core.dll" DESTINATION "${PLUGIN_DIR}/32") - + INSTALL_EXTERNAL_PROJECT(RemoteVstPlugin32) ELSEIF(LMMS_BUILD_LINUX) # Use winegcc INCLUDE(CheckWineGcc) @@ -82,9 +72,7 @@ ELSEIF(CMAKE_TOOLCHAIN_FILE_32) "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH_32}" "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE_32}" ) - INSTALL(FILES "${CMAKE_PREFIX_PATH_32}/bin/Qt5Core.dll" DESTINATION "${PLUGIN_DIR}/32") - INSTALL(FILES "${CMAKE_PREFIX_PATH_32}/bin/zlib1.dll" DESTINATION "${PLUGIN_DIR}/32") - INSTALL(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/../32/RemoteVstPlugin32.exe" DESTINATION "${PLUGIN_DIR}/32") + INSTALL_EXTERNAL_PROJECT(RemoteVstPlugin32) ELSE() MESSAGE(WARNING "Can't build RemoteVstPlugin32, unknown environment. Please supply CMAKE_TOOLCHAIN_FILE_32 and optionally CMAKE_PREFIX_PATH_32") RETURN() diff --git a/plugins/vst_base/RemoteVstPlugin64.cmake b/plugins/vst_base/RemoteVstPlugin64.cmake index 4b02bf8ab..65b33a162 100644 --- a/plugins/vst_base/RemoteVstPlugin64.cmake +++ b/plugins/vst_base/RemoteVstPlugin64.cmake @@ -1,6 +1,5 @@ IF(LMMS_BUILD_WIN64) ADD_SUBDIRECTORY(RemoteVstPlugin) - INSTALL(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/../RemoteVstPlugin64.exe" DESTINATION "${PLUGIN_DIR}") ELSEIF(LMMS_BUILD_LINUX) INCLUDE(CheckWineGcc) CheckWineGcc(64 "${WINEGCC}" WINEGCC_WORKING) diff --git a/plugins/vst_base/VstPlugin.h b/plugins/vst_base/VstPlugin.h index 5b459d40d..26e7fec36 100644 --- a/plugins/vst_base/VstPlugin.h +++ b/plugins/vst_base/VstPlugin.h @@ -49,7 +49,7 @@ public: void tryLoad( const QString &remoteVstPluginExecutable ); - virtual bool processMessage( const message & _m ); + bool processMessage( const message & _m ) override; inline bool hasEditor() const { @@ -99,17 +99,17 @@ public: QWidget * pluginWidget(); - virtual void loadSettings( const QDomElement & _this ); - virtual void saveSettings( QDomDocument & _doc, QDomElement & _this ); + void loadSettings( const QDomElement & _this ) override; + void saveSettings( QDomDocument & _doc, QDomElement & _this ) override; - inline virtual QString nodeName() const + virtual QString nodeName() const override { return "vstplugin"; } virtual void createUI(QWidget *parent); - bool eventFilter(QObject *obj, QEvent *event); + bool eventFilter(QObject *obj, QEvent *event) override; QString embedMethod() const; diff --git a/plugins/zynaddsubfx/CMakeLists.txt b/plugins/zynaddsubfx/CMakeLists.txt index f1d37fa3e..f9cc4efd3 100644 --- a/plugins/zynaddsubfx/CMakeLists.txt +++ b/plugins/zynaddsubfx/CMakeLists.txt @@ -3,7 +3,7 @@ INCLUDE(BuildPlugin) set(CMAKE_POSITION_INDEPENDENT_CODE ON) # definitions for ZynAddSubFX -IF(LMMS_BUILD_LINUX OR LMMS_BUILD_APPLE OR LMMS_BUILD_OPENBSD) +IF(LMMS_BUILD_LINUX OR LMMS_BUILD_APPLE OR LMMS_BUILD_OPENBSD OR LMMS_BUILD_FREEBSD) FIND_PACKAGE(X11) INCLUDE_DIRECTORIES(${X11_INCLUDE_DIR}) ADD_DEFINITIONS(-DOS_LINUX) @@ -162,6 +162,8 @@ SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) ADD_EXECUTABLE(RemoteZynAddSubFx RemoteZynAddSubFx.cpp "${WINRC}") INSTALL(TARGETS RemoteZynAddSubFx RUNTIME DESTINATION "${PLUGIN_DIR}") +# Needed to deploy dependencies of RemoteZynAddSubFx +SET_PROPERTY(GLOBAL APPEND PROPERTY PLUGINS_BUILT "RemoteZynAddSubFx") IF(LMMS_BUILD_WIN32) SET_TARGET_PROPERTIES(RemoteZynAddSubFx PROPERTIES LINK_FLAGS "${LINK_FLAGS} -mwindows") diff --git a/src/3rdparty/CMakeLists.txt b/src/3rdparty/CMakeLists.txt index 473e7702f..bdc4a4d86 100644 --- a/src/3rdparty/CMakeLists.txt +++ b/src/3rdparty/CMakeLists.txt @@ -10,3 +10,22 @@ ENDIF() ADD_SUBDIRECTORY(rpmalloc) ADD_SUBDIRECTORY(weakjack) + +# The lockless ring buffer library is compiled as part of the core +SET(RINGBUFFER_DIR "${CMAKE_SOURCE_DIR}/src/3rdparty/ringbuffer/") +SET(RINGBUFFER_DIR ${RINGBUFFER_DIR} PARENT_SCOPE) +# Create a dummy ringbuffer_export.h, since ringbuffer is not compiled as a library +FILE(WRITE ${CMAKE_BINARY_DIR}/src/ringbuffer_export.h + "#include \"${CMAKE_BINARY_DIR}/src/lmms_export.h\"\n + #define RINGBUFFER_EXPORT LMMS_EXPORT") +# Enable MLOCK support for ringbuffer if available +INCLUDE(CheckIncludeFiles) +CHECK_INCLUDE_FILES(sys/mman.h HAVE_SYS_MMAN) +IF(HAVE_SYS_MMAN) + SET(USE_MLOCK ON) +ELSE() + SET(USE_MLOCK OFF) +ENDIF() +# Generate ringbuffer configuration headers +CONFIGURE_FILE(${RINGBUFFER_DIR}/src/ringbuffer-config.h.in ${CMAKE_BINARY_DIR}/src/ringbuffer-config.h) +CONFIGURE_FILE(${RINGBUFFER_DIR}/src/ringbuffer-version.h.in ${CMAKE_BINARY_DIR}/src/ringbuffer-version.h) diff --git a/src/3rdparty/ringbuffer b/src/3rdparty/ringbuffer new file mode 160000 index 000000000..82ed7cfb9 --- /dev/null +++ b/src/3rdparty/ringbuffer @@ -0,0 +1 @@ +Subproject commit 82ed7cfb9ad40467421d8b14ca1af0350e92613c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4ac6bf133..59710926d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,6 +27,7 @@ INCLUDE_DIRECTORIES( "${CMAKE_BINARY_DIR}/include" "${CMAKE_SOURCE_DIR}" "${CMAKE_SOURCE_DIR}/include" + "${RINGBUFFER_DIR}/include" ) IF(WIN32 AND MSVC) @@ -89,6 +90,8 @@ IF(NOT ("${LAME_INCLUDE_DIRS}" STREQUAL "")) INCLUDE_DIRECTORIES("${LAME_INCLUDE_DIRS}") ENDIF() +LIST(APPEND LMMS_SRCS "${RINGBUFFER_DIR}/src/lib/ringbuffer.cpp") + # Use libraries in non-standard directories (e.g., another version of Qt) IF(LMMS_BUILD_LINUX) LINK_LIBRARIES(-Wl,--enable-new-dtags) @@ -186,210 +189,30 @@ FOREACH(LIB ${LMMS_REQUIRED_LIBS}) ENDIF() ENDFOREACH() - -# Install -IF(NOT MSVC) - IF(LMMS_BUILD_WIN32) - SET_TARGET_PROPERTIES(lmms PROPERTIES - LINK_FLAGS "${LINK_FLAGS} -mwindows" - ENABLE_EXPORTS ON +IF(LMMS_BUILD_WIN32) + SET_TARGET_PROPERTIES(lmms PROPERTIES + ENABLE_EXPORTS ON + ) + IF(LMMS_BUILD_MSYS) + # ENABLE_EXPORTS property has no effect in some MSYS2 configurations. + # Add the linker flag manually to create liblmms.dll.a import library + SET_PROPERTY(TARGET lmms + APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--out-implib,liblmms.dll.a" ) + ENDIF() +ELSE() + IF(NOT LMMS_BUILD_APPLE) + SET_TARGET_PROPERTIES(lmms PROPERTIES LINK_FLAGS "${LINK_FLAGS} -Wl,-E") + ENDIF(NOT LMMS_BUILD_APPLE) - IF(LMMS_BUILD_MSYS) - # ENABLE_EXPORTS property has no effect in some MSYS2 configurations. - # Add the linker flag manually to create liblmms.dll.a import library - SET_PROPERTY(TARGET lmms - APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--out-implib,liblmms.dll.a" - ) - ENDIF() + if(CMAKE_INSTALL_MANDIR) + SET(INSTALL_MANDIR ${CMAKE_INSTALL_MANDIR}) + ELSE(CMAKE_INSTALL_MANDIR) + SET(INSTALL_MANDIR ${CMAKE_INSTALL_PREFIX}/share/man) + ENDIF(CMAKE_INSTALL_MANDIR) + INSTALL(FILES "${CMAKE_BINARY_DIR}/lmms.1.gz" + DESTINATION "${INSTALL_MANDIR}/man1/" + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) +ENDIF() - IF(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") - ADD_CUSTOM_COMMAND(TARGET lmms POST_BUILD COMMAND "${STRIP}" "$") - ENDIF() - - INSTALL(TARGETS lmms RUNTIME DESTINATION "${BIN_DIR}") - INSTALL(FILES - "${MINGW_PREFIX}/bin/Qt5Core.dll" - "${MINGW_PREFIX}/bin/Qt5Gui.dll" - "${MINGW_PREFIX}/bin/Qt5Widgets.dll" - "${MINGW_PREFIX}/bin/Qt5Xml.dll" - DESTINATION .) - INSTALL(FILES - "${MINGW_PREFIX}/lib/qt5/plugins/platforms/qwindows.dll" - DESTINATION ./platforms) - INSTALL(FILES - "${MINGW_PREFIX}/bin/libsamplerate-0.dll" - "${MINGW_PREFIX}/bin/libsndfile-1.dll" - "${MINGW_PREFIX}/bin/libvorbis-0.dll" - "${MINGW_PREFIX}/bin/libvorbisenc-2.dll" - "${MINGW_PREFIX}/bin/libvorbisfile-3.dll" - "${MINGW_PREFIX}/bin/libjpeg-9.dll" - "${MINGW_PREFIX}/bin/libogg-0.dll" - "${MINGW_PREFIX}/bin/libmp3lame-0.dll" - "${MINGW_PREFIX}/bin/libfftw3f-3.dll" - "${MINGW_PREFIX}/bin/libFLAC-8.dll" - "${MINGW_PREFIX}/bin/libpng16-16.dll" - "${MINGW_PREFIX}/bin/SDL.dll" - "${MINGW_PREFIX}/bin/libglib-2.0-0.dll" - "${MINGW_PREFIX}/bin/libgthread-2.0-0.dll" - "${MINGW_PREFIX}/bin/zlib1.dll" - "${MINGW_PREFIX}/${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32/bin/libwinpthread-1.dll" - DESTINATION .) - IF(LMMS_BUILD_MSYS) - INSTALL(FILES - "${MINGW_PREFIX}/bin/libwinpthread-1.dll" - "${MINGW_PREFIX}/bin/libgcc_s_seh-1.dll" - "${MINGW_PREFIX}/bin/libstdc++-6.dll" - DESTINATION .) - ELSE() - INSTALL(FILES - "${MINGW_PREFIX}/${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32/bin/libwinpthread-1.dll" - DESTINATION .) - ENDIF() - IF(FLTK_FOUND) - INSTALL(FILES - "${MINGW_PREFIX}/bin/libfltk.dll" - DESTINATION .) - ENDIF() - IF(FLUIDSYNTH_FOUND) - INSTALL(FILES - "${MINGW_PREFIX}/bin/libfluidsynth.dll" - DESTINATION .) - ENDIF() - IF(GIG_FOUND) - # Handle libgig-*.dll - FILE(GLOB GIG_LIBRARY "${MINGW_PREFIX}/bin/libgig-*.dll") - INSTALL(FILES - ${GIG_LIBRARY} - DESTINATION .) - ENDIF() - IF(PORTAUDIO_FOUND) - INSTALL(FILES - "${MINGW_PREFIX}/bin/libportaudio-2.dll" - DESTINATION .) - ENDIF() - IF(SOUNDIO_FOUND) - INSTALL(FILES - "${MINGW_PREFIX}/lib/libsoundio.dll" - DESTINATION .) - ENDIF() - - ELSE(LMMS_BUILD_WIN32) - IF(NOT LMMS_BUILD_APPLE) - SET_TARGET_PROPERTIES(lmms PROPERTIES LINK_FLAGS "${LINK_FLAGS} -Wl,-E") - ENDIF(NOT LMMS_BUILD_APPLE) - - INSTALL(TARGETS lmms RUNTIME DESTINATION "${BIN_DIR}") - INSTALL(FILES "${CMAKE_BINARY_DIR}/lmms.1.gz" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/man/man1/" PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) - - ENDIF(LMMS_BUILD_WIN32) -ELSE(NOT MSVC) - SET_TARGET_PROPERTIES(lmms PROPERTIES - ENABLE_EXPORTS ON - ) - INSTALL(TARGETS lmms RUNTIME DESTINATION "${BIN_DIR}") - - SET_TARGET_PROPERTIES(lmms PROPERTIES - LINK_FLAGS "${LINK_FLAGS} -mwindows" - ENABLE_EXPORTS ON - ) - - #CMAKE_FIND_ROOT_PATH - SET(VCPKG_ROOT ${CMAKE_FIND_ROOT_PATH}) - - INSTALL(TARGETS lmms RUNTIME DESTINATION "${BIN_DIR}") - - INSTALL(FILES - "${VCPKG_ROOT}/bin/Qt5Core.dll" - "${VCPKG_ROOT}/bin/Qt5Gui.dll" - "${VCPKG_ROOT}/bin/Qt5Widgets.dll" - "${VCPKG_ROOT}/bin/Qt5Xml.dll" - - "${VCPKG_ROOT}/bin/zlib1.dll" - "${VCPKG_ROOT}/bin/jpeg62.dll" - "${VCPKG_ROOT}/bin/libpng16.dll" - "${VCPKG_ROOT}/bin/gthread-2.dll" - "${VCPKG_ROOT}/bin/glib-2.dll" - "${VCPKG_ROOT}/bin/harfbuzz.dll" - "${VCPKG_ROOT}/bin/pcre2-16.dll" - "${VCPKG_ROOT}/bin/double-conversion.dll" - "${VCPKG_ROOT}/bin/freetype.dll" - "${VCPKG_ROOT}/bin/libbz2.dll" - "${VCPKG_ROOT}/bin/pcre.dll" - "${VCPKG_ROOT}/bin/libiconv.dll" - "${VCPKG_ROOT}/bin/libcharset.dll" - "${VCPKG_ROOT}/bin/libintl.dll" - DESTINATION .) - - INSTALL(FILES - "${VCPKG_ROOT}/plugins/platforms/qwindows.dll" - DESTINATION ./platforms) - - INSTALL(FILES - "${VCPKG_ROOT}/bin/libsndfile-1.dll" - "${VCPKG_ROOT}/bin/ogg.dll" - "${VCPKG_ROOT}/bin/vorbis.dll" - "${VCPKG_ROOT}/bin/vorbisenc.dll" - "${VCPKG_ROOT}/bin/FLAC.dll" - "${VCPKG_ROOT}/bin/vorbisfile.dll" - - "${VCPKG_ROOT}/bin/libsamplerate-0.dll" - "${VCPKG_ROOT}/bin/SDL2.dll" - "${VCPKG_ROOT}/bin/fftw3f.dll" - DESTINATION .) - - #not yet in vcpkg - #IF(LAME_FOUND) - # INSTALL(FILES - # "${VCPKG_ROOT}/bin/libmp3lame-0.dll" - # DESTINATION .) - #ENDIF(LAME_FOUND) - - IF(FLTK_FOUND) - INSTALL(FILES - "${VCPKG_ROOT}/bin/libfltk_SHARED.dll" - - "${VCPKG_ROOT}/bin/zlib1.dll" - "${VCPKG_ROOT}/bin/jpeg62.dll" - DESTINATION .) - ENDIF() - - IF(FLUIDSYNTH_FOUND) - INSTALL(FILES - "${VCPKG_ROOT}/bin/libfluidsynth-1.dll" - "${VCPKG_ROOT}/bin/glib-2.dll" - "${VCPKG_ROOT}/bin/pcre.dll" - "${VCPKG_ROOT}/bin/libiconv.dll" - "${VCPKG_ROOT}/bin/libcharset.dll" - "${VCPKG_ROOT}/bin/libintl.dll" - DESTINATION .) - ENDIF() - - #not yet included in vcpkg - #IF(GIG_FOUND) - # # Handle libgig-*.dll - # FILE(GLOB GIG_LIBRARY "${VCPKG_ROOT}/bin/libgig-*.dll") - # INSTALL(FILES - # ${GIG_LIBRARY} - # DESTINATION .) - #ENDIF() - - IF(PORTAUDIO_FOUND) - IF(LMMS_BUILD_WIN64) - INSTALL(FILES - "${VCPKG_ROOT}/bin/portaudio-x64.dll" - DESTINATION .) - ELSE(LMMS_BUILD_WIN64) - INSTALL(FILES - "${VCPKG_ROOT}/bin/portaudio-x86.dll" - DESTINATION .) - ENDIF(LMMS_BUILD_WIN64) - ENDIF() - - #not yet in vcpkg - #IF(SOUNDIO_FOUND) - # INSTALL(FILES - # "${VCPKG_ROOT}/bin/libsoundio.dll" - # DESTINATION .) - #ENDIF() -ENDIF(NOT MSVC) +INSTALL(TARGETS lmms RUNTIME DESTINATION "${BIN_DIR}") diff --git a/src/core/AutomationPattern.cpp b/src/core/AutomationPattern.cpp index e36838d80..b38c704ef 100644 --- a/src/core/AutomationPattern.cpp +++ b/src/core/AutomationPattern.cpp @@ -180,7 +180,7 @@ MidiTime AutomationPattern::timeMapLength() const { if( m_timeMap.isEmpty() ) return 0; timeMap::const_iterator it = m_timeMap.end(); - return MidiTime( MidiTime( (it-1).key() ).nextFullTact(), 0 ); + return MidiTime( MidiTime( (it-1).key() ).nextFullBar(), 0 ); } diff --git a/src/core/BBTrackContainer.cpp b/src/core/BBTrackContainer.cpp index e349c7b02..ac4b6cb1a 100644 --- a/src/core/BBTrackContainer.cpp +++ b/src/core/BBTrackContainer.cpp @@ -62,7 +62,7 @@ bool BBTrackContainer::play( MidiTime _start, fpp_t _frames, return false; } - _start = _start % ( lengthOfBB( _tco_num ) * MidiTime::ticksPerTact() ); + _start = _start % ( lengthOfBB( _tco_num ) * MidiTime::ticksPerBar() ); TrackList tl = tracks(); for( TrackList::iterator it = tl.begin(); it != tl.end(); ++it ) @@ -90,9 +90,9 @@ void BBTrackContainer::updateAfterTrackAdd() -tact_t BBTrackContainer::lengthOfBB( int _bb ) const +bar_t BBTrackContainer::lengthOfBB( int _bb ) const { - MidiTime max_length = MidiTime::ticksPerTact(); + MidiTime max_length = MidiTime::ticksPerBar(); const TrackList & tl = tracks(); for (Track* t : tl) @@ -104,7 +104,7 @@ tact_t BBTrackContainer::lengthOfBB( int _bb ) const } } - return max_length.nextFullTact(); + return max_length.nextFullBar(); } @@ -124,7 +124,7 @@ void BBTrackContainer::removeBB( int _bb ) for( TrackList::iterator it = tl.begin(); it != tl.end(); ++it ) { delete ( *it )->getTCO( _bb ); - ( *it )->removeTact( _bb * DefaultTicksPerTact ); + ( *it )->removeBar( _bb * DefaultTicksPerBar ); } if( _bb <= currentBB() ) { @@ -151,7 +151,7 @@ void BBTrackContainer::swapBB( int _bb1, int _bb2 ) void BBTrackContainer::updateBBTrack( TrackContentObject * _tco ) { BBTrack * t = BBTrack::findBBTrack( _tco->startPosition() / - DefaultTicksPerTact ); + DefaultTicksPerBar ); if( t != NULL ) { t->dataChanged(); @@ -247,16 +247,13 @@ AutomatedValueMap BBTrackContainer::automatedValuesAt(MidiTime time, int tcoNum) Q_ASSERT(tcoNum >= 0); Q_ASSERT(time.getTicks() >= 0); - auto length_tacts = lengthOfBB(tcoNum); - auto length_ticks = length_tacts * MidiTime::ticksPerTact(); - if (time > length_ticks) { + auto length_bars = lengthOfBB(tcoNum); + auto length_ticks = length_bars * MidiTime::ticksPerBar(); + if (time > length_ticks) + { time = length_ticks; } - return TrackContainer::automatedValuesAt(time + (MidiTime::ticksPerTact() * tcoNum), tcoNum); + return TrackContainer::automatedValuesAt(time + (MidiTime::ticksPerBar() * tcoNum), tcoNum); } - - - - diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ba41e089c..a50b32a0f 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,5 +1,6 @@ set(LMMS_SRCS ${LMMS_SRCS} + core/AutomatableModel.cpp core/AutomationPattern.cpp core/BandLimitedWave.cpp diff --git a/src/core/ConfigManager.cpp b/src/core/ConfigManager.cpp index d8c783dd2..b8e8cd4ae 100644 --- a/src/core/ConfigManager.cpp +++ b/src/core/ConfigManager.cpp @@ -22,6 +22,7 @@ * */ + #include #include #include @@ -36,9 +37,10 @@ #include "lmmsversion.h" -static inline QString ensureTrailingSlash( const QString & s ) + +static inline QString ensureTrailingSlash(const QString & s ) { - if( ! s.isEmpty() && !s.endsWith('/') && !s.endsWith('\\') ) + if(! s.isEmpty() && !s.endsWith('/') && !s.endsWith('\\')) { return s + '/'; } @@ -50,14 +52,14 @@ ConfigManager * ConfigManager::s_instanceOfMe = NULL; ConfigManager::ConfigManager() : - m_lmmsRcFile( QDir::home().absolutePath() +"/.lmmsrc.xml" ), - m_workingDir( QStandardPaths::writableLocation( QStandardPaths::DocumentsLocation ) + "/lmms/"), - m_dataDir( "data:/" ), - m_artworkDir( defaultArtworkDir() ), - m_vstDir( m_workingDir + "vst/" ), - m_gigDir( m_workingDir + GIG_PATH ), - m_sf2Dir( m_workingDir + SF2_PATH ), - m_version( defaultVersion() ) + m_workingDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/lmms/"), + m_dataDir("data:/"), + m_vstDir(m_workingDir + "vst/"), + m_sf2Dir(m_workingDir + SF2_PATH), + m_gigDir(m_workingDir + GIG_PATH), + m_themeDir(defaultThemeDir()), + m_lmmsRcFile(QDir::home().absolutePath() +"/.lmmsrc.xml"), + m_version(defaultVersion()) { // Detect < 1.2.0 working directory as a courtesy if ( QFileInfo( QDir::home().absolutePath() + "/lmms/projects/" ).exists() ) @@ -125,19 +127,19 @@ ConfigManager::~ConfigManager() void ConfigManager::upgrade_1_1_90() { // Remove trailing " (bad latency!)" string which was once saved with PulseAudio - if( value( "mixer", "audiodev" ).startsWith( "PulseAudio (" ) ) + if(value("mixer", "audiodev").startsWith("PulseAudio (")) { setValue("mixer", "audiodev", "PulseAudio"); } // MidiAlsaRaw used to store the device info as "Device" instead of "device" - if ( value( "MidiAlsaRaw", "device" ).isNull() ) + if (value("MidiAlsaRaw", "device").isNull()) { // copy "device" = "Device" and then delete the old "Device" (further down) - QString oldDevice = value( "MidiAlsaRaw", "Device" ); + QString oldDevice = value("MidiAlsaRaw", "Device"); setValue("MidiAlsaRaw", "device", oldDevice); } - if ( !value( "MidiAlsaRaw", "device" ).isNull() ) + if (!value("MidiAlsaRaw", "device").isNull()) { // delete the old "Device" in the case that we just copied it to "device" // or if the user somehow set both the "Device" and "device" fields @@ -149,9 +151,9 @@ void ConfigManager::upgrade_1_1_90() void ConfigManager::upgrade_1_1_91() { // rename displaydbv to displaydbfs - if ( !value( "app", "displaydbv" ).isNull() ) { - setValue( "app", "displaydbfs", value( "app", "displaydbv" ) ); - deleteValue( "app", "displaydbv" ); + if (!value("app", "displaydbv").isNull()) { + setValue("app", "displaydbfs", value("app", "displaydbv")); + deleteValue("app", "displaydbv"); } } @@ -159,27 +161,27 @@ void ConfigManager::upgrade_1_1_91() void ConfigManager::upgrade() { // Skip the upgrade if versions match - if ( m_version == LMMS_VERSION ) + if (m_version == LMMS_VERSION) { return; } ProjectVersion createdWith = m_version; - if ( createdWith.setCompareType(ProjectVersion::Build) < "1.1.90" ) + if (createdWith.setCompareType(ProjectVersion::Build) < "1.1.90") { upgrade_1_1_90(); } - if ( createdWith.setCompareType(ProjectVersion::Build) < "1.1.91" ) + if (createdWith.setCompareType(ProjectVersion::Build) < "1.1.91") { upgrade_1_1_91(); } // Don't use old themes as they break the UI (i.e. 0.4 != 1.0, etc) - if ( createdWith.setCompareType(ProjectVersion::Minor) != LMMS_VERSION ) + if (createdWith.setCompareType(ProjectVersion::Minor) != LMMS_VERSION) { - m_artworkDir = defaultArtworkDir(); + m_themeDir = defaultThemeDir(); } // Bump the version, now that we are upgraded @@ -221,107 +223,115 @@ QString ConfigManager::vstEmbedMethod() const bool ConfigManager::hasWorkingDir() const { - return QDir( m_workingDir ).exists(); + return QDir(m_workingDir).exists(); } -void ConfigManager::setWorkingDir( const QString & wd ) +void ConfigManager::setWorkingDir(const QString & workingDir) { - m_workingDir = ensureTrailingSlash( QDir::cleanPath( wd ) ); + m_workingDir = ensureTrailingSlash(QDir::cleanPath(workingDir)); } -void ConfigManager::setVSTDir( const QString & _vd ) +void ConfigManager::setVSTDir(const QString & vstDir) { - m_vstDir = ensureTrailingSlash( _vd ); + m_vstDir = ensureTrailingSlash(vstDir); } -void ConfigManager::setArtworkDir( const QString & _ad ) +void ConfigManager::setLADSPADir(const QString & ladspaDir) { - m_artworkDir = ensureTrailingSlash( _ad ); + m_ladspaDir = ladspaDir; } -void ConfigManager::setLADSPADir( const QString & _fd ) -{ - m_ladDir = _fd; -} - - - - -void ConfigManager::setSTKDir( const QString & _fd ) +void ConfigManager::setSTKDir(const QString & stkDir) { #ifdef LMMS_HAVE_STK - m_stkDir = ensureTrailingSlash( _fd ); + m_stkDir = ensureTrailingSlash(stkDir); #endif } -void ConfigManager::setDefaultSoundfont( const QString & _sf ) +void ConfigManager::setSF2Dir(const QString & sf2Dir) +{ + m_sf2Dir = sf2Dir; +} + + + + +void ConfigManager::setSF2File(const QString & sf2File) { #ifdef LMMS_HAVE_FLUIDSYNTH - m_defaultSoundfont = _sf; + m_sf2File = sf2File; #endif } -void ConfigManager::setBackgroundArtwork( const QString & _ba ) +void ConfigManager::setGIGDir(const QString & gigDir) { - m_backgroundArtwork = _ba; + m_gigDir = gigDir; } -void ConfigManager::setGIGDir(const QString &gd) + + + +void ConfigManager::setThemeDir(const QString & themeDir) { - m_gigDir = gd; + m_themeDir = ensureTrailingSlash(themeDir); } -void ConfigManager::setSF2Dir(const QString &sfd) + + + +void ConfigManager::setBackgroundPicFile(const QString & backgroundPicFile) { - m_sf2Dir = sfd; + m_backgroundPicFile = backgroundPicFile; } + + void ConfigManager::createWorkingDir() { - QDir().mkpath( m_workingDir ); + QDir().mkpath(m_workingDir); - QDir().mkpath( userProjectsDir() ); - QDir().mkpath( userTemplateDir() ); - QDir().mkpath( userSamplesDir() ); - QDir().mkpath( userPresetsDir() ); - QDir().mkpath( userGigDir() ); - QDir().mkpath( userSf2Dir() ); - QDir().mkpath( userVstDir() ); - QDir().mkpath( userLadspaDir() ); + QDir().mkpath(userProjectsDir()); + QDir().mkpath(userTemplateDir()); + QDir().mkpath(userSamplesDir()); + QDir().mkpath(userPresetsDir()); + QDir().mkpath(userGigDir()); + QDir().mkpath(userSf2Dir()); + QDir().mkpath(userVstDir()); + QDir().mkpath(userLadspaDir()); } -void ConfigManager::addRecentlyOpenedProject( const QString & file ) +void ConfigManager::addRecentlyOpenedProject(const QString & file) { - QFileInfo recentFile( file ); - if( recentFile.suffix().toLower() == "mmp" || + QFileInfo recentFile(file); + if(recentFile.suffix().toLower() == "mmp" || recentFile.suffix().toLower() == "mmpz" || - recentFile.suffix().toLower() == "mpt" ) + recentFile.suffix().toLower() == "mpt") { - m_recentlyOpenedProjects.removeAll( file ); - if( m_recentlyOpenedProjects.size() > 50 ) + m_recentlyOpenedProjects.removeAll(file); + if(m_recentlyOpenedProjects.size() > 50) { m_recentlyOpenedProjects.removeLast(); } - m_recentlyOpenedProjects.push_front( file ); + m_recentlyOpenedProjects.push_front(file); ConfigManager::inst()->saveConfigFile(); } } @@ -329,18 +339,18 @@ void ConfigManager::addRecentlyOpenedProject( const QString & file ) -const QString & ConfigManager::value( const QString & cls, - const QString & attribute ) const +const QString & ConfigManager::value(const QString & cls, + const QString & attribute) const { - if( m_settings.contains( cls ) ) + if(m_settings.contains(cls)) { - for( stringPairVector::const_iterator it = + for(stringPairVector::const_iterator it = m_settings[cls].begin(); - it != m_settings[cls].end(); ++it ) + it != m_settings[cls].end(); ++it) { - if( ( *it ).first == attribute ) + if((*it).first == attribute) { - return ( *it ).second ; + return (*it).second ; } } } @@ -350,49 +360,49 @@ const QString & ConfigManager::value( const QString & cls, -const QString & ConfigManager::value( const QString & cls, +const QString & ConfigManager::value(const QString & cls, const QString & attribute, - const QString & defaultVal ) const + const QString & defaultVal) const { - const QString & val = value( cls, attribute ); + const QString & val = value(cls, attribute); return val.isEmpty() ? defaultVal : val; } -void ConfigManager::setValue( const QString & cls, +void ConfigManager::setValue(const QString & cls, const QString & attribute, - const QString & value ) + const QString & value) { - if( m_settings.contains( cls ) ) + if(m_settings.contains(cls)) { - for( QPair& pair : m_settings[cls]) + for(QPair& pair : m_settings[cls]) { - if( pair.first == attribute ) + if(pair.first == attribute) { - if ( pair.second != value ) + if (pair.second != value) { pair.second = value; - emit valueChanged( cls, attribute, value ); + emit valueChanged(cls, attribute, value); } return; } } } // not in map yet, so we have to add it... - m_settings[cls].push_back( qMakePair( attribute, value ) ); + m_settings[cls].push_back(qMakePair(attribute, value)); } -void ConfigManager::deleteValue( const QString & cls, const QString & attribute) +void ConfigManager::deleteValue(const QString & cls, const QString & attribute) { - if( m_settings.contains( cls ) ) + if(m_settings.contains(cls)) { - for( stringPairVector::iterator it = m_settings[cls].begin(); - it != m_settings[cls].end(); ++it ) + for(stringPairVector::iterator it = m_settings[cls].begin(); + it != m_settings[cls].end(); ++it) { - if( ( *it ).first == attribute ) + if((*it).first == attribute) { m_settings[cls].erase(it); return; @@ -402,23 +412,23 @@ void ConfigManager::deleteValue( const QString & cls, const QString & attribute) } -void ConfigManager::loadConfigFile( const QString & configFile ) +void ConfigManager::loadConfigFile(const QString & configFile) { // read the XML file and create DOM tree // Allow configuration file override through --config commandline option - if ( !configFile.isEmpty() ) + if (!configFile.isEmpty()) { m_lmmsRcFile = configFile; } - QFile cfg_file( m_lmmsRcFile ); + QFile cfg_file(m_lmmsRcFile); QDomDocument dom_tree; - if( cfg_file.open( QIODevice::ReadOnly ) ) + if(cfg_file.open(QIODevice::ReadOnly)) { QString errorString; int errorLine, errorCol; - if( dom_tree.setContent( &cfg_file, false, &errorString, &errorLine, &errorCol ) ) + if(dom_tree.setContent(&cfg_file, false, &errorString, &errorLine, &errorCol)) { // get the head information from the DOM QDomElement root = dom_tree.documentElement(); @@ -426,41 +436,41 @@ void ConfigManager::loadConfigFile( const QString & configFile ) QDomNode node = root.firstChild(); // Cache the config version for upgrade() - if ( !root.attribute( "version" ).isNull() ) { - m_version = root.attribute( "version" ); + if (!root.attribute("version").isNull()) { + m_version = root.attribute("version"); } // create the settings-map out of the DOM - while( !node.isNull() ) + while(!node.isNull()) { - if( node.isElement() && - node.toElement().hasAttributes () ) + if(node.isElement() && + node.toElement().hasAttributes ()) { stringPairVector attr; QDomNamedNodeMap node_attr = node.toElement().attributes(); - for( int i = 0; i < node_attr.count(); - ++i ) + for(int i = 0; i < node_attr.count(); + ++i) { - QDomNode n = node_attr.item( i ); - if( n.isAttr() ) + QDomNode n = node_attr.item(i); + if(n.isAttr()) { - attr.push_back( qMakePair( n.toAttr().name(), - n.toAttr().value() ) ); + attr.push_back(qMakePair(n.toAttr().name(), + n.toAttr().value())); } } m_settings[node.nodeName()] = attr; } - else if( node.nodeName() == "recentfiles" ) + else if(node.nodeName() == "recentfiles") { m_recentlyOpenedProjects.clear(); QDomNode n = node.firstChild(); - while( !n.isNull() ) + while(!n.isNull()) { - if( n.isElement() && n.toElement().hasAttributes() ) + if(n.isElement() && n.toElement().hasAttributes()) { m_recentlyOpenedProjects << - n.toElement().attribute( "path" ); + n.toElement().attribute("path"); } n = n.nextSibling(); } @@ -468,45 +478,45 @@ void ConfigManager::loadConfigFile( const QString & configFile ) node = node.nextSibling(); } - if( value( "paths", "artwork" ) != "" ) + if(value("paths", "theme") != "") { - m_artworkDir = value( "paths", "artwork" ); + m_themeDir = value("paths", "theme"); #ifdef LMMS_BUILD_WIN32 // Detect a QDir/QFile hang on Windows // see issue #3417 on github - bool badPath = ( m_artworkDir == "/" || m_artworkDir == "\\" ); + bool badPath = (m_themeDir == "/" || m_themeDir == "\\"); #else bool badPath = false; #endif - if( badPath || !QDir( m_artworkDir ).exists() || - !QFile( m_artworkDir + "/style.css" ).exists() ) + if(badPath || !QDir(m_themeDir).exists() || + !QFile(m_themeDir + "/style.css").exists()) { - m_artworkDir = defaultArtworkDir(); + m_themeDir = defaultThemeDir(); } - m_artworkDir = ensureTrailingSlash(m_artworkDir); + m_themeDir = ensureTrailingSlash(m_themeDir); } - setWorkingDir( value( "paths", "workingdir" ) ); + setWorkingDir(value("paths", "workingdir")); - setGIGDir( value( "paths", "gigdir" ) == "" ? gigDir() : value( "paths", "gigdir" ) ); - setSF2Dir( value( "paths", "sf2dir" ) == "" ? sf2Dir() : value( "paths", "sf2dir" ) ); - setVSTDir( value( "paths", "vstdir" ) ); - setLADSPADir( value( "paths", "laddir" ) ); + setGIGDir(value("paths", "gigdir") == "" ? gigDir() : value("paths", "gigdir")); + setSF2Dir(value("paths", "sf2dir") == "" ? sf2Dir() : value("paths", "sf2dir")); + setVSTDir(value("paths", "vstdir")); + setLADSPADir(value("paths", "ladspadir")); #ifdef LMMS_HAVE_STK - setSTKDir( value( "paths", "stkdir" ) ); + setSTKDir(value("paths", "stkdir")); #endif #ifdef LMMS_HAVE_FLUIDSYNTH - setDefaultSoundfont( value( "paths", "defaultsf2" ) ); + setSF2File(value("paths", "defaultsf2")); #endif - setBackgroundArtwork( value( "paths", "backgroundartwork" ) ); + setBackgroundPicFile(value("paths", "backgroundtheme")); } - else if( gui ) + else if(gui) { - QMessageBox::warning( NULL, MainWindow::tr( "Configuration file" ), - MainWindow::tr( "Error while parsing configuration file at line %1:%2: %3" ). - arg( errorLine ). - arg( errorCol ). - arg( errorString ) ); + QMessageBox::warning(NULL, MainWindow::tr("Configuration file"), + MainWindow::tr("Error while parsing configuration file at line %1:%2: %3"). + arg(errorLine). + arg(errorCol). + arg(errorString)); } cfg_file.close(); } @@ -517,21 +527,21 @@ void ConfigManager::loadConfigFile( const QString & configFile ) !QDir( m_vstDir ).exists() ) { #ifdef LMMS_BUILD_WIN32 - QString programFiles = QString::fromLocal8Bit( getenv( "ProgramFiles" ) ); + QString programFiles = QString::fromLocal8Bit(getenv("ProgramFiles")); m_vstDir = programFiles + "/VstPlugins/"; #else m_vstDir = m_workingDir + "plugins/vst/"; #endif } - if( m_ladDir.isEmpty() ) + if(m_ladspaDir.isEmpty() ) { - m_ladDir = userLadspaDir(); + m_ladspaDir = userLadspaDir(); } #ifdef LMMS_HAVE_STK - if( m_stkDir.isEmpty() || m_stkDir == QDir::separator() || m_stkDir == "/" || - !QDir( m_stkDir ).exists() ) + if(m_stkDir.isEmpty() || m_stkDir == QDir::separator() || m_stkDir == "/" || + !QDir(m_stkDir).exists()) { #if defined(LMMS_BUILD_WIN32) m_stkDir = m_dataDir + "stk/rawwaves/"; @@ -557,11 +567,11 @@ void ConfigManager::loadConfigFile( const QString & configFile ) QStringList searchPaths; if(! qgetenv("LMMS_THEME_PATH").isNull()) searchPaths << qgetenv("LMMS_THEME_PATH"); - searchPaths << artworkDir() << defaultArtworkDir(); - QDir::setSearchPaths( "resources", searchPaths); + searchPaths << themeDir() << defaultThemeDir(); + QDir::setSearchPaths("resources", searchPaths); // Create any missing subdirectories in the working dir, but only if the working dir exists - if( hasWorkingDir() ) + if(hasWorkingDir()) { createWorkingDir(); } @@ -572,72 +582,72 @@ void ConfigManager::loadConfigFile( const QString & configFile ) void ConfigManager::saveConfigFile() { - setValue( "paths", "artwork", m_artworkDir ); - setValue( "paths", "workingdir", m_workingDir ); - setValue( "paths", "vstdir", m_vstDir ); - setValue( "paths", "gigdir", m_gigDir ); - setValue( "paths", "sf2dir", m_sf2Dir ); - setValue( "paths", "laddir", m_ladDir ); + setValue("paths", "theme", m_themeDir); + setValue("paths", "workingdir", m_workingDir); + setValue("paths", "vstdir", m_vstDir); + setValue("paths", "gigdir", m_gigDir); + setValue("paths", "sf2dir", m_sf2Dir); + setValue("paths", "ladspadir", m_ladspaDir); #ifdef LMMS_HAVE_STK - setValue( "paths", "stkdir", m_stkDir ); + setValue("paths", "stkdir", m_stkDir); #endif #ifdef LMMS_HAVE_FLUIDSYNTH - setValue( "paths", "defaultsf2", m_defaultSoundfont ); + setValue("paths", "defaultsf2", m_sf2File); #endif - setValue( "paths", "backgroundartwork", m_backgroundArtwork ); + setValue("paths", "backgroundtheme", m_backgroundPicFile); - QDomDocument doc( "lmms-config-file" ); + QDomDocument doc("lmms-config-file"); - QDomElement lmms_config = doc.createElement( "lmms" ); - lmms_config.setAttribute( "version", m_version ); - doc.appendChild( lmms_config ); + QDomElement lmms_config = doc.createElement("lmms"); + lmms_config.setAttribute("version", m_version); + doc.appendChild(lmms_config); - for( settingsMap::iterator it = m_settings.begin(); - it != m_settings.end(); ++it ) + for(settingsMap::iterator it = m_settings.begin(); + it != m_settings.end(); ++it) { - QDomElement n = doc.createElement( it.key() ); - for( stringPairVector::iterator it2 = ( *it ).begin(); - it2 != ( *it ).end(); ++it2 ) + QDomElement n = doc.createElement(it.key()); + for(stringPairVector::iterator it2 = (*it).begin(); + it2 != (*it).end(); ++it2) { - n.setAttribute( ( *it2 ).first, ( *it2 ).second ); + n.setAttribute((*it2).first, (*it2).second); } - lmms_config.appendChild( n ); + lmms_config.appendChild(n); } - QDomElement recent_files = doc.createElement( "recentfiles" ); + QDomElement recent_files = doc.createElement("recentfiles"); - for( QStringList::iterator it = m_recentlyOpenedProjects.begin(); - it != m_recentlyOpenedProjects.end(); ++it ) + for(QStringList::iterator it = m_recentlyOpenedProjects.begin(); + it != m_recentlyOpenedProjects.end(); ++it) { - QDomElement n = doc.createElement( "file" ); - n.setAttribute( "path", *it ); - recent_files.appendChild( n ); + QDomElement n = doc.createElement("file"); + n.setAttribute("path", *it); + recent_files.appendChild(n); } - lmms_config.appendChild( recent_files ); + lmms_config.appendChild(recent_files); - QString xml = "\n" + doc.toString( 2 ); + QString xml = "\n" + doc.toString(2); - QFile outfile( m_lmmsRcFile ); - if( !outfile.open( QIODevice::WriteOnly | QIODevice::Truncate ) ) + QFile outfile(m_lmmsRcFile); + if(!outfile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QString title, message; - title = MainWindow::tr( "Could not open file" ); - message = MainWindow::tr( "Could not open file %1 " + title = MainWindow::tr("Could not open file"); + message = MainWindow::tr("Could not open file %1 " "for writing.\nPlease make " "sure you have write " "permission to the file and " "the directory containing the " "file and try again!" - ).arg( m_lmmsRcFile ); - if( gui ) + ).arg(m_lmmsRcFile); + if(gui) { - QMessageBox::critical( NULL, title, message, + QMessageBox::critical(NULL, title, message, QMessageBox::Ok, - QMessageBox::NoButton ); + QMessageBox::NoButton); } return; } - outfile.write( xml.toUtf8() ); + outfile.write(xml.toUtf8()); outfile.close(); } diff --git a/src/core/Engine.cpp b/src/core/Engine.cpp index d2b4a9cc2..ce82310fa 100644 --- a/src/core/Engine.cpp +++ b/src/core/Engine.cpp @@ -105,10 +105,10 @@ void LmmsCore::destroy() delete ConfigManager::inst(); } -float LmmsCore::framesPerTick(sample_rate_t sample_rate) +float LmmsCore::framesPerTick(sample_rate_t sampleRate) { - return sample_rate * 60.0f * 4 / - DefaultTicksPerTact / s_song->getTempo(); + return sampleRate * 60.0f * 4 / + DefaultTicksPerBar / s_song->getTempo(); } @@ -117,7 +117,7 @@ float LmmsCore::framesPerTick(sample_rate_t sample_rate) void LmmsCore::updateFramesPerTick() { s_framesPerTick = s_mixer->processingSampleRate() * 60.0f * 4 / - DefaultTicksPerTact / s_song->getTempo(); + DefaultTicksPerBar / s_song->getTempo(); } diff --git a/src/core/FxMixer.cpp b/src/core/FxMixer.cpp index 032090bf1..f04435e05 100644 --- a/src/core/FxMixer.cpp +++ b/src/core/FxMixer.cpp @@ -336,6 +336,11 @@ void FxMixer::deleteChannel( int index ) deleteChannelSend( ch->m_receives.first() ); } + // if m_lastSoloed was our index, reset it + if (m_lastSoloed == index) { m_lastSoloed = -1; } + // if m_lastSoloed is > delete index, it will move left + else if (m_lastSoloed > index) { --m_lastSoloed; } + // actually delete the channel m_fxChannels.remove(index); delete ch; @@ -373,6 +378,10 @@ void FxMixer::moveChannelLeft( int index ) // channels to swap int a = index - 1, b = index; + // check if m_lastSoloed is one of our swaps + if (m_lastSoloed == a) { m_lastSoloed = b; } + else if (m_lastSoloed == b) { m_lastSoloed = a; } + // go through every instrument and adjust for the channel index change QVector songTrackList = Engine::getSong()->tracks(); QVector bbTrackList = Engine::getBBTrackContainer()->tracks(); diff --git a/src/core/Mixer.cpp b/src/core/Mixer.cpp index 2550b072e..3f22a22e1 100644 --- a/src/core/Mixer.cpp +++ b/src/core/Mixer.cpp @@ -361,12 +361,12 @@ const surroundSampleFrame * Mixer::renderNextBuffer() // Stop crash with metronome if empty project Engine::getSong()->countTracks() ) { - tick_t ticksPerTact = MidiTime::ticksPerTact(); - if ( p.getTicks() % (ticksPerTact / 1 ) == 0 ) + tick_t ticksPerBar = MidiTime::ticksPerBar(); + if ( p.getTicks() % ( ticksPerBar / 1 ) == 0 ) { addPlayHandle( new SamplePlayHandle( "misc/metronome02.ogg" ) ); } - else if ( p.getTicks() % (ticksPerTact / + else if ( p.getTicks() % ( ticksPerBar / song->getTimeSigModel().getNumerator() ) == 0 ) { addPlayHandle( new SamplePlayHandle( "misc/metronome01.ogg" ) ); @@ -1247,7 +1247,7 @@ void Mixer::fifoWriter::run() disable_denormals(); #if 0 -#ifdef LMMS_BUILD_LINUX +#if defined(LMMS_BUILD_LINUX) || defined(LMMS_BUILD_FREEBSD) #ifdef LMMS_HAVE_SCHED_H cpu_set_t mask; CPU_ZERO( &mask ); @@ -1288,5 +1288,3 @@ void Mixer::fifoWriter::write( surroundSampleFrame * buffer ) m_mixer->m_doChangesMutex.unlock(); } - - diff --git a/src/core/NotePlayHandle.cpp b/src/core/NotePlayHandle.cpp index 0039f935a..9f934c619 100644 --- a/src/core/NotePlayHandle.cpp +++ b/src/core/NotePlayHandle.cpp @@ -196,7 +196,12 @@ void NotePlayHandle::play( sampleFrame * _working_buffer ) lock(); - if( m_totalFramesPlayed == 0 && !m_hasMidiNote + /* It is possible for NotePlayHandle::noteOff to be called before NotePlayHandle::play, + * which results in a note-on message being sent without a subsequent note-off message. + * Therefore, we check here whether the note has already been released before sending + * the note-on message. */ + if( !m_released + && m_totalFramesPlayed == 0 && !m_hasMidiNote && ( hasParent() || ! m_instrumentTrack->isArpeggioEnabled() ) ) { m_hasMidiNote = true; diff --git a/src/core/PresetPreviewPlayHandle.cpp b/src/core/PresetPreviewPlayHandle.cpp index ca0e52194..11b145b22 100644 --- a/src/core/PresetPreviewPlayHandle.cpp +++ b/src/core/PresetPreviewPlayHandle.cpp @@ -54,7 +54,7 @@ public: { } - virtual QString nodeName() const + QString nodeName() const override { return "previewtrackcontainer"; } diff --git a/src/core/ProjectRenderer.cpp b/src/core/ProjectRenderer.cpp index 71a5aaff8..19bdf4be8 100644 --- a/src/core/ProjectRenderer.cpp +++ b/src/core/ProjectRenderer.cpp @@ -168,7 +168,7 @@ void ProjectRenderer::run() { MemoryManager::ThreadGuard mmThreadGuard; Q_UNUSED(mmThreadGuard); #if 0 -#ifdef LMMS_BUILD_LINUX +#if defined(LMMS_BUILD_LINUX) || defined(LMMS_BUILD_FREEBSD) #ifdef LMMS_HAVE_SCHED_H cpu_set_t mask; CPU_ZERO( &mask ); diff --git a/src/core/SampleBuffer.cpp b/src/core/SampleBuffer.cpp index 779592529..d0c39b13a 100644 --- a/src/core/SampleBuffer.cpp +++ b/src/core/SampleBuffer.cpp @@ -370,11 +370,14 @@ void SampleBuffer::directFloatWrite ( sample_t * & _fbuf, f_cnt_t _frames, int _ void SampleBuffer::normalizeSampleRate( const sample_rate_t _src_sr, bool _keep_settings ) { + const sample_rate_t old_rate = m_sampleRate; // do samplerate-conversion to our default-samplerate if( _src_sr != mixerSampleRate() ) { SampleBuffer * resampled = resample( _src_sr, mixerSampleRate() ); + + m_sampleRate = mixerSampleRate(); MM_FREE( m_data ); m_frames = resampled->frames(); m_data = MM_ALLOC( sampleFrame, m_frames ); @@ -389,6 +392,16 @@ void SampleBuffer::normalizeSampleRate( const sample_rate_t _src_sr, m_loopStartFrame = m_startFrame = 0; m_loopEndFrame = m_endFrame = m_frames; } + else if( old_rate != mixerSampleRate() ) + { + auto old_rate_to_new_rate_ratio = static_cast(mixerSampleRate()) / old_rate; + + m_startFrame = qBound(0, f_cnt_t(m_startFrame*old_rate_to_new_rate_ratio), m_frames); + m_endFrame = qBound(m_startFrame, f_cnt_t(m_endFrame*old_rate_to_new_rate_ratio), m_frames); + m_loopStartFrame = qBound(0, f_cnt_t(m_loopStartFrame*old_rate_to_new_rate_ratio), m_frames); + m_loopEndFrame = qBound(m_loopStartFrame, f_cnt_t(m_loopEndFrame*old_rate_to_new_rate_ratio), m_frames); + m_sampleRate = mixerSampleRate(); + } } diff --git a/src/core/Song.cpp b/src/core/Song.cpp index 336aa3df2..78c9f422a 100644 --- a/src/core/Song.cpp +++ b/src/core/Song.cpp @@ -55,7 +55,7 @@ #include "PeakController.h" -tick_t MidiTime::s_ticksPerTact = DefaultTicksPerTact; +tick_t MidiTime::s_ticksPerBar = DefaultTicksPerBar; @@ -66,7 +66,7 @@ Song::Song() : this ) ) ), m_tempoModel( DefaultTempo, MinTempo, MaxTempo, this, tr( "Tempo" ) ), m_timeSigModel( this ), - m_oldTicksPerTact( DefaultTicksPerTact ), + m_oldTicksPerBar( DefaultTicksPerBar ), m_masterVolumeModel( 100, 0, 200, this, tr( "Master volume" ) ), m_masterPitchModel( 0, -12, 12, this, tr( "Master pitch" ) ), m_fileName(), @@ -86,7 +86,7 @@ Song::Song() : m_patternToPlay( NULL ), m_loopPattern( false ), m_elapsedTicks( 0 ), - m_elapsedTacts( 0 ), + m_elapsedBars( 0 ), m_loopRenderCount(1), m_loopRenderRemaining(1) { @@ -162,10 +162,10 @@ void Song::setTempo() void Song::setTimeSignature() { - MidiTime::setTicksPerTact( ticksPerTact() ); - emit timeSignatureChanged( m_oldTicksPerTact, ticksPerTact() ); + MidiTime::setTicksPerBar( ticksPerBar() ); + emit timeSignatureChanged( m_oldTicksPerBar, ticksPerBar() ); emit dataChanged(); - m_oldTicksPerTact = ticksPerTact(); + m_oldTicksPerBar = ticksPerBar(); m_vstSyncController.setTimeSignature( getTimeSigModel().getNumerator(), getTimeSigModel().getDenominator() ); @@ -286,20 +286,20 @@ void Song::processNextBuffer() int ticks = m_playPos[m_playMode].getTicks() + ( int )( currentFrame / framesPerTick ); - // did we play a whole tact? - if( ticks >= MidiTime::ticksPerTact() ) + // did we play a whole bar? + if( ticks >= MidiTime::ticksPerBar() ) { // per default we just continue playing even if // there's no more stuff to play // (song-play-mode) - int maxTact = m_playPos[m_playMode].getTact() + int maxBar = m_playPos[m_playMode].getBar() + 2; - // then decide whether to go over to next tact - // or to loop back to first tact + // then decide whether to go over to next bar + // or to loop back to first bar if( m_playMode == Mode_PlayBB ) { - maxTact = Engine::getBBTrackContainer() + maxBar = Engine::getBBTrackContainer() ->lengthOfCurrentBB(); } else if( m_playMode == Mode_PlayPattern && @@ -307,17 +307,17 @@ void Song::processNextBuffer() tl != NULL && tl->loopPointsEnabled() == false ) { - maxTact = m_patternToPlay->length() - .getTact(); + maxBar = m_patternToPlay->length() + .getBar(); } // end of played object reached? - if( m_playPos[m_playMode].getTact() + 1 - >= maxTact ) + if( m_playPos[m_playMode].getBar() + 1 + >= maxBar ) { // then start from beginning and keep // offset - ticks %= ( maxTact * MidiTime::ticksPerTact() ); + ticks %= ( maxBar * MidiTime::ticksPerBar() ); // wrap milli second counter setToTimeByTicks(ticks); @@ -407,8 +407,8 @@ void Song::processNextBuffer() m_playPos[m_playMode].setCurrentFrame( framesToPlay + currentFrame ); m_elapsedMilliSeconds[m_playMode] += MidiTime::ticksToMilliseconds(framesToPlay / framesPerTick, getTempo()); - m_elapsedTacts = m_playPos[Mode_PlaySong].getTact(); - m_elapsedTicks = ( m_playPos[Mode_PlaySong].getTicks() % ticksPerTact() ) / 48; + m_elapsedBars = m_playPos[Mode_PlaySong].getBar(); + m_elapsedTicks = ( m_playPos[Mode_PlaySong].getTicks() % ticksPerBar() ) / 48; } } @@ -619,7 +619,7 @@ void Song::updateLength() continue; } - const tact_t cur = ( *it )->length(); + const bar_t cur = ( *it )->length(); if( cur > m_length ) { m_length = cur; @@ -805,7 +805,7 @@ void Song::insertBar() for( TrackList::const_iterator it = tracks().begin(); it != tracks().end(); ++it ) { - ( *it )->insertTact( m_playPos[Mode_PlaySong] ); + ( *it )->insertBar( m_playPos[Mode_PlaySong] ); } m_tracksMutex.unlock(); } @@ -819,7 +819,7 @@ void Song::removeBar() for( TrackList::const_iterator it = tracks().begin(); it != tracks().end(); ++it ) { - ( *it )->removeTact( m_playPos[Mode_PlaySong] ); + ( *it )->removeBar( m_playPos[Mode_PlaySong] ); } m_tracksMutex.unlock(); } diff --git a/src/core/Track.cpp b/src/core/Track.cpp index fe66ab4a5..5c61dc5ab 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -73,6 +73,10 @@ */ const int RESIZE_GRIP_WIDTH = 4; +/*! Alternate between a darker and a lighter background color every 4 bars + */ +const int BARS_PER_GROUP = 4; + /*! A pointer for that text bubble used when moving segments, etc. * @@ -489,8 +493,8 @@ void TrackContentObjectView::updateLength() else { setFixedWidth( - static_cast( m_tco->length() * pixelsPerTact() / - MidiTime::ticksPerTact() ) + 1 /*+ + static_cast( m_tco->length() * pixelsPerBar() / + MidiTime::ticksPerBar() ) + 1 /*+ TCO_BORDER_WIDTH * 2-1*/ ); } m_trackView->trackContainerView()->update(); @@ -528,6 +532,7 @@ void TrackContentObjectView::dragEnterEvent( QDragEnterEvent * dee ) { TrackContentWidget * tcw = getTrackView()->getTrackContentWidget(); MidiTime tcoPos = MidiTime( m_tco->startPosition() ); + if( tcw->canPasteSelection( tcoPos, dee ) == false ) { dee->ignore(); @@ -567,6 +572,7 @@ void TrackContentObjectView::dropEvent( QDropEvent * de ) { TrackContentWidget * tcw = getTrackView()->getTrackContentWidget(); MidiTime tcoPos = MidiTime( m_tco->startPosition() ); + if( tcw->pasteSelection( tcoPos, de ) == true ) { de->accept(); @@ -656,7 +662,7 @@ DataFile TrackContentObjectView::createTCODataFiles( // initialTrackIndex is the index of the track that was touched metadata.setAttribute( "initialTrackIndex", initialTrackIndex ); metadata.setAttribute( "trackContainerId", tc->id() ); - // grabbedTCOPos is the pos of the tact containing the TCO we grabbed + // grabbedTCOPos is the pos of the bar containing the TCO we grabbed metadata.setAttribute( "grabbedTCOPos", m_tco->startPosition() ); dataFile.content().appendChild( metadata ); @@ -770,23 +776,23 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me ) { s_textFloat->setTitle( tr( "Current position" ) ); s_textFloat->setText( QString( "%1:%2" ). - arg( m_tco->startPosition().getTact() + 1 ). + arg( m_tco->startPosition().getBar() + 1 ). arg( m_tco->startPosition().getTicks() % - MidiTime::ticksPerTact() ) ); + MidiTime::ticksPerBar() ) ); } else if( m_action == Resize || m_action == ResizeLeft ) { s_textFloat->setTitle( tr( "Current length" ) ); s_textFloat->setText( tr( "%1:%2 (%3:%4 to %5:%6)" ). - arg( m_tco->length().getTact() ). + arg( m_tco->length().getBar() ). arg( m_tco->length().getTicks() % - MidiTime::ticksPerTact() ). - arg( m_tco->startPosition().getTact() + 1 ). + MidiTime::ticksPerBar() ). + arg( m_tco->startPosition().getBar() + 1 ). arg( m_tco->startPosition().getTicks() % - MidiTime::ticksPerTact() ). - arg( m_tco->endPosition().getTact() + 1 ). + MidiTime::ticksPerBar() ). + arg( m_tco->endPosition().getBar() + 1 ). arg( m_tco->endPosition().getTicks() % - MidiTime::ticksPerTact() ) ); + MidiTime::ticksPerBar() ) ); } // s_textFloat->reparent( this ); // setup text-float as if TCO was already moved/resized @@ -893,7 +899,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) m_hint = NULL; } - const float ppt = m_trackView->trackContainerView()->pixelsPerTact(); + const float ppb = m_trackView->trackContainerView()->pixelsPerBar(); if( m_action == Move ) { MidiTime newPos = draggedTCOPos( me ); @@ -903,9 +909,9 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) m_tco->movePosition( newPos ); m_trackView->getTrackContentWidget()->changePosition(); s_textFloat->setText( QString( "%1:%2" ). - arg( newPos.getTact() + 1 ). + arg( newPos.getBar() + 1 ). arg( newPos.getTicks() % - MidiTime::ticksPerTact() ) ); + MidiTime::ticksPerBar() ) ); s_textFloat->moveGlobal( this, QPoint( width() + 2, height() + 2 ) ); } else if( m_action == MoveSelection ) @@ -945,12 +951,12 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) const bool unquantized = (me->modifiers() & Qt::ControlModifier) || (me->modifiers() & Qt::AltModifier); const float snapSize = gui->songEditor()->m_editor->getSnapSize(); // Length in ticks of one snap increment - const MidiTime snapLength = MidiTime( (int)(snapSize * MidiTime::ticksPerTact()) ); + const MidiTime snapLength = MidiTime( (int)(snapSize * MidiTime::ticksPerBar()) ); if( m_action == Resize ) { // The clip's new length - MidiTime l = static_cast( me->x() * MidiTime::ticksPerTact() / ppt ); + MidiTime l = static_cast( me->x() * MidiTime::ticksPerBar() / ppb ); if ( unquantized ) { // We want to preserve this adjusted offset, @@ -985,8 +991,8 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) const int x = mapToParent( me->pos() ).x() - m_initialMousePos.x(); MidiTime t = qMax( 0, (int) - m_trackView->trackContainerView()->currentPosition()+ - static_cast( x * MidiTime::ticksPerTact() / ppt ) ); + m_trackView->trackContainerView()->currentPosition() + + static_cast( x * MidiTime::ticksPerBar() / ppb ) ); if( unquantized ) { // We want to preserve this adjusted offset, @@ -1023,15 +1029,15 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) } } s_textFloat->setText( tr( "%1:%2 (%3:%4 to %5:%6)" ). - arg( m_tco->length().getTact() ). + arg( m_tco->length().getBar() ). arg( m_tco->length().getTicks() % - MidiTime::ticksPerTact() ). - arg( m_tco->startPosition().getTact() + 1 ). + MidiTime::ticksPerBar() ). + arg( m_tco->startPosition().getBar() + 1 ). arg( m_tco->startPosition().getTicks() % - MidiTime::ticksPerTact() ). - arg( m_tco->endPosition().getTact() + 1 ). + MidiTime::ticksPerBar() ). + arg( m_tco->endPosition().getBar() + 1 ). arg( m_tco->endPosition().getTicks() % - MidiTime::ticksPerTact() ) ); + MidiTime::ticksPerBar() ) ); s_textFloat->moveGlobal( this, QPoint( width() + 2, height() + 2) ); } else @@ -1127,13 +1133,13 @@ void TrackContentObjectView::contextMenuEvent( QContextMenuEvent * cme ) -/*! \brief How many pixels a tact (bar) takes for this trackContentObjectView. +/*! \brief How many pixels a bar takes for this trackContentObjectView. * - * \return the number of pixels per tact (bar). + * \return the number of pixels per bar. */ -float TrackContentObjectView::pixelsPerTact() +float TrackContentObjectView::pixelsPerBar() { - return m_trackView->trackContainerView()->pixelsPerTact(); + return m_trackView->trackContainerView()->pixelsPerBar(); } @@ -1181,11 +1187,11 @@ bool TrackContentObjectView::mouseMovedDistance( QMouseEvent * me, int distance */ MidiTime TrackContentObjectView::draggedTCOPos( QMouseEvent * me ) { - //Pixels per tact - const float ppt = m_trackView->trackContainerView()->pixelsPerTact(); + //Pixels per bar + const float ppb = m_trackView->trackContainerView()->pixelsPerBar(); // The pixel distance that the mouse has moved const int mouseOff = mapToGlobal(me->pos()).x() - m_initialMouseGlobalPos.x(); - MidiTime newPos = m_initialTCOPos + mouseOff * MidiTime::ticksPerTact() / ppt; + MidiTime newPos = m_initialTCOPos + mouseOff * MidiTime::ticksPerBar() / ppb; MidiTime offset = newPos - m_initialTCOPos; // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize if ( me->button() != Qt::NoButton @@ -1264,13 +1270,12 @@ TrackContentWidget::~TrackContentWidget() void TrackContentWidget::updateBackground() { - const int tactsPerBar = 4; const TrackContainerView * tcv = m_trackView->trackContainerView(); - // Assume even-pixels-per-tact. Makes sense, should be like this anyways - int ppt = static_cast( tcv->pixelsPerTact() ); + // Assume even-pixels-per-bar. Makes sense, should be like this anyways + int ppb = static_cast( tcv->pixelsPerBar() ); - int w = ppt * tactsPerBar; + int w = ppb * BARS_PER_GROUP; int h = height(); m_background = QPixmap( w * 2, height() ); QPainter pmp( &m_background ); @@ -1281,13 +1286,13 @@ void TrackContentWidget::updateBackground() // draw lines // vertical lines pmp.setPen( QPen( gridColor(), 1 ) ); - for( float x = 0; x < w * 2; x += ppt ) + for( float x = 0; x < w * 2; x += ppb ) { pmp.drawLine( QLineF( x, 0.0, x, h ) ); } pmp.setPen( QPen( embossColor(), 1 ) ); - for( float x = 1.0; x < w * 2; x += ppt ) + for( float x = 1.0; x < w * 2; x += ppb ) { pmp.drawLine( QLineF( x, 0.0, x, h ) ); } @@ -1382,7 +1387,7 @@ void TrackContentWidget::changePosition( const MidiTime & newPos ) it != m_tcoViews.end(); ++it ) { if( ( *it )->getTrackContentObject()-> - startPosition().getTact() == curBB ) + startPosition().getBar() == curBB ) { ( *it )->move( 0, ( *it )->y() ); ( *it )->raise(); @@ -1398,7 +1403,7 @@ void TrackContentWidget::changePosition( const MidiTime & newPos ) it != m_tcoViews.end(); ++it ) { if( ( *it )->getTrackContentObject()-> - startPosition().getTact() != curBB ) + startPosition().getBar() != curBB ) { ( *it )->hide(); } @@ -1415,7 +1420,7 @@ void TrackContentWidget::changePosition( const MidiTime & newPos ) const int begin = pos; const int end = endPosition( pos ); - const float ppt = m_trackView->trackContainerView()->pixelsPerTact(); + const float ppb = m_trackView->trackContainerView()->pixelsPerBar(); setUpdatesEnabled( false ); for( tcoViewVector::iterator it = m_tcoViews.begin(); @@ -1432,8 +1437,8 @@ void TrackContentWidget::changePosition( const MidiTime & newPos ) ( te >= begin && te <= end ) || ( ts <= begin && te >= end ) ) { - tcov->move( static_cast( ( ts - begin ) * ppt / - MidiTime::ticksPerTact() ), + tcov->move( static_cast( ( ts - begin ) * ppb / + MidiTime::ticksPerBar() ), tcov->y() ); if( !tcov->isVisible() ) { @@ -1454,7 +1459,7 @@ void TrackContentWidget::changePosition( const MidiTime & newPos ) -/*! \brief Return the position of the trackContentWidget in Tacts. +/*! \brief Return the position of the trackContentWidget in bars. * * \param mouseX the mouse's current X position in pixels. */ @@ -1463,8 +1468,8 @@ MidiTime TrackContentWidget::getPosition( int mouseX ) TrackContainerView * tv = m_trackView->trackContainerView(); return MidiTime( tv->currentPosition() + mouseX * - MidiTime::ticksPerTact() / - static_cast( tv->pixelsPerTact() ) ); + MidiTime::ticksPerBar() / + static_cast( tv->pixelsPerBar() ) ); } @@ -1477,7 +1482,7 @@ MidiTime TrackContentWidget::getPosition( int mouseX ) void TrackContentWidget::dragEnterEvent( QDragEnterEvent * dee ) { MidiTime tcoPos = getPosition( dee->pos().x() ); - if( canPasteSelection( tcoPos, dee ) == false ) + if( canPasteSelection( tcoPos, dee ) == false ) { dee->ignore(); } @@ -1518,7 +1523,7 @@ bool TrackContentWidget::canPasteSelection( MidiTime tcoPos, const QDropEvent* d QDomElement metadata = dataFile.content().firstChildElement( "copyMetadata" ); QDomAttr tcoPosAttr = metadata.attributeNode( "grabbedTCOPos" ); MidiTime grabbedTCOPos = tcoPosAttr.value().toInt(); - MidiTime grabbedTCOTact = MidiTime( grabbedTCOPos.getTact(), 0 ); + MidiTime grabbedTCOBar = MidiTime( grabbedTCOPos.getBar(), 0 ); // Extract the track index that was originally clicked QDomAttr tiAttr = metadata.attributeNode( "initialTrackIndex" ); @@ -1528,10 +1533,10 @@ bool TrackContentWidget::canPasteSelection( MidiTime tcoPos, const QDropEvent* d const TrackContainer::TrackList tracks = t->trackContainer()->tracks(); const int currentTrackIndex = tracks.indexOf( t ); - // Don't paste if we're on the same tact + // Don't paste if we're on the same bar auto sourceTrackContainerId = metadata.attributeNode( "trackContainerId" ).value().toUInt(); if( de->source() && sourceTrackContainerId == t->trackContainer()->id() && - tcoPos == grabbedTCOTact && currentTrackIndex == initialTrackIndex ) + tcoPos == grabbedTCOBar && currentTrackIndex == initialTrackIndex ) { return false; } @@ -1596,7 +1601,7 @@ bool TrackContentWidget::pasteSelection( MidiTime tcoPos, QDropEvent * de ) QDomAttr tcoPosAttr = metadata.attributeNode( "grabbedTCOPos" ); MidiTime grabbedTCOPos = tcoPosAttr.value().toInt(); - // Snap the mouse position to the beginning of the dropped tact, in ticks + // Snap the mouse position to the beginning of the dropped bar, in ticks const TrackContainer::TrackList tracks = getTrack()->trackContainer()->tracks(); const int currentTrackIndex = tracks.indexOf( getTrack() ); @@ -1631,7 +1636,7 @@ bool TrackContentWidget::pasteSelection( MidiTime tcoPos, QDropEvent * de ) // The new position is the old position plus the offset. MidiTime pos = tcoElement.attributeNode( "pos" ).value().toInt() + offset; // If we land on ourselves, offset by one snap - MidiTime shift = MidiTime::ticksPerTact() * gui->songEditor()->m_editor->getSnapSize(); + MidiTime shift = MidiTime::ticksPerBar() * gui->songEditor()->m_editor->getSnapSize(); if (offset == 0) { pos += shift; } TrackContentObject * tco = t->createTCO( pos ); @@ -1695,8 +1700,8 @@ void TrackContentWidget::mousePressEvent( QMouseEvent * me ) so.at( i )->setSelected( false); } getTrack()->addJournalCheckPoint(); - const MidiTime pos = getPosition( me->x() ).getTact() * - MidiTime::ticksPerTact(); + const MidiTime pos = getPosition( me->x() ).getBar() * + MidiTime::ticksPerBar(); TrackContentObject * tco = getTrack()->createTCO( pos ); tco->saveJournallingState( false ); @@ -1714,15 +1719,15 @@ void TrackContentWidget::mousePressEvent( QMouseEvent * me ) */ void TrackContentWidget::paintEvent( QPaintEvent * pe ) { - // Assume even-pixels-per-tact. Makes sense, should be like this anyways + // Assume even-pixels-per-bar. Makes sense, should be like this anyways const TrackContainerView * tcv = m_trackView->trackContainerView(); - int ppt = static_cast( tcv->pixelsPerTact() ); + int ppb = static_cast( tcv->pixelsPerBar() ); QPainter p( this ); // Don't draw background on BB-Editor if( m_trackView->trackContainerView() != gui->getBBEditor()->trackContainerView() ) { p.drawTiledPixmap( rect(), m_background, QPoint( - tcv->currentPosition().getTact() * ppt, 0 ) ); + tcv->currentPosition().getBar() * ppb, 0 ) ); } } @@ -1755,15 +1760,15 @@ Track * TrackContentWidget::getTrack() -/*! \brief Return the end position of the trackContentWidget in Tacts. +/*! \brief Return the end position of the trackContentWidget in Bars. * * \param posStart the starting position of the Widget (from getPosition()) */ MidiTime TrackContentWidget::endPosition( const MidiTime & posStart ) { - const float ppt = m_trackView->trackContainerView()->pixelsPerTact(); + const float ppb = m_trackView->trackContainerView()->pixelsPerBar(); const int w = width(); - return posStart + static_cast( w * MidiTime::ticksPerTact() / ppt ); + return posStart + static_cast( w * MidiTime::ticksPerBar() / ppb ); } @@ -2417,7 +2422,7 @@ TrackContentObject * Track::getTCO( int tcoNum ) } printf( "called Track::getTCO( %d ), " "but TCO %d doesn't exist\n", tcoNum, tcoNum ); - return createTCO( tcoNum * MidiTime::ticksPerTact() ); + return createTCO( tcoNum * MidiTime::ticksPerBar() ); } @@ -2525,17 +2530,17 @@ void Track::createTCOsForBB( int bb ) * in ascending order by TCO time, once we hit a TCO that was earlier * than the insert time, we could fall out of the loop early. */ -void Track::insertTact( const MidiTime & pos ) +void Track::insertBar( const MidiTime & pos ) { // we'll increase the position of every TCO, positioned behind pos, by - // one tact + // one bar for( tcoVector::iterator it = m_trackContentObjects.begin(); it != m_trackContentObjects.end(); ++it ) { if( ( *it )->startPosition() >= pos ) { ( *it )->movePosition( (*it)->startPosition() + - MidiTime::ticksPerTact() ); + MidiTime::ticksPerBar() ); } } } @@ -2547,17 +2552,17 @@ void Track::insertTact( const MidiTime & pos ) * * \param pos The time at which we want to remove the bar. */ -void Track::removeTact( const MidiTime & pos ) +void Track::removeBar( const MidiTime & pos ) { // we'll decrease the position of every TCO, positioned behind pos, by - // one tact + // one bar for( tcoVector::iterator it = m_trackContentObjects.begin(); it != m_trackContentObjects.end(); ++it ) { if( ( *it )->startPosition() >= pos ) { ( *it )->movePosition( qMax( ( *it )->startPosition() - - MidiTime::ticksPerTact(), 0 ) ); + MidiTime::ticksPerBar(), 0 ) ); } } } @@ -2571,7 +2576,7 @@ void Track::removeTact( const MidiTime & pos ) * keeping track of the latest time found in ticks. Then we return * that in bars by dividing by the number of ticks per bar. */ -tact_t Track::length() const +bar_t Track::length() const { // find last end-position tick_t last = 0; @@ -2591,7 +2596,7 @@ tact_t Track::length() const } } - return last / MidiTime::ticksPerTact(); + return last / MidiTime::ticksPerBar(); } diff --git a/src/core/TrackContainer.cpp b/src/core/TrackContainer.cpp index edea9aa14..95dd46f29 100644 --- a/src/core/TrackContainer.cpp +++ b/src/core/TrackContainer.cpp @@ -313,7 +313,7 @@ AutomatedValueMap TrackContainer::automatedValuesFromTracks(const TrackList &tra MidiTime bbTime = time - tco->startPosition(); bbTime = std::min(bbTime, tco->length()); - bbTime = bbTime % (bbContainer->lengthOfBB(bbIndex) * MidiTime::ticksPerTact()); + bbTime = bbTime % (bbContainer->lengthOfBB(bbIndex) * MidiTime::ticksPerBar()); auto bbValues = bbContainer->automatedValuesAt(bbTime, bbIndex); for (auto it=bbValues.begin(); it != bbValues.end(); it++) @@ -344,8 +344,3 @@ DummyTrackContainer::DummyTrackContainer() : m_dummyInstrumentTrack->setJournalling( false ); } - - - - - diff --git a/src/core/audio/AudioJack.cpp b/src/core/audio/AudioJack.cpp index e149f5cbd..aebfe5e1c 100644 --- a/src/core/audio/AudioJack.cpp +++ b/src/core/audio/AudioJack.cpp @@ -454,7 +454,7 @@ AudioJack::setupWidget::setupWidget( QWidget * _parent ) : m_clientName = new QLineEdit( cn, this ); m_clientName->setGeometry( 10, 20, 160, 20 ); - QLabel * cn_lbl = new QLabel( tr( "CLIENT-NAME" ), this ); + QLabel * cn_lbl = new QLabel( tr( "Client name" ), this ); cn_lbl->setFont( pointSize<7>( cn_lbl->font() ) ); cn_lbl->setGeometry( 10, 40, 160, 10 ); @@ -466,7 +466,7 @@ AudioJack::setupWidget::setupWidget( QWidget * _parent ) : m_channels = new LcdSpinBox( 1, this ); m_channels->setModel( m ); - m_channels->setLabel( tr( "CHANNELS" ) ); + m_channels->setLabel( tr( "Channels" ) ); m_channels->move( 180, 20 ); } diff --git a/src/core/audio/AudioOss.cpp b/src/core/audio/AudioOss.cpp index c9ad01801..cbf9278a7 100644 --- a/src/core/audio/AudioOss.cpp +++ b/src/core/audio/AudioOss.cpp @@ -59,7 +59,7 @@ #ifndef _PATH_DEV_DSP -#ifdef __OpenBSD__ +#if defined(__NetBSD__) || defined(__OpenBSD__) #define _PATH_DEV_DSP "/dev/audio" #else #define _PATH_DEV_DSP "/dev/dsp" @@ -327,7 +327,7 @@ AudioOss::setupWidget::setupWidget( QWidget * _parent ) : m_device = new QLineEdit( probeDevice(), this ); m_device->setGeometry( 10, 20, 160, 20 ); - QLabel * dev_lbl = new QLabel( tr( "DEVICE" ), this ); + QLabel * dev_lbl = new QLabel( tr( "Device" ), this ); dev_lbl->setFont( pointSize<7>( dev_lbl->font() ) ); dev_lbl->setGeometry( 10, 40, 160, 10 ); @@ -339,7 +339,7 @@ AudioOss::setupWidget::setupWidget( QWidget * _parent ) : m_channels = new LcdSpinBox( 1, this ); m_channels->setModel( m ); - m_channels->setLabel( tr( "CHANNELS" ) ); + m_channels->setLabel( tr( "Channels" ) ); m_channels->move( 180, 20 ); } diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index 61dca4a22..ad67277ab 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -412,14 +412,14 @@ AudioPortAudio::setupWidget::setupWidget( QWidget * _parent ) : m_backend = new ComboBox( this, "BACKEND" ); m_backend->setGeometry( 64, 15, 260, 20 ); - QLabel * backend_lbl = new QLabel( tr( "BACKEND" ), this ); + QLabel * backend_lbl = new QLabel( tr( "Backend" ), this ); backend_lbl->setFont( pointSize<7>( backend_lbl->font() ) ); backend_lbl->move( 8, 18 ); m_device = new ComboBox( this, "DEVICE" ); m_device->setGeometry( 64, 35, 260, 20 ); - QLabel * dev_lbl = new QLabel( tr( "DEVICE" ), this ); + QLabel * dev_lbl = new QLabel( tr( "Device" ), this ); dev_lbl->setFont( pointSize<7>( dev_lbl->font() ) ); dev_lbl->move( 8, 38 ); @@ -431,7 +431,7 @@ AudioPortAudio::setupWidget::setupWidget( QWidget * _parent ) : m_channels = new LcdSpinBox( 1, this ); m_channels->setModel( m ); - m_channels->setLabel( tr( "CHANNELS" ) ); + m_channels->setLabel( tr( "Channels" ) ); m_channels->move( 308, 20 );*/ connect( &m_setupUtil.m_backendModel, SIGNAL( dataChanged() ), diff --git a/src/core/audio/AudioPulseAudio.cpp b/src/core/audio/AudioPulseAudio.cpp index 857ef981b..af14960a7 100644 --- a/src/core/audio/AudioPulseAudio.cpp +++ b/src/core/audio/AudioPulseAudio.cpp @@ -314,7 +314,7 @@ AudioPulseAudio::setupWidget::setupWidget( QWidget * _parent ) : m_device = new QLineEdit( AudioPulseAudio::probeDevice(), this ); m_device->setGeometry( 10, 20, 160, 20 ); - QLabel * dev_lbl = new QLabel( tr( "DEVICE" ), this ); + QLabel * dev_lbl = new QLabel( tr( "Device" ), this ); dev_lbl->setFont( pointSize<7>( dev_lbl->font() ) ); dev_lbl->setGeometry( 10, 40, 160, 10 ); @@ -326,7 +326,7 @@ AudioPulseAudio::setupWidget::setupWidget( QWidget * _parent ) : m_channels = new LcdSpinBox( 1, this ); m_channels->setModel( m ); - m_channels->setLabel( tr( "CHANNELS" ) ); + m_channels->setLabel( tr( "Channels" ) ); m_channels->move( 180, 20 ); } diff --git a/src/core/audio/AudioSdl.cpp b/src/core/audio/AudioSdl.cpp index 42adb9b33..b970ba630 100644 --- a/src/core/audio/AudioSdl.cpp +++ b/src/core/audio/AudioSdl.cpp @@ -325,7 +325,7 @@ AudioSdl::setupWidget::setupWidget( QWidget * _parent ) : m_device = new QLineEdit( dev, this ); m_device->setGeometry( 10, 20, 160, 20 ); - QLabel * dev_lbl = new QLabel( tr( "DEVICE" ), this ); + QLabel * dev_lbl = new QLabel( tr( "Device" ), this ); dev_lbl->setFont( pointSize<7>( dev_lbl->font() ) ); dev_lbl->setGeometry( 10, 40, 160, 10 ); diff --git a/src/core/audio/AudioSndio.cpp b/src/core/audio/AudioSndio.cpp index 853d734d5..24bef9246 100644 --- a/src/core/audio/AudioSndio.cpp +++ b/src/core/audio/AudioSndio.cpp @@ -193,7 +193,7 @@ AudioSndio::setupWidget::setupWidget( QWidget * _parent ) : m_device = new QLineEdit( "", this ); m_device->setGeometry( 10, 20, 160, 20 ); - QLabel * dev_lbl = new QLabel( tr( "DEVICE" ), this ); + QLabel * dev_lbl = new QLabel( tr( "Device" ), this ); dev_lbl->setFont( pointSize<6>( dev_lbl->font() ) ); dev_lbl->setGeometry( 10, 40, 160, 10 ); @@ -205,7 +205,7 @@ AudioSndio::setupWidget::setupWidget( QWidget * _parent ) : m_channels = new LcdSpinBox( 1, this ); m_channels->setModel( m ); - m_channels->setLabel( tr( "CHANNELS" ) ); + m_channels->setLabel( tr( "Channels" ) ); m_channels->move( 180, 20 ); } diff --git a/src/core/audio/AudioSoundIo.cpp b/src/core/audio/AudioSoundIo.cpp index cde14a1c5..2c3d493a6 100644 --- a/src/core/audio/AudioSoundIo.cpp +++ b/src/core/audio/AudioSoundIo.cpp @@ -426,14 +426,14 @@ AudioSoundIo::setupWidget::setupWidget( QWidget * _parent ) : m_backend = new ComboBox( this, "BACKEND" ); m_backend->setGeometry( 64, 15, 260, 20 ); - QLabel * backend_lbl = new QLabel( tr( "BACKEND" ), this ); + QLabel * backend_lbl = new QLabel( tr( "Backend" ), this ); backend_lbl->setFont( pointSize<7>( backend_lbl->font() ) ); backend_lbl->move( 8, 18 ); m_device = new ComboBox( this, "DEVICE" ); m_device->setGeometry( 64, 35, 260, 20 ); - QLabel * dev_lbl = new QLabel( tr( "DEVICE" ), this ); + QLabel * dev_lbl = new QLabel( tr( "Device" ), this ); dev_lbl->setFont( pointSize<7>( dev_lbl->font() ) ); dev_lbl->move( 8, 38 ); diff --git a/src/core/fft_helpers.cpp b/src/core/fft_helpers.cpp index bc7d289e3..2cf54b7f2 100644 --- a/src/core/fft_helpers.cpp +++ b/src/core/fft_helpers.cpp @@ -66,6 +66,7 @@ int normalize(const float *abs_spectrum, float *norm_spectrum, unsigned int bin_ if (abs_spectrum == NULL || norm_spectrum == NULL) {return -1;} if (bin_count == 0 || block_size == 0) {return -1;} + block_size /= 2; for (i = 0; i < bin_count; i++) { norm_spectrum[i] = abs_spectrum[i] / block_size; diff --git a/src/core/main.cpp b/src/core/main.cpp index 1a1d61d8c..531a0a4da 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -721,7 +721,7 @@ int main( int argc, char * * argv ) // try to set realtime priority -#ifdef LMMS_BUILD_LINUX +#if defined(LMMS_BUILD_LINUX) || defined(LMMS_BUILD_FREEBSD) #ifdef LMMS_HAVE_SCHED_H #ifndef __OpenBSD__ struct sched_param sparam; diff --git a/src/core/midi/MidiAlsaSeq.cpp b/src/core/midi/MidiAlsaSeq.cpp index e420ebc08..56fd956d4 100644 --- a/src/core/midi/MidiAlsaSeq.cpp +++ b/src/core/midi/MidiAlsaSeq.cpp @@ -563,7 +563,7 @@ void MidiAlsaSeq::run() case SND_SEQ_EVENT_CONTROLLER: dest->processInEvent( MidiEvent( - MidiControlChange, + MidiControlChange, ev->data.control.channel, ev->data.control.param, ev->data.control.value, source ), @@ -572,11 +572,11 @@ void MidiAlsaSeq::run() case SND_SEQ_EVENT_PGMCHANGE: dest->processInEvent( MidiEvent( - MidiProgramChange, + MidiProgramChange, ev->data.control.channel, - ev->data.control.param, - ev->data.control.value, source ), - MidiTime() ); + ev->data.control.value, 0, + source ), + MidiTime() ); break; case SND_SEQ_EVENT_CHANPRESS: diff --git a/src/core/midi/MidiClient.cpp b/src/core/midi/MidiClient.cpp index 03eec4e38..e37f59c06 100644 --- a/src/core/midi/MidiClient.cpp +++ b/src/core/midi/MidiClient.cpp @@ -222,12 +222,16 @@ void MidiClientRaw::parseData( const unsigned char c ) case MidiNoteOff: case MidiNoteOn: case MidiKeyPressure: - case MidiProgramChange: case MidiChannelPressure: m_midiParseData.m_midiEvent.setKey( m_midiParseData.m_buffer[0] - KeysPerOctave ); m_midiParseData.m_midiEvent.setVelocity( m_midiParseData.m_buffer[1] ); break; + case MidiProgramChange: + m_midiParseData.m_midiEvent.setKey( m_midiParseData.m_buffer[0] ); + m_midiParseData.m_midiEvent.setVelocity( m_midiParseData.m_buffer[1] ); + break; + case MidiControlChange: m_midiParseData.m_midiEvent.setControllerNumber( m_midiParseData.m_buffer[0] ); m_midiParseData.m_midiEvent.setControllerValue( m_midiParseData.m_buffer[1] ); diff --git a/src/core/midi/MidiOss.cpp b/src/core/midi/MidiOss.cpp index a8e948efc..c1c990b0b 100644 --- a/src/core/midi/MidiOss.cpp +++ b/src/core/midi/MidiOss.cpp @@ -71,7 +71,11 @@ QString MidiOss::probeDevice() { return getenv( "MIDIDEV" ); } +#ifdef __NetBSD__ + return "/dev/rmidi0"; +#else return "/dev/midi"; +#endif } return dev; } diff --git a/src/core/midi/MidiTime.cpp b/src/core/midi/MidiTime.cpp index 82ed642ba..4e718a1d8 100644 --- a/src/core/midi/MidiTime.cpp +++ b/src/core/midi/MidiTime.cpp @@ -53,8 +53,8 @@ int TimeSig::denominator() const -MidiTime::MidiTime( const tact_t tact, const tick_t ticks ) : - m_ticks( tact * s_ticksPerTact + ticks ) +MidiTime::MidiTime( const bar_t bar, const tick_t ticks ) : + m_ticks( bar * s_ticksPerBar + ticks ) { } @@ -66,7 +66,7 @@ MidiTime::MidiTime( const tick_t ticks ) : MidiTime MidiTime::quantize(float bars) const { //The intervals we should snap to, our new position should be a factor of this - int interval = s_ticksPerTact * bars; + int interval = s_ticksPerBar * bars; //The lower position we could snap to int lowPos = m_ticks / interval; //Offset from the lower position @@ -78,9 +78,9 @@ MidiTime MidiTime::quantize(float bars) const } -MidiTime MidiTime::toAbsoluteTact() const +MidiTime MidiTime::toAbsoluteBar() const { - return getTact() * s_ticksPerTact; + return getBar() * s_ticksPerBar; } @@ -98,15 +98,15 @@ MidiTime& MidiTime::operator-=( const MidiTime& time ) } -tact_t MidiTime::getTact() const +bar_t MidiTime::getBar() const { - return m_ticks / s_ticksPerTact; + return m_ticks / s_ticksPerBar; } -tact_t MidiTime::nextFullTact() const +bar_t MidiTime::nextFullBar() const { - return (m_ticks + (s_ticksPerTact-1)) / s_ticksPerTact; + return ( m_ticks + ( s_ticksPerBar - 1 ) ) / s_ticksPerBar; } @@ -131,23 +131,23 @@ MidiTime::operator int() const tick_t MidiTime::ticksPerBeat( const TimeSig &sig ) const { // (number of ticks per bar) divided by (number of beats per bar) - return ticksPerTact(sig) / sig.numerator(); + return ticksPerBar(sig) / sig.numerator(); } tick_t MidiTime::getTickWithinBar( const TimeSig &sig ) const { - return m_ticks % ticksPerTact(sig); + return m_ticks % ticksPerBar( sig ); } tick_t MidiTime::getBeatWithinBar( const TimeSig &sig ) const { - return getTickWithinBar(sig) / ticksPerBeat(sig); + return getTickWithinBar( sig ) / ticksPerBeat( sig ); } tick_t MidiTime::getTickWithinBeat( const TimeSig &sig ) const { - return getTickWithinBar(sig) % ticksPerBeat(sig); + return getTickWithinBar( sig ) % ticksPerBeat( sig ); } @@ -160,9 +160,9 @@ f_cnt_t MidiTime::frames( const float framesPerTick ) const return 0; } -double MidiTime::getTimeInMilliseconds(bpm_t beatsPerMinute) const +double MidiTime::getTimeInMilliseconds( bpm_t beatsPerMinute ) const { - return ticksToMilliseconds(getTicks(), beatsPerMinute); + return ticksToMilliseconds( getTicks(), beatsPerMinute ); } MidiTime MidiTime::fromFrames( const f_cnt_t frames, const float framesPerTick ) @@ -171,39 +171,39 @@ MidiTime MidiTime::fromFrames( const f_cnt_t frames, const float framesPerTick ) } -tick_t MidiTime::ticksPerTact() +tick_t MidiTime::ticksPerBar() { - return s_ticksPerTact; + return s_ticksPerBar; } -tick_t MidiTime::ticksPerTact( const TimeSig &sig ) +tick_t MidiTime::ticksPerBar( const TimeSig &sig ) { - return DefaultTicksPerTact * sig.numerator() / sig.denominator(); + return DefaultTicksPerBar * sig.numerator() / sig.denominator(); } -int MidiTime::stepsPerTact() +int MidiTime::stepsPerBar() { - int steps = ticksPerTact() / DefaultBeatsPerTact; + int steps = ticksPerBar() / DefaultBeatsPerBar; return qMax( 1, steps ); } -void MidiTime::setTicksPerTact( tick_t tpt ) +void MidiTime::setTicksPerBar( tick_t tpb ) { - s_ticksPerTact = tpt; + s_ticksPerBar = tpb; } MidiTime MidiTime::stepPosition( int step ) { - return step * ticksPerTact() / stepsPerTact(); + return step * ticksPerBar() / stepsPerBar(); } -double MidiTime::ticksToMilliseconds(tick_t ticks, bpm_t beatsPerMinute) +double MidiTime::ticksToMilliseconds( tick_t ticks, bpm_t beatsPerMinute ) { - return MidiTime::ticksToMilliseconds(static_cast(ticks), beatsPerMinute); + return MidiTime::ticksToMilliseconds( static_cast(ticks), beatsPerMinute ); } double MidiTime::ticksToMilliseconds(double ticks, bpm_t beatsPerMinute) diff --git a/src/gui/AudioDeviceSetupWidget.cpp b/src/gui/AudioDeviceSetupWidget.cpp index 86800643e..fbec38c76 100644 --- a/src/gui/AudioDeviceSetupWidget.cpp +++ b/src/gui/AudioDeviceSetupWidget.cpp @@ -24,9 +24,9 @@ #include "AudioDeviceSetupWidget.h" -AudioDeviceSetupWidget::AudioDeviceSetupWidget( const QString & _caption, QWidget * _parent ) : - TabWidget( TabWidget::tr( "Settings for %1" ).arg(TabWidget::tr( _caption.toLatin1() ) ).toUpper(), - _parent ) + +AudioDeviceSetupWidget::AudioDeviceSetupWidget(const QString & caption, QWidget * parent) : + TabWidget(TabWidget::tr("Settings for %1").arg(TabWidget::tr(caption.toLatin1())), parent) { } diff --git a/src/gui/AutomationPatternView.cpp b/src/gui/AutomationPatternView.cpp index 6879b5bbd..130d51a0e 100644 --- a/src/gui/AutomationPatternView.cpp +++ b/src/gui/AutomationPatternView.cpp @@ -278,10 +278,10 @@ void AutomationPatternView::paintEvent( QPaintEvent * ) p.fillRect( rect(), c ); } - const float ppt = fixedTCOs() ? + const float ppb = fixedTCOs() ? ( parentWidget()->width() - 2 * TCO_BORDER_WIDTH ) - / (float) m_pat->timeMapLength().getTact() : - pixelsPerTact(); + / (float) m_pat->timeMapLength().getBar() : + pixelsPerBar(); const int x_base = TCO_BORDER_WIDTH; @@ -290,7 +290,7 @@ void AutomationPatternView::paintEvent( QPaintEvent * ) const float y_scale = max - min; const float h = ( height() - 2 * TCO_BORDER_WIDTH ) / y_scale; - const float ppTick = ppt / MidiTime::ticksPerTact(); + const float ppTick = ppb / MidiTime::ticksPerBar(); p.translate( 0.0f, max * height() / y_scale - TCO_BORDER_WIDTH ); p.scale( 1.0f, -h ); @@ -366,15 +366,15 @@ void AutomationPatternView::paintEvent( QPaintEvent * ) } p.setRenderHints( QPainter::Antialiasing, false ); - p.resetMatrix(); + p.resetTransform(); // bar lines const int lineSize = 3; p.setPen( c.darker( 300 ) ); - for( tact_t t = 1; t < width() - TCO_BORDER_WIDTH; ++t ) + for( bar_t t = 1; t < width() - TCO_BORDER_WIDTH; ++t ) { - const int tx = x_base + static_cast( ppt * t ) - 2; + const int tx = x_base + static_cast( ppb * t ) - 2; p.drawLine( tx, TCO_BORDER_WIDTH, tx, TCO_BORDER_WIDTH + lineSize ); p.drawLine( tx, rect().bottom() - ( lineSize + TCO_BORDER_WIDTH ), tx, rect().bottom() - TCO_BORDER_WIDTH ); diff --git a/src/gui/ControllerConnectionDialog.cpp b/src/gui/ControllerConnectionDialog.cpp index 02857b034..f0d3d10e9 100644 --- a/src/gui/ControllerConnectionDialog.cpp +++ b/src/gui/ControllerConnectionDialog.cpp @@ -63,7 +63,7 @@ public: } - virtual void processInEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset = 0 ) + void processInEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset = 0 ) override { if( event.type() == MidiControlChange && ( m_midiPort.inputChannel() == 0 || m_midiPort.inputChannel() == event.channel() + 1 ) ) diff --git a/src/gui/FxMixerView.cpp b/src/gui/FxMixerView.cpp index 4ae2a630a..54bbff70f 100644 --- a/src/gui/FxMixerView.cpp +++ b/src/gui/FxMixerView.cpp @@ -115,7 +115,7 @@ FxMixerView::FxMixerView() : ChannelArea( QWidget * parent, FxMixerView * mv ) : QScrollArea( parent ), m_mv( mv ) {} ~ChannelArea() {} - virtual void keyPressEvent( QKeyEvent * e ) + void keyPressEvent( QKeyEvent * e ) override { m_mv->keyPressEvent( e ); } diff --git a/src/gui/GuiApplication.cpp b/src/gui/GuiApplication.cpp index a7a3d1baa..fb2e3eae3 100644 --- a/src/gui/GuiApplication.cpp +++ b/src/gui/GuiApplication.cpp @@ -67,8 +67,8 @@ GuiApplication::GuiApplication() ConfigManager::inst()->createWorkingDir(); } // Init style and palette - QDir::addSearchPath("artwork", ConfigManager::inst()->artworkDir()); - QDir::addSearchPath("artwork", ConfigManager::inst()->defaultArtworkDir()); + QDir::addSearchPath("artwork", ConfigManager::inst()->themeDir()); + QDir::addSearchPath("artwork", ConfigManager::inst()->defaultThemeDir()); QDir::addSearchPath("artwork", ":/artwork"); LmmsStyle* lmmsstyle = new LmmsStyle(); diff --git a/src/gui/LmmsPalette.cpp b/src/gui/LmmsPalette.cpp index e58e72cea..e0b356d7a 100644 --- a/src/gui/LmmsPalette.cpp +++ b/src/gui/LmmsPalette.cpp @@ -42,9 +42,7 @@ LmmsPalette::LmmsPalette( QWidget * parent, QStyle * stylearg ) : m_buttonText( 0,0,0 ), m_brightText( 74, 253, 133 ), m_highlight( 100, 100, 100 ), - m_highlightedText( 255, 255, 255 ), - m_toolTipText( 0, 0, 0 ), - m_toolTipBase( 128, 128, 128 ) + m_highlightedText( 255, 255, 255 ) { setStyle( stylearg ); stylearg->polish( this ); @@ -72,8 +70,6 @@ LmmsPalette::~LmmsPalette() ACCESSMET( brightText, setBrightText ) ACCESSMET( highlight, setHighlight ) ACCESSMET( highlightedText, setHighlightedText ) - ACCESSMET( toolTipText, setToolTipText ) - ACCESSMET( toolTipBase, setToolTipBase ) QPalette LmmsPalette::palette() const @@ -90,8 +86,6 @@ QPalette LmmsPalette::palette() const pal.setColor( QPalette::Shadow, shadow() ); pal.setColor( QPalette::Highlight, highlight() ); pal.setColor( QPalette::HighlightedText, highlightedText() ); - pal.setBrush( QPalette::ToolTipText, QBrush( toolTipText() ) ); - pal.setBrush( QPalette::ToolTipBase, QBrush( toolTipBase() ) ); return pal; } diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 0914d1685..acdbabb35 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -174,16 +174,16 @@ MainWindow::MainWindow() : m_workspace = new QMdiArea( splitter ); // Load background - emit initProgress(tr("Loading background artwork")); - QString bgArtwork = ConfigManager::inst()->backgroundArtwork(); - QImage bgImage; - if( !bgArtwork.isEmpty() ) + emit initProgress(tr("Loading background picture")); + QString backgroundPicFile = ConfigManager::inst()->backgroundPicFile(); + QImage backgroundPic; + if( !backgroundPicFile.isEmpty() ) { - bgImage = QImage( bgArtwork ); + backgroundPic = QImage( backgroundPicFile ); } - if( !bgImage.isNull() ) + if( !backgroundPicFile.isNull() ) { - m_workspace->setBackground( bgImage ); + m_workspace->setBackground( backgroundPic ); } else { @@ -291,7 +291,7 @@ void MainWindow::finalize() tr( "&Save" ), this, SLOT( saveProject() ), QKeySequence::Save ); - project_menu->addAction( embed::getIconPixmap( "project_saveas" ), + project_menu->addAction( embed::getIconPixmap( "project_save" ), tr( "Save &As..." ), this, SLOT( saveProjectAs() ), Qt::CTRL + Qt::SHIFT + Qt::Key_S ); @@ -300,8 +300,9 @@ void MainWindow::finalize() this, SLOT( saveProjectAsNewVersion() ), Qt::CTRL + Qt::ALT + Qt::Key_S ); - project_menu->addAction( tr( "Save as default template" ), - this, SLOT( saveProjectAsDefaultTemplate() ) ); + project_menu->addAction( embed::getIconPixmap( "project_save" ), + tr( "Save as default template" ), + this, SLOT( saveProjectAsDefaultTemplate() ) ); project_menu->addSeparator(); project_menu->addAction( embed::getIconPixmap( "project_import" ), @@ -1517,7 +1518,12 @@ void MainWindow::exportProject(bool multiExport) // Get first extension from selected dropdown. // i.e. ".wav" from "WAV-File (*.wav), Dummy-File (*.dum)" suffix = efd.selectedNameFilter().mid( stx + 2, etx - stx - 2 ).split( " " )[0].trimmed(); - exportFileName.remove( "." + suffix, Qt::CaseInsensitive ); + + Qt::CaseSensitivity cs = Qt::CaseSensitive; +#if defined(LMMS_BUILD_APPLE) || defined(LMMS_BUILD_WIN32) + cs = Qt::CaseInsensitive; +#endif + exportFileName.remove( "." + suffix, cs ); if ( efd.selectedFiles()[0].endsWith( suffix ) ) { if( VersionedSaveDialog::fileExistsQuery( exportFileName + suffix, diff --git a/src/gui/MidiSetupWidget.cpp b/src/gui/MidiSetupWidget.cpp index f3001b3af..0c34544d6 100644 --- a/src/gui/MidiSetupWidget.cpp +++ b/src/gui/MidiSetupWidget.cpp @@ -29,23 +29,22 @@ #include "ConfigManager.h" #include "gui_templates.h" -MidiSetupWidget::MidiSetupWidget( const QString & caption, const QString & configSection, - const QString & devName, QWidget * parent ) : - TabWidget( TabWidget::tr( "Settings for %1" ).arg( - tr( caption.toLatin1() ) ).toUpper(), parent ), +MidiSetupWidget::MidiSetupWidget(const QString & caption, const QString & configSection, + const QString & devName, QWidget * parent) : + TabWidget(TabWidget::tr("Settings for %1").arg(tr(caption.toLatin1())), parent), m_configSection(configSection), m_device(nullptr) { // supply devName=QString() (distinct from QString("")) - // to indicate that there is no editable DEVICE field + // to indicate that there is no editable device field if (!devName.isNull()) { - m_device = new QLineEdit( devName, this ); - m_device->setGeometry( 10, 20, 160, 20 ); + m_device = new QLineEdit(devName, this); + m_device->setGeometry(10, 20, 160, 20); - QLabel * dev_lbl = new QLabel( tr( "DEVICE" ), this ); - dev_lbl->setFont( pointSize<7>( dev_lbl->font() ) ); - dev_lbl->setGeometry( 10, 40, 160, 10 ); + QLabel * dev_lbl = new QLabel(tr("Device"), this); + dev_lbl->setFont(pointSize<7>(dev_lbl->font())); + dev_lbl->setGeometry(10, 40, 160, 10); } } @@ -53,8 +52,8 @@ void MidiSetupWidget::saveSettings() { if (!m_configSection.isEmpty() && m_device) { - ConfigManager::inst()->setValue( m_configSection, "device", - m_device->text() ); + ConfigManager::inst()->setValue(m_configSection, "device", + m_device->text()); } } @@ -65,4 +64,3 @@ void MidiSetupWidget::show() parentWidget()->setVisible(visible); QWidget::setVisible(visible); } - diff --git a/src/gui/PianoView.cpp b/src/gui/PianoView.cpp index c1be922c6..c5f1b623f 100644 --- a/src/gui/PianoView.cpp +++ b/src/gui/PianoView.cpp @@ -187,7 +187,7 @@ int PianoView::getKeyFromKeyEvent( QKeyEvent * _ke ) case 27: return 31; // ] } #endif -#if defined(LMMS_BUILD_LINUX) || defined(LMMS_BUILD_OPENBSD) +#if defined(LMMS_BUILD_LINUX) || defined(LMMS_BUILD_OPENBSD) || defined(LMMS_BUILD_FREEBSD) switch( k ) { case 52: return 0; // Z = C diff --git a/src/gui/RowTableView.cpp b/src/gui/RowTableView.cpp index a4daeb17f..9830354be 100644 --- a/src/gui/RowTableView.cpp +++ b/src/gui/RowTableView.cpp @@ -39,12 +39,12 @@ public: } virtual void paint( QPainter * painter, const QStyleOptionViewItem & option, - const QModelIndex & index ) const; + const QModelIndex & index ) const override; protected: virtual void initStyleOption( QStyleOptionViewItem * option, - const QModelIndex & index ) const; + const QModelIndex & index ) const override; private: diff --git a/src/gui/SetupDialog.cpp b/src/gui/SetupDialog.cpp index 5ab9630b2..885f43dec 100644 --- a/src/gui/SetupDialog.cpp +++ b/src/gui/SetupDialog.cpp @@ -22,6 +22,7 @@ * */ + #include #include #include @@ -30,291 +31,247 @@ #include #include +#include "debug.h" +#include "embed.h" +#include "Engine.h" +#include "FileDialog.h" +#include "gui_templates.h" +#include "MainWindow.h" +#include "Mixer.h" +#include "ProjectJournal.h" #include "SetupDialog.h" #include "TabBar.h" #include "TabButton.h" -#include "gui_templates.h" -#include "Mixer.h" -#include "MainWindow.h" -#include "ProjectJournal.h" -#include "embed.h" -#include "Engine.h" -#include "debug.h" #include "ToolTip.h" -#include "FileDialog.h" -// platform-specific audio-interface-classes +// Platform-specific audio-interface classes. #include "AudioAlsa.h" #include "AudioAlsaSetupWidget.h" +#include "AudioDummy.h" #include "AudioJack.h" #include "AudioOss.h" -#include "AudioSndio.h" #include "AudioPortAudio.h" -#include "AudioSoundIo.h" #include "AudioPulseAudio.h" #include "AudioSdl.h" -#include "AudioDummy.h" +#include "AudioSndio.h" +#include "AudioSoundIo.h" -// platform-specific midi-interface-classes +// Platform-specific midi-interface classes. #include "MidiAlsaRaw.h" #include "MidiAlsaSeq.h" +#include "MidiApple.h" +#include "MidiDummy.h" #include "MidiJack.h" #include "MidiOss.h" #include "MidiSndio.h" #include "MidiWinMM.h" -#include "MidiApple.h" -#include "MidiDummy.h" + constexpr int BUFFERSIZE_RESOLUTION = 32; -inline void labelWidget( QWidget * _w, const QString & _txt ) +inline void labelWidget(QWidget * w, const QString & txt) { - QLabel * title = new QLabel( _txt, _w ); + QLabel * title = new QLabel(txt, w); QFont f = title->font(); - f.setBold( true ); - title->setFont( pointSize<12>( f ) ); + f.setBold(true); + title->setFont(pointSize<12>(f)); - assert( dynamic_cast( _w->layout() ) != NULL ); + assert(dynamic_cast(w->layout()) != NULL); - dynamic_cast( _w->layout() )->addSpacing( 5 ); - dynamic_cast( _w->layout() )->addWidget( title ); - dynamic_cast( _w->layout() )->addSpacing( 10 ); + dynamic_cast(w->layout())->addSpacing(5); + dynamic_cast(w->layout())->addWidget(title); } -SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) : - m_bufferSize( ConfigManager::inst()->value( "mixer", - "framesperaudiobuffer" ).toInt() ), - m_toolTips( !ConfigManager::inst()->value( "tooltips", - "disabled" ).toInt() ), - m_warnAfterSetup( !ConfigManager::inst()->value( "app", - "nomsgaftersetup" ).toInt() ), - m_displaydBFS( ConfigManager::inst()->value( "app", - "displaydbfs" ).toInt() ), - m_MMPZ( !ConfigManager::inst()->value( "app", "nommpz" ).toInt() ), - m_disableBackup( !ConfigManager::inst()->value( "app", - "disablebackup" ).toInt() ), - m_openLastProject( ConfigManager::inst()->value( "app", - "openlastproject" ).toInt() ), - m_NaNHandler( ConfigManager::inst()->value( "app", - "nanhandler", "1" ).toInt() ), - m_hqAudioDev( ConfigManager::inst()->value( "mixer", - "hqaudio" ).toInt() ), - m_lang( ConfigManager::inst()->value( "app", - "language" ) ), - m_workingDir( QDir::toNativeSeparators( ConfigManager::inst()->workingDir() ) ), - m_vstDir( QDir::toNativeSeparators( ConfigManager::inst()->vstDir() ) ), - m_artworkDir( QDir::toNativeSeparators( ConfigManager::inst()->artworkDir() ) ), - m_ladDir( QDir::toNativeSeparators( ConfigManager::inst()->ladspaDir() ) ), - m_gigDir( QDir::toNativeSeparators( ConfigManager::inst()->gigDir() ) ), - m_sf2Dir( QDir::toNativeSeparators( ConfigManager::inst()->sf2Dir() ) ), +SetupDialog::SetupDialog(ConfigTabs tab_to_open) : + m_displaydBFS(ConfigManager::inst()->value( + "app", "displaydbfs").toInt()), + m_tooltips(!ConfigManager::inst()->value( + "tooltips", "disabled").toInt()), + m_displayWaveform(ConfigManager::inst()->value( + "ui", "displaywaveform").toInt()), + m_printNoteLabels(ConfigManager::inst()->value( + "ui", "printnotelabels").toInt()), + m_compactTrackButtons(ConfigManager::inst()->value( + "ui", "compacttrackbuttons").toInt()), + m_oneInstrumentTrackWindow(ConfigManager::inst()->value( + "ui", "oneinstrumenttrackwindow").toInt()), + m_MMPZ(!ConfigManager::inst()->value( + "app", "nommpz").toInt()), + m_disableBackup(!ConfigManager::inst()->value( + "app", "disablebackup").toInt()), + m_openLastProject(ConfigManager::inst()->value( + "app", "openlastproject").toInt()), + m_lang(ConfigManager::inst()->value( + "app", "language")), + m_saveInterval( ConfigManager::inst()->value( + "ui", "saveinterval").toInt() < 1 ? + MainWindow::DEFAULT_SAVE_INTERVAL_MINUTES : + ConfigManager::inst()->value( + "ui", "saveinterval").toInt()), + m_enableAutoSave(ConfigManager::inst()->value( + "ui", "enableautosave", "1").toInt()), + m_enableRunningAutoSave(ConfigManager::inst()->value( + "ui", "enablerunningautosave", "0").toInt()), + m_smoothScroll(ConfigManager::inst()->value( + "ui", "smoothscroll").toInt()), + m_animateAFP(ConfigManager::inst()->value( + "ui", "animateafp", "1").toInt()), + m_vstEmbedMethod(ConfigManager::inst()->vstEmbedMethod()), + m_vstAlwaysOnTop(ConfigManager::inst()->value( + "ui", "vstalwaysontop").toInt()), + m_syncVSTPlugins(ConfigManager::inst()->value( + "ui", "syncvstplugins", "1").toInt()), + m_disableAutoQuit(ConfigManager::inst()->value( + "ui", "disableautoquit", "1").toInt()), + m_NaNHandler(ConfigManager::inst()->value( + "app", "nanhandler", "1").toInt()), + m_hqAudioDev(ConfigManager::inst()->value( + "mixer", "hqaudio").toInt()), + m_bufferSize(ConfigManager::inst()->value( + "mixer", "framesperaudiobuffer").toInt()), + m_workingDir(QDir::toNativeSeparators(ConfigManager::inst()->workingDir())), + m_vstDir(QDir::toNativeSeparators(ConfigManager::inst()->vstDir())), + m_ladspaDir(QDir::toNativeSeparators(ConfigManager::inst()->ladspaDir())), + m_gigDir(QDir::toNativeSeparators(ConfigManager::inst()->gigDir())), + m_sf2Dir(QDir::toNativeSeparators(ConfigManager::inst()->sf2Dir())), #ifdef LMMS_HAVE_FLUIDSYNTH - m_defaultSoundfont( QDir::toNativeSeparators( ConfigManager::inst()->defaultSoundfont() ) ), + m_sf2File(QDir::toNativeSeparators(ConfigManager::inst()->sf2File())), #endif -#ifdef LMMS_HAVE_STK - m_stkDir( QDir::toNativeSeparators( ConfigManager::inst()->stkDir() ) ), -#endif - m_backgroundArtwork( QDir::toNativeSeparators( ConfigManager::inst()->backgroundArtwork() ) ), - m_smoothScroll( ConfigManager::inst()->value( "ui", "smoothscroll" ).toInt() ), - m_enableAutoSave( ConfigManager::inst()->value( "ui", "enableautosave", "1" ).toInt() ), - m_enableRunningAutoSave( ConfigManager::inst()->value( "ui", "enablerunningautosave", "0" ).toInt() ), - m_saveInterval( ConfigManager::inst()->value( "ui", "saveinterval" ).toInt() < 1 ? - MainWindow::DEFAULT_SAVE_INTERVAL_MINUTES : - ConfigManager::inst()->value( "ui", "saveinterval" ).toInt() ), - m_oneInstrumentTrackWindow( ConfigManager::inst()->value( "ui", - "oneinstrumenttrackwindow" ).toInt() ), - m_compactTrackButtons( ConfigManager::inst()->value( "ui", - "compacttrackbuttons" ).toInt() ), - m_syncVSTPlugins( ConfigManager::inst()->value( "ui", - "syncvstplugins", "1" ).toInt() ), - m_animateAFP(ConfigManager::inst()->value( "ui", - "animateafp", "1" ).toInt() ), - m_printNoteLabels(ConfigManager::inst()->value( "ui", - "printnotelabels").toInt() ), - m_displayWaveform(ConfigManager::inst()->value( "ui", - "displaywaveform").toInt() ), - m_disableAutoQuit(ConfigManager::inst()->value( "ui", - "disableautoquit", "1" ).toInt() ), - m_vstEmbedMethod( ConfigManager::inst()->vstEmbedMethod() ), - m_vstAlwaysOnTop( ConfigManager::inst()->value( "ui", - "vstalwaysontop" ).toInt() ) + m_themeDir(QDir::toNativeSeparators(ConfigManager::inst()->themeDir())), + m_backgroundPicFile(QDir::toNativeSeparators(ConfigManager::inst()->backgroundPicFile())) { - setWindowIcon( embed::getIconPixmap( "setup_general" ) ); - setWindowTitle( tr( "Setup LMMS" ) ); - setModal( true ); - setFixedSize( 452, 570 ); + setWindowIcon(embed::getIconPixmap("setup_general")); + setWindowTitle(tr("Settings")); + // TODO: Equivalent to the new setWindowFlag(Qt::WindowContextHelpButtonHint, false) + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setModal(true); + setFixedSize(454, 400); - Engine::projectJournal()->setJournalling( false ); + Engine::projectJournal()->setJournalling(false); - QVBoxLayout * vlayout = new QVBoxLayout( this ); - vlayout->setSpacing( 0 ); - vlayout->setMargin( 0 ); - QWidget * settings = new QWidget( this ); - QHBoxLayout * hlayout = new QHBoxLayout( settings ); - hlayout->setSpacing( 0 ); - hlayout->setMargin( 0 ); - m_tabBar = new TabBar( settings, QBoxLayout::TopToBottom ); - m_tabBar->setExclusive( true ); - m_tabBar->setFixedWidth( 72 ); - - QWidget * ws = new QWidget( settings ); - int wsHeight = 420; -#ifdef LMMS_HAVE_STK - wsHeight += 50; -#endif -#ifdef LMMS_HAVE_FLUIDSYNTH - wsHeight += 50; -#endif - ws->setFixedSize( 360, wsHeight ); - QWidget * general = new QWidget( ws ); - general->setFixedSize( 360, 290 ); - QVBoxLayout * gen_layout = new QVBoxLayout( general ); - gen_layout->setSpacing( 0 ); - gen_layout->setMargin( 0 ); - labelWidget( general, tr( "General settings" ) ); - - TabWidget * bufsize_tw = new TabWidget( tr( "BUFFER SIZE" ), general ); - bufsize_tw->setFixedHeight( 80 ); - - m_bufSizeSlider = new QSlider( Qt::Horizontal, bufsize_tw ); - m_bufSizeSlider->setRange( 1, 128 ); - m_bufSizeSlider->setTickPosition( QSlider::TicksBelow ); - m_bufSizeSlider->setPageStep( 8 ); - m_bufSizeSlider->setTickInterval( 8 ); - m_bufSizeSlider->setGeometry( 10, 16, 340, 18 ); - m_bufSizeSlider->setValue( m_bufferSize / BUFFERSIZE_RESOLUTION ); - - connect( m_bufSizeSlider, SIGNAL( valueChanged( int ) ), this, - SLOT( setBufferSize( int ) ) ); - - m_bufSizeLbl = new QLabel( bufsize_tw ); - m_bufSizeLbl->setGeometry( 10, 40, 200, 32 ); - setBufferSize( m_bufSizeSlider->value() ); - - QPushButton * bufsize_reset_btn = new QPushButton( - embed::getIconPixmap( "reload" ), "", bufsize_tw ); - bufsize_reset_btn->setGeometry( 320, 40, 28, 28 ); - connect( bufsize_reset_btn, SIGNAL( clicked() ), this, - SLOT( resetBufSize() ) ); - ToolTip::add( bufsize_reset_btn, tr( "Reset to default value" ) ); - - TabWidget * misc_tw = new TabWidget( tr( "MISC" ), general ); + // Constants for positioning LED check boxes. const int XDelta = 10; const int YDelta = 18; - const int HeaderSize = 30; - int labelNumber = 0; - auto addLedCheckBox = [&XDelta, &YDelta, &misc_tw, &labelNumber, this]( + // Main widget. + QWidget * main_w = new QWidget(this); + + + // Vertical layout. + QVBoxLayout * vlayout = new QVBoxLayout(this); + vlayout->setSpacing(0); + vlayout->setMargin(0); + + // Horizontal layout. + QHBoxLayout * hlayout = new QHBoxLayout(main_w); + hlayout->setSpacing(0); + hlayout->setMargin(0); + + // Tab bar for the main tabs. + m_tabBar = new TabBar(main_w, QBoxLayout::TopToBottom); + m_tabBar->setExclusive(true); + m_tabBar->setFixedWidth(72); + + // Settings widget. + QWidget * settings_w = new QWidget(main_w); + settings_w->setFixedSize(360, 360); + + // General widget. + QWidget * general_w = new QWidget(settings_w); + QVBoxLayout * general_layout = new QVBoxLayout(general_w); + general_layout->setSpacing(10); + general_layout->setMargin(0); + labelWidget(general_w, tr("General")); + + + auto addLedCheckBox = [&XDelta, &YDelta, this]( const char* ledText, + TabWidget* tw, + int& counter, bool initialState, - const char* toggledSlot + const char* toggledSlot, + bool showRestartWarning ){ - LedCheckBox * checkBox = new LedCheckBox(tr(ledText), misc_tw); - labelNumber++; - checkBox->move(XDelta, YDelta*labelNumber); + LedCheckBox * checkBox = new LedCheckBox(tr(ledText), tw); + counter++; + checkBox->move(XDelta, YDelta * counter); checkBox->setChecked(initialState); connect(checkBox, SIGNAL(toggled(bool)), this, toggledSlot); + if (showRestartWarning) + { + connect(checkBox, SIGNAL(toggled(bool)), this, SLOT(showRestartWarning())); + } }; - addLedCheckBox("Enable tooltips", - m_toolTips, SLOT(toggleToolTips(bool))); - addLedCheckBox("Show restart warning after changing settings", - m_warnAfterSetup, SLOT(toggleWarnAfterSetup(bool))); - addLedCheckBox("Display volume as dBFS ", - m_displaydBFS, SLOT(toggleDisplaydBFS(bool))); - addLedCheckBox("Compress project files per default", - m_MMPZ, SLOT(toggleMMPZ(bool))); - addLedCheckBox("One instrument track window mode", - m_oneInstrumentTrackWindow, - SLOT(toggleOneInstrumentTrackWindow(bool))); - addLedCheckBox("HQ-mode for output audio-device", - m_hqAudioDev, SLOT(toggleHQAudioDev(bool))); - addLedCheckBox("Compact track buttons", - m_compactTrackButtons, SLOT(toggleCompactTrackButtons(bool))); - addLedCheckBox("Sync VST plugins to host playback", - m_syncVSTPlugins, SLOT(toggleSyncVSTPlugins(bool))); - addLedCheckBox("Enable note labels in piano roll", - m_printNoteLabels, SLOT(toggleNoteLabels(bool))); - addLedCheckBox("Enable waveform display by default", - m_displayWaveform, SLOT(toggleDisplayWaveform(bool))); - addLedCheckBox("Keep effects running even without input", - m_disableAutoQuit, SLOT(toggleDisableAutoquit(bool))); - addLedCheckBox("Create backup file when saving a project", - m_disableBackup, SLOT(toggleDisableBackup(bool))); - addLedCheckBox("Reopen last project on start", - m_openLastProject, SLOT(toggleOpenLastProject(bool))); - misc_tw->setFixedHeight( YDelta*labelNumber + HeaderSize ); + int counter = 0; - // Advanced setting, hidden for now - if( false ) + // GUI tab. + TabWidget * gui_tw = new TabWidget( + tr("Graphical user interface (GUI)"), general_w); + + + addLedCheckBox("Display volume as dBFS ", gui_tw, counter, + m_displaydBFS, SLOT(toggleDisplaydBFS(bool)), true); + addLedCheckBox("Enable tooltips", gui_tw, counter, + m_tooltips, SLOT(toggleTooltips(bool)), true); + addLedCheckBox("Enable master oscilloscope by default", gui_tw, counter, + m_displayWaveform, SLOT(toggleDisplayWaveform(bool)), true); + addLedCheckBox("Enable all note labels in piano roll", gui_tw, counter, + m_printNoteLabels, SLOT(toggleNoteLabels(bool)), false); + addLedCheckBox("Enable compact track buttons", gui_tw, counter, + m_compactTrackButtons, SLOT(toggleCompactTrackButtons(bool)), true); + addLedCheckBox("Enable one instrument-track-window mode", gui_tw, counter, + m_oneInstrumentTrackWindow, SLOT(toggleOneInstrumentTrackWindow(bool)), true); + + gui_tw->setFixedHeight(YDelta + YDelta * counter); + + + counter = 0; + + // Projects tab. + TabWidget * projects_tw = new TabWidget( + tr("Projects"), general_w); + + + addLedCheckBox("Compress project files by default", projects_tw, counter, + m_MMPZ, SLOT(toggleMMPZ(bool)), true); + addLedCheckBox("Create a backup file when saving a project", projects_tw, counter, + m_disableBackup, SLOT(toggleDisableBackup(bool)), false); + addLedCheckBox("Reopen last project on startup", projects_tw, counter, + m_openLastProject, SLOT(toggleOpenLastProject(bool)), false); + + projects_tw->setFixedHeight(YDelta + YDelta * counter); + + // Language tab. + TabWidget * lang_tw = new TabWidget( + tr("Language"), general_w); + lang_tw->setFixedHeight(48); + QComboBox * changeLang = new QComboBox(lang_tw); + changeLang->move(XDelta, 20); + + QDir dir(ConfigManager::inst()->localeDir()); + QStringList fileNames = dir.entryList(QStringList("*.qm")); + for(int i = 0; i < fileNames.size(); ++i) { - LedCheckBox * useNaNHandler = new LedCheckBox( - tr( "Use built-in NaN handler" ), - misc_tw ); - useNaNHandler->setChecked( m_NaNHandler ); + // Get locale extracted by filename. + fileNames[i].truncate(fileNames[i].lastIndexOf('.')); + m_languages.append(fileNames[i]); + QString lang = QLocale(m_languages.last()).nativeLanguageName(); + changeLang->addItem(lang); } - TabWidget* embed_tw = new TabWidget( tr( "PLUGIN EMBEDDING" ), general); - embed_tw->setFixedHeight( 66 ); - m_vstEmbedComboBox = new QComboBox( embed_tw ); - m_vstEmbedComboBox->move( XDelta, YDelta ); - - QStringList embedMethods = ConfigManager::availabeVstEmbedMethods(); - m_vstEmbedComboBox->addItem( tr( "No embedding" ), "none" ); - if( embedMethods.contains("qt") ) + // If language unset, fallback to system language when available. + if(m_lang == "") { - m_vstEmbedComboBox->addItem( tr( "Embed using Qt API" ), "qt" ); - } - if( embedMethods.contains("win32") ) - { - m_vstEmbedComboBox->addItem( tr( "Embed using native Win32 API" ), "win32" ); - } - if( embedMethods.contains("xembed") ) - { - m_vstEmbedComboBox->addItem( tr( "Embed using XEmbed protocol" ), "xembed" ); - } - m_vstEmbedComboBox->setCurrentIndex( m_vstEmbedComboBox->findData( m_vstEmbedMethod ) ); - connect( m_vstEmbedComboBox, SIGNAL( currentIndexChanged( int ) ), - this, SLOT( vstEmbedMethodChanged() ) ); - - m_vstAlwaysOnTopCheckBox = new LedCheckBox( - tr( "Keep plugin windows on top when not embedded" ), - embed_tw ); - m_vstAlwaysOnTopCheckBox->move( 20, 44 ); - m_vstAlwaysOnTopCheckBox->setChecked( m_vstAlwaysOnTop ); - m_vstAlwaysOnTopCheckBox->setVisible( m_vstEmbedMethod == "none" ); - connect( m_vstAlwaysOnTopCheckBox, SIGNAL( toggled( bool ) ), - this, SLOT( toggleVSTAlwaysOnTop( bool ) ) ); - - TabWidget * lang_tw = new TabWidget( tr( "LANGUAGE" ), general ); - lang_tw->setFixedHeight( 48 ); - QComboBox * changeLang = new QComboBox( lang_tw ); - changeLang->move( XDelta, YDelta ); - - QDir dir( ConfigManager::inst()->localeDir() ); - QStringList fileNames = dir.entryList( QStringList( "*.qm" ) ); - for( int i = 0; i < fileNames.size(); ++i ) - { - // get locale extracted by filename - fileNames[i].truncate( fileNames[i].lastIndexOf( '.' ) ); - m_languages.append( fileNames[i] ); - QString lang = QLocale( m_languages.last() ).nativeLanguageName(); - changeLang->addItem( lang ); - } - connect( changeLang, SIGNAL( currentIndexChanged( int ) ), - this, SLOT( setLanguage( int ) ) ); - - //If language unset, fallback to system language when available - if( m_lang == "" ) - { - QString tmp = QLocale::system().name().left( 2 ); - if( m_languages.contains( tmp ) ) + QString tmp = QLocale::system().name().left(2); + if(m_languages.contains(tmp)) { m_lang = tmp; } @@ -324,69 +281,439 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) : } } - for( int i = 0; i < changeLang->count(); ++i ) + for(int i = 0; i < changeLang->count(); ++i) { - if( m_lang == m_languages.at( i ) ) + if(m_lang == m_languages.at(i)) { - changeLang->setCurrentIndex( i ); + changeLang->setCurrentIndex(i); break; } } - gen_layout->addWidget( bufsize_tw ); - gen_layout->addSpacing( 10 ); - gen_layout->addWidget( misc_tw ); - gen_layout->addSpacing( 10 ); - gen_layout->addWidget( embed_tw ); - gen_layout->addSpacing( 10 ); - gen_layout->addWidget( lang_tw ); - gen_layout->addStretch(); + connect(changeLang, SIGNAL(currentIndexChanged(int)), + this, SLOT(setLanguage(int))); + connect(changeLang, SIGNAL(currentIndexChanged(int)), + this, SLOT(showRestartWarning())); + + + // General layout ordering. + general_layout->addWidget(gui_tw); + general_layout->addWidget(projects_tw); + general_layout->addWidget(lang_tw); + general_layout->addStretch(); - QWidget * paths = new QWidget( ws ); - int pathsHeight = 420; -#ifdef LMMS_HAVE_STK - pathsHeight += 55; + + // Performance widget. + QWidget * performance_w = new QWidget(settings_w); + QVBoxLayout * performance_layout = new QVBoxLayout(performance_w); + performance_layout->setSpacing(10); + performance_layout->setMargin(0); + labelWidget(performance_w, + tr("Performance")); + + + // Autosave tab. + TabWidget * auto_save_tw = new TabWidget( + tr("Autosave"), performance_w); + auto_save_tw->setFixedHeight(106); + + m_saveIntervalSlider = new QSlider(Qt::Horizontal, auto_save_tw); + m_saveIntervalSlider->setValue(m_saveInterval); + m_saveIntervalSlider->setRange(1, 20); + m_saveIntervalSlider->setTickInterval(1); + m_saveIntervalSlider->setPageStep(1); + m_saveIntervalSlider->setGeometry(10, 18, 340, 18); + m_saveIntervalSlider->setTickPosition(QSlider::TicksBelow); + + connect(m_saveIntervalSlider, SIGNAL(valueChanged(int)), + this, SLOT(setAutoSaveInterval(int))); + + m_saveIntervalLbl = new QLabel(auto_save_tw); + m_saveIntervalLbl->setGeometry(10, 40, 200, 24); + setAutoSaveInterval(m_saveIntervalSlider->value()); + + m_autoSave = new LedCheckBox( + tr("Enable autosave"), auto_save_tw); + m_autoSave->move(10, 70); + m_autoSave->setChecked(m_enableAutoSave); + connect(m_autoSave, SIGNAL(toggled(bool)), + this, SLOT(toggleAutoSave(bool))); + + m_runningAutoSave = new LedCheckBox( + tr("Allow autosave while playing"), auto_save_tw); + m_runningAutoSave->move(20, 88); + m_runningAutoSave->setChecked(m_enableRunningAutoSave); + connect(m_runningAutoSave, SIGNAL(toggled(bool)), + this, SLOT(toggleRunningAutoSave(bool))); + + QPushButton * autoSaveResetBtn = new QPushButton( + embed::getIconPixmap("reload"), "", auto_save_tw); + autoSaveResetBtn->setGeometry(320, 70, 28, 28); + connect(autoSaveResetBtn, SIGNAL(clicked()), + this, SLOT(resetAutoSave())); + + m_saveIntervalSlider->setEnabled(m_enableAutoSave); + m_runningAutoSave->setVisible(m_enableAutoSave); + + + counter = 0; + + // UI effect vs. performance tab. + TabWidget * ui_fx_tw = new TabWidget( + tr("User interface (UI) effects vs. performance"), performance_w); + + addLedCheckBox("Smooth scroll in song editor", ui_fx_tw, counter, + m_smoothScroll, SLOT(toggleSmoothScroll(bool)), false); + addLedCheckBox("Display playback cursor in AudioFileProcessor", ui_fx_tw, counter, + m_animateAFP, SLOT(toggleAnimateAFP(bool)), false); + + ui_fx_tw->setFixedHeight(YDelta + YDelta * counter); + + + counter = 0; + + // Plugins tab. + TabWidget * plugins_tw = new TabWidget( + tr("Plugins"), performance_w); + + m_vstEmbedLbl = new QLabel(plugins_tw); + m_vstEmbedLbl->move(XDelta, YDelta * ++counter); + m_vstEmbedLbl->setText(tr("VST plugins embedding:")); + + m_vstEmbedComboBox = new QComboBox(plugins_tw); + m_vstEmbedComboBox->move(XDelta, YDelta * ++counter); + + QStringList embedMethods = ConfigManager::availabeVstEmbedMethods(); + m_vstEmbedComboBox->addItem(tr("No embedding"), "none"); + if(embedMethods.contains("qt")) + { + m_vstEmbedComboBox->addItem(tr("Embed using Qt API"), "qt"); + } + if(embedMethods.contains("win32")) + { + m_vstEmbedComboBox->addItem(tr("Embed using native Win32 API"), "win32"); + } + if(embedMethods.contains("xembed")) + { + m_vstEmbedComboBox->addItem(tr("Embed using XEmbed protocol"), "xembed"); + } + m_vstEmbedComboBox->setCurrentIndex(m_vstEmbedComboBox->findData(m_vstEmbedMethod)); + connect(m_vstEmbedComboBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(vstEmbedMethodChanged())); + + counter += 2; + + m_vstAlwaysOnTopCheckBox = new LedCheckBox( + tr("Keep plugin windows on top when not embedded"), plugins_tw); + m_vstAlwaysOnTopCheckBox->move(20, 66); + m_vstAlwaysOnTopCheckBox->setChecked(m_vstAlwaysOnTop); + m_vstAlwaysOnTopCheckBox->setVisible(m_vstEmbedMethod == "none"); + connect(m_vstAlwaysOnTopCheckBox, SIGNAL(toggled(bool)), + this, SLOT(toggleVSTAlwaysOnTop(bool))); + + addLedCheckBox("Sync VST plugins to host playback", plugins_tw, counter, + m_syncVSTPlugins, SLOT(toggleSyncVSTPlugins(bool)), false); + + addLedCheckBox("Keep effects running even without input", plugins_tw, counter, + m_disableAutoQuit, SLOT(toggleDisableAutoQuit(bool)), false); + + plugins_tw->setFixedHeight(YDelta + YDelta * counter); + + + // Performance layout ordering. + performance_layout->addWidget(auto_save_tw); + performance_layout->addWidget(ui_fx_tw); + performance_layout->addWidget(plugins_tw); + performance_layout->addStretch(); + + + + // Audio widget. + QWidget * audio_w = new QWidget(settings_w); + QVBoxLayout * audio_layout = new QVBoxLayout(audio_w); + audio_layout->setSpacing(10); + audio_layout->setMargin(0); + labelWidget(audio_w, + tr("Audio")); + + // Audio interface tab. + TabWidget * audioiface_tw = new TabWidget( + tr("Audio interface"), audio_w); + audioiface_tw->setFixedHeight(56); + + m_audioInterfaces = new QComboBox(audioiface_tw); + m_audioInterfaces->setGeometry(10, 20, 240, 28); + + + // Ifaces-settings-widget. + QWidget * as_w = new QWidget(audio_w); + as_w->setFixedHeight(60); + + QHBoxLayout * as_w_layout = new QHBoxLayout(as_w); + as_w_layout->setSpacing(0); + as_w_layout->setMargin(0); + +#ifdef LMMS_HAVE_JACK + m_audioIfaceSetupWidgets[AudioJack::name()] = + new AudioJack::setupWidget(as_w); #endif -#ifdef LMMS_HAVE_FLUIDSYNTH - pathsHeight += 55; + +#ifdef LMMS_HAVE_ALSA + m_audioIfaceSetupWidgets[AudioAlsa::name()] = + new AudioAlsaSetupWidget(as_w); #endif - paths->setFixedSize( 360, pathsHeight ); - QVBoxLayout * dir_layout = new QVBoxLayout( paths ); - dir_layout->setSpacing( 0 ); - dir_layout->setMargin( 0 ); - labelWidget( paths, tr( "Paths" ) ); - QLabel * title = new QLabel( tr( "Directories" ), paths ); - QFont f = title->font(); - f.setBold( true ); - title->setFont( pointSize<12>( f ) ); + +#ifdef LMMS_HAVE_PULSEAUDIO + m_audioIfaceSetupWidgets[AudioPulseAudio::name()] = + new AudioPulseAudio::setupWidget(as_w); +#endif + +#ifdef LMMS_HAVE_PORTAUDIO + m_audioIfaceSetupWidgets[AudioPortAudio::name()] = + new AudioPortAudio::setupWidget(as_w); +#endif + +#ifdef LMMS_HAVE_SOUNDIO + m_audioIfaceSetupWidgets[AudioSoundIo::name()] = + new AudioSoundIo::setupWidget(as_w); +#endif + +#ifdef LMMS_HAVE_SDL + m_audioIfaceSetupWidgets[AudioSdl::name()] = + new AudioSdl::setupWidget(as_w); +#endif + +#ifdef LMMS_HAVE_OSS + m_audioIfaceSetupWidgets[AudioOss::name()] = + new AudioOss::setupWidget(as_w); +#endif + +#ifdef LMMS_HAVE_SNDIO + m_audioIfaceSetupWidgets[AudioSndio::name()] = + new AudioSndio::setupWidget(as_w); +#endif + + m_audioIfaceSetupWidgets[AudioDummy::name()] = + new AudioDummy::setupWidget(as_w); - QScrollArea *pathScroll = new QScrollArea( paths ); + for(AswMap::iterator it = m_audioIfaceSetupWidgets.begin(); + it != m_audioIfaceSetupWidgets.end(); ++it) + { + m_audioIfaceNames[ + tr(it.key().toLatin1())] = it.key(); + } + for(trMap::iterator it = m_audioIfaceNames.begin(); + it != m_audioIfaceNames.end(); ++it) + { + QWidget * audioWidget = m_audioIfaceSetupWidgets[it.value()]; + audioWidget->hide(); + as_w_layout->addWidget(audioWidget); + m_audioInterfaces->addItem(it.key()); + } - QWidget *pathSelectors = new QWidget( ws ); - QVBoxLayout *pathSelectorLayout = new QVBoxLayout; - pathScroll->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn ); - pathScroll->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); - pathScroll->resize( 362, pathsHeight - 50 ); - pathScroll->move( 0, 30 ); - pathSelectors->resize( 360, pathsHeight - 50 ); + // If no preferred audio device is saved, save the current one. + QString audioDevName = ConfigManager::inst()->value("mixer", "audiodev"); + if (m_audioInterfaces->findText(audioDevName) < 0) + { + audioDevName = Engine::mixer()->audioDevName(); + ConfigManager::inst()->setValue("mixer", "audiodev", audioDevName); + } + m_audioInterfaces-> + setCurrentIndex(m_audioInterfaces->findText(audioDevName)); + m_audioIfaceSetupWidgets[audioDevName]->show(); + + connect(m_audioInterfaces, SIGNAL(activated(const QString &)), + this, SLOT(audioInterfaceChanged(const QString &))); + + // Advanced setting, hidden for now + if(false) + { + LedCheckBox * useNaNHandler = new LedCheckBox( + tr("Use built-in NaN handler"), audio_w); + useNaNHandler->setChecked(m_NaNHandler); + } + + // HQ mode LED. + LedCheckBox * hqaudio = new LedCheckBox( + tr("HQ mode for output audio device"), audio_w); + hqaudio->move(10, 0); + hqaudio->setChecked(m_hqAudioDev); + connect(hqaudio, SIGNAL(toggled(bool)), + this, SLOT(toggleHQAudioDev(bool))); + + + // Buffer size tab. + TabWidget * bufferSize_tw = new TabWidget( + tr("Buffer size"), audio_w); + bufferSize_tw->setFixedHeight(76); + + m_bufferSizeSlider = new QSlider(Qt::Horizontal, bufferSize_tw); + m_bufferSizeSlider->setRange(1, 128); + m_bufferSizeSlider->setTickInterval(8); + m_bufferSizeSlider->setPageStep(8); + m_bufferSizeSlider->setValue(m_bufferSize / BUFFERSIZE_RESOLUTION); + m_bufferSizeSlider->setGeometry(10, 18, 340, 18); + m_bufferSizeSlider->setTickPosition(QSlider::TicksBelow); + + connect(m_bufferSizeSlider, SIGNAL(valueChanged(int)), + this, SLOT(setBufferSize(int))); + connect(m_bufferSizeSlider, SIGNAL(valueChanged(int)), + this, SLOT(showRestartWarning())); + + m_bufferSizeLbl = new QLabel(bufferSize_tw); + m_bufferSizeLbl->setGeometry(10, 40, 200, 24); + setBufferSize(m_bufferSizeSlider->value()); + + QPushButton * bufferSize_reset_btn = new QPushButton( + embed::getIconPixmap("reload"), "", bufferSize_tw); + bufferSize_reset_btn->setGeometry(320, 40, 28, 28); + connect(bufferSize_reset_btn, SIGNAL(clicked()), + this, SLOT(resetBufferSize())); + ToolTip::add(bufferSize_reset_btn, + tr("Reset to default value")); + + + // Audio layout ordering. + audio_layout->addWidget(audioiface_tw); + audio_layout->addWidget(as_w); + audio_layout->addWidget(hqaudio); + audio_layout->addWidget(bufferSize_tw); + audio_layout->addStretch(); + + + + // MIDI widget. + QWidget * midi_w = new QWidget(settings_w); + QVBoxLayout * midi_layout = new QVBoxLayout(midi_w); + midi_layout->setSpacing(10); + midi_layout->setMargin(0); + labelWidget(midi_w, + tr("MIDI")); + + // MIDI interface tab. + TabWidget * midiiface_tw = new TabWidget( + tr("MIDI interface"), midi_w); + midiiface_tw->setFixedHeight(56); + + m_midiInterfaces = new QComboBox(midiiface_tw); + m_midiInterfaces->setGeometry(10, 20, 240, 28); + + // Ifaces-settings-widget. + QWidget * ms_w = new QWidget(midi_w); + ms_w->setFixedHeight(60); + + QHBoxLayout * ms_w_layout = new QHBoxLayout(ms_w); + ms_w_layout->setSpacing(0); + ms_w_layout->setMargin(0); + +#ifdef LMMS_HAVE_ALSA + m_midiIfaceSetupWidgets[MidiAlsaSeq::name()] = + MidiSetupWidget::create(ms_w); + m_midiIfaceSetupWidgets[MidiAlsaRaw::name()] = + MidiSetupWidget::create(ms_w); +#endif + +#ifdef LMMS_HAVE_JACK + m_midiIfaceSetupWidgets[MidiJack::name()] = + MidiSetupWidget::create(ms_w); +#endif + +#ifdef LMMS_HAVE_OSS + m_midiIfaceSetupWidgets[MidiOss::name()] = + MidiSetupWidget::create(ms_w); +#endif + +#ifdef LMMS_HAVE_SNDIO + m_midiIfaceSetupWidgets[MidiSndio::name()] = + MidiSetupWidget::create(ms_w); +#endif + +#ifdef LMMS_BUILD_WIN32 + m_midiIfaceSetupWidgets[MidiWinMM::name()] = + MidiSetupWidget::create(ms_w); +#endif + +#ifdef LMMS_BUILD_APPLE + m_midiIfaceSetupWidgets[MidiApple::name()] = + MidiSetupWidget::create(ms_w); +#endif + + m_midiIfaceSetupWidgets[MidiDummy::name()] = + MidiSetupWidget::create(ms_w); + + + for(MswMap::iterator it = m_midiIfaceSetupWidgets.begin(); + it != m_midiIfaceSetupWidgets.end(); ++it) + { + m_midiIfaceNames[ + tr(it.key().toLatin1())] = it.key(); + } + for(trMap::iterator it = m_midiIfaceNames.begin(); + it != m_midiIfaceNames.end(); ++it) + { + QWidget * midiWidget = m_midiIfaceSetupWidgets[it.value()]; + midiWidget->hide(); + ms_w_layout->addWidget(midiWidget); + m_midiInterfaces->addItem(it.key()); + } + + QString midiDevName = ConfigManager::inst()->value("mixer", "mididev"); + if (m_midiInterfaces->findText(midiDevName) < 0) + { + midiDevName = Engine::mixer()->midiClientName(); + ConfigManager::inst()->setValue("mixer", "mididev", midiDevName); + } + m_midiInterfaces->setCurrentIndex(m_midiInterfaces->findText(midiDevName)); + m_midiIfaceSetupWidgets[midiDevName]->show(); + + connect(m_midiInterfaces, SIGNAL(activated(const QString &)), + this, SLOT(midiInterfaceChanged(const QString &))); + + + // MIDI layout ordering. + midi_layout->addWidget(midiiface_tw); + midi_layout->addWidget(ms_w); + midi_layout->addStretch(); + + + + // Paths widget. + QWidget * paths_w = new QWidget(settings_w); + + QVBoxLayout * paths_layout = new QVBoxLayout(paths_w); + paths_layout->setSpacing(10); + paths_layout->setMargin(0); + + labelWidget(paths_w, tr("Paths")); + + + // Paths scroll area. + QScrollArea * pathsScroll = new QScrollArea(paths_w); + pathsScroll->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + pathsScroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + // Path selectors widget. + QWidget * pathSelectors = new QWidget(paths_w); const int txtLength = 284; - const int btnStart = 297; + const int btnStart = 300; + // Path selectors layout. + QVBoxLayout * pathSelectorsLayout = new QVBoxLayout; + pathSelectorsLayout->setSpacing(10); auto addPathEntry = [&](const char* caption, const QString& content, const char* setSlot, const char* openSlot, QLineEdit*& lineEdit, - QWidget* twParent, const char* pixmap = "project_open") { - TabWidget * newTw = new TabWidget(tr(caption).toUpper(), - twParent); + TabWidget * newTw = new TabWidget(tr(caption), + pathSelectors); newTw->setFixedHeight(48); lineEdit = new QLineEdit(content, newTw); @@ -401,397 +728,122 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) : selectBtn->move(btnStart, 16); connect(selectBtn, SIGNAL(clicked()), this, openSlot); - pathSelectorLayout->addWidget(newTw); - pathSelectorLayout->addSpacing(10); + pathSelectorsLayout->addWidget(newTw); + pathSelectorsLayout->addSpacing(10); }; addPathEntry("LMMS working directory", m_workingDir, SLOT(setWorkingDir(const QString &)), SLOT(openWorkingDir()), - m_wdLineEdit, pathSelectors); - addPathEntry("GIG directory", m_gigDir, - SLOT(setGIGDir(const QString &)), - SLOT(openGIGDir()), - m_gigLineEdit, pathSelectors); + m_workingDirLineEdit); + addPathEntry("VST plugins directory", m_vstDir, + SLOT(setVSTDir(const QString &)), + SLOT(openVSTDir()), + m_vstDirLineEdit); + addPathEntry("LADSPA plugins directories", m_ladspaDir, + SLOT(setLADSPADir(const QString &)), + SLOT(openLADSPADir()), + m_ladspaDirLineEdit, "add_folder"); addPathEntry("SF2 directory", m_sf2Dir, SLOT(setSF2Dir(const QString &)), SLOT(openSF2Dir()), - m_sf2LineEdit, pathSelectors); - addPathEntry("VST-plugin directory", m_vstDir, - SLOT(setVSTDir(const QString &)), - SLOT(openVSTDir()), - m_vdLineEdit, pathSelectors); - addPathEntry("LADSPA plugin directories", m_ladDir, - SLOT(setLADSPADir(const QString &)), - SLOT(openLADSPADir()), - m_ladLineEdit, paths, - "add_folder"); -#ifdef LMMS_HAVE_STK - addPathEntry("STK rawwave directory", m_stkDir, - SLOT(setSTKDir(const QString &)), - SLOT(openSTKDir()), - m_stkLineEdit, paths); -#endif + m_sf2DirLineEdit); #ifdef LMMS_HAVE_FLUIDSYNTH - addPathEntry("Default Soundfont File", m_defaultSoundfont, - SLOT(setDefaultSoundfont(const QString &)), - SLOT(openDefaultSoundfont()), - m_sfLineEdit, paths); + addPathEntry("Default SF2", m_sf2File, + SLOT(setSF2File(const QString &)), + SLOT(openSF2File()), + m_sf2FileLineEdit); #endif - addPathEntry("Themes directory", m_artworkDir, - SLOT(setArtworkDir(const QString &)), - SLOT(openArtworkDir()), - m_adLineEdit, pathSelectors); - pathSelectorLayout->addStretch(); - addPathEntry("Background artwork", m_backgroundArtwork, - SLOT(setBackgroundArtwork(const QString &)), - SLOT(openBackgroundArtwork()), - m_baLineEdit, paths); - pathSelectors->setLayout(pathSelectorLayout); - - - dir_layout->addWidget(pathSelectors); - - pathScroll->setWidget(pathSelectors); - pathScroll->setWidgetResizable(true); - - - - QWidget * performance = new QWidget( ws ); - performance->setFixedSize( 360, 200 ); - QVBoxLayout * perf_layout = new QVBoxLayout( performance ); - perf_layout->setSpacing( 0 ); - perf_layout->setMargin( 0 ); - labelWidget( performance, tr( "Performance settings" ) ); - - - TabWidget * auto_save_tw = new TabWidget( - tr( "Auto save" ).toUpper(), performance ); - auto_save_tw->setFixedHeight( 110 ); - - m_saveIntervalSlider = new QSlider( Qt::Horizontal, auto_save_tw ); - m_saveIntervalSlider->setRange( 1, 20 ); - m_saveIntervalSlider->setTickPosition( QSlider::TicksBelow ); - m_saveIntervalSlider->setPageStep( 1 ); - m_saveIntervalSlider->setTickInterval( 1 ); - m_saveIntervalSlider->setGeometry( 10, 16, 340, 18 ); - m_saveIntervalSlider->setValue( m_saveInterval ); - - connect( m_saveIntervalSlider, SIGNAL( valueChanged( int ) ), this, - SLOT( setAutoSaveInterval( int ) ) ); - - m_saveIntervalLbl = new QLabel( auto_save_tw ); - m_saveIntervalLbl->setGeometry( 10, 40, 200, 24 ); - setAutoSaveInterval( m_saveIntervalSlider->value() ); - - m_autoSave = new LedCheckBox( - tr( "Enable auto-save" ), auto_save_tw ); - m_autoSave->move( 10, 70 ); - m_autoSave->setChecked( m_enableAutoSave ); - connect( m_autoSave, SIGNAL( toggled( bool ) ), - this, SLOT( toggleAutoSave( bool ) ) ); - - m_runningAutoSave = new LedCheckBox( - tr( "Allow auto-save while playing" ), auto_save_tw ); - m_runningAutoSave->move( 20, 90 ); - m_runningAutoSave->setChecked( m_enableRunningAutoSave ); - connect( m_runningAutoSave, SIGNAL( toggled( bool ) ), - this, SLOT( toggleRunningAutoSave( bool ) ) ); - - QPushButton * autoSaveResetBtn = new QPushButton( - embed::getIconPixmap( "reload" ), "", auto_save_tw ); - autoSaveResetBtn->setGeometry( 320, 70, 28, 28 ); - connect( autoSaveResetBtn, SIGNAL( clicked() ), this, - SLOT( resetAutoSave() ) ); - ToolTip::add( autoSaveResetBtn, tr( "Reset to default value" ) ); - - m_saveIntervalSlider->setEnabled( m_enableAutoSave ); - m_runningAutoSave->setVisible( m_enableAutoSave ); - - - perf_layout->addWidget( auto_save_tw ); - perf_layout->addSpacing( 10 ); - - - TabWidget * ui_fx_tw = new TabWidget( tr( "UI effects vs. " - "performance" ).toUpper(), - performance ); - ui_fx_tw->setFixedHeight( 70 ); - - LedCheckBox * smoothScroll = new LedCheckBox( - tr( "Smooth scroll in Song Editor" ), ui_fx_tw ); - smoothScroll->move( 10, 20 ); - smoothScroll->setChecked( m_smoothScroll ); - connect( smoothScroll, SIGNAL( toggled( bool ) ), - this, SLOT( toggleSmoothScroll( bool ) ) ); - - LedCheckBox * animAFP = new LedCheckBox( - tr( "Show playback cursor in AudioFileProcessor" ), - ui_fx_tw ); - animAFP->move( 10, 40 ); - animAFP->setChecked( m_animateAFP ); - connect( animAFP, SIGNAL( toggled( bool ) ), - this, SLOT( toggleAnimateAFP( bool ) ) ); - - - - perf_layout->addWidget( ui_fx_tw ); - perf_layout->addStretch(); - - - - QWidget * audio = new QWidget( ws ); - audio->setFixedSize( 360, 200 ); - QVBoxLayout * audio_layout = new QVBoxLayout( audio ); - audio_layout->setSpacing( 0 ); - audio_layout->setMargin( 0 ); - labelWidget( audio, tr( "Audio settings" ) ); - - TabWidget * audioiface_tw = new TabWidget( tr( "AUDIO INTERFACE" ), - audio ); - audioiface_tw->setFixedHeight( 60 ); - - m_audioInterfaces = new QComboBox( audioiface_tw ); - m_audioInterfaces->setGeometry( 10, 20, 240, 22 ); - - - // create ifaces-settings-widget - QWidget * asw = new QWidget( audio ); - asw->setFixedHeight( 60 ); - - QHBoxLayout * asw_layout = new QHBoxLayout( asw ); - asw_layout->setSpacing( 0 ); - asw_layout->setMargin( 0 ); - //asw_layout->setAutoAdd( true ); - -#ifdef LMMS_HAVE_JACK - m_audioIfaceSetupWidgets[AudioJack::name()] = - new AudioJack::setupWidget( asw ); -#endif - -#ifdef LMMS_HAVE_ALSA - m_audioIfaceSetupWidgets[AudioAlsa::name()] = - new AudioAlsaSetupWidget( asw ); -#endif - -#ifdef LMMS_HAVE_PULSEAUDIO - m_audioIfaceSetupWidgets[AudioPulseAudio::name()] = - new AudioPulseAudio::setupWidget( asw ); -#endif - -#ifdef LMMS_HAVE_PORTAUDIO - m_audioIfaceSetupWidgets[AudioPortAudio::name()] = - new AudioPortAudio::setupWidget( asw ); -#endif - -#ifdef LMMS_HAVE_SOUNDIO - m_audioIfaceSetupWidgets[AudioSoundIo::name()] = - new AudioSoundIo::setupWidget( asw ); -#endif - -#ifdef LMMS_HAVE_SDL - m_audioIfaceSetupWidgets[AudioSdl::name()] = - new AudioSdl::setupWidget( asw ); -#endif - -#ifdef LMMS_HAVE_OSS - m_audioIfaceSetupWidgets[AudioOss::name()] = - new AudioOss::setupWidget( asw ); -#endif - -#ifdef LMMS_HAVE_SNDIO - m_audioIfaceSetupWidgets[AudioSndio::name()] = - new AudioSndio::setupWidget( asw ); -#endif - m_audioIfaceSetupWidgets[AudioDummy::name()] = - new AudioDummy::setupWidget( asw ); - - - for( AswMap::iterator it = m_audioIfaceSetupWidgets.begin(); - it != m_audioIfaceSetupWidgets.end(); ++it ) - { - m_audioIfaceNames[tr( it.key().toLatin1())] = it.key(); - } - for( trMap::iterator it = m_audioIfaceNames.begin(); - it != m_audioIfaceNames.end(); ++it ) - { - QWidget * audioWidget = m_audioIfaceSetupWidgets[it.value()]; - audioWidget->hide(); - asw_layout->addWidget( audioWidget ); - m_audioInterfaces->addItem( it.key() ); - } - - // If no preferred audio device is saved, save the current one - QString audioDevName = - ConfigManager::inst()->value( "mixer", "audiodev" ); - if( m_audioInterfaces->findText(audioDevName) < 0 ) - { - audioDevName = Engine::mixer()->audioDevName(); - ConfigManager::inst()->setValue( - "mixer", "audiodev", audioDevName ); - } - m_audioInterfaces-> - setCurrentIndex( m_audioInterfaces->findText( audioDevName ) ); - m_audioIfaceSetupWidgets[audioDevName]->show(); - - connect( m_audioInterfaces, SIGNAL( activated( const QString & ) ), - this, SLOT( audioInterfaceChanged( const QString & ) ) ); - - - audio_layout->addWidget( audioiface_tw ); - audio_layout->addSpacing( 20 ); - audio_layout->addWidget( asw ); - audio_layout->addStretch(); - - - - QWidget * midi = new QWidget( ws ); - QVBoxLayout * midi_layout = new QVBoxLayout( midi ); - midi_layout->setSpacing( 0 ); - midi_layout->setMargin( 0 ); - labelWidget( midi, tr( "MIDI settings" ) ); - - TabWidget * midiiface_tw = new TabWidget( tr( "MIDI INTERFACE" ), - midi ); - midiiface_tw->setFixedHeight( 60 ); - - m_midiInterfaces = new QComboBox( midiiface_tw ); - m_midiInterfaces->setGeometry( 10, 20, 240, 22 ); - - - // create ifaces-settings-widget - QWidget * msw = new QWidget( midi ); - msw->setFixedHeight( 60 ); - - QHBoxLayout * msw_layout = new QHBoxLayout( msw ); - msw_layout->setSpacing( 0 ); - msw_layout->setMargin( 0 ); - //msw_layout->setAutoAdd( true ); - -#ifdef LMMS_HAVE_ALSA - m_midiIfaceSetupWidgets[MidiAlsaSeq::name()] = - MidiSetupWidget::create( msw ); - m_midiIfaceSetupWidgets[MidiAlsaRaw::name()] = - MidiSetupWidget::create( msw ); -#endif - -#ifdef LMMS_HAVE_JACK - m_midiIfaceSetupWidgets[MidiJack::name()] = - MidiSetupWidget::create( msw ); -#endif - -#ifdef LMMS_HAVE_OSS - m_midiIfaceSetupWidgets[MidiOss::name()] = - MidiSetupWidget::create( msw ); -#endif - -#ifdef LMMS_HAVE_SNDIO - m_midiIfaceSetupWidgets[MidiSndio::name()] = - MidiSetupWidget::create( msw ); -#endif - -#ifdef LMMS_BUILD_WIN32 - m_midiIfaceSetupWidgets[MidiWinMM::name()] = - MidiSetupWidget::create( msw ); -#endif - -#ifdef LMMS_BUILD_APPLE - m_midiIfaceSetupWidgets[MidiApple::name()] = - MidiSetupWidget::create( msw ); -#endif - - m_midiIfaceSetupWidgets[MidiDummy::name()] = - MidiSetupWidget::create( msw ); - - - for( MswMap::iterator it = m_midiIfaceSetupWidgets.begin(); - it != m_midiIfaceSetupWidgets.end(); ++it ) - { - m_midiIfaceNames[tr( it.key().toLatin1())] = it.key(); - } - for( trMap::iterator it = m_midiIfaceNames.begin(); - it != m_midiIfaceNames.end(); ++it ) - { - QWidget * midiWidget = m_midiIfaceSetupWidgets[it.value()]; - midiWidget->hide(); - msw_layout->addWidget( midiWidget ); - m_midiInterfaces->addItem( it.key() ); - } - - QString midiDevName = - ConfigManager::inst()->value( "mixer", "mididev" ); - if( m_midiInterfaces->findText(midiDevName) < 0 ) - { - midiDevName = Engine::mixer()->midiClientName(); - ConfigManager::inst()->setValue( - "mixer", "mididev", midiDevName ); - } - m_midiInterfaces->setCurrentIndex( - m_midiInterfaces->findText( midiDevName ) ); - m_midiIfaceSetupWidgets[midiDevName]->show(); - - connect( m_midiInterfaces, SIGNAL( activated( const QString & ) ), - this, SLOT( midiInterfaceChanged( const QString & ) ) ); - - - midi_layout->addWidget( midiiface_tw ); - midi_layout->addSpacing( 20 ); - midi_layout->addWidget( msw ); - midi_layout->addStretch(); - - - m_tabBar->addTab( general, tr( "General settings" ), 0, false, true - )->setIcon( embed::getIconPixmap( "setup_general" ) ); - m_tabBar->addTab( paths, tr( "Paths" ), 1, false, true - )->setIcon( embed::getIconPixmap( - "setup_directories" ) ); - m_tabBar->addTab( performance, tr( "Performance settings" ), 2, false, - true )->setIcon( embed::getIconPixmap( - "setup_performance" ) ); - m_tabBar->addTab( audio, tr( "Audio settings" ), 3, false, true - )->setIcon( embed::getIconPixmap( "setup_audio" ) ); - m_tabBar->addTab( midi, tr( "MIDI settings" ), 4, true, true - )->setIcon( embed::getIconPixmap( "setup_midi" ) ); - - - m_tabBar->setActiveTab( _tab_to_open ); - - hlayout->addWidget( m_tabBar ); - hlayout->addSpacing( 10 ); - hlayout->addWidget( ws ); - hlayout->addSpacing( 10 ); - hlayout->addStretch(); - - QWidget * buttons = new QWidget( this ); - QHBoxLayout * btn_layout = new QHBoxLayout( buttons ); - btn_layout->setSpacing( 0 ); - btn_layout->setMargin( 0 ); - QPushButton * ok_btn = new QPushButton( embed::getIconPixmap( "apply" ), - tr( "OK" ), buttons ); - connect( ok_btn, SIGNAL( clicked() ), this, SLOT( accept() ) ); - - QPushButton * cancel_btn = new QPushButton( embed::getIconPixmap( - "cancel" ), - tr( "Cancel" ), - buttons ); - connect( cancel_btn, SIGNAL( clicked() ), this, SLOT( reject() ) ); - - btn_layout->addStretch(); - btn_layout->addSpacing( 10 ); - btn_layout->addWidget( ok_btn ); - btn_layout->addSpacing( 10 ); - btn_layout->addWidget( cancel_btn ); - btn_layout->addSpacing( 10 ); - - vlayout->addWidget( settings ); - vlayout->addSpacing( 10 ); - vlayout->addWidget( buttons ); - vlayout->addSpacing( 10 ); - vlayout->addStretch(); + addPathEntry("GIG directory", m_gigDir, + SLOT(setGIGDir(const QString &)), + SLOT(openGIGDir()), + m_gigDirLineEdit); + addPathEntry("Theme directory", m_themeDir, + SLOT(setThemeDir(const QString &)), + SLOT(openThemeDir()), + m_themeDirLineEdit); + addPathEntry("Background artwork", m_backgroundPicFile, + SLOT(setBackgroundPicFile(const QString &)), + SLOT(openBackgroundPicFile()), + m_backgroundPicFileLineEdit); + + pathSelectorsLayout->addStretch(); + + pathSelectors->setLayout(pathSelectorsLayout); + + pathsScroll->setWidget(pathSelectors); + pathsScroll->setWidgetResizable(true); + + paths_layout->addWidget(pathsScroll); + paths_layout->addStretch(); + + // Major tabs ordering. + m_tabBar->addTab(general_w, + tr("General"), 0, false, true)->setIcon( + embed::getIconPixmap("setup_general")); + m_tabBar->addTab(performance_w, + tr("Performance"), 1, false, true)->setIcon( + embed::getIconPixmap("setup_performance")); + m_tabBar->addTab(audio_w, + tr("Audio"), 2, false, true)->setIcon( + embed::getIconPixmap("setup_audio")); + m_tabBar->addTab(midi_w, + tr("MIDI"), 3, false, true)->setIcon( + embed::getIconPixmap("setup_midi")); + m_tabBar->addTab(paths_w, + tr("Paths"), 4, true, true)->setIcon( + embed::getIconPixmap("setup_directories")); + + m_tabBar->setActiveTab(tab_to_open); + + // Horizontal layout ordering. + hlayout->addSpacing(2); + hlayout->addWidget(m_tabBar); + hlayout->addSpacing(10); + hlayout->addWidget(settings_w); + hlayout->addSpacing(10); + + // Extras widget and layout. + QWidget * extras_w = new QWidget(this); + QHBoxLayout * extras_layout = new QHBoxLayout(extras_w); + extras_layout->setSpacing(0); + extras_layout->setMargin(0); + + // Restart warning label. + restartWarningLbl = new QLabel( + tr("Some changes require restarting."), extras_w); + restartWarningLbl->hide(); + + // OK button. + QPushButton * ok_btn = new QPushButton( + embed::getIconPixmap("apply"), + tr("OK"), extras_w); + connect(ok_btn, SIGNAL(clicked()), + this, SLOT(accept())); + + // Cancel button. + QPushButton * cancel_btn = new QPushButton( + embed::getIconPixmap("cancel"), + tr("Cancel"), extras_w); + connect(cancel_btn, SIGNAL(clicked()), + this, SLOT(reject())); + + // Extras layout ordering. + extras_layout->addSpacing(10); + extras_layout->addWidget(restartWarningLbl); + extras_layout->addStretch(); + extras_layout->addWidget(ok_btn); + extras_layout->addSpacing(10); + extras_layout->addWidget(cancel_btn); + extras_layout->addSpacing(10); + + // Vertical layout ordering. + vlayout->addWidget(main_w); + vlayout->addSpacing(10); + vlayout->addWidget(extras_w); + vlayout->addSpacing(10); show(); - - } @@ -799,7 +851,7 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) : SetupDialog::~SetupDialog() { - Engine::projectJournal()->setJournalling( true ); + Engine::projectJournal()->setJournalling(true); } @@ -807,286 +859,146 @@ SetupDialog::~SetupDialog() void SetupDialog::accept() { - if( m_warnAfterSetup ) - { - QMessageBox::information( NULL, tr( "Restart LMMS" ), - tr( "Please note that most changes " - "won't take effect until " - "you restart LMMS!" ), - QMessageBox::Ok ); - } - - // Hide dialog before setting values. This prevents an obscure bug - // where non-embedded VST windows would steal focus and prevent LMMS - // from taking mouse input, rendering the application unusable. + /* Hide dialog before setting values. This prevents an obscure bug + where non-embedded VST windows would steal focus and prevent LMMS + from taking mouse input, rendering the application unusable. */ QDialog::accept(); - ConfigManager::inst()->setValue( "mixer", "framesperaudiobuffer", - QString::number( m_bufferSize ) ); - ConfigManager::inst()->setValue( "mixer", "audiodev", - m_audioIfaceNames[m_audioInterfaces->currentText()] ); - ConfigManager::inst()->setValue( "mixer", "mididev", - m_midiIfaceNames[m_midiInterfaces->currentText()] ); - ConfigManager::inst()->setValue( "tooltips", "disabled", - QString::number( !m_toolTips ) ); - ConfigManager::inst()->setValue( "app", "nomsgaftersetup", - QString::number( !m_warnAfterSetup ) ); - ConfigManager::inst()->setValue( "app", "displaydbfs", - QString::number( m_displaydBFS ) ); - ConfigManager::inst()->setValue( "app", "nommpz", - QString::number( !m_MMPZ ) ); - ConfigManager::inst()->setValue( "app", "disablebackup", - QString::number( !m_disableBackup ) ); - ConfigManager::inst()->setValue( "app", "openlastproject", - QString::number( m_openLastProject ) ); - ConfigManager::inst()->setValue( "app", "nanhandler", - QString::number( m_NaNHandler ) ); - ConfigManager::inst()->setValue( "mixer", "hqaudio", - QString::number( m_hqAudioDev ) ); - ConfigManager::inst()->setValue( "ui", "smoothscroll", - QString::number( m_smoothScroll ) ); - ConfigManager::inst()->setValue( "ui", "enableautosave", - QString::number( m_enableAutoSave ) ); - ConfigManager::inst()->setValue( "ui", "saveinterval", - QString::number( m_saveInterval ) ); - ConfigManager::inst()->setValue( "ui", "enablerunningautosave", - QString::number( m_enableRunningAutoSave ) ); - ConfigManager::inst()->setValue( "ui", "oneinstrumenttrackwindow", - QString::number( m_oneInstrumentTrackWindow ) ); - ConfigManager::inst()->setValue( "ui", "compacttrackbuttons", - QString::number( m_compactTrackButtons ) ); - ConfigManager::inst()->setValue( "ui", "syncvstplugins", - QString::number( m_syncVSTPlugins ) ); - ConfigManager::inst()->setValue( "ui", "animateafp", - QString::number( m_animateAFP ) ); - ConfigManager::inst()->setValue( "ui", "printnotelabels", - QString::number( m_printNoteLabels ) ); - ConfigManager::inst()->setValue( "ui", "displaywaveform", - QString::number( m_displayWaveform ) ); - ConfigManager::inst()->setValue( "ui", "disableautoquit", - QString::number( m_disableAutoQuit ) ); - ConfigManager::inst()->setValue( "app", "language", m_lang ); - ConfigManager::inst()->setValue( "ui", "vstembedmethod", - m_vstEmbedMethod ); - ConfigManager::inst()->setValue( "ui", "vstalwaysontop", - QString::number( m_vstAlwaysOnTop ) ); + ConfigManager::inst()->setValue("app", "displaydbfs", + QString::number(m_displaydBFS)); + ConfigManager::inst()->setValue("tooltips", "disabled", + QString::number(!m_tooltips)); + ConfigManager::inst()->setValue("ui", "displaywaveform", + QString::number(m_displayWaveform)); + ConfigManager::inst()->setValue("ui", "printnotelabels", + QString::number(m_printNoteLabels)); + ConfigManager::inst()->setValue("ui", "compacttrackbuttons", + QString::number(m_compactTrackButtons)); + ConfigManager::inst()->setValue("ui", "oneinstrumenttrackwindow", + QString::number(m_oneInstrumentTrackWindow)); + ConfigManager::inst()->setValue("app", "nommpz", + QString::number(!m_MMPZ)); + ConfigManager::inst()->setValue("app", "disablebackup", + QString::number(!m_disableBackup)); + ConfigManager::inst()->setValue("app", "openlastproject", + QString::number(m_openLastProject)); + ConfigManager::inst()->setValue("app", "language", m_lang); + ConfigManager::inst()->setValue("ui", "saveinterval", + QString::number(m_saveInterval)); + ConfigManager::inst()->setValue("ui", "enableautosave", + QString::number(m_enableAutoSave)); + ConfigManager::inst()->setValue("ui", "enablerunningautosave", + QString::number(m_enableRunningAutoSave)); + ConfigManager::inst()->setValue("ui", "smoothscroll", + QString::number(m_smoothScroll)); + ConfigManager::inst()->setValue("ui", "animateafp", + QString::number(m_animateAFP)); + ConfigManager::inst()->setValue("ui", "vstembedmethod", + m_vstEmbedComboBox->currentData().toString()); + ConfigManager::inst()->setValue("ui", "vstalwaysontop", + QString::number(m_vstAlwaysOnTop)); + ConfigManager::inst()->setValue("ui", "syncvstplugins", + QString::number(m_syncVSTPlugins)); + ConfigManager::inst()->setValue("ui", "disableautoquit", + QString::number(m_disableAutoQuit)); + ConfigManager::inst()->setValue("mixer", "audiodev", + m_audioIfaceNames[m_audioInterfaces->currentText()]); + ConfigManager::inst()->setValue("app", "nanhandler", + QString::number(m_NaNHandler)); + ConfigManager::inst()->setValue("mixer", "hqaudio", + QString::number(m_hqAudioDev)); + ConfigManager::inst()->setValue("mixer", "framesperaudiobuffer", + QString::number(m_bufferSize)); + ConfigManager::inst()->setValue("mixer", "mididev", + m_midiIfaceNames[m_midiInterfaces->currentText()]); ConfigManager::inst()->setWorkingDir(QDir::fromNativeSeparators(m_workingDir)); ConfigManager::inst()->setVSTDir(QDir::fromNativeSeparators(m_vstDir)); - ConfigManager::inst()->setGIGDir(QDir::fromNativeSeparators(m_gigDir)); + ConfigManager::inst()->setLADSPADir(QDir::fromNativeSeparators(m_ladspaDir)); ConfigManager::inst()->setSF2Dir(QDir::fromNativeSeparators(m_sf2Dir)); - ConfigManager::inst()->setArtworkDir(QDir::fromNativeSeparators(m_artworkDir)); - ConfigManager::inst()->setLADSPADir(QDir::fromNativeSeparators(m_ladDir)); #ifdef LMMS_HAVE_FLUIDSYNTH - ConfigManager::inst()->setDefaultSoundfont( m_defaultSoundfont ); + ConfigManager::inst()->setSF2File(m_sf2File); #endif -#ifdef LMMS_HAVE_STK - ConfigManager::inst()->setSTKDir(QDir::fromNativeSeparators(m_stkDir)); -#endif - ConfigManager::inst()->setBackgroundArtwork( m_backgroundArtwork ); + ConfigManager::inst()->setGIGDir(QDir::fromNativeSeparators(m_gigDir)); + ConfigManager::inst()->setThemeDir(QDir::fromNativeSeparators(m_themeDir)); + ConfigManager::inst()->setBackgroundPicFile(m_backgroundPicFile); - // tell all audio-settings-widget to save their settings - for( AswMap::iterator it = m_audioIfaceSetupWidgets.begin(); - it != m_audioIfaceSetupWidgets.end(); ++it ) + // Tell all audio-settings-widgets to save their settings. + for(AswMap::iterator it = m_audioIfaceSetupWidgets.begin(); + it != m_audioIfaceSetupWidgets.end(); ++it) { it.value()->saveSettings(); } - // tell all MIDI-settings-widget to save their settings - for( MswMap::iterator it = m_midiIfaceSetupWidgets.begin(); - it != m_midiIfaceSetupWidgets.end(); ++it ) + // Tell all MIDI-settings-widgets to save their settings. + for(MswMap::iterator it = m_midiIfaceSetupWidgets.begin(); + it != m_midiIfaceSetupWidgets.end(); ++it) { it.value()->saveSettings(); } - ConfigManager::inst()->saveConfigFile(); } -void SetupDialog::setBufferSize( int _value ) +// General settings slots. + +void SetupDialog::toggleDisplaydBFS(bool enabled) { - const int step = DEFAULT_BUFFER_SIZE / BUFFERSIZE_RESOLUTION; - if( _value > step && _value % step ) - { - int mod_value = _value % step; - if( mod_value < step / 2 ) - { - m_bufSizeSlider->setValue( _value - mod_value ); - } - else - { - m_bufSizeSlider->setValue( _value + step - mod_value ); - } - return; - } - - if( m_bufSizeSlider->value() != _value ) - { - m_bufSizeSlider->setValue( _value ); - } - - m_bufferSize = _value * BUFFERSIZE_RESOLUTION; - m_bufSizeLbl->setText( tr( "Frames: %1\nLatency: %2 ms" ).arg( - m_bufferSize ).arg( - 1000.0f * m_bufferSize / - Engine::mixer()->processingSampleRate(), - 0, 'f', 1 ) ); + m_displaydBFS = enabled; } - - -void SetupDialog::resetBufSize() +void SetupDialog::toggleTooltips(bool enabled) { - setBufferSize( DEFAULT_BUFFER_SIZE / BUFFERSIZE_RESOLUTION ); + m_tooltips = enabled; } - - -void SetupDialog::toggleToolTips( bool _enabled ) +void SetupDialog::toggleDisplayWaveform(bool enabled) { - m_toolTips = _enabled; + m_displayWaveform = enabled; } - - -void SetupDialog::toggleWarnAfterSetup( bool _enabled ) +void SetupDialog::toggleNoteLabels(bool enabled) { - m_warnAfterSetup = _enabled; + m_printNoteLabels = enabled; } - - -void SetupDialog::toggleDisplaydBFS( bool _enabled ) +void SetupDialog::toggleCompactTrackButtons(bool enabled) { - m_displaydBFS = _enabled; + m_compactTrackButtons = enabled; } - - -void SetupDialog::toggleMMPZ( bool _enabled ) +void SetupDialog::toggleOneInstrumentTrackWindow(bool enabled) { - m_MMPZ = _enabled; + m_oneInstrumentTrackWindow = enabled; } - - -void SetupDialog::toggleDisableBackup( bool _enabled ) +void SetupDialog::toggleMMPZ(bool enabled) { - m_disableBackup = _enabled; + m_MMPZ = enabled; } - - -void SetupDialog::toggleOpenLastProject( bool _enabled ) +void SetupDialog::toggleDisableBackup(bool enabled) { - m_openLastProject = _enabled; + m_disableBackup = enabled; } - - -void SetupDialog::toggleHQAudioDev( bool _enabled ) +void SetupDialog::toggleOpenLastProject(bool enabled) { - m_hqAudioDev = _enabled; + m_openLastProject = enabled; } - - -void SetupDialog::toggleSmoothScroll( bool _enabled ) -{ - m_smoothScroll = _enabled; -} - - - - -void SetupDialog::toggleAutoSave( bool _enabled ) -{ - m_enableAutoSave = _enabled; - m_saveIntervalSlider->setEnabled( _enabled ); - m_runningAutoSave->setVisible( _enabled ); - setAutoSaveInterval( m_saveIntervalSlider->value() ); -} - - - - -void SetupDialog::toggleRunningAutoSave( bool _enabled ) -{ - m_enableRunningAutoSave = _enabled; -} - - - - -void SetupDialog::toggleCompactTrackButtons( bool _enabled ) -{ - m_compactTrackButtons = _enabled; -} - - - - - -void SetupDialog::toggleSyncVSTPlugins( bool _enabled ) -{ - m_syncVSTPlugins = _enabled; -} - -void SetupDialog::toggleAnimateAFP( bool _enabled ) -{ - m_animateAFP = _enabled; -} - - -void SetupDialog::toggleNoteLabels( bool en ) -{ - m_printNoteLabels = en; -} - - -void SetupDialog::toggleDisplayWaveform( bool en ) -{ - m_displayWaveform = en; -} - - -void SetupDialog::toggleDisableAutoquit( bool en ) -{ - m_disableAutoQuit = en; -} - - -void SetupDialog::toggleOneInstrumentTrackWindow( bool _enabled ) -{ - m_oneInstrumentTrackWindow = _enabled; -} - - -void SetupDialog::vstEmbedMethodChanged() -{ - m_vstEmbedMethod = m_vstEmbedComboBox->currentData().toString(); - m_vstAlwaysOnTopCheckBox->setVisible( m_vstEmbedMethod == "none" ); -} - - -void SetupDialog::toggleVSTAlwaysOnTop( bool en ) -{ - m_vstAlwaysOnTop = en; -} - - -void SetupDialog::setLanguage( int lang ) +void SetupDialog::setLanguage(int lang) { m_lang = m_languages[lang]; } @@ -1094,270 +1006,322 @@ void SetupDialog::setLanguage( int lang ) +// Performance settings slots. -void SetupDialog::openWorkingDir() -{ - QString new_dir = FileDialog::getExistingDirectory( this, - tr( "Choose LMMS working directory" ), m_workingDir ); - if( ! new_dir.isEmpty() ) - { - m_wdLineEdit->setText( new_dir ); - } -} - -void SetupDialog::openGIGDir() -{ - QString new_dir = FileDialog::getExistingDirectory( this, - tr( "Choose your GIG directory" ), - m_gigDir ); - if( ! new_dir.isEmpty() ) - { - m_gigLineEdit->setText( new_dir ); - } -} - -void SetupDialog::openSF2Dir() -{ - QString new_dir = FileDialog::getExistingDirectory( this, - tr( "Choose your SF2 directory" ), - m_sf2Dir ); - if( ! new_dir.isEmpty() ) - { - m_sf2LineEdit->setText( new_dir ); - } -} - - - - -void SetupDialog::setWorkingDir( const QString & _wd ) -{ - m_workingDir = _wd; -} - - - - -void SetupDialog::openVSTDir() -{ - QString new_dir = FileDialog::getExistingDirectory( this, - tr( "Choose your VST-plugin directory" ), - m_vstDir ); - if( ! new_dir.isEmpty() ) - { - m_vdLineEdit->setText( new_dir ); - } -} - - - - -void SetupDialog::setVSTDir( const QString & _vd ) -{ - m_vstDir = _vd; -} - -void SetupDialog::setGIGDir(const QString &_gd) -{ - m_gigDir = _gd; -} - -void SetupDialog::setSF2Dir(const QString &_sfd) -{ - m_sf2Dir = _sfd; -} - - - - -void SetupDialog::openArtworkDir() -{ - QString new_dir = FileDialog::getExistingDirectory( this, - tr( "Choose artwork-theme directory" ), - m_artworkDir ); - if( ! new_dir.isEmpty() ) - { - m_adLineEdit->setText( new_dir ); - } -} - - - - -void SetupDialog::setArtworkDir( const QString & _ad ) -{ - m_artworkDir = _ad; -} - - - - -void SetupDialog::openLADSPADir() -{ - QString new_dir = FileDialog::getExistingDirectory( this, - tr( "Choose LADSPA plugin directory" ), - m_ladDir ); - if( ! new_dir.isEmpty() ) - { - if( m_ladLineEdit->text() == "" ) - { - m_ladLineEdit->setText( new_dir ); - } - else - { - m_ladLineEdit->setText( m_ladLineEdit->text() + "," + - new_dir ); - } - } -} - - - -void SetupDialog::openSTKDir() -{ -#ifdef LMMS_HAVE_STK - QString new_dir = FileDialog::getExistingDirectory( this, - tr( "Choose STK rawwave directory" ), - m_stkDir ); - if( ! new_dir.isEmpty() ) - { - m_stkLineEdit->setText( new_dir ); - } -#endif -} - - - - -void SetupDialog::openDefaultSoundfont() -{ -#ifdef LMMS_HAVE_FLUIDSYNTH - QString new_file = FileDialog::getOpenFileName( this, - tr( "Choose default SoundFont" ), m_defaultSoundfont, - "SoundFont2 Files (*.sf2)" ); - - if( ! new_file.isEmpty() ) - { - m_sfLineEdit->setText( new_file ); - } -#endif -} - - - - -void SetupDialog::openBackgroundArtwork() -{ - QList fileTypesList = QImageReader::supportedImageFormats(); - QString fileTypes; - for( int i = 0; i < fileTypesList.count(); i++ ) - { - if( fileTypesList[i] != fileTypesList[i].toUpper() ) - { - if( !fileTypes.isEmpty() ) - { - fileTypes += " "; - } - fileTypes += "*." + QString( fileTypesList[i] ); - } - } - - QString dir = ( m_backgroundArtwork.isEmpty() ) ? - m_artworkDir : - m_backgroundArtwork; - QString new_file = FileDialog::getOpenFileName( this, - tr( "Choose background artwork" ), dir, - "Image Files (" + fileTypes + ")" ); - - if( ! new_file.isEmpty() ) - { - m_baLineEdit->setText( new_file ); - } -} - - - - -void SetupDialog::setLADSPADir( const QString & _fd ) -{ - m_ladDir = _fd; -} - - - - -void SetupDialog::setSTKDir( const QString & _fd ) -{ -#ifdef LMMS_HAVE_STK - m_stkDir = _fd; -#endif -} - - - - -void SetupDialog::setDefaultSoundfont( const QString & _sf ) -{ -#ifdef LMMS_HAVE_FLUIDSYNTH - m_defaultSoundfont = _sf; -#endif -} - - - - -void SetupDialog::setBackgroundArtwork( const QString & _ba ) -{ - m_backgroundArtwork = _ba; -} - - - - -void SetupDialog::setAutoSaveInterval( int value ) +void SetupDialog::setAutoSaveInterval(int value) { m_saveInterval = value; - m_saveIntervalSlider->setValue( m_saveInterval ); - QString minutes = m_saveInterval > 1 ? tr( "minutes" ) : tr( "minute" ); - minutes = QString( "%1 %2" ).arg( QString::number( m_saveInterval ), minutes ); - minutes = m_enableAutoSave ? minutes : tr( "Disabled" ); - m_saveIntervalLbl->setText( tr( "Auto-save interval: %1" ).arg( minutes ) ); + m_saveIntervalSlider->setValue(m_saveInterval); + QString minutes = m_saveInterval > 1 ? tr("minutes") : tr("minute"); + minutes = QString("%1 %2").arg(QString::number(m_saveInterval), minutes); + minutes = m_enableAutoSave ? minutes : tr("Disabled"); + m_saveIntervalLbl->setText( + tr("Autosave interval: %1").arg(minutes)); } +void SetupDialog::toggleAutoSave(bool enabled) +{ + m_enableAutoSave = enabled; + m_saveIntervalSlider->setEnabled(enabled); + m_runningAutoSave->setVisible(enabled); + setAutoSaveInterval(m_saveIntervalSlider->value()); +} + + +void SetupDialog::toggleRunningAutoSave(bool enabled) +{ + m_enableRunningAutoSave = enabled; +} void SetupDialog::resetAutoSave() { - setAutoSaveInterval( MainWindow::DEFAULT_SAVE_INTERVAL_MINUTES ); - m_autoSave->setChecked( true ); - m_runningAutoSave->setChecked( false ); + setAutoSaveInterval(MainWindow::DEFAULT_SAVE_INTERVAL_MINUTES); + m_autoSave->setChecked(true); + m_runningAutoSave->setChecked(false); +} + + +void SetupDialog::toggleSmoothScroll(bool enabled) +{ + m_smoothScroll = enabled; +} + + +void SetupDialog::toggleAnimateAFP(bool enabled) +{ + m_animateAFP = enabled; +} + + +void SetupDialog::toggleSyncVSTPlugins(bool enabled) +{ + m_syncVSTPlugins = enabled; +} + + +void SetupDialog::vstEmbedMethodChanged() +{ + m_vstEmbedMethod = m_vstEmbedComboBox->currentData().toString(); + m_vstAlwaysOnTopCheckBox->setVisible(m_vstEmbedMethod == "none"); +} + + +void SetupDialog::toggleVSTAlwaysOnTop(bool enabled) +{ + m_vstAlwaysOnTop = enabled; +} + + +void SetupDialog::toggleDisableAutoQuit(bool enabled) +{ + m_disableAutoQuit = enabled; } -void SetupDialog::audioInterfaceChanged( const QString & _iface ) +// Audio settings slots. + +void SetupDialog::toggleHQAudioDev(bool enabled) { - for( AswMap::iterator it = m_audioIfaceSetupWidgets.begin(); - it != m_audioIfaceSetupWidgets.end(); ++it ) + m_hqAudioDev = enabled; +} + + +void SetupDialog::audioInterfaceChanged(const QString & iface) +{ + for(AswMap::iterator it = m_audioIfaceSetupWidgets.begin(); + it != m_audioIfaceSetupWidgets.end(); ++it) { it.value()->hide(); } - m_audioIfaceSetupWidgets[m_audioIfaceNames[_iface]]->show(); + m_audioIfaceSetupWidgets[m_audioIfaceNames[iface]]->show(); } - - -void SetupDialog::midiInterfaceChanged( const QString & _iface ) +void SetupDialog::setBufferSize(int value) { - for( MswMap::iterator it = m_midiIfaceSetupWidgets.begin(); - it != m_midiIfaceSetupWidgets.end(); ++it ) + const int step = DEFAULT_BUFFER_SIZE / BUFFERSIZE_RESOLUTION; + if(value > step && value % step) + { + int mod_value = value % step; + if(mod_value < step / 2) + { + m_bufferSizeSlider->setValue(value - mod_value); + } + else + { + m_bufferSizeSlider->setValue(value + step - mod_value); + } + return; + } + + if(m_bufferSizeSlider->value() != value) + { + m_bufferSizeSlider->setValue(value); + } + + m_bufferSize = value * BUFFERSIZE_RESOLUTION; + m_bufferSizeLbl->setText(tr("Frames: %1\nLatency: %2 ms").arg(m_bufferSize).arg( + 1000.0f * m_bufferSize / Engine::mixer()->processingSampleRate(), 0, 'f', 1)); +} + + +void SetupDialog::resetBufferSize() +{ + setBufferSize(DEFAULT_BUFFER_SIZE / BUFFERSIZE_RESOLUTION); +} + + +// MIDI settings slots. + +void SetupDialog::midiInterfaceChanged(const QString & iface) +{ + for(MswMap::iterator it = m_midiIfaceSetupWidgets.begin(); + it != m_midiIfaceSetupWidgets.end(); ++it) { it.value()->hide(); } - m_midiIfaceSetupWidgets[m_midiIfaceNames[_iface]]->show(); + m_midiIfaceSetupWidgets[m_midiIfaceNames[iface]]->show(); +} + + +// Paths settings slots. + +void SetupDialog::openWorkingDir() +{ + QString new_dir = FileDialog::getExistingDirectory(this, + tr("Choose the LMMS working directory"), m_workingDir); + if (!new_dir.isEmpty()) + { + m_workingDirLineEdit->setText(new_dir); + } +} + + +void SetupDialog::setWorkingDir(const QString & workingDir) +{ + m_workingDir = workingDir; +} + + +void SetupDialog::openVSTDir() +{ + QString new_dir = FileDialog::getExistingDirectory(this, + tr("Choose your VST plugins directory"), m_vstDir); + if (!new_dir.isEmpty()) + { + m_vstDirLineEdit->setText(new_dir); + } +} + + +void SetupDialog::setVSTDir(const QString & vstDir) +{ + m_vstDir = vstDir; +} + + +void SetupDialog::openLADSPADir() +{ + QString new_dir = FileDialog::getExistingDirectory(this, + tr("Choose your LADSPA plugins directory"), m_ladspaDir); + if (!new_dir.isEmpty()) + { + if(m_ladspaDirLineEdit->text() == "") + { + m_ladspaDirLineEdit->setText(new_dir); + } + else + { + m_ladspaDirLineEdit->setText(m_ladspaDirLineEdit->text() + "," + + new_dir); + } + } +} + + +void SetupDialog::setLADSPADir(const QString & ladspaDir) +{ + m_ladspaDir = ladspaDir; +} + + +void SetupDialog::openSF2Dir() +{ + QString new_dir = FileDialog::getExistingDirectory(this, + tr("Choose your SF2 directory"), m_sf2Dir); + if (!new_dir.isEmpty()) + { + m_sf2DirLineEdit->setText(new_dir); + } +} + + +void SetupDialog::setSF2Dir(const QString & sf2Dir) +{ + m_sf2Dir = sf2Dir; +} + + +void SetupDialog::openSF2File() +{ +#ifdef LMMS_HAVE_FLUIDSYNTH + QString new_file = FileDialog::getOpenFileName(this, + tr("Choose your default SF2"), m_sf2File, "SoundFont 2 files (*.sf2)"); + + if (!new_file.isEmpty()) + { + m_sf2FileLineEdit->setText(new_file); + } +#endif +} + + +void SetupDialog::setSF2File(const QString & sf2File) +{ +#ifdef LMMS_HAVE_FLUIDSYNTH + m_sf2File = sf2File; +#endif +} + + +void SetupDialog::openGIGDir() +{ + QString new_dir = FileDialog::getExistingDirectory(this, + tr("Choose your GIG directory"), m_gigDir); + if(new_dir != QString::null) + { + m_gigDirLineEdit->setText(new_dir); + } +} + + +void SetupDialog::setGIGDir(const QString & gigDir) +{ + m_gigDir = gigDir; +} + + +void SetupDialog::openThemeDir() +{ + QString new_dir = FileDialog::getExistingDirectory(this, + tr("Choose your theme directory"), m_themeDir); + if(new_dir != QString::null) + { + m_themeDirLineEdit->setText(new_dir); + } +} + + +void SetupDialog::setThemeDir(const QString & themeDir) +{ + m_themeDir = themeDir; +} + + +void SetupDialog::openBackgroundPicFile() +{ + QList fileTypesList = QImageReader::supportedImageFormats(); + QString fileTypes; + for(int i = 0; i < fileTypesList.count(); i++) + { + if(fileTypesList[i] != fileTypesList[i].toUpper()) + { + if(!fileTypes.isEmpty()) + { + fileTypes += " "; + } + fileTypes += "*." + QString(fileTypesList[i]); + } + } + + QString dir = (m_backgroundPicFile.isEmpty()) ? + m_themeDir : + m_backgroundPicFile; + QString new_file = FileDialog::getOpenFileName(this, + tr("Choose your background picture"), dir, "Picture files (" + fileTypes + ")"); + + if(new_file != QString::null) + { + m_backgroundPicFileLineEdit->setText(new_file); + } +} + + +void SetupDialog::setBackgroundPicFile(const QString & backgroundPicFile) +{ + m_backgroundPicFile = backgroundPicFile; +} + + + + +void SetupDialog::showRestartWarning() +{ + restartWarningLbl->show(); } diff --git a/src/gui/TimeLineWidget.cpp b/src/gui/TimeLineWidget.cpp index dfa7e388f..bd196de7f 100644 --- a/src/gui/TimeLineWidget.cpp +++ b/src/gui/TimeLineWidget.cpp @@ -42,7 +42,7 @@ QPixmap * TimeLineWidget::s_posMarkerPixmap = NULL; -TimeLineWidget::TimeLineWidget( const int xoff, const int yoff, const float ppt, +TimeLineWidget::TimeLineWidget( const int xoff, const int yoff, const float ppb, Song::PlayPos & pos, const MidiTime & begin, Song::PlayModes mode, QWidget * parent ) : QWidget( parent ), @@ -61,7 +61,7 @@ TimeLineWidget::TimeLineWidget( const int xoff, const int yoff, const float ppt, m_changedPosition( true ), m_xOffset( xoff ), m_posMarkerX( 0 ), - m_ppt( ppt ), + m_ppb( ppb ), m_pos( pos ), m_begin( begin ), m_mode( mode ), @@ -71,7 +71,7 @@ TimeLineWidget::TimeLineWidget( const int xoff, const int yoff, const float ppt, m_moveXOff( 0 ) { m_loopPos[0] = 0; - m_loopPos[1] = DefaultTicksPerTact; + m_loopPos[1] = DefaultTicksPerBar; if( s_posMarkerPixmap == NULL ) { @@ -247,18 +247,18 @@ void TimeLineWidget::paintEvent( QPaintEvent * ) QColor const & barLineColor = getBarLineColor(); QColor const & barNumberColor = getBarNumberColor(); - tact_t barNumber = m_begin.getTact(); + bar_t barNumber = m_begin.getBar(); int const x = m_xOffset + s_posMarkerPixmap->width() / 2 - - ( ( static_cast( m_begin * m_ppt ) / MidiTime::ticksPerTact() ) % static_cast( m_ppt ) ); + ( ( static_cast( m_begin * m_ppb ) / MidiTime::ticksPerBar() ) % static_cast( m_ppb ) ); - for( int i = 0; x + i * m_ppt < width(); ++i ) + for( int i = 0; x + i * m_ppb < width(); ++i ) { ++barNumber; if( ( barNumber - 1 ) % qMax( 1, qRound( 1.0f / 3.0f * - MidiTime::ticksPerTact() / m_ppt ) ) == 0 ) + MidiTime::ticksPerBar() / m_ppb ) ) == 0 ) { - const int cx = x + qRound( i * m_ppt ); + const int cx = x + qRound( i * m_ppb ); p.setPen( barLineColor ); p.drawLine( cx, 5, cx, height() - 6 ); @@ -313,7 +313,7 @@ void TimeLineWidget::mousePressEvent( QMouseEvent* event ) else if( event->button() == Qt::RightButton ) { m_moveXOff = s_posMarkerPixmap->width() / 2; - const MidiTime t = m_begin + static_cast( qMax( event->x() - m_xOffset - m_moveXOff, 0 ) * MidiTime::ticksPerTact() / m_ppt ); + const MidiTime t = m_begin + static_cast( qMax( event->x() - m_xOffset - m_moveXOff, 0 ) * MidiTime::ticksPerBar() / m_ppb ); const MidiTime loopMid = ( m_loopPos[0] + m_loopPos[1] ) / 2; if( t < loopMid ) @@ -349,7 +349,7 @@ void TimeLineWidget::mousePressEvent( QMouseEvent* event ) void TimeLineWidget::mouseMoveEvent( QMouseEvent* event ) { parentWidget()->update(); // essential for widgets that this timeline had taken their mouse move event from. - const MidiTime t = m_begin + static_cast( qMax( event->x() - m_xOffset - m_moveXOff, 0 ) * MidiTime::ticksPerTact() / m_ppt ); + const MidiTime t = m_begin + static_cast( qMax( event->x() - m_xOffset - m_moveXOff, 0 ) * MidiTime::ticksPerBar() / m_ppb ); switch( m_action ) { @@ -387,10 +387,14 @@ void TimeLineWidget::mouseMoveEvent( QMouseEvent* event ) { // Note, swap 1 and 0 below and the behavior "skips" the other // marking instead of pushing it. - if( m_action == MoveLoopBegin ) - m_loopPos[0] -= MidiTime::ticksPerTact(); + if( m_action == MoveLoopBegin ) + { + m_loopPos[0] -= MidiTime::ticksPerBar(); + } else - m_loopPos[1] += MidiTime::ticksPerTact(); + { + m_loopPos[1] += MidiTime::ticksPerBar(); + } } update(); break; diff --git a/src/gui/TrackContainerView.cpp b/src/gui/TrackContainerView.cpp index 649323c07..9b51c76f2 100644 --- a/src/gui/TrackContainerView.cpp +++ b/src/gui/TrackContainerView.cpp @@ -54,9 +54,8 @@ TrackContainerView::TrackContainerView( TrackContainer * _tc ) : m_tc( _tc ), m_trackViews(), m_scrollArea( new scrollArea( this ) ), - m_ppt( DEFAULT_PIXELS_PER_TACT ), - m_rubberBand( new RubberBand( m_scrollArea ) ), - m_origin() + m_ppb( DEFAULT_PIXELS_PER_BAR ), + m_rubberBand( new RubberBand( m_scrollArea ) ) { m_tc->setHook( this ); //keeps the direction of the widget, undepended on the locale @@ -306,9 +305,9 @@ bool TrackContainerView::allowRubberband() const -void TrackContainerView::setPixelsPerTact( int _ppt ) +void TrackContainerView::setPixelsPerBar( int ppb ) { - m_ppt = _ppt; + m_ppb = ppb; // tell all TrackContentWidgets to update their background tile pixmap for( trackViewList::Iterator it = m_trackViews.begin(); @@ -345,12 +344,8 @@ void TrackContainerView::dragEnterEvent( QDragEnterEvent * _dee ) arg( Track::SampleTrack ) ); } -void TrackContainerView::selectRegionFromPixels(int xStart, int xEnd) -{ - m_rubberBand->setEnabled( true ); - m_rubberBand->show(); - m_rubberBand->setGeometry( min( xStart, xEnd ), 0, max( xStart, xEnd ) - min( xStart, xEnd ), std::numeric_limits::max() ); -} + + void TrackContainerView::stopRubberBand() { @@ -427,55 +422,18 @@ void TrackContainerView::dropEvent( QDropEvent * _de ) -void TrackContainerView::mousePressEvent( QMouseEvent * _me ) -{ - if( allowRubberband() == true ) - { - m_origin = m_scrollArea->mapFromParent( _me->pos() ); - m_rubberBand->setEnabled( true ); - m_rubberBand->setGeometry( QRect( m_origin, QSize() ) ); - m_rubberBand->show(); - } - QWidget::mousePressEvent( _me ); -} - - - - -void TrackContainerView::mouseMoveEvent( QMouseEvent * _me ) -{ - if( rubberBandActive() == true ) - { - m_rubberBand->setGeometry( QRect( m_origin, - m_scrollArea->mapFromParent( _me->pos() ) ). - normalized() ); - } - QWidget::mouseMoveEvent( _me ); -} - - - - -void TrackContainerView::mouseReleaseEvent( QMouseEvent * _me ) -{ - m_rubberBand->hide(); - m_rubberBand->setEnabled( false ); - QWidget::mouseReleaseEvent( _me ); -} - - - - - void TrackContainerView::resizeEvent( QResizeEvent * _re ) { realignTracks(); QWidget::resizeEvent( _re ); } + + + RubberBand *TrackContainerView::rubberBand() const { - return m_rubberBand; + return m_rubberBand; } diff --git a/src/gui/dialogs/FileDialog.cpp b/src/gui/dialogs/FileDialog.cpp index 3ce10760a..54cc9d6e4 100644 --- a/src/gui/dialogs/FileDialog.cpp +++ b/src/gui/dialogs/FileDialog.cpp @@ -47,7 +47,7 @@ FileDialog::FileDialog( QWidget *parent, const QString &caption, // Find downloads directory QDir downloadDir( QDir::homePath() + "/Downloads" ); if ( ! downloadDir.exists() ) - downloadDir = QStandardPaths::writableLocation( QStandardPaths::DownloadLocation ); + downloadDir.setPath(QStandardPaths::writableLocation( QStandardPaths::DownloadLocation )); if ( downloadDir.exists() ) urls << QUrl::fromLocalFile( downloadDir.absolutePath() ); diff --git a/src/gui/editors/AutomationEditor.cpp b/src/gui/editors/AutomationEditor.cpp index 94e9d5cc8..bf56e3039 100644 --- a/src/gui/editors/AutomationEditor.cpp +++ b/src/gui/editors/AutomationEditor.cpp @@ -92,7 +92,7 @@ AutomationEditor::AutomationEditor() : m_moveStartTick( 0 ), m_drawLastLevel( 0.0f ), m_drawLastTick( 0 ), - m_ppt( DEFAULT_PPT ), + m_ppb( DEFAULT_PPB ), m_y_delta( DEFAULT_Y_DELTA ), m_y_auto( true ), m_editMode( DRAW ), @@ -149,7 +149,7 @@ AutomationEditor::AutomationEditor() : } // add time-line - m_timeLine = new TimeLineWidget( VALUES_WIDTH, 0, m_ppt, + m_timeLine = new TimeLineWidget( VALUES_WIDTH, 0, m_ppb, Engine::getSong()->getPlayPos( Song::Mode_PlayAutomationPattern ), m_currentPosition, @@ -198,6 +198,8 @@ AutomationEditor::AutomationEditor() : setCurrentPattern( NULL ); setMouseTracking( true ); + setFocusPolicy( Qt::StrongFocus ); + setFocus(); } @@ -512,7 +514,7 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent ) x -= VALUES_WIDTH; // get tick in which the user clicked - int pos_ticks = x * MidiTime::ticksPerTact() / m_ppt + + int pos_ticks = x * MidiTime::ticksPerBar() / m_ppb + m_currentPosition; // get time map of current pattern @@ -529,7 +531,7 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent ) if( pos_ticks >= it.key() && ( it+1==time_map.end() || pos_ticks <= (it+1).key() ) && - ( pos_ticks<= it.key() + MidiTime::ticksPerTact() *4 / m_ppt ) && + ( pos_ticks<= it.key() + MidiTime::ticksPerBar() *4 / m_ppb ) && ( level == it.value() || mouseEvent->button() == Qt::RightButton ) ) { break; @@ -581,7 +583,7 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent ) int aligned_x = (int)( (float)( ( it.key() - m_currentPosition ) * - m_ppt ) / MidiTime::ticksPerTact() ); + m_ppb ) / MidiTime::ticksPerBar() ); m_moveXOffset = x - aligned_x - 1; // set move-cursor QCursor c( Qt::SizeAllCursor ); @@ -738,7 +740,7 @@ void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent ) x -= m_moveXOffset; } - int pos_ticks = x * MidiTime::ticksPerTact() / m_ppt + + int pos_ticks = x * MidiTime::ticksPerBar() / m_ppb + m_currentPosition; if( mouseEvent->buttons() & Qt::LeftButton && m_editMode == DRAW ) { @@ -870,7 +872,7 @@ void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent ) } // get tick in which the cursor is posated - int pos_ticks = x * MidiTime::ticksPerTact() / m_ppt + + int pos_ticks = x * MidiTime::ticksPerBar() / m_ppb + m_currentPosition; m_selectedTick = pos_ticks - m_selectStartTick; @@ -891,7 +893,7 @@ void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent ) // move selection + selected values // do horizontal move-stuff - int pos_ticks = x * MidiTime::ticksPerTact() / m_ppt + + int pos_ticks = x * MidiTime::ticksPerBar() / m_ppb + m_currentPosition; int ticks_diff = pos_ticks - m_moveStartTick; @@ -916,8 +918,8 @@ void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent ) } m_selectStartTick += ticks_diff; - int tact_diff = ticks_diff / MidiTime::ticksPerTact(); - ticks_diff = ticks_diff % MidiTime::ticksPerTact(); + int bar_diff = ticks_diff / MidiTime::ticksPerBar(); + ticks_diff = ticks_diff % MidiTime::ticksPerBar(); // do vertical move-stuff @@ -965,24 +967,24 @@ void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent ) MidiTime new_value_pos; if( it.key() ) { - int value_tact = + int value_bar = ( it.key() / - MidiTime::ticksPerTact() ) - + tact_diff; + MidiTime::ticksPerBar() ) + + bar_diff; int value_ticks = ( it.key() % - MidiTime::ticksPerTact() ) + MidiTime::ticksPerBar() ) + ticks_diff; // ensure value_ticks range - if( value_ticks / MidiTime::ticksPerTact() ) + if( value_ticks / MidiTime::ticksPerBar() ) { - value_tact += value_ticks - / MidiTime::ticksPerTact(); + value_bar += value_ticks + / MidiTime::ticksPerBar(); value_ticks %= - MidiTime::ticksPerTact(); + MidiTime::ticksPerBar(); } m_pattern->removeValue( it.key() ); - new_value_pos = MidiTime( value_tact, + new_value_pos = MidiTime( value_bar, value_ticks ); } new_selValuesForMove[ @@ -1030,7 +1032,7 @@ void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent ) } // get tick in which the cursor is posated - int pos_ticks = x * MidiTime::ticksPerTact() / m_ppt + + int pos_ticks = x * MidiTime::ticksPerBar() / m_ppb + m_currentPosition; m_selectedTick = pos_ticks - @@ -1114,7 +1116,7 @@ inline void AutomationEditor::drawAutomationPoint( QPainter & p, timeMap::iterat { int x = xCoordOfTick( it.key() ); int y = yCoordOfLevel( it.value() ); - const int outerRadius = qBound( 3, ( m_ppt * AutomationPattern::quantization() ) / 576, 5 ); // man, getting this calculation right took forever + const int outerRadius = qBound( 3, ( m_ppb * AutomationPattern::quantization() ) / 576, 5 ); // man, getting this calculation right took forever p.setPen( QPen( vertexColor().lighter( 200 ) ) ); p.setBrush( QBrush( vertexColor() ) ); p.drawEllipse( x - outerRadius, y - outerRadius, outerRadius * 2, outerRadius * 2 ); @@ -1286,20 +1288,20 @@ void AutomationEditor::paintEvent(QPaintEvent * pe ) / static_cast( Engine::getSong()->getTimeSigModel().getDenominator() ); float zoomFactor = m_zoomXLevels[m_zoomingXModel.value()]; //the bars which disappears at the left side by scrolling - int leftBars = m_currentPosition * zoomFactor / MidiTime::ticksPerTact(); + int leftBars = m_currentPosition * zoomFactor / MidiTime::ticksPerBar(); //iterates the visible bars and draw the shading on uneven bars - for( int x = VALUES_WIDTH, barCount = leftBars; x < width() + m_currentPosition * zoomFactor / timeSignature; x += m_ppt, ++barCount ) + for( int x = VALUES_WIDTH, barCount = leftBars; x < width() + m_currentPosition * zoomFactor / timeSignature; x += m_ppb, ++barCount ) { if( ( barCount + leftBars ) % 2 != 0 ) { - p.fillRect( x - m_currentPosition * zoomFactor / timeSignature, TOP_MARGIN, m_ppt, + p.fillRect( x - m_currentPosition * zoomFactor / timeSignature, TOP_MARGIN, m_ppb, height() - ( SCROLLBAR_SIZE + TOP_MARGIN ), backgroundShade() ); } } // Draw the beat grid - int ticksPerBeat = DefaultTicksPerTact / + int ticksPerBeat = DefaultTicksPerBar / Engine::getSong()->getTimeSigModel().getDenominator(); for( tick = m_currentPosition - m_currentPosition % ticksPerBeat, @@ -1312,10 +1314,10 @@ void AutomationEditor::paintEvent(QPaintEvent * pe ) } // and finally bars - for( tick = m_currentPosition - m_currentPosition % MidiTime::ticksPerTact(), + for( tick = m_currentPosition - m_currentPosition % MidiTime::ticksPerBar(), x = xCoordOfTick( tick ); x<=width(); - tick += MidiTime::ticksPerTact(), x = xCoordOfTick( tick ) ) + tick += MidiTime::ticksPerBar(), x = xCoordOfTick( tick ) ) { p.setPen( barLineColor() ); p.drawLine( x, grid_bottom, x, x_line_end ); @@ -1450,9 +1452,9 @@ void AutomationEditor::paintEvent(QPaintEvent * pe ) } // now draw selection-frame - int x = ( sel_pos_start - m_currentPosition ) * m_ppt / - MidiTime::ticksPerTact(); - int w = ( sel_pos_end - sel_pos_start ) * m_ppt / MidiTime::ticksPerTact(); + int x = ( sel_pos_start - m_currentPosition ) * m_ppb / + MidiTime::ticksPerBar(); + int w = ( sel_pos_end - sel_pos_start ) * m_ppb / MidiTime::ticksPerBar(); int y, h; if( m_y_auto ) { @@ -1482,7 +1484,7 @@ void AutomationEditor::paintEvent(QPaintEvent * pe ) m_leftRightScroll->setPageStep( l ); } - if( validPattern() && GuiApplication::instance()->automationEditor()->hasFocus() ) + if(validPattern() && GuiApplication::instance()->automationEditor()->m_editor->hasFocus()) { drawCross( p ); @@ -1524,7 +1526,7 @@ void AutomationEditor::paintEvent(QPaintEvent * pe ) int AutomationEditor::xCoordOfTick(int tick ) { return VALUES_WIDTH + ( ( tick - m_currentPosition ) - * m_ppt / MidiTime::ticksPerTact() ); + * m_ppb / MidiTime::ticksPerBar() ); } @@ -1685,11 +1687,11 @@ void AutomationEditor::wheelEvent(QWheelEvent * we ) } x = qBound( 0, x, m_zoomingXModel.size() - 1 ); - int mouseX = (we->x() - VALUES_WIDTH)* MidiTime::ticksPerTact(); + int mouseX = (we->x() - VALUES_WIDTH)* MidiTime::ticksPerBar(); // ticks based on the mouse x-position where the scroll wheel was used - int ticks = mouseX / m_ppt; + int ticks = mouseX / m_ppb; // what would be the ticks in the new zoom level on the very same mouse x - int newTicks = mouseX / (DEFAULT_PPT * m_zoomXLevels[x]); + int newTicks = mouseX / (DEFAULT_PPB * m_zoomXLevels[x]); // scroll so the tick "selected" by the mouse x doesn't move on the screen m_leftRightScroll->setValue(m_leftRightScroll->value() + ticks - newTicks); @@ -1956,7 +1958,7 @@ void AutomationEditor::getSelectedValues( timeMap & selected_values ) ++it ) { //TODO: Add constant - tick_t len_ticks = MidiTime::ticksPerTact() / 16; + tick_t len_ticks = MidiTime::ticksPerBar() / 16; float level = it.value(); tick_t pos_ticks = it.key(); @@ -2093,17 +2095,17 @@ void AutomationEditor::updatePosition(const MidiTime & t ) m_scrollBack == true ) { const int w = width() - VALUES_WIDTH; - if( t > m_currentPosition + w * MidiTime::ticksPerTact() / m_ppt ) + if( t > m_currentPosition + w * MidiTime::ticksPerBar() / m_ppb ) { - m_leftRightScroll->setValue( t.getTact() * - MidiTime::ticksPerTact() ); + m_leftRightScroll->setValue( t.getBar() * + MidiTime::ticksPerBar() ); } else if( t < m_currentPosition ) { - MidiTime t_ = qMax( t - w * MidiTime::ticksPerTact() * - MidiTime::ticksPerTact() / m_ppt, 0 ); - m_leftRightScroll->setValue( t_.getTact() * - MidiTime::ticksPerTact() ); + MidiTime t_ = qMax( t - w * MidiTime::ticksPerBar() * + MidiTime::ticksPerBar() / m_ppb, 0 ); + m_leftRightScroll->setValue( t_.getBar() * + MidiTime::ticksPerBar() ); } m_scrollBack = false; } @@ -2114,11 +2116,11 @@ void AutomationEditor::updatePosition(const MidiTime & t ) void AutomationEditor::zoomingXChanged() { - m_ppt = m_zoomXLevels[m_zoomingXModel.value()] * DEFAULT_PPT; + m_ppb = m_zoomXLevels[m_zoomingXModel.value()] * DEFAULT_PPB; - assert( m_ppt > 0 ); + assert( m_ppb > 0 ); - m_timeLine->setPixelsPerTact( m_ppt ); + m_timeLine->setPixelsPerBar( m_ppb ); update(); } @@ -2157,9 +2159,9 @@ void AutomationEditor::setQuantization() } else { - quantization = DefaultTicksPerTact; + quantization = DefaultTicksPerBar; } - quantization = DefaultTicksPerTact / quantization; + quantization = DefaultTicksPerBar / quantization; AutomationPattern::setQuantization( quantization ); update(); @@ -2516,6 +2518,11 @@ void AutomationEditorWindow::clearCurrentPattern() setCurrentPattern(nullptr); } +void AutomationEditorWindow::focusInEvent(QFocusEvent * event) +{ + m_editor->setFocus( event->reason() ); +} + void AutomationEditorWindow::play() { m_editor->play(); diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 5edc5d47c..3b42bd9b2 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -24,6 +24,8 @@ * */ +#include "PianoRoll.h" + #include #include #include @@ -34,7 +36,6 @@ #include #include #include -#include #ifndef __USE_XOPEN #define __USE_XOPEN @@ -46,7 +47,6 @@ #include "AutomationEditor.h" #include "ActionGroup.h" #include "ConfigManager.h" -#include "PianoRoll.h" #include "BBTrackContainer.h" #include "Clipboard.h" #include "ComboBox.h" @@ -139,7 +139,7 @@ PianoRoll::PianoRollKeyTypes PianoRoll::prKeyOrder[] = } ; -const int DEFAULT_PR_PPT = KEY_LINE_HEIGHT * DefaultStepsPerTact; +const int DEFAULT_PR_PPB = KEY_LINE_HEIGHT * DefaultStepsPerBar; const QVector PianoRoll::m_zoomLevels = { 0.125f, 0.25f, 0.5f, 1.0f, 2.0f, 4.0f, 8.0f }; @@ -168,8 +168,8 @@ PianoRoll::PianoRoll() : m_lastMouseY( 0 ), m_oldNotesEditHeight( 100 ), m_notesEditHeight( 100 ), - m_ppt( DEFAULT_PR_PPT ), - m_lenOfNewNotes( MidiTime( 0, DefaultTicksPerTact/4 ) ), + m_ppb( DEFAULT_PR_PPB ), + m_lenOfNewNotes( MidiTime( 0, DefaultTicksPerBar/4 ) ), m_lastNoteVolume( DefaultVolume ), m_lastNotePanning( DefaultPanning ), m_startKey( INITIAL_START_KEY ), @@ -178,7 +178,7 @@ PianoRoll::PianoRoll() : m_ctrlMode( ModeDraw ), m_mouseDownRight( false ), m_scrollBack( false ), - m_stepRecorderWidget(this, DEFAULT_PR_PPT, PR_TOP_MARGIN, PR_BOTTOM_MARGIN + m_notesEditHeight, WHITE_KEY_WIDTH, 0), + m_stepRecorderWidget(this, DEFAULT_PR_PPB, PR_TOP_MARGIN, PR_BOTTOM_MARGIN + m_notesEditHeight, WHITE_KEY_WIDTH, 0), m_stepRecorder(*this, m_stepRecorderWidget), m_barLineColor( 0, 0, 0 ), m_beatLineColor( 0, 0, 0 ), @@ -203,20 +203,15 @@ PianoRoll::PianoRoll() : m_nemStr.push_back( tr( "Note Velocity" ) ); m_nemStr.push_back( tr( "Note Panning" ) ); - QSignalMapper * signalMapper = new QSignalMapper( this ); m_noteEditMenu = new QMenu( this ); m_noteEditMenu->clear(); for( int i = 0; i < m_nemStr.size(); ++i ) { QAction * act = new QAction( m_nemStr.at(i), this ); - connect( act, SIGNAL(triggered()), signalMapper, SLOT(map()) ); - signalMapper->setMapping( act, i ); + connect( act, &QAction::triggered, [this, i](){ changeNoteEditMode(i); } ); m_noteEditMenu->addAction( act ); } - connect( signalMapper, SIGNAL(mapped(int)), - this, SLOT(changeNoteEditMode(int)) ); - signalMapper = new QSignalMapper( this ); m_semiToneMarkerMenu = new QMenu( this ); QAction* markSemitoneAction = new QAction( tr("Mark/unmark current semitone"), this ); @@ -226,19 +221,12 @@ PianoRoll::PianoRoll() : QAction* unmarkAllAction = new QAction( tr("Unmark all"), this ); QAction* copyAllNotesAction = new QAction( tr("Select all notes on this key"), this); - connect( markSemitoneAction, SIGNAL(triggered()), signalMapper, SLOT(map()) ); - connect( markAllOctaveSemitonesAction, SIGNAL(triggered()), signalMapper, SLOT(map()) ); - connect( markScaleAction, SIGNAL(triggered()), signalMapper, SLOT(map()) ); - connect( markChordAction, SIGNAL(triggered()), signalMapper, SLOT(map()) ); - connect( unmarkAllAction, SIGNAL(triggered()), signalMapper, SLOT(map()) ); - connect( copyAllNotesAction, SIGNAL(triggered()), signalMapper, SLOT(map()) ); - - signalMapper->setMapping( markSemitoneAction, static_cast( stmaMarkCurrentSemiTone ) ); - signalMapper->setMapping( markAllOctaveSemitonesAction, static_cast( stmaMarkAllOctaveSemiTones ) ); - signalMapper->setMapping( markScaleAction, static_cast( stmaMarkCurrentScale ) ); - signalMapper->setMapping( markChordAction, static_cast( stmaMarkCurrentChord ) ); - signalMapper->setMapping( unmarkAllAction, static_cast( stmaUnmarkAll ) ); - signalMapper->setMapping( copyAllNotesAction, static_cast( stmaCopyAllNotesOnKey ) ); + connect( markSemitoneAction, &QAction::triggered, [this](){ markSemiTone(stmaMarkCurrentSemiTone); }); + connect( markAllOctaveSemitonesAction, &QAction::triggered, [this](){ markSemiTone(stmaMarkAllOctaveSemiTones); }); + connect( markScaleAction, &QAction::triggered, [this](){ markSemiTone(stmaMarkCurrentScale); }); + connect( markChordAction, &QAction::triggered, [this](){ markSemiTone(stmaMarkCurrentChord); }); + connect( unmarkAllAction, &QAction::triggered, [this](){ markSemiTone(stmaUnmarkAll); }); + connect( copyAllNotesAction, &QAction::triggered, [this](){ markSemiTone(stmaCopyAllNotesOnKey); }); markScaleAction->setEnabled( false ); markChordAction->setEnabled( false ); @@ -246,8 +234,6 @@ PianoRoll::PianoRoll() : connect( this, SIGNAL(semiToneMarkerMenuScaleSetEnabled(bool)), markScaleAction, SLOT(setEnabled(bool)) ); connect( this, SIGNAL(semiToneMarkerMenuChordSetEnabled(bool)), markChordAction, SLOT(setEnabled(bool)) ); - connect( signalMapper, SIGNAL(mapped(int)), this, SLOT(markSemiTone(int)) ); - m_semiToneMarkerMenu->addAction( markSemitoneAction ); m_semiToneMarkerMenu->addAction( markAllOctaveSemitonesAction ); m_semiToneMarkerMenu->addAction( markScaleAction ); @@ -316,7 +302,7 @@ PianoRoll::PianoRoll() : setAttribute( Qt::WA_OpaquePaintEvent, true ); // add time-line - m_timeLine = new TimeLineWidget( WHITE_KEY_WIDTH, 0, m_ppt, + m_timeLine = new TimeLineWidget( WHITE_KEY_WIDTH, 0, m_ppb, Engine::getSong()->getPlayPos( Song::Mode_PlayPattern ), m_currentPosition, @@ -549,7 +535,10 @@ void PianoRoll::markSemiTone( int i ) for (int ix = 0; ix < aok.size(); ++ix) { i = std::find(m_markedSemiTones.begin(), m_markedSemiTones.end(), aok.at(ix)); - m_markedSemiTones.erase(i); + if (i != m_markedSemiTones.end()) + { + m_markedSemiTones.erase(i); + } } } else @@ -655,6 +644,32 @@ void PianoRoll::clearGhostPattern() } +void PianoRoll::loadMarkedSemiTones(const QDomElement & de) +{ + // clear marked semitones to prevent leftover marks + m_markedSemiTones.clear(); + if (de.isElement()) + { + QDomNode node = de.firstChild(); + while (!node.isNull()) + { + bool ok; + int key = node.toElement().attribute( + QString("key"), QString("-1")).toInt(&ok, 10); + if (ok && key >= 0) + { + m_markedSemiTones.append(key); + } + node = node.nextSibling(); + } + } + // from markSemiTone, required otherwise marks will not show + std::sort(m_markedSemiTones.begin(), m_markedSemiTones.end(), std::greater()); + QList::iterator new_end = std::unique(m_markedSemiTones.begin(), m_markedSemiTones.end()); + m_markedSemiTones.erase(new_end, m_markedSemiTones.end()); +} + + void PianoRoll::setCurrentPattern( Pattern* newPattern ) { if( hasValidPattern() ) @@ -744,28 +759,28 @@ void PianoRoll::selectRegionFromPixels( int xStart, int xEnd ) xEnd -= WHITE_KEY_WIDTH; // select an area of notes - int pos_ticks = xStart * MidiTime::ticksPerTact() / m_ppt + + int posTicks = xStart * MidiTime::ticksPerBar() / m_ppb + m_currentPosition; - int key_num = 0; - m_selectStartTick = pos_ticks; + int keyNum = 0; + m_selectStartTick = posTicks; m_selectedTick = 0; - m_selectStartKey = key_num; + m_selectStartKey = keyNum; m_selectedKeys = 1; // change size of selection // get tick in which the cursor is posated - pos_ticks = xEnd * MidiTime::ticksPerTact() / m_ppt + + posTicks = xEnd * MidiTime::ticksPerBar() / m_ppb + m_currentPosition; - key_num = 120; + keyNum = 120; - m_selectedTick = pos_ticks - m_selectStartTick; + m_selectedTick = posTicks - m_selectStartTick; if( (int) m_selectStartTick + m_selectedTick < 0 ) { m_selectedTick = -static_cast( m_selectStartTick ); } - m_selectedKeys = key_num - m_selectStartKey; - if( key_num <= m_selectStartKey ) + m_selectedKeys = keyNum - m_selectStartKey; + if( keyNum <= m_selectStartKey ) { --m_selectedKeys; } @@ -1018,7 +1033,7 @@ void PianoRoll::drawDetuningInfo( QPainter & _p, const Note * _n, int _x, for( timeMap::ConstIterator it = map.begin(); it != map.end(); ++it ) { int pos_ticks = it.key(); - int pos_x = _x + pos_ticks * m_ppt / MidiTime::ticksPerTact(); + int pos_x = _x + pos_ticks * m_ppb / MidiTime::ticksPerBar(); const float level = it.value(); @@ -1253,7 +1268,7 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke) // Move selected notes by one bar to the left if (hasValidPattern()) { - shiftPos( direction * MidiTime::ticksPerTact() ); + shiftPos( direction * MidiTime::ticksPerBar() ); } } else if( ke->modifiers() & Qt::ShiftModifier && m_action == ActionNone) @@ -1557,7 +1572,7 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) x -= WHITE_KEY_WIDTH; // get tick in which the user clicked - int pos_ticks = x * MidiTime::ticksPerTact() / m_ppt + + int pos_ticks = x * MidiTime::ticksPerBar() / m_ppb + m_currentPosition; @@ -1587,7 +1602,7 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) || ( edit_note && pos_ticks <= note->pos() + - NOTE_EDIT_LINE_WIDTH * MidiTime::ticksPerTact() / m_ppt ) + NOTE_EDIT_LINE_WIDTH * MidiTime::ticksPerBar() / m_ppb ) ) ) { @@ -1731,8 +1746,8 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) // clicked at the "tail" of the note? - if( pos_ticks * m_ppt / MidiTime::ticksPerTact() > - m_currentNote->endPos() * m_ppt / MidiTime::ticksPerTact() - RESIZE_AREA_WIDTH + if( pos_ticks * m_ppb / MidiTime::ticksPerBar() > + m_currentNote->endPos() * m_ppb / MidiTime::ticksPerBar() - RESIZE_AREA_WIDTH && m_currentNote->length() > 0 ) { m_pattern->addJournalCheckPoint(); @@ -1887,10 +1902,10 @@ void PianoRoll::mouseDoubleClickEvent(QMouseEvent * me ) int pixel_range = 4; int x = me->x() - WHITE_KEY_WIDTH; const int ticks_start = ( x-pixel_range/2 ) * - MidiTime::ticksPerTact() / m_ppt + m_currentPosition; + MidiTime::ticksPerBar() / m_ppb + m_currentPosition; const int ticks_end = ( x+pixel_range/2 ) * - MidiTime::ticksPerTact() / m_ppt + m_currentPosition; - const int ticks_middle = x * MidiTime::ticksPerTact() / m_ppt + m_currentPosition; + MidiTime::ticksPerBar() / m_ppb + m_currentPosition; + const int ticks_middle = x * MidiTime::ticksPerBar() / m_ppb + m_currentPosition; // go through notes to figure out which one we want to change bool altPressed = me->modifiers() & Qt::AltModifier; @@ -1933,6 +1948,10 @@ void PianoRoll::mouseDoubleClickEvent(QMouseEvent * me ) enterValue( &nv ); } } + else + { + QWidget::mouseDoubleClickEvent(me); + } } @@ -2285,9 +2304,9 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) // convert to ticks so that we can check which notes // are in the range int ticks_start = ( x-pixel_range/2 ) * - MidiTime::ticksPerTact() / m_ppt + m_currentPosition; + MidiTime::ticksPerBar() / m_ppb + m_currentPosition; int ticks_end = ( x+pixel_range/2 ) * - MidiTime::ticksPerTact() / m_ppt + m_currentPosition; + MidiTime::ticksPerBar() / m_ppb + m_currentPosition; // get note-vector of current pattern const NoteVector & notes = m_pattern->notes(); @@ -2383,8 +2402,8 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) // set move- or resize-cursor // get tick in which the cursor is posated - int pos_ticks = ( x * MidiTime::ticksPerTact() ) / - m_ppt + m_currentPosition; + int pos_ticks = ( x * MidiTime::ticksPerBar() ) / + m_ppb + m_currentPosition; // get note-vector of current pattern const NoteVector & notes = m_pattern->notes(); @@ -2416,7 +2435,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) Note *note = *it; // x coordinate of the right edge of the note int noteRightX = ( note->pos() + note->length() - - m_currentPosition) * m_ppt/MidiTime::ticksPerTact(); + m_currentPosition) * m_ppb/MidiTime::ticksPerBar(); // cursor at the "tail" of the note? bool atTail = note->length() > 0 && x > noteRightX - RESIZE_AREA_WIDTH; @@ -2455,7 +2474,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) // change size of selection // get tick in which the cursor is posated - int pos_ticks = x * MidiTime::ticksPerTact() / m_ppt + + int pos_ticks = x * MidiTime::ticksPerBar() / m_ppb + m_currentPosition; m_selectedTick = pos_ticks - m_selectStartTick; @@ -2477,7 +2496,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) // any key if in erase mode // get tick in which the user clicked - int pos_ticks = x * MidiTime::ticksPerTact() / m_ppt + + int pos_ticks = x * MidiTime::ticksPerBar() / m_ppb + m_currentPosition; @@ -2508,8 +2527,8 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) ( edit_note && pos_ticks <= note->pos() + NOTE_EDIT_LINE_WIDTH * - MidiTime::ticksPerTact() / - m_ppt ) + MidiTime::ticksPerBar() / + m_ppb ) ) ) { @@ -2558,7 +2577,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) } // get tick in which the cursor is posated - int pos_ticks = x * MidiTime::ticksPerTact()/ m_ppt + + int pos_ticks = x * MidiTime::ticksPerBar()/ m_ppb + m_currentPosition; m_selectedTick = pos_ticks - @@ -2619,7 +2638,7 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl ) // convert pixels to ticks and keys int off_x = x - m_moveStartX; - int off_ticks = off_x * MidiTime::ticksPerTact() / m_ppt; + int off_ticks = off_x * MidiTime::ticksPerBar() / m_ppb; int off_key = getKey( y ) - getKey( m_moveStartY ); // handle scroll changes while dragging @@ -2803,10 +2822,10 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl ) Engine::getSong()->setModified(); } -int PianoRoll::xCoordOfTick(int tick ) +int PianoRoll::xCoordOfTick( int tick ) { return WHITE_KEY_WIDTH + ( ( tick - m_currentPosition ) - * m_ppt / MidiTime::ticksPerTact() ); + * m_ppb / MidiTime::ticksPerBar() ); } void PianoRoll::paintEvent(QPaintEvent * pe ) @@ -3103,20 +3122,20 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) / static_cast( Engine::getSong()->getTimeSigModel().getDenominator() ); float zoomFactor = m_zoomLevels[m_zoomingModel.value()]; //the bars which disappears at the left side by scrolling - int leftBars = m_currentPosition * zoomFactor / MidiTime::ticksPerTact(); + int leftBars = m_currentPosition * zoomFactor / MidiTime::ticksPerBar(); //iterates the visible bars and draw the shading on uneven bars - for( int x = WHITE_KEY_WIDTH, barCount = leftBars; x < width() + m_currentPosition * zoomFactor / timeSignature; x += m_ppt, ++barCount ) + for( int x = WHITE_KEY_WIDTH, barCount = leftBars; x < width() + m_currentPosition * zoomFactor / timeSignature; x += m_ppb, ++barCount ) { if( ( barCount + leftBars ) % 2 != 0 ) { - p.fillRect( x - m_currentPosition * zoomFactor / timeSignature, PR_TOP_MARGIN, m_ppt, + p.fillRect( x - m_currentPosition * zoomFactor / timeSignature, PR_TOP_MARGIN, m_ppb, height() - ( PR_BOTTOM_MARGIN + PR_TOP_MARGIN ), backgroundShade() ); } } // Draw the vertical beat lines - int ticksPerBeat = DefaultTicksPerTact / + int ticksPerBeat = DefaultTicksPerBar / Engine::getSong()->getTimeSigModel().getDenominator(); for( tick = m_currentPosition - m_currentPosition % ticksPerBeat, @@ -3128,9 +3147,9 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) } // Draw the vertical bar lines - for( tick = m_currentPosition - m_currentPosition % MidiTime::ticksPerTact(), + for( tick = m_currentPosition - m_currentPosition % MidiTime::ticksPerBar(), x = xCoordOfTick( tick ); x <= width(); - tick += MidiTime::ticksPerTact(), x = xCoordOfTick( tick ) ) + tick += MidiTime::ticksPerBar(), x = xCoordOfTick( tick ) ) { p.setPen( barLineColor() ); p.drawLine( x, PR_TOP_MARGIN, x, height() - PR_BOTTOM_MARGIN ); @@ -3202,9 +3221,9 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) int pos_ticks = note->pos(); - int note_width = len_ticks * m_ppt / MidiTime::ticksPerTact(); + int note_width = len_ticks * m_ppb / MidiTime::ticksPerBar(); const int x = ( pos_ticks - m_currentPosition ) * - m_ppt / MidiTime::ticksPerTact(); + m_ppb / MidiTime::ticksPerBar(); // skip this note if not in visible area at all if( !( x + note_width >= 0 && x <= width() - WHITE_KEY_WIDTH ) ) { @@ -3244,9 +3263,9 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) int pos_ticks = note->pos(); - int note_width = len_ticks * m_ppt / MidiTime::ticksPerTact(); + int note_width = len_ticks * m_ppb / MidiTime::ticksPerBar(); const int x = ( pos_ticks - m_currentPosition ) * - m_ppt / MidiTime::ticksPerTact(); + m_ppb / MidiTime::ticksPerBar(); // skip this note if not in visible area at all if( !( x + note_width >= 0 && x <= width() - WHITE_KEY_WIDTH ) ) { @@ -3332,9 +3351,9 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) int pos_ticks = note->pos(); - int note_width = len_ticks * m_ppt / MidiTime::ticksPerTact(); + int note_width = len_ticks * m_ppb / MidiTime::ticksPerBar(); const int x = ( pos_ticks - m_currentPosition ) * - m_ppt / MidiTime::ticksPerTact(); + m_ppb / MidiTime::ticksPerBar(); // skip this note if not in visible area at all if( !( x + note_width >= 0 && x <= width() - WHITE_KEY_WIDTH ) ) { @@ -3374,10 +3393,10 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) m_notesEditHeight - PR_BOTTOM_MARGIN ); // now draw selection-frame - int x = ( ( sel_pos_start - m_currentPosition ) * m_ppt ) / - MidiTime::ticksPerTact(); - int w = ( ( ( sel_pos_end - m_currentPosition ) * m_ppt ) / - MidiTime::ticksPerTact() ) - x; + int x = ( ( sel_pos_start - m_currentPosition ) * m_ppb ) / + MidiTime::ticksPerBar(); + int w = ( ( ( sel_pos_end - m_currentPosition ) * m_ppb ) / + MidiTime::ticksPerBar() ) - x; int y = (int) y_base - sel_key_start * KEY_LINE_HEIGHT; int h = (int) y_base - sel_key_end * KEY_LINE_HEIGHT - y; p.setPen( selectedNoteColor() ); @@ -3493,9 +3512,9 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) int pixel_range = 8; int x = we->x() - WHITE_KEY_WIDTH; int ticks_start = ( x - pixel_range / 2 ) * - MidiTime::ticksPerTact() / m_ppt + m_currentPosition; + MidiTime::ticksPerBar() / m_ppb + m_currentPosition; int ticks_end = ( x + pixel_range / 2 ) * - MidiTime::ticksPerTact() / m_ppt + m_currentPosition; + MidiTime::ticksPerBar() / m_ppb + m_currentPosition; // When alt is pressed we only edit the note under the cursor bool altPressed = we->modifiers() & Qt::AltModifier; @@ -3596,11 +3615,11 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) } z = qBound( 0, z, m_zoomingModel.size() - 1 ); - int x = (we->x() - WHITE_KEY_WIDTH)* MidiTime::ticksPerTact(); + int x = (we->x() - WHITE_KEY_WIDTH)* MidiTime::ticksPerBar(); // ticks based on the mouse x-position where the scroll wheel was used - int ticks = x / m_ppt; + int ticks = x / m_ppb; // what would be the ticks in the new zoom level on the very same mouse x - int newTicks = x / (DEFAULT_PR_PPT * m_zoomLevels[z]); + int newTicks = x / (DEFAULT_PR_PPB * m_zoomLevels[z]); // scroll so the tick "selected" by the mouse x doesn't move on the screen m_leftRightScroll->setValue(m_leftRightScroll->value() + ticks - newTicks); // update combobox with zooming-factor @@ -4024,7 +4043,7 @@ void PianoRoll::copyToClipboard( const NoteVector & notes ) const QDomElement note_list = dataFile.createElement( "note-list" ); dataFile.content().appendChild( note_list ); - MidiTime start_pos( notes.front()->pos().getTact(), 0 ); + MidiTime start_pos( notes.front()->pos().getBar(), 0 ); for( const Note *note : notes ) { Note clip_note( *note ); @@ -4065,6 +4084,8 @@ void PianoRoll::cutSelectedNotes() if( ! selected_notes.empty() ) { + m_pattern->addJournalCheckPoint(); + copyToClipboard( selected_notes ); Engine::getSong()->setModified(); @@ -4183,15 +4204,15 @@ void PianoRoll::deleteSelectedNotes() void PianoRoll::autoScroll( const MidiTime & t ) { const int w = width() - WHITE_KEY_WIDTH; - if( t > m_currentPosition + w * MidiTime::ticksPerTact() / m_ppt ) + if( t > m_currentPosition + w * MidiTime::ticksPerBar() / m_ppb ) { - m_leftRightScroll->setValue( t.getTact() * MidiTime::ticksPerTact() ); + m_leftRightScroll->setValue( t.getBar() * MidiTime::ticksPerBar() ); } else if( t < m_currentPosition ) { - MidiTime t2 = qMax( t - w * MidiTime::ticksPerTact() * - MidiTime::ticksPerTact() / m_ppt, (tick_t) 0 ); - m_leftRightScroll->setValue( t2.getTact() * MidiTime::ticksPerTact() ); + MidiTime t2 = qMax( t - w * MidiTime::ticksPerBar() * + MidiTime::ticksPerBar() / m_ppb, (tick_t) 0 ); + m_leftRightScroll->setValue( t2.getBar() * MidiTime::ticksPerBar() ); } m_scrollBack = false; } @@ -4245,12 +4266,12 @@ void PianoRoll::updatePositionStepRecording( const MidiTime & t ) void PianoRoll::zoomingChanged() { - m_ppt = m_zoomLevels[m_zoomingModel.value()] * DEFAULT_PR_PPT; + m_ppb = m_zoomLevels[m_zoomingModel.value()] * DEFAULT_PR_PPB; - assert( m_ppt > 0 ); + assert( m_ppb > 0 ); - m_timeLine->setPixelsPerTact( m_ppt ); - m_stepRecorderWidget.setPixelsPerTact( m_ppt ); + m_timeLine->setPixelsPerBar( m_ppb ); + m_stepRecorderWidget.setPixelsPerBar( m_ppb ); update(); } @@ -4280,12 +4301,12 @@ int PianoRoll::quantization() const } else { - return DefaultTicksPerTact / 16; + return DefaultTicksPerBar / 16; } } QString text = m_quantizeModel.currentText(); - return DefaultTicksPerTact / text.right( text.length() - 2 ).toInt(); + return DefaultTicksPerBar / text.right( text.length() - 2 ).toInt(); } @@ -4353,7 +4374,7 @@ MidiTime PianoRoll::newNoteLen() const } QString text = m_noteLenModel.currentText(); - return DefaultTicksPerTact / text.right( text.length() - 2 ).toInt(); + return DefaultTicksPerBar / text.right( text.length() - 2 ).toInt(); } @@ -4381,7 +4402,7 @@ Note * PianoRoll::noteUnderMouse() int key_num = getKey( pos.y() ); int pos_ticks = ( pos.x() - WHITE_KEY_WIDTH ) * - MidiTime::ticksPerTact() / m_ppt + m_currentPosition; + MidiTime::ticksPerBar() / m_ppb + m_currentPosition; // loop through whole note-vector... for( Note* const& note : m_pattern->notes() ) @@ -4697,6 +4718,18 @@ void PianoRollWindow::saveSettings( QDomDocument & doc, QDomElement & de ) de.appendChild( ghostNotesRoot ); } + if (m_editor->m_markedSemiTones.length() > 0) + { + QDomElement markedSemiTonesRoot = doc.createElement("markedSemiTones"); + for (int ix = 0; ix < m_editor->m_markedSemiTones.size(); ++ix) + { + QDomElement semiToneNode = doc.createElement("semiTone"); + semiToneNode.setAttribute("key", m_editor->m_markedSemiTones.at(ix)); + markedSemiTonesRoot.appendChild(semiToneNode); + } + de.appendChild(markedSemiTonesRoot); + } + MainWindow::saveWidgetState( this, de ); } @@ -4706,6 +4739,7 @@ void PianoRollWindow::saveSettings( QDomDocument & doc, QDomElement & de ) void PianoRollWindow::loadSettings( const QDomElement & de ) { m_editor->loadGhostNotes( de.firstChildElement("ghostnotes") ); + m_editor->loadMarkedSemiTones(de.firstChildElement("markedSemiTones")); MainWindow::restoreWidgetState( this, de ); } diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 6e23fcdbe..2c2485d00 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -50,7 +50,7 @@ #include "TimeDisplayWidget.h" #include "AudioDevice.h" #include "PianoRoll.h" - +#include "Track.h" positionLine::positionLine( QWidget * parent ) : QWidget( parent ) @@ -80,17 +80,22 @@ SongEditor::SongEditor( Song * song ) : m_proportionalSnap( false ), m_scrollBack( false ), m_smoothScroll( ConfigManager::inst()->value( "ui", "smoothscroll" ).toInt() ), - m_mode(DrawMode) + m_mode(DrawMode), + m_origin(), + m_scrollPos(), + m_mousePos(), + m_rubberBandStartTrackview(0), + m_rubberbandStartMidipos(0), + m_currentZoomingValue(m_zoomingModel->value()), + m_trackHeadWidth(ConfigManager::inst()->value("ui", "compacttrackbuttons").toInt()==1 + ? DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT + TRACK_OP_WIDTH_COMPACT + : DEFAULT_SETTINGS_WIDGET_WIDTH + TRACK_OP_WIDTH), + m_selectRegion(false) { m_zoomingModel->setParent(this); m_snappingModel->setParent(this); - // create time-line - m_widgetWidthTotal = ConfigManager::inst()->value( "ui", - "compacttrackbuttons" ).toInt()==1 ? - DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT + TRACK_OP_WIDTH_COMPACT : - DEFAULT_SETTINGS_WIDGET_WIDTH + TRACK_OP_WIDTH; - m_timeLine = new TimeLineWidget( m_widgetWidthTotal, 32, - pixelsPerTact(), + m_timeLine = new TimeLineWidget( m_trackHeadWidth, 32, + pixelsPerBar(), m_song->m_playPos[Song::Mode_PlaySong], m_currentPosition, Song::Mode_PlaySong, this ); @@ -232,6 +237,10 @@ SongEditor::SongEditor( Song * song ) : this, SLOT( scrolled( int ) ) ); connect( m_song, SIGNAL( lengthChanged( int ) ), this, SLOT( updateScrollBar( int ) ) ); + connect(m_leftRightScroll, SIGNAL(valueChanged(int)),this, SLOT(updateRubberband())); + connect(contentWidget()->verticalScrollBar(), SIGNAL(valueChanged(int)),this, SLOT(updateRubberband())); + connect(m_timeLine, SIGNAL(selectionFinished()), this, SLOT(stopSelectRegion())); + //Set up zooming model for( float const & zoomLevel : m_zoomLevels ) @@ -346,6 +355,99 @@ void SongEditor::scrolled( int new_pos ) +void SongEditor::selectRegionFromPixels(int xStart, int xEnd) +{ + if (!m_selectRegion) + { + m_selectRegion = true; + + //deselect all tcos + for (auto &it : findChildren()) { it->setSelected(false); } + + rubberBand()->setEnabled(true); + rubberBand()->show(); + + //we save the position of scrollbars, mouse position and zooming level + m_origin = QPoint(xStart, 0); + m_scrollPos = QPoint(m_leftRightScroll->value(), contentWidget()->verticalScrollBar()->value()); + m_currentZoomingValue = zoomingModel()->value(); + + //calculate the song position where the mouse was clicked + m_rubberbandStartMidipos = MidiTime((xStart - m_trackHeadWidth) + / pixelsPerBar() * MidiTime::ticksPerBar()) + + m_currentPosition; + m_rubberBandStartTrackview = 0; + } + //the current mouse position within the borders of song editor + m_mousePos = QPoint(qMax(m_trackHeadWidth, qMin(xEnd, width())) + , std::numeric_limits::max()); + updateRubberband(); +} + + + + +void SongEditor::stopSelectRegion() +{ + m_selectRegion = false; +} + + + + +void SongEditor::updateRubberband() +{ + if (rubberBandActive()) + { + int originX = m_origin.x(); + + //take care of the zooming + if (m_currentZoomingValue != m_zoomingModel->value()) + { + originX = m_trackHeadWidth + (originX - m_trackHeadWidth) + * m_zoomLevels[m_zoomingModel->value()] / m_zoomLevels[m_currentZoomingValue]; + } + + //take care of the scrollbar position + int hs = (m_leftRightScroll->value() - m_scrollPos.x()) * pixelsPerBar(); + int vs = contentWidget()->verticalScrollBar()->value() - m_scrollPos.y(); + + //the adjusted origin point + QPoint origin = QPoint(qMax(originX - hs, m_trackHeadWidth), m_origin.y() - vs); + + //paint the rubber band rect + rubberBand()->setGeometry(QRect(origin, + contentWidget()->mapFromParent(QPoint(m_mousePos.x(), m_mousePos.y())) + ).normalized()); + + //the index of the TrackView the mouse is hover + int rubberBandTrackview = trackIndexFromSelectionPoint(m_mousePos.y()); + + //the miditime the mouse is hover + MidiTime rubberbandMidipos = MidiTime((qMin(m_mousePos.x(), width()) - m_trackHeadWidth) + / pixelsPerBar() * MidiTime::ticksPerBar()) + + m_currentPosition; + + //are tcos in the rect of selection? + for (auto &it : findChildren()) + { + TrackContentObjectView * tco = dynamic_cast(it); + if (tco) + { + auto indexOfTrackView = trackViews().indexOf(tco->getTrackView()); + bool isBeetweenRubberbandViews = indexOfTrackView >= qMin(m_rubberBandStartTrackview, rubberBandTrackview) + && indexOfTrackView <= qMax(m_rubberBandStartTrackview, rubberBandTrackview); + bool isBeetweenRubberbandMidiPos = tco->getTrackContentObject()->endPosition() >= qMin(m_rubberbandStartMidipos, rubberbandMidipos) + && tco->getTrackContentObject()->startPosition() <= qMax(m_rubberbandStartMidipos, rubberbandMidipos); + it->setSelected(isBeetweenRubberbandViews && isBeetweenRubberbandMidiPos); + } + } + } +} + + + + void SongEditor::setEditMode( EditMode mode ) { m_mode = mode; @@ -383,7 +485,7 @@ void SongEditor::keyPressEvent( QKeyEvent * ke ) } else if( ke->key() == Qt::Key_Left ) { - tick_t t = m_song->currentTick() - MidiTime::ticksPerTact(); + tick_t t = m_song->currentTick() - MidiTime::ticksPerBar(); if( t >= 0 ) { m_song->setPlayPos( t, Song::Mode_PlaySong ); @@ -391,7 +493,7 @@ void SongEditor::keyPressEvent( QKeyEvent * ke ) } else if( ke->key() == Qt::Key_Right ) { - tick_t t = m_song->currentTick() + MidiTime::ticksPerTact(); + tick_t t = m_song->currentTick() + MidiTime::ticksPerBar(); if( t < MaxSongLength ) { m_song->setPlayPos( t, Song::Mode_PlaySong ); @@ -447,20 +549,20 @@ void SongEditor::wheelEvent( QWheelEvent * we ) z = qBound( 0, z, m_zoomingModel->size() - 1 ); - int x = (we->x() - m_widgetWidthTotal); - // tact based on the mouse x-position where the scroll wheel was used - int tact= x / pixelsPerTact(); - // what would be the tact in the new zoom level on the very same mouse x - int newTact = x / DEFAULT_PIXELS_PER_TACT / m_zoomLevels[z]; - // scroll so the tact "selected" by the mouse x doesn't move on the screen - m_leftRightScroll->setValue(m_leftRightScroll->value() + tact - newTact); + int x = we->x() - m_trackHeadWidth; + // bar based on the mouse x-position where the scroll wheel was used + int bar = x / pixelsPerBar(); + // what would be the bar in the new zoom level on the very same mouse x + int newBar = x / DEFAULT_PIXELS_PER_BAR / m_zoomLevels[z]; + // scroll so the bar "selected" by the mouse x doesn't move on the screen + m_leftRightScroll->setValue(m_leftRightScroll->value() + bar - newBar); // update combobox with zooming-factor m_zoomingModel->setValue( z ); // update timeline m_song->m_playPos[Song::Mode_PlaySong].m_timeLine-> - setPixelsPerTact( pixelsPerTact() ); + setPixelsPerBar( pixelsPerBar() ); // and make sure, all TCO's are resized and relocated realignTracks(); } @@ -480,7 +582,7 @@ void SongEditor::wheelEvent( QWheelEvent * we ) void SongEditor::closeEvent( QCloseEvent * ce ) - { +{ if( parentWidget() ) { parentWidget()->hide(); @@ -490,7 +592,53 @@ void SongEditor::closeEvent( QCloseEvent * ce ) hide(); } ce->ignore(); - } +} + + + + +void SongEditor::mousePressEvent(QMouseEvent *me) +{ + if (allowRubberband()) + { + //we save the position of scrollbars, mouse position and zooming level + m_scrollPos = QPoint(m_leftRightScroll->value(), contentWidget()->verticalScrollBar()->value()); + m_origin = contentWidget()->mapFromParent(QPoint(me->pos().x(), me->pos().y())); + m_currentZoomingValue = zoomingModel()->value(); + + //paint the rubberband + rubberBand()->setEnabled(true); + rubberBand()->setGeometry(QRect(m_origin, QSize())); + rubberBand()->show(); + + //the trackView(index) and the miditime where the mouse was clicked + m_rubberBandStartTrackview = trackIndexFromSelectionPoint(me->y()); + m_rubberbandStartMidipos = MidiTime((me->x() - m_trackHeadWidth) + / pixelsPerBar() * MidiTime::ticksPerBar()) + + m_currentPosition; + } + QWidget::mousePressEvent(me); +} + + + + +void SongEditor::mouseMoveEvent(QMouseEvent *me) +{ + m_mousePos = me->pos(); + updateRubberband(); + QWidget::mouseMoveEvent(me); +} + + + + +void SongEditor::mouseReleaseEvent(QMouseEvent *me) +{ + rubberBand()->hide(); + rubberBand()->setEnabled(false); + QWidget::mouseReleaseEvent(me); +} @@ -643,14 +791,14 @@ void SongEditor::updatePosition( const MidiTime & t ) const int w = width() - widgetWidth - trackOpWidth - contentWidget()->verticalScrollBar()->width(); // width of right scrollbar - if( t > m_currentPosition + w * MidiTime::ticksPerTact() / - pixelsPerTact() ) + if( t > m_currentPosition + w * MidiTime::ticksPerBar() / + pixelsPerBar() ) { - animateScroll( m_leftRightScroll, t.getTact(), m_smoothScroll ); + animateScroll( m_leftRightScroll, t.getBar(), m_smoothScroll ); } else if( t < m_currentPosition ) { - animateScroll( m_leftRightScroll, t.getTact(), m_smoothScroll ); + animateScroll( m_leftRightScroll, t.getBar(), m_smoothScroll ); } m_scrollBack = false; } @@ -683,11 +831,12 @@ void SongEditor::updatePositionLine() void SongEditor::zoomingChanged() { - setPixelsPerTact( m_zoomLevels[m_zoomingModel->value()] * DEFAULT_PIXELS_PER_TACT ); + setPixelsPerBar( m_zoomLevels[m_zoomingModel->value()] * DEFAULT_PIXELS_PER_BAR ); m_song->m_playPos[Song::Mode_PlaySong].m_timeLine-> - setPixelsPerTact( pixelsPerTact() ); + setPixelsPerBar( pixelsPerBar() ); realignTracks(); + updateRubberband(); } @@ -713,6 +862,26 @@ bool SongEditor::allowRubberband() const +int SongEditor::trackIndexFromSelectionPoint(int yPos) +{ + const TrackView * tv = trackViewAt(yPos - m_timeLine->height()); + return tv ? indexOfTrackView(tv) + : yPos < m_timeLine->height() ? 0 + : trackViews().count(); +} + + + + +int SongEditor::indexOfTrackView(const TrackView *tv) +{ + return static_cast(std::distance(trackViews().begin(), + std::find(trackViews().begin(), trackViews().end(), tv))); +} + + + + ComboBoxModel *SongEditor::zoomingModel() const { return m_zoomingModel; diff --git a/src/gui/menus/TemplatesMenu.cpp b/src/gui/menus/TemplatesMenu.cpp index 5fb740203..b944b7cf1 100644 --- a/src/gui/menus/TemplatesMenu.cpp +++ b/src/gui/menus/TemplatesMenu.cpp @@ -11,6 +11,8 @@ TemplatesMenu::TemplatesMenu(QWidget *parent) : QMenu(tr("New from template"), parent) { + setIcon(embed::getIconPixmap("project_new")); + connect( this, SIGNAL( aboutToShow() ), SLOT( fillTemplatesMenu() ) ); connect( this, SIGNAL( triggered( QAction * ) ), SLOT( createNewProjectFromTemplate( QAction * ) ) ); diff --git a/src/gui/widgets/GroupBox.cpp b/src/gui/widgets/GroupBox.cpp index 158390bb5..06b8e1c5c 100644 --- a/src/gui/widgets/GroupBox.cpp +++ b/src/gui/widgets/GroupBox.cpp @@ -90,7 +90,7 @@ void GroupBox::paintEvent( QPaintEvent * pe ) p.fillRect( 0, 0, width() - 1, height() - 1, p.background() ); // outer rect - p.setPen( p.background().color().dark( 150 ) ); + p.setPen( p.background().color().darker( 150 ) ); p.drawRect( 0, 0, width() - 1, height() - 1 ); // draw line below titlebar diff --git a/src/gui/widgets/Rubberband.cpp b/src/gui/widgets/Rubberband.cpp index 6bf702edc..0a4e891b5 100644 --- a/src/gui/widgets/Rubberband.cpp +++ b/src/gui/widgets/Rubberband.cpp @@ -66,18 +66,6 @@ QVector RubberBand::selectedObjects() const void RubberBand::resizeEvent( QResizeEvent * _re ) { QRubberBand::resizeEvent( _re ); - if( isEnabled() ) - { - QVector so = selectableObjects(); - for( QVector::iterator it = so.begin(); - it != so.end(); ++it ) - { - ( *it )->setSelected( QRect( pos(), size() ).intersects( - QRect( ( *it )->mapTo( parentWidget(), - QPoint() ), - ( *it )->size() ) ) ); - } - } } diff --git a/src/gui/widgets/SideBar.cpp b/src/gui/widgets/SideBar.cpp index 01ea58919..36c417b93 100644 --- a/src/gui/widgets/SideBar.cpp +++ b/src/gui/widgets/SideBar.cpp @@ -49,7 +49,7 @@ public: return m_orientation; } - virtual QSize sizeHint() const + QSize sizeHint() const override { QSize s = QToolButton::sizeHint(); s.setWidth( s.width() + 8 ); @@ -62,7 +62,7 @@ public: protected: - virtual void paintEvent( QPaintEvent * ) + void paintEvent( QPaintEvent * ) override { QStylePainter p( this ); QStyleOptionToolButton opt; @@ -121,6 +121,9 @@ void SideBar::appendTab( SideBarWidget *widget ) widget->setMinimumWidth( 200 ); ToolTip::add( button, widget->title() ); + + connect(widget, &SideBarWidget::closeButtonClicked, + [=]() { button->click(); }); } diff --git a/src/gui/widgets/SideBarWidget.cpp b/src/gui/widgets/SideBarWidget.cpp index c1b46cfa6..41647a4fd 100644 --- a/src/gui/widgets/SideBarWidget.cpp +++ b/src/gui/widgets/SideBarWidget.cpp @@ -22,23 +22,31 @@ * */ +#include "SideBarWidget.h" + #include #include #include -#include "SideBarWidget.h" +#include "embed.h" SideBarWidget::SideBarWidget( const QString & _title, const QPixmap & _icon, QWidget * _parent ) : QWidget( _parent ), m_title( _title ), - m_icon( _icon ) + m_icon(_icon), + m_buttonSize(17, 17) { m_contents = new QWidget( this ); m_layout = new QVBoxLayout( m_contents ); m_layout->setSpacing( 5 ); m_layout->setMargin( 0 ); + m_closeBtn = new QPushButton(embed::getIconPixmap("close"), QString(), this); + m_closeBtn->resize(m_buttonSize); + m_closeBtn->setToolTip(tr("Close")); + connect(m_closeBtn, &QPushButton::clicked, + [=]() { this->closeButtonClicked(); }); } @@ -80,6 +88,7 @@ void SideBarWidget::resizeEvent( QResizeEvent * ) const int MARGIN = 6; m_contents->setGeometry( MARGIN, 40 + MARGIN, width() - MARGIN * 2, height() - MARGIN * 2 - 40 ); + m_closeBtn->move(m_contents->geometry().width() - MARGIN - 5, 5); } diff --git a/src/gui/widgets/StepRecorderWidget.cpp b/src/gui/widgets/StepRecorderWidget.cpp index f59e235fc..a546c2a2c 100644 --- a/src/gui/widgets/StepRecorderWidget.cpp +++ b/src/gui/widgets/StepRecorderWidget.cpp @@ -26,7 +26,7 @@ StepRecorderWidget::StepRecorderWidget( QWidget * parent, - const int ppt, + const int ppb, const int marginTop, const int marginBottom, const int marginLeft, @@ -42,15 +42,15 @@ StepRecorderWidget::StepRecorderWidget( m_colorLineStart = baseColor.darker(120); setAttribute(Qt::WA_NoSystemBackground, true); - setPixelsPerTact(ppt); + setPixelsPerBar(ppb); m_top = m_marginTop; m_left = m_marginLeft; } -void StepRecorderWidget::setPixelsPerTact(int ppt) +void StepRecorderWidget::setPixelsPerBar(int ppb) { - m_ppt = ppt; + m_ppb = ppb; } void StepRecorderWidget::setCurrentPosition(MidiTime currentPosition) @@ -125,7 +125,7 @@ void StepRecorderWidget::paintEvent(QPaintEvent * pe) int StepRecorderWidget::xCoordOfTick(int tick) { - return m_marginLeft + ((tick - m_currentPosition) * m_ppt / MidiTime::ticksPerTact()); + return m_marginLeft + ((tick - m_currentPosition) * m_ppb / MidiTime::ticksPerBar()); } diff --git a/src/gui/widgets/TempoSyncKnob.cpp b/src/gui/widgets/TempoSyncKnob.cpp index 1e2e249f3..d769fd831 100644 --- a/src/gui/widgets/TempoSyncKnob.cpp +++ b/src/gui/widgets/TempoSyncKnob.cpp @@ -291,7 +291,11 @@ void TempoSyncKnob::showCustom() if( m_custom == NULL ) { m_custom = new MeterDialog( gui->mainWindow()->workspace() ); - gui->mainWindow()->addWindowedWidget( m_custom ); + QMdiSubWindow * subWindow = gui->mainWindow()->addWindowedWidget( m_custom ); + Qt::WindowFlags flags = subWindow->windowFlags(); + flags &= ~Qt::WindowMaximizeButtonHint; + subWindow->setWindowFlags( flags ); + subWindow->setFixedSize( subWindow->size() ); m_custom->setWindowTitle( "Meter" ); m_custom->setModel( &model()->m_custom ); } diff --git a/src/gui/widgets/TimeDisplayWidget.cpp b/src/gui/widgets/TimeDisplayWidget.cpp index e9a831193..01604a9dc 100644 --- a/src/gui/widgets/TimeDisplayWidget.cpp +++ b/src/gui/widgets/TimeDisplayWidget.cpp @@ -100,11 +100,11 @@ void TimeDisplayWidget::updateTime() case BarsTicks: int tick; tick = s->getPlayPos().getTicks(); - m_majorLCD.setValue((int)(tick / s->ticksPerTact()) + 1); - m_minorLCD.setValue((tick % s->ticksPerTact()) / - (s->ticksPerTact() / s->getTimeSigModel().getNumerator() ) +1); - m_milliSecondsLCD.setValue((tick % s->ticksPerTact()) % - (s->ticksPerTact() / s->getTimeSigModel().getNumerator())); + m_majorLCD.setValue((int)(tick / s->ticksPerBar()) + 1); + m_minorLCD.setValue((tick % s->ticksPerBar()) / + (s->ticksPerBar() / s->getTimeSigModel().getNumerator() ) +1); + m_milliSecondsLCD.setValue((tick % s->ticksPerBar()) % + (s->ticksPerBar() / s->getTimeSigModel().getNumerator())); break; default: break; diff --git a/src/gui/widgets/VisualizationWidget.cpp b/src/gui/widgets/VisualizationWidget.cpp index 7234331df..635f96896 100644 --- a/src/gui/widgets/VisualizationWidget.cpp +++ b/src/gui/widgets/VisualizationWidget.cpp @@ -210,7 +210,7 @@ QColor const & VisualizationWidget::determineLineColor(float level) const { return normalColor(); } - else if( level < 1.0f ) + else if( level <= 1.0f ) { return warningColor(); } diff --git a/src/lmmsconfig.h.in b/src/lmmsconfig.h.in index 02d07f1e4..3ea9d749c 100644 --- a/src/lmmsconfig.h.in +++ b/src/lmmsconfig.h.in @@ -3,6 +3,7 @@ #cmakedefine LMMS_BUILD_WIN64 #cmakedefine LMMS_BUILD_APPLE #cmakedefine LMMS_BUILD_OPENBSD +#cmakedefine LMMS_BUILD_FREEBSD #cmakedefine LMMS_BUILD_HAIKU #cmakedefine LMMS_HOST_X86 diff --git a/src/tracks/AutomationTrack.cpp b/src/tracks/AutomationTrack.cpp index 11c919f0e..430f54a56 100644 --- a/src/tracks/AutomationTrack.cpp +++ b/src/tracks/AutomationTrack.cpp @@ -121,9 +121,9 @@ void AutomationTrackView::dropEvent( QDropEvent * _de ) currentPosition() + ( _de->pos().x() - getTrackContentWidget()->x() ) * - MidiTime::ticksPerTact() / - static_cast( trackContainerView()->pixelsPerTact() ) ) - .toAbsoluteTact(); + MidiTime::ticksPerBar() / + static_cast( trackContainerView()->pixelsPerBar() ) ) + .toAbsoluteBar(); if( pos.getTicks() < 0 ) { diff --git a/src/tracks/BBTrack.cpp b/src/tracks/BBTrack.cpp index 205a22087..a779e2ea4 100644 --- a/src/tracks/BBTrack.cpp +++ b/src/tracks/BBTrack.cpp @@ -51,7 +51,7 @@ BBTCO::BBTCO( Track * _track ) : m_color( 128, 128, 128 ), m_useStyleColor( true ) { - tact_t t = Engine::getBBTrackContainer()->lengthOfBB( bbTrackIndex() ); + bar_t t = Engine::getBBTrackContainer()->lengthOfBB( bbTrackIndex() ); if( t > 0 ) { saveJournallingState( false ); @@ -218,8 +218,8 @@ void BBTCOView::paintEvent( QPaintEvent * ) : ( m_bbTCO->m_useStyleColor ? painter.background().color() : m_bbTCO->colorObj() ) ); - lingrad.setColorAt( 0, c.light( 130 ) ); - lingrad.setColorAt( 1, c.light( 70 ) ); + lingrad.setColorAt( 0, c.lighter( 130 ) ); + lingrad.setColorAt( 1, c.lighter( 70 ) ); // paint a black rectangle under the pattern to prevent glitches with transparent backgrounds p.fillRect( rect(), QColor( 0, 0, 0 ) ); @@ -237,12 +237,12 @@ void BBTCOView::paintEvent( QPaintEvent * ) const int lineSize = 3; p.setPen( c.darker( 200 ) ); - tact_t t = Engine::getBBTrackContainer()->lengthOfBB( m_bbTCO->bbTrackIndex() ); - if( m_bbTCO->length() > MidiTime::ticksPerTact() && t > 0 ) + bar_t t = Engine::getBBTrackContainer()->lengthOfBB( m_bbTCO->bbTrackIndex() ); + if( m_bbTCO->length() > MidiTime::ticksPerBar() && t > 0 ) { - for( int x = static_cast( t * pixelsPerTact() ); + for( int x = static_cast( t * pixelsPerBar() ); x < width() - 2; - x += static_cast( t * pixelsPerTact() ) ) + x += static_cast( t * pixelsPerBar() ) ) { p.drawLine( x, TCO_BORDER_WIDTH, x, TCO_BORDER_WIDTH + lineSize ); p.drawLine( x, rect().bottom() - ( TCO_BORDER_WIDTH + lineSize ), diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index 730ab97bd..b44d1b4fa 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -677,7 +677,7 @@ bool InstrumentTrack::play( const MidiTime & _start, const fpp_t _frames, if( cur_start > 0 ) { - // skip notes which are posated before start-tact + // skip notes which are posated before start-bar while( nit != notes.end() && ( *nit )->pos() < cur_start ) { ++nit; @@ -1239,6 +1239,7 @@ void InstrumentTrackView::muteChanged() +//FIXME: This is identical to SampleTrackView::createFxMenu QMenu * InstrumentTrackView::createFxMenu(QString title, QString newFxLabel) { int channelIndex = model()->effectChannelModel()->value(); @@ -1253,8 +1254,6 @@ QMenu * InstrumentTrackView::createFxMenu(QString title, QString newFxLabel) QMenu *fxMenu = new QMenu( title ); - QSignalMapper * fxMenuSignalMapper = new QSignalMapper(fxMenu); - fxMenu->addAction( newFxLabel, this, SLOT( createFxLine() ) ); fxMenu->addSeparator(); @@ -1264,14 +1263,14 @@ QMenu * InstrumentTrackView::createFxMenu(QString title, QString newFxLabel) if ( currentChannel != fxChannel ) { + auto index = currentChannel->m_channelIndex; QString label = tr( "FX %1: %2" ).arg( currentChannel->m_channelIndex ).arg( currentChannel->m_name ); - QAction * action = fxMenu->addAction( label, fxMenuSignalMapper, SLOT( map() ) ); - fxMenuSignalMapper->setMapping(action, currentChannel->m_channelIndex); + fxMenu->addAction(label, [this, index](){ + assignFxLine(index); + }); } } - connect(fxMenuSignalMapper, SIGNAL(mapped(int)), this, SLOT(assignFxLine(int))); - return fxMenu; } diff --git a/src/tracks/Pattern.cpp b/src/tracks/Pattern.cpp index 32baf0b14..125e84a1f 100644 --- a/src/tracks/Pattern.cpp +++ b/src/tracks/Pattern.cpp @@ -56,7 +56,7 @@ Pattern::Pattern( InstrumentTrack * _instrument_track ) : TrackContentObject( _instrument_track ), m_instrumentTrack( _instrument_track ), m_patternType( BeatPattern ), - m_steps( MidiTime::stepsPerTact() ) + m_steps( MidiTime::stepsPerBar() ) { setName( _instrument_track->name() ); if( _instrument_track->trackContainer() @@ -161,7 +161,7 @@ void Pattern::updateLength() return; } - tick_t max_length = MidiTime::ticksPerTact(); + tick_t max_length = MidiTime::ticksPerBar(); for( NoteVector::ConstIterator it = m_notes.begin(); it != m_notes.end(); ++it ) @@ -172,8 +172,8 @@ void Pattern::updateLength() ( *it )->endPos() ); } } - changeLength( MidiTime( max_length ).nextFullTact() * - MidiTime::ticksPerTact() ); + changeLength( MidiTime( max_length ).nextFullBar() * + MidiTime::ticksPerBar() ); updateBBTrack(); } @@ -182,7 +182,7 @@ void Pattern::updateLength() MidiTime Pattern::beatPatternLength() const { - tick_t max_length = MidiTime::ticksPerTact(); + tick_t max_length = MidiTime::ticksPerBar(); for( NoteVector::ConstIterator it = m_notes.begin(); it != m_notes.end(); ++it ) @@ -194,13 +194,13 @@ MidiTime Pattern::beatPatternLength() const } } - if( m_steps != MidiTime::stepsPerTact() ) + if( m_steps != MidiTime::stepsPerBar() ) { - max_length = m_steps * MidiTime::ticksPerTact() / - MidiTime::stepsPerTact(); + max_length = m_steps * MidiTime::ticksPerBar() / + MidiTime::stepsPerBar(); } - return MidiTime( max_length ).nextFullTact() * MidiTime::ticksPerTact(); + return MidiTime( max_length ).nextFullBar() * MidiTime::ticksPerBar(); } @@ -298,7 +298,7 @@ void Pattern::clearNotes() Note * Pattern::addStepNote( int step ) { - return addNote( Note( MidiTime( -DefaultTicksPerTact ), + return addNote( Note( MidiTime( -DefaultTicksPerBar ), MidiTime::stepPosition( step ) ), false ); } @@ -417,7 +417,7 @@ void Pattern::loadSettings( const QDomElement & _this ) m_steps = _this.attribute( "steps" ).toInt(); if( m_steps == 0 ) { - m_steps = MidiTime::stepsPerTact(); + m_steps = MidiTime::stepsPerBar(); } checkType(); @@ -466,7 +466,7 @@ void Pattern::clear() void Pattern::addSteps() { - m_steps += MidiTime::stepsPerTact(); + m_steps += MidiTime::stepsPerBar(); updateLength(); emit dataChanged(); } @@ -497,7 +497,7 @@ void Pattern::cloneSteps() void Pattern::removeSteps() { - int n = MidiTime::stepsPerTact(); + int n = MidiTime::stepsPerBar(); if( n < m_steps ) { for( int i = m_steps - n; i < m_steps; ++i ) @@ -555,19 +555,19 @@ bool Pattern::empty() void Pattern::changeTimeSignature() { - MidiTime last_pos = MidiTime::ticksPerTact() - 1; + MidiTime last_pos = MidiTime::ticksPerBar() - 1; for( NoteVector::ConstIterator cit = m_notes.begin(); cit != m_notes.end(); ++cit ) { if( ( *cit )->length() < 0 && ( *cit )->pos() > last_pos ) { - last_pos = ( *cit )->pos()+MidiTime::ticksPerTact() / - MidiTime::stepsPerTact(); + last_pos = ( *cit )->pos()+MidiTime::ticksPerBar() / + MidiTime::stepsPerBar(); } } - last_pos = last_pos.nextFullTact() * MidiTime::ticksPerTact(); - m_steps = qMax( MidiTime::stepsPerTact(), - last_pos.getTact() * MidiTime::stepsPerTact() ); + last_pos = last_pos.nextFullBar() * MidiTime::ticksPerBar(); + m_steps = qMax( MidiTime::stepsPerBar(), + last_pos.getBar() * MidiTime::stepsPerBar() ); updateLength(); } @@ -715,7 +715,7 @@ void PatternView::mousePressEvent( QMouseEvent * _me ) { if( _me->button() == Qt::LeftButton && m_pat->m_patternType == Pattern::BeatPattern && - ( fixedTCOs() || pixelsPerTact() >= 96 ) && + ( fixedTCOs() || pixelsPerBar() >= 96 ) && _me->y() > height() - s_stepBtnOff->height() ) // when mouse button is pressed in beat/bassline -mode @@ -785,7 +785,7 @@ void PatternView::mouseDoubleClickEvent(QMouseEvent *_me) void PatternView::wheelEvent( QWheelEvent * _we ) { if( m_pat->m_patternType == Pattern::BeatPattern && - ( fixedTCOs() || pixelsPerTact() >= 96 ) && + ( fixedTCOs() || pixelsPerBar() >= 96 ) && _we->y() > height() - s_stepBtnOff->height() ) { // get the step number that was wheeled on and @@ -902,14 +902,14 @@ void PatternView::paintEvent( QPaintEvent * ) textBoxHeight = fontMetrics.height() + 2 * textTop; } - // Compute pixels per tact + // Compute pixels per bar const int baseWidth = fixedTCOs() ? parentWidget()->width() - 2 * TCO_BORDER_WIDTH : width() - TCO_BORDER_WIDTH; - const float pixelsPerTact = baseWidth / (float) m_pat->length().getTact(); + const float pixelsPerBar = baseWidth / (float) m_pat->length().getBar(); - // Length of one tact/beat in the [0,1] x [0,1] coordinate system - const float tactLength = 1. / m_pat->length().getTact(); - const float tickLength = tactLength / MidiTime::ticksPerTact(); + // Length of one bar/beat in the [0,1] x [0,1] coordinate system + const float barLength = 1. / m_pat->length().getBar(); + const float tickLength = barLength / MidiTime::ticksPerBar(); const int x_base = TCO_BORDER_WIDTH; @@ -1029,7 +1029,7 @@ void PatternView::paintEvent( QPaintEvent * ) } // beat pattern paint event - else if( beatPattern && ( fixedTCOs() || pixelsPerTact >= 96 ) ) + else if( beatPattern && ( fixedTCOs() || pixelsPerBar >= 96 ) ) { QPixmap stepon0; QPixmap stepon200; @@ -1097,14 +1097,14 @@ void PatternView::paintEvent( QPaintEvent * ) const int lineSize = 3; p.setPen( c.darker( 200 ) ); - for( tact_t t = 1; t < m_pat->length().getTact(); ++t ) + for( bar_t t = 1; t < m_pat->length().getBar(); ++t ) { - p.drawLine( x_base + static_cast( pixelsPerTact * t ) - 1, + p.drawLine( x_base + static_cast( pixelsPerBar * t ) - 1, TCO_BORDER_WIDTH, x_base + static_cast( - pixelsPerTact * t ) - 1, TCO_BORDER_WIDTH + lineSize ); - p.drawLine( x_base + static_cast( pixelsPerTact * t ) - 1, + pixelsPerBar * t ) - 1, TCO_BORDER_WIDTH + lineSize ); + p.drawLine( x_base + static_cast( pixelsPerBar * t ) - 1, rect().bottom() - ( lineSize + TCO_BORDER_WIDTH ), - x_base + static_cast( pixelsPerTact * t ) - 1, + x_base + static_cast( pixelsPerBar * t ) - 1, rect().bottom() - TCO_BORDER_WIDTH ); } diff --git a/src/tracks/SampleTrack.cpp b/src/tracks/SampleTrack.cpp index 4b51ef6ec..72f63bb05 100644 --- a/src/tracks/SampleTrack.cpp +++ b/src/tracks/SampleTrack.cpp @@ -157,7 +157,7 @@ void SampleTCO::setSampleFile( const QString & _sf ) { //When creating an empty sample pattern make it a bar long float nom = Engine::getSong()->getTimeSigModel().getNumerator(); float den = Engine::getSong()->getTimeSigModel().getDenominator(); - length = DefaultTicksPerTact * ( nom / den ); + length = DefaultTicksPerBar * ( nom / den ); } else { //Otherwise set it to the sample's length @@ -521,18 +521,18 @@ void SampleTCOView::paintEvent( QPaintEvent * pe ) p.setPen( !muted ? painter.pen().brush().color() : mutedColor() ); const int spacing = TCO_BORDER_WIDTH + 1; - const float ppt = fixedTCOs() ? + const float ppb = fixedTCOs() ? ( parentWidget()->width() - 2 * TCO_BORDER_WIDTH ) - / (float) m_tco->length().getTact() : - pixelsPerTact(); + / (float) m_tco->length().getBar() : + pixelsPerBar(); float nom = Engine::getSong()->getTimeSigModel().getNumerator(); float den = Engine::getSong()->getTimeSigModel().getDenominator(); - float ticksPerTact = DefaultTicksPerTact * nom / den; + float ticksPerBar = DefaultTicksPerBar * nom / den; - float offset = m_tco->startTimeOffset() / ticksPerTact * pixelsPerTact(); + float offset = m_tco->startTimeOffset() / ticksPerBar * pixelsPerBar(); QRect r = QRect( TCO_BORDER_WIDTH + offset, spacing, - qMax( static_cast( m_tco->sampleLength() * ppt / ticksPerTact ), 1 ), rect().bottom() - 2 * spacing ); + qMax( static_cast( m_tco->sampleLength() * ppb / ticksPerBar ), 1 ), rect().bottom() - 2 * spacing ); m_tco->m_sampleBuffer->visualize( p, r, pe->rect() ); QFileInfo fileInfo(m_tco->m_sampleBuffer->audioFile()); @@ -847,6 +847,7 @@ SampleTrackView::~SampleTrackView() +//FIXME: This is identical to InstrumentTrackView::createFxMenu QMenu * SampleTrackView::createFxMenu(QString title, QString newFxLabel) { int channelIndex = model()->effectChannelModel()->value(); @@ -861,8 +862,6 @@ QMenu * SampleTrackView::createFxMenu(QString title, QString newFxLabel) QMenu *fxMenu = new QMenu(title); - QSignalMapper * fxMenuSignalMapper = new QSignalMapper(fxMenu); - fxMenu->addAction(newFxLabel, this, SLOT(createFxLine())); fxMenu->addSeparator(); @@ -872,14 +871,14 @@ QMenu * SampleTrackView::createFxMenu(QString title, QString newFxLabel) if (currentChannel != fxChannel) { + const auto index = currentChannel->m_channelIndex; QString label = tr("FX %1: %2").arg(currentChannel->m_channelIndex).arg(currentChannel->m_name); - QAction * action = fxMenu->addAction(label, fxMenuSignalMapper, SLOT(map())); - fxMenuSignalMapper->setMapping(action, currentChannel->m_channelIndex); + fxMenu->addAction(label, [this, index](){ + assignFxLine(index); + }); } } - connect(fxMenuSignalMapper, SIGNAL(mapped(int)), this, SLOT(assignFxLine(int))); - return fxMenu; } @@ -929,8 +928,8 @@ void SampleTrackView::dropEvent(QDropEvent *de) MidiTime tcoPos = trackContainerView()->fixedTCOs() ? MidiTime(0) - : MidiTime(((xPos - trackHeadWidth) / trackContainerView()->pixelsPerTact() - * MidiTime::ticksPerTact()) + trackContainerView()->currentPosition() + : MidiTime(((xPos - trackHeadWidth) / trackContainerView()->pixelsPerBar() + * MidiTime::ticksPerBar()) + trackContainerView()->currentPosition() ).quantize(1.0); SampleTCO * sTco = static_cast(getTrack()->createTCO(tcoPos)); diff --git a/tests/src/tracks/AutomationTrackTest.cpp b/tests/src/tracks/AutomationTrackTest.cpp index f9f77fac4..291ae293e 100644 --- a/tests/src/tracks/AutomationTrackTest.cpp +++ b/tests/src/tracks/AutomationTrackTest.cpp @@ -186,12 +186,12 @@ private slots: QVERIFY(! bbContainer->automatedValuesAt(5, bbTrack2.index()).size()); BBTCO tco(&bbTrack); - tco.changeLength(MidiTime::ticksPerTact() * 2); + tco.changeLength(MidiTime::ticksPerBar() * 2); tco.movePosition(0); QCOMPARE(song->automatedValuesAt(0)[&model], 0.0f); QCOMPARE(song->automatedValuesAt(5)[&model], 0.5f); - QCOMPARE(song->automatedValuesAt(MidiTime::ticksPerTact() + 5)[&model], 0.5f); + QCOMPARE(song->automatedValuesAt(MidiTime::ticksPerBar() + 5)[&model], 0.5f); } void testGlobalAutomation()