diff --git a/.appveyor.yml b/.appveyor.yml index 7ca7d58c4ce..9b25ff5e437 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -8,7 +8,11 @@ environment: matrix: - compiler: msvc install: - - vcpkg install --triplet %PLATFORM%-windows --recurse fftw3 libsamplerate libsndfile sdl2 + - cd C:\Tools\vcpkg + - git pull + - .\bootstrap-vcpkg.bat + - cd %APPVEYOR_BUILD_FOLDER% + - vcpkg install --triplet %PLATFORM%-windows --recurse fftw3 libsamplerate libsndfile lilv lv2 sdl2 - nuget install clcache -Version 4.1.0 build_script: - cd %APPVEYOR_BUILD_FOLDER% diff --git a/.circleci/config.yml b/.circleci/config.yml index f7f509d7e90..2d15efd1e10 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -170,7 +170,7 @@ jobs: environment: <<: *common_environment macos: - xcode: "9.3.1" + xcode: "10.3.0" steps: - checkout - *init @@ -179,9 +179,9 @@ jobs: - run: name: Install Homebrew dependencies command: | - # unlink Homebrew's python 2 to prevent an node-gyp error - brew unlink python@2 || true - 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 + # uninstall Homebrew's python 2 to prevent errors on brew install + brew uninstall python@2 || true + brew update && brew install ccache fftw cmake pkg-config libogg libvorbis lame libsndfile libsamplerate jack sdl libgig libsoundio lilv lv2 stk fluid-synth portaudio fltk qt5 carla - run: name: Install nodejs dependencies command: npm install -g appdmg diff --git a/.gitmodules b/.gitmodules index 92842a9f6e8..408f0fea0d2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,7 +3,7 @@ url = https://github.com/Lukas-W/qt5-x11embed.git [submodule "src/3rdparty/rpmalloc/rpmalloc"] path = src/3rdparty/rpmalloc/rpmalloc - url = https://github.com/rampantpixels/rpmalloc.git + url = https://github.com/mjansson/rpmalloc.git [submodule "plugins/zynaddsubfx/zynaddsubfx"] path = plugins/zynaddsubfx/zynaddsubfx url = https://github.com/lmms/zynaddsubfx.git @@ -43,3 +43,12 @@ [submodule "plugins/carlabase/carla"] path = plugins/carlabase/carla url = https://github.com/falktx/carla +[submodule "plugins/sid/resid"] + path = plugins/Sid/resid + url = https://github.com/simonowen/resid +[submodule "src/3rdparty/jack2"] + path = src/3rdparty/jack2 + url = https://github.com/jackaudio/jack2 +[submodule "plugins/LadspaEffect/cmt/cmt"] + path = plugins/LadspaEffect/cmt/cmt + url = https://github.com/lmms/cmt diff --git a/.travis.yml b/.travis.yml index c548adc26b3..d2d92d897ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ matrix: git: depth: false - os: osx - osx_image: xcode9.4 + osx_image: xcode10.3 before_install: # appdmg doesn't work with old Node.js - if [ "$TRAVIS_OS_NAME" = osx ]; then nvm install 10; fi @@ -31,17 +31,3 @@ script: ${TRAVIS_BUILD_DIR}/.travis/script.sh after_script: ${TRAVIS_BUILD_DIR}/.travis/after_script.sh before_deploy: - if [ "$TARGET_OS" != debian-sid ]; then make package; fi -deploy: - provider: releases - api_key: - secure: d4a+x4Gugpss7JK2DcHjyBZDmEFFh4iVfKDfITSD50T6Mc6At4LMgojvEu+6qT6IyOY2vm3UVT6fhyeuWDTRDwW9tfFlaHVA0h8aTRD+eAXOA7pQ8rEMwQO3+WCKuKTfEqUkpL4wxhww8dpkv54tqeIs0S4TBqz9tk8UhzU7XbE= - file_glob: true - file: - - lmms-${TRAVIS_TAG:1}-$TARGET_OS.exe - - /var/cache/pbuilder/result/lmms_*.tar.xz - skip_cleanup: true - on: - tags: true - all_branches: true - condition: '"$TARGET_DEPLOY" = True' - repo: LMMS/lmms diff --git a/.travis/linux..install.sh b/.travis/linux..install.sh index fd2b79d948e..d56645603a1 100755 --- a/.travis/linux..install.sh +++ b/.travis/linux..install.sh @@ -13,8 +13,11 @@ SWH_PACKAGES="perl libxml2-utils libxml-perl liblist-moreutils-perl" # VST dependencies VST_PACKAGES="wine-dev qt59x11extras qtbase5-private-dev libxcb-util0-dev libxcb-keysyms1-dev" +# LV2 dependencies; libsuil-dev is not required +LV2_PACKAGES="lv2-dev liblilv-dev" + # Help with unmet dependencies -PACKAGES="$PACKAGES $SWH_PACKAGES $VST_PACKAGES libjack-jackd2-0" +PACKAGES="$PACKAGES $SWH_PACKAGES $VST_PACKAGES $LV2_PACKAGES libjack-jackd2-0" # shellcheck disable=SC2086 sudo apt-get install -y $PACKAGES diff --git a/.travis/osx..install.sh b/.travis/osx..install.sh index 93d478c40f4..42bf66acab4 100755 --- a/.travis/osx..install.sh +++ b/.travis/osx..install.sh @@ -2,7 +2,7 @@ set -e -PACKAGES="cmake pkg-config libogg libvorbis lame libsndfile libsamplerate jack sdl libgig libsoundio stk fluid-synth portaudio node fltk qt carla" +PACKAGES="cmake pkg-config libogg libvorbis lame libsndfile libsamplerate lilv lv2 jack sdl libgig libsoundio stk fluid-synth portaudio node fltk qt carla" if "${TRAVIS}"; then PACKAGES="$PACKAGES ccache" diff --git a/.travis/script.sh b/.travis/script.sh index a6d87b37f0d..21d27b08025 100755 --- a/.travis/script.sh +++ b/.travis/script.sh @@ -13,7 +13,7 @@ if [ "$TYPE" = 'style' ]; then else - export CMAKE_FLAGS="-DCMAKE_BUILD_TYPE=RelWithDebInfo" + export CMAKE_FLAGS="-DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUNDLE_QT_TRANSLATIONS=ON" if [ -z "$TRAVIS_TAG" ]; then export CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_CCACHE=ON" diff --git a/CMakeLists.txt b/CMakeLists.txt index 815d591bc6a..eca2b5b5643 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,10 @@ IF(COMMAND CMAKE_POLICY) CMAKE_POLICY(SET CMP0057 NEW) ENDIF(COMMAND CMAKE_POLICY) + +# Import of windows.h breaks min()/max() +ADD_DEFINITIONS(-DNOMINMAX) + INCLUDE(PluginList) INCLUDE(CheckSubmodules) INCLUDE(AddFileDependencies) @@ -27,7 +31,7 @@ INCLUDE(GenerateExportHeader) STRING(TOUPPER "${CMAKE_PROJECT_NAME}" PROJECT_NAME_UCASE) -SET(PROJECT_YEAR 2019) +SET(PROJECT_YEAR 2020) SET(PROJECT_AUTHOR "LMMS Developers") SET(PROJECT_URL "https://lmms.io") @@ -35,16 +39,16 @@ SET(PROJECT_EMAIL "lmms-devel@lists.sourceforge.net") 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 "1") -SET(VERSION_STAGE "") -SET(VERSION_BUILD "0") +SET(VERSION_MINOR "3") +SET(VERSION_RELEASE "0") +SET(VERSION_STAGE "alpha") +SET(VERSION_BUILD "") SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_RELEASE}") IF(VERSION_STAGE) SET(VERSION "${VERSION}-${VERSION_STAGE}") ENDIF() IF(VERSION_BUILD) - SET(VERSION "${VERSION}.${VERSION_BUILD}") + SET(VERSION "${VERSION}-${VERSION_BUILD}") ENDIF() # Override version information for non-base builds @@ -58,6 +62,8 @@ OPTION(WANT_CARLA "Include Carla plugin" ON) OPTION(WANT_CMT "Include Computer Music Toolkit LADSPA plugins" ON) OPTION(WANT_JACK "Include JACK (Jack Audio Connection Kit) support" ON) OPTION(WANT_WEAKJACK "Loosely link JACK libraries" ON) +OPTION(WANT_LV2 "Include Lv2 plugins" ON) +OPTION(WANT_SUIL "Include SUIL for LV2 plugin UIs" ON) OPTION(WANT_MP3LAME "Include MP3/Lame support" ON) OPTION(WANT_OGGVORBIS "Include OGG/Vorbis support" ON) OPTION(WANT_PULSEAUDIO "Include PulseAudio support" ON) @@ -75,6 +81,7 @@ OPTION(WANT_VST_32 "Include 32-bit VST support" ON) OPTION(WANT_VST_64 "Include 64-bit VST support" ON) OPTION(WANT_WINMM "Include WinMM MIDI support" OFF) OPTION(WANT_DEBUG_FPE "Debug floating point exceptions" OFF) +OPTION(BUNDLE_QT_TRANSLATIONS "Install Qt translation files for LMMS" OFF) IF(LMMS_BUILD_APPLE) @@ -94,14 +101,13 @@ ENDIF(LMMS_BUILD_APPLE) IF(LMMS_BUILD_WIN32) SET(WANT_ALSA OFF) - SET(WANT_JACK OFF) SET(WANT_PULSEAUDIO OFF) SET(WANT_SNDIO OFF) SET(WANT_SOUNDIO OFF) SET(WANT_WINMM ON) + SET(BUNDLE_QT_TRANSLATIONS ON) SET(LMMS_HAVE_WINMM TRUE) SET(STATUS_ALSA "") - SET(STATUS_JACK "") SET(STATUS_PULSEAUDIO "") SET(STATUS_SOUNDIO "") SET(STATUS_WINMM "OK") @@ -171,6 +177,17 @@ ENDIF() # Resolve Qt5::qmake to full path for use in packaging scripts GET_TARGET_PROPERTY(QT_QMAKE_EXECUTABLE "${Qt5Core_QMAKE_EXECUTABLE}" IMPORTED_LOCATION) +# Find the location of Qt translation files +execute_process(COMMAND ${QT_QMAKE_EXECUTABLE} -query QT_INSTALL_TRANSLATIONS + OUTPUT_VARIABLE QT_TRANSLATIONS_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET +) +IF(EXISTS "${QT_TRANSLATIONS_DIR}") + MESSAGE("-- Found Qt translations in ${QT_TRANSLATIONS_DIR}") + ADD_DEFINITIONS(-D'QT_TRANSLATIONS_DIR="${QT_TRANSLATIONS_DIR}"') +ENDIF() + # check for libsndfile FIND_PACKAGE(SndFile REQUIRED) IF(NOT SNDFILE_FOUND) @@ -181,6 +198,44 @@ IF(NOT SNDFILE_VERSION VERSION_LESS 1.0.26) SET(LMMS_HAVE_SF_COMPLEVEL TRUE) ENDIF() +IF(WANT_LV2) + IF(PKG_CONFIG_FOUND) + PKG_CHECK_MODULES(LV2 lv2) + PKG_CHECK_MODULES(LILV lilv-0) + ENDIF() + IF(NOT LV2_FOUND AND NOT LILV_FOUND) + FIND_PACKAGE(LV2 CONFIG) + FIND_PACKAGE(LILV CONFIG) + IF(LILV_FOUND) + SET(LILV_LIBRARIES "lilv::lilv") + ENDIF() + ENDIF() + IF(LV2_FOUND AND LILV_FOUND) + SET(LMMS_HAVE_LV2 TRUE) + SET(STATUS_LV2 "OK") + ELSE() + SET(STATUS_LV2 "not found, install it or set PKG_CONFIG_PATH appropriately") + ENDIF() +ELSE(WANT_LV2) + SET(STATUS_LV2 "not built as requested") +ENDIF(WANT_LV2) + +IF(WANT_SUIL) + IF(PKG_CONFIG_FOUND) + PKG_CHECK_MODULES(SUIL suil-0) + IF(SUIL_FOUND) + SET(LMMS_HAVE_SUIL TRUE) + SET(STATUS_SUIL "OK") + ELSE() + SET(STATUS_SUIL "not found, install it or set PKG_CONFIG_PATH appropriately") + ENDIF() + ELSE() + SET(STATUS_SUIL "not found, requires pkg-config") + ENDIF() +ELSE(WANT_SUIL) + SET(STATUS_SUIL "not built as requested") +ENDIF(WANT_SUIL) + IF(WANT_CALF) SET(LMMS_HAVE_CALF TRUE) SET(STATUS_CALF "OK") @@ -384,23 +439,26 @@ ENDIF(NOT LMMS_HAVE_ALSA) # check for JACK IF(WANT_JACK) - PKG_CHECK_MODULES(JACK jack>=0.77) - IF(JACK_FOUND) - IF(WANT_WEAKJACK) - SET(LMMS_HAVE_WEAKJACK TRUE) - SET(WEAKJACK_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/src/3rdparty/weakjack/weakjack") - SET(STATUS_JACK "OK (weak linking enabled)") - # use dlsym instead - SET(JACK_LIBRARIES ${CMAKE_DL_LIBS}) - ELSE() + IF(WANT_WEAKJACK) + SET(LMMS_HAVE_WEAKJACK TRUE) + SET(WEAKJACK_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/src/3rdparty/weakjack/weakjack) + SET(JACK_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/3rdparty/jack2/common) + SET(STATUS_JACK "OK (weak linking enabled)") + # use dlsym instead + SET(JACK_LIBRARIES ${CMAKE_DL_LIBS}) + SET(LMMS_HAVE_JACK TRUE) + SET(JACK_FOUND TRUE) + ELSE() + PKG_CHECK_MODULES(JACK jack>=0.77) + IF(JACK_FOUND) SET(STATUS_JACK "OK") ENDIF() - SET(LMMS_HAVE_JACK TRUE) - ELSE(JACK_FOUND) + ENDIF() + + IF(NOT JACK_FOUND) SET(JACK_INCLUDE_DIRS "") - SET(STATUS_JACK "not found, please install libjack0.100.0-dev (or similar) " - "if you require JACK support") - ENDIF(JACK_FOUND) + SET(STATUS_JACK "not found") + ENDIF() ENDIF(WANT_JACK) # check for FFTW3F-library @@ -438,9 +496,9 @@ If(WANT_GIG) ENDIF(WANT_GIG) # check for pthreads -IF(LMMS_BUILD_LINUX OR LMMS_BUILD_APPLE OR LMMS_BUILD_OPENBSD OR LMMS_BUILD_FREEBSD) +IF(LMMS_BUILD_LINUX OR LMMS_BUILD_APPLE OR LMMS_BUILD_OPENBSD OR LMMS_BUILD_FREEBSD OR LMMS_BUILD_HAIKU) FIND_PACKAGE(Threads) -ENDIF(LMMS_BUILD_LINUX OR LMMS_BUILD_APPLE OR LMMS_BUILD_OPENBSD OR LMMS_BUILD_FREEBSD) +ENDIF(LMMS_BUILD_LINUX OR LMMS_BUILD_APPLE OR LMMS_BUILD_OPENBSD OR LMMS_BUILD_FREEBSD OR LMMS_BUILD_HAIKU) # check for sndio (roaraudio won't work yet) IF(WANT_SNDIO) @@ -686,6 +744,8 @@ MESSAGE( MESSAGE( "Optional plugins\n" "----------------\n" +"* Lv2 plugins : ${STATUS_LV2}\n" +"* SUIL for plugin UIs : ${STATUS_SUIL}\n" "* ZynAddSubFX instrument : ${STATUS_ZYN}\n" "* Carla Patchbay & Rack : ${STATUS_CARLA}\n" "* SoundFont2 player : ${STATUS_FLUIDSYNTH}\n" diff --git a/README.md b/README.md index 1061ecff600..6b23673d746 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ [![Join the chat at Discord](https://img.shields.io/badge/chat-on%20discord-7289DA.svg)](https://discord.gg/3sc5su7) [![Localise on transifex](https://img.shields.io/badge/localise-on_transifex-green.svg)](https://www.transifex.com/lmms/lmms/) +**A soft PR-Freeze is currently underway to prepare for refactoring ([#5592](https://github.com/LMMS/lmms/issues/5592)). Please do not open non-essential PRs at this time.** + What is LMMS? -------------- @@ -53,7 +55,6 @@ Information about what you can do and how can be found in the Before coding a new big feature, please _always_ [file an issue](https://github.com/LMMS/lmms/issues/new) for your idea and -suggestions about your feature and about the intended implementation on GitHub -or post to the LMMS developers mailinglist (lmms-devel@lists.sourceforge.net) -and wait for replies! Maybe there are different ideas, improvements, hints or +suggestions about your feature and about the intended implementation on GitHub, +or ask in one of the tech channels on Discord and wait for replies! Maybe there are different ideas, improvements, or hints, or maybe your feature is not welcome/needed at the moment. diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index b27dec91e0f..833fad5819f 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -9,7 +9,7 @@ IF(VERSION_STAGE) SET(CPACK_PACKAGE_VERSION_PATCH "${CPACK_PACKAGE_VERSION_PATCH}-${VERSION_STAGE}") ENDIF() IF(VERSION_BUILD) - SET(CPACK_PACKAGE_VERSION_PATCH "${CPACK_PACKAGE_VERSION_PATCH}.${VERSION_BUILD}") + SET(CPACK_PACKAGE_VERSION_PATCH "${CPACK_PACKAGE_VERSION_PATCH}-${VERSION_BUILD}") ENDIF() SET(CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME_UCASE}") SET(CPACK_SOURCE_GENERATOR "TBZ2") diff --git a/cmake/apple/CMakeLists.txt b/cmake/apple/CMakeLists.txt index 835d886b9b6..0b66689e75d 100644 --- a/cmake/apple/CMakeLists.txt +++ b/cmake/apple/CMakeLists.txt @@ -9,6 +9,11 @@ SET(MACOSX_BUNDLE_MIMETYPE "application/x-lmms-project") SET(MACOSX_BUNDLE_MIMETYPE_ICON "project.icns") SET(MACOSX_BUNDLE_MIMETYPE_ID "io.lmms") SET(MACOSX_BUNDLE_PROJECT_URL "${PROJECT_URL}") +SET(MACOSX_BUNDLE_DMG_TITLE "${MACOSX_BUNDLE_BUNDLE_NAME} ${MACOSX_BUNDLE_LONG_VERSION_STRING}") + +# FIXME: appdmg won't allow volume names > 27 char +# See also https://github.com/LinusU/node-appdmg/issues/48 +STRING(SUBSTRING "${MACOSX_BUNDLE_DMG_TITLE}" 0 27 MACOSX_BUNDLE_DMG_TITLE) CONFIGURE_FILE("lmms.plist.in" "${CMAKE_BINARY_DIR}/Info.plist") CONFIGURE_FILE("install_apple.sh.in" "${CMAKE_BINARY_DIR}/install_apple.sh" @ONLY) diff --git a/cmake/apple/package_apple.json.in b/cmake/apple/package_apple.json.in index 1d1147cbf21..f6660b345bc 100644 --- a/cmake/apple/package_apple.json.in +++ b/cmake/apple/package_apple.json.in @@ -1,5 +1,5 @@ { - "title": "@MACOSX_BUNDLE_BUNDLE_NAME@ @MACOSX_BUNDLE_LONG_VERSION_STRING@", + "title": "@MACOSX_BUNDLE_DMG_TITLE@", "background": "@CMAKE_SOURCE_DIR@/cmake/apple/dmg_branding.png", "icon-size": 128, "contents": [ diff --git a/cmake/modules/PluginList.cmake b/cmake/modules/PluginList.cmake index 2d853038873..ed4ffd2eb10 100644 --- a/cmake/modules/PluginList.cmake +++ b/cmake/modules/PluginList.cmake @@ -39,6 +39,8 @@ SET(LMMS_PLUGIN_LIST HydrogenImport ladspa_browser LadspaEffect + Lv2Effect + Lv2Instrument lb302 MidiImport MidiExport @@ -54,7 +56,7 @@ SET(LMMS_PLUGIN_LIST ReverbSC sf2_player sfxr - sid + Sid SpectrumAnalyzer stereo_enhancer stereo_matrix diff --git a/cmake/modules/VersionInfo.cmake b/cmake/modules/VersionInfo.cmake index cf6932cbbba..9571514a6eb 100644 --- a/cmake/modules/VersionInfo.cmake +++ b/cmake/modules/VersionInfo.cmake @@ -1,29 +1,56 @@ FIND_PACKAGE(Git) IF(GIT_FOUND AND NOT FORCE_VERSION) - # Look for git tag information (e.g. Tagged: "v1.0.0", Non-tagged: "v1.0.0-123-a1b2c3d") + SET(MAJOR_VERSION 0) + SET(MINOR_VERSION 0) + SET(PATCH_VERSION 0) + # Look for git tag information (e.g. Tagged: "v1.0.0", Untagged: "v1.0.0-123-a1b2c3d") + # Untagged format: [latest tag]-[number of commits]-[latest commit hash] EXECUTE_PROCESS( COMMAND "${GIT_EXECUTABLE}" describe --tags --match v[0-9].[0-9].[0-9]* OUTPUT_VARIABLE GIT_TAG WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" TIMEOUT 10 OUTPUT_STRIP_TRAILING_WHITESPACE) + # Read: TAG_LIST = GIT_TAG.split("-") STRING(REPLACE "-" ";" TAG_LIST "${GIT_TAG}") + # Read: TAG_LIST_LENGTH = TAG_LIST.length() LIST(LENGTH TAG_LIST TAG_LIST_LENGTH) + # Untagged versions contain at least 2 dashes, giving 3 strings on split. + # Hence, for untagged versions TAG_LIST_LENGTH = [dashes in latest tag] + 3. + # Corollary: if TAG_LIST_LENGTH <= 2, the version must be tagged. IF(TAG_LIST_LENGTH GREATER 0) + # Set FORCE_VERSION to TAG_LIST[0], strip any 'v's to get MAJ.MIN.PAT LIST(GET TAG_LIST 0 FORCE_VERSION) STRING(REPLACE "v" "" FORCE_VERSION "${FORCE_VERSION}") + # Split FORCE_VERSION on '.' and populate MAJOR/MINOR/PATCH_VERSION + STRING(REPLACE "." ";" MAJ_MIN_PAT "${FORCE_VERSION}") + LIST(GET MAJ_MIN_PAT 0 MAJOR_VERSION) + LIST(GET MAJ_MIN_PAT 1 MINOR_VERSION) + LIST(GET MAJ_MIN_PAT 2 PATCH_VERSION) ENDIF() + # 1 dash total: Dash in latest tag, no additional commits => pre-release IF(TAG_LIST_LENGTH EQUAL 2) LIST(GET TAG_LIST 1 VERSION_STAGE) SET(FORCE_VERSION "${FORCE_VERSION}-${VERSION_STAGE}") + # 2 dashes: Assume untagged with no dashes in latest tag name => stable + commits ELSEIF(TAG_LIST_LENGTH EQUAL 3) + # Get the number of commits and latest commit hash LIST(GET TAG_LIST 1 EXTRA_COMMITS) - SET(FORCE_VERSION "${FORCE_VERSION}.${EXTRA_COMMITS}") + LIST(GET TAG_LIST 2 COMMIT_HASH) + # Bump the patch version + MATH(EXPR PATCH_VERSION "${PATCH_VERSION}+1") + # Set the version to MAJOR.MINOR.PATCH-EXTRA_COMMITS+COMMIT_HASH + SET(FORCE_VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}") + SET(FORCE_VERSION "${FORCE_VERSION}-${EXTRA_COMMITS}+${COMMIT_HASH}") + # 3 dashes: Assume untagged with 1 dash in latest tag name => pre-release + commits ELSEIF(TAG_LIST_LENGTH EQUAL 4) + # Get pre-release stage, number of commits, and latest commit hash LIST(GET TAG_LIST 1 VERSION_STAGE) LIST(GET TAG_LIST 2 EXTRA_COMMITS) - SET(FORCE_VERSION - "${FORCE_VERSION}-${VERSION_STAGE}.${EXTRA_COMMITS}") + LIST(GET TAG_LIST 3 COMMIT_HASH) + # Set the version to MAJOR.MINOR.PATCH-VERSION_STAGE.EXTRA_COMMITS+COMMIT_HASH + SET(FORCE_VERSION "${FORCE_VERSION}-${VERSION_STAGE}") + SET(FORCE_VERSION "${FORCE_VERSION}.${EXTRA_COMMITS}+${COMMIT_HASH}") ENDIF() ENDIF() @@ -74,4 +101,3 @@ MESSAGE("\n" "* Override version: -DFORCE_VERSION=x.x.x-x\n" "* Ignore Git information: -DFORCE_VERSION=internal\n" ) - diff --git a/data/locale/CMakeLists.txt b/data/locale/CMakeLists.txt index 9cb25f4265c..4ce666dcfef 100644 --- a/data/locale/CMakeLists.txt +++ b/data/locale/CMakeLists.txt @@ -47,9 +47,9 @@ FOREACH(_item ${qm_targets}) ADD_DEPENDENCIES(finalize-locales "${_item}") ENDFOREACH(_item ${qm_targets}) -IF(LMMS_BUILD_WIN32) - FILE(GLOB QT_QM_FILES "${QT_TRANSLATIONS_DIR}/qt*[^h].qm") +IF(BUNDLE_QT_TRANSLATIONS) + FILE(GLOB QT_QM_FILES "${QT_TRANSLATIONS_DIR}/qt*.qm") LIST(SORT QT_QM_FILES) -ENDIF(LMMS_BUILD_WIN32) +ENDIF() INSTALL(FILES ${QM_FILES} ${QT_QM_FILES} DESTINATION "${LMMS_DATA_DIR}/locale") diff --git a/data/presets/AudioFileProcessor/Bass-Mania.xpf b/data/presets/AudioFileProcessor/Bass-Mania.xpf index 4a92c00289f..f6a0164350f 100644 --- a/data/presets/AudioFileProcessor/Bass-Mania.xpf +++ b/data/presets/AudioFileProcessor/Bass-Mania.xpf @@ -6,7 +6,7 @@ - + diff --git a/data/presets/AudioFileProcessor/Erazor.xpf b/data/presets/AudioFileProcessor/Erazor.xpf index f106c27f893..a0481bbc420 100644 --- a/data/presets/AudioFileProcessor/Erazor.xpf +++ b/data/presets/AudioFileProcessor/Erazor.xpf @@ -8,7 +8,7 @@ - + diff --git a/data/presets/AudioFileProcessor/Fat-Reversed-Kick.xpf b/data/presets/AudioFileProcessor/Fat-Reversed-Kick.xpf index f9f11ef8b75..2609144de1d 100644 --- a/data/presets/AudioFileProcessor/Fat-Reversed-Kick.xpf +++ b/data/presets/AudioFileProcessor/Fat-Reversed-Kick.xpf @@ -6,7 +6,7 @@ - + diff --git a/data/presets/AudioFileProcessor/Kick-4-your-Subwoofer.xpf b/data/presets/AudioFileProcessor/Kick-4-your-Subwoofer.xpf index 6a9da93ce1d..ac60499f793 100644 --- a/data/presets/AudioFileProcessor/Kick-4-your-Subwoofer.xpf +++ b/data/presets/AudioFileProcessor/Kick-4-your-Subwoofer.xpf @@ -3,16 +3,15 @@ - - + + - + - - + \ No newline at end of file diff --git a/data/presets/AudioFileProcessor/SString.xpf b/data/presets/AudioFileProcessor/SString.xpf index 1def1d71942..bcff41ef671 100644 --- a/data/presets/AudioFileProcessor/SString.xpf +++ b/data/presets/AudioFileProcessor/SString.xpf @@ -3,7 +3,7 @@ - + diff --git a/data/presets/AudioFileProcessor/orion.xpf b/data/presets/AudioFileProcessor/orion.xpf index 101286b298e..21b31dee0c9 100644 --- a/data/presets/AudioFileProcessor/orion.xpf +++ b/data/presets/AudioFileProcessor/orion.xpf @@ -3,7 +3,7 @@ - + diff --git a/data/presets/BitInvader/alien_strings.xpf b/data/presets/BitInvader/alien_strings.xpf index d29fdca1070..f8e6cf1a540 100644 --- a/data/presets/BitInvader/alien_strings.xpf +++ b/data/presets/BitInvader/alien_strings.xpf @@ -13,6 +13,15 @@ + + + + + + + + + diff --git a/data/presets/BitInvader/bell.xpf b/data/presets/BitInvader/bell.xpf index a5346e212d3..f142e64f80a 100644 --- a/data/presets/BitInvader/bell.xpf +++ b/data/presets/BitInvader/bell.xpf @@ -3,10 +3,10 @@ - + - + diff --git a/data/presets/BitInvader/drama.xpf b/data/presets/BitInvader/drama.xpf index fc564fa586e..b69f60c3050 100644 --- a/data/presets/BitInvader/drama.xpf +++ b/data/presets/BitInvader/drama.xpf @@ -13,6 +13,15 @@ + + + + + + + + + diff --git a/data/presets/BitInvader/pluck.xpf b/data/presets/BitInvader/pluck.xpf index b71974e4edf..db933579083 100644 --- a/data/presets/BitInvader/pluck.xpf +++ b/data/presets/BitInvader/pluck.xpf @@ -3,16 +3,25 @@ - + - + + + + + + + + + + diff --git a/data/presets/BitInvader/soft_pad.xpf b/data/presets/BitInvader/soft_pad.xpf index 63803acb874..f36ba5401a1 100644 --- a/data/presets/BitInvader/soft_pad.xpf +++ b/data/presets/BitInvader/soft_pad.xpf @@ -3,8 +3,8 @@ - - + + diff --git a/data/presets/BitInvader/spacefx.xpf b/data/presets/BitInvader/spacefx.xpf index b10f4737789..21b374b128f 100644 --- a/data/presets/BitInvader/spacefx.xpf +++ b/data/presets/BitInvader/spacefx.xpf @@ -6,7 +6,7 @@ - + diff --git a/data/presets/BitInvader/subbass.xpf b/data/presets/BitInvader/subbass.xpf index 50ebb46c6f7..8af395d75e4 100644 --- a/data/presets/BitInvader/subbass.xpf +++ b/data/presets/BitInvader/subbass.xpf @@ -6,7 +6,7 @@ - + diff --git a/data/presets/BitInvader/toy_piano.xpf b/data/presets/BitInvader/toy_piano.xpf index 0fed791d1c3..5928aa4ff71 100644 --- a/data/presets/BitInvader/toy_piano.xpf +++ b/data/presets/BitInvader/toy_piano.xpf @@ -3,10 +3,10 @@ - - + + - + diff --git a/data/presets/BitInvader/wah_synth.xpf b/data/presets/BitInvader/wah_synth.xpf index e8e68c53885..c6d77a04443 100644 --- a/data/presets/BitInvader/wah_synth.xpf +++ b/data/presets/BitInvader/wah_synth.xpf @@ -3,10 +3,10 @@ - + - + diff --git a/data/presets/Kicker/Clap.xpf b/data/presets/Kicker/Clap.xpf index d354051ce63..12a0989cb76 100644 --- a/data/presets/Kicker/Clap.xpf +++ b/data/presets/Kicker/Clap.xpf @@ -3,7 +3,7 @@ - + diff --git a/data/presets/Kicker/HihatOpen.xpf b/data/presets/Kicker/HihatOpen.xpf index c0f0aa69235..e0ccd7a70f8 100644 --- a/data/presets/Kicker/HihatOpen.xpf +++ b/data/presets/Kicker/HihatOpen.xpf @@ -5,7 +5,7 @@ - + diff --git a/data/presets/Kicker/Shaker.xpf b/data/presets/Kicker/Shaker.xpf index 13eee953e90..0102f8caca1 100644 --- a/data/presets/Kicker/Shaker.xpf +++ b/data/presets/Kicker/Shaker.xpf @@ -8,7 +8,7 @@ - + diff --git a/data/presets/Kicker/SnareLong.xpf b/data/presets/Kicker/SnareLong.xpf index b8b2f9d884a..8c5202c054c 100644 --- a/data/presets/Kicker/SnareLong.xpf +++ b/data/presets/Kicker/SnareLong.xpf @@ -8,7 +8,7 @@ - + diff --git a/data/presets/Kicker/TrapKick.xpf b/data/presets/Kicker/TrapKick.xpf index a8ad8976da1..28827b9461d 100644 --- a/data/presets/Kicker/TrapKick.xpf +++ b/data/presets/Kicker/TrapKick.xpf @@ -8,7 +8,7 @@ - + diff --git a/data/presets/LB302/STrash.xpf b/data/presets/LB302/STrash.xpf index bd928e63cd4..a539be35ef5 100644 --- a/data/presets/LB302/STrash.xpf +++ b/data/presets/LB302/STrash.xpf @@ -3,23 +3,11 @@ - + - - - - - - - - - - - - @@ -31,14 +19,6 @@ - - - - - - - - diff --git a/data/presets/Monstro/Growl.xpf b/data/presets/Monstro/Growl.xpf index f553b16411f..307343d488c 100644 --- a/data/presets/Monstro/Growl.xpf +++ b/data/presets/Monstro/Growl.xpf @@ -1,22 +1,22 @@ - + - - + + - + - - - - + + + + - - - + + + - + @@ -30,39 +30,39 @@ - - + + - - - + + + - - + + - - + + - - - - - + + + + + - - + + - + @@ -70,11 +70,11 @@ - - + + - + diff --git a/data/presets/OpulenZ/Clarinet.xpf b/data/presets/OpulenZ/Clarinet.xpf index 3301318a282..5d516a215ee 100644 --- a/data/presets/OpulenZ/Clarinet.xpf +++ b/data/presets/OpulenZ/Clarinet.xpf @@ -5,7 +5,7 @@ - + diff --git a/data/presets/OpulenZ/Combo_organ.xpf b/data/presets/OpulenZ/Combo_organ.xpf index 21e2d8a62ec..06c9e06610f 100644 --- a/data/presets/OpulenZ/Combo_organ.xpf +++ b/data/presets/OpulenZ/Combo_organ.xpf @@ -3,9 +3,9 @@ - + - + diff --git a/data/presets/OpulenZ/Epiano.xpf b/data/presets/OpulenZ/Epiano.xpf index dea947763e3..3478d7e3e71 100644 --- a/data/presets/OpulenZ/Epiano.xpf +++ b/data/presets/OpulenZ/Epiano.xpf @@ -5,7 +5,7 @@ - + diff --git a/data/presets/OpulenZ/Organ_leslie.xpf b/data/presets/OpulenZ/Organ_leslie.xpf index a1c5c024e8b..5cf5ef983aa 100644 --- a/data/presets/OpulenZ/Organ_leslie.xpf +++ b/data/presets/OpulenZ/Organ_leslie.xpf @@ -5,7 +5,7 @@ - + diff --git a/data/presets/OpulenZ/Square.xpf b/data/presets/OpulenZ/Square.xpf index ad0aaca52f4..8fba89a8b33 100644 --- a/data/presets/OpulenZ/Square.xpf +++ b/data/presets/OpulenZ/Square.xpf @@ -5,7 +5,7 @@ - + diff --git a/data/presets/Organic/Rubberband.xpf b/data/presets/Organic/Rubberband.xpf index 1dd0a194146..9b328541e96 100644 --- a/data/presets/Organic/Rubberband.xpf +++ b/data/presets/Organic/Rubberband.xpf @@ -3,19 +3,27 @@ - + - + - + + + + + + + + + diff --git a/data/presets/Organic/organ_blues.xpf b/data/presets/Organic/organ_blues.xpf index a35bbfda855..c5cf9d04e2f 100644 --- a/data/presets/Organic/organ_blues.xpf +++ b/data/presets/Organic/organ_blues.xpf @@ -6,7 +6,7 @@ - + diff --git a/data/presets/Organic/organ_risingsun.xpf b/data/presets/Organic/organ_risingsun.xpf index b5dc7590639..311504acba0 100644 --- a/data/presets/Organic/organ_risingsun.xpf +++ b/data/presets/Organic/organ_risingsun.xpf @@ -6,7 +6,7 @@ - + diff --git a/data/presets/Organic/puresine.xpf b/data/presets/Organic/puresine.xpf index 0c77ca9ca42..9c5088cdd19 100644 --- a/data/presets/Organic/puresine.xpf +++ b/data/presets/Organic/puresine.xpf @@ -6,7 +6,7 @@ - + diff --git a/data/presets/Organic/sequencer_64.xpf b/data/presets/Organic/sequencer_64.xpf index c1f8fc22398..f2d5016fb5b 100644 --- a/data/presets/Organic/sequencer_64.xpf +++ b/data/presets/Organic/sequencer_64.xpf @@ -6,7 +6,7 @@ - + diff --git a/data/presets/SID/Bass.xpf b/data/presets/SID/Bass.xpf index c5f605c8fd7..24dd6ded217 100644 --- a/data/presets/SID/Bass.xpf +++ b/data/presets/SID/Bass.xpf @@ -8,7 +8,7 @@ - + diff --git a/data/presets/TripleOscillator/AnalogDreamz.xpf b/data/presets/TripleOscillator/AnalogDreamz.xpf index 0af114cb9dd..38865bf9ef3 100644 --- a/data/presets/TripleOscillator/AnalogDreamz.xpf +++ b/data/presets/TripleOscillator/AnalogDreamz.xpf @@ -3,9 +3,9 @@ - + - + diff --git a/data/presets/TripleOscillator/Arpeggio.xpf b/data/presets/TripleOscillator/Arpeggio.xpf index 32300966fc2..ad600d1383e 100644 --- a/data/presets/TripleOscillator/Arpeggio.xpf +++ b/data/presets/TripleOscillator/Arpeggio.xpf @@ -4,9 +4,9 @@ - + - + diff --git a/data/presets/TripleOscillator/ArpeggioPing.xpf b/data/presets/TripleOscillator/ArpeggioPing.xpf index 5da4c30d83f..e42604b8f62 100644 --- a/data/presets/TripleOscillator/ArpeggioPing.xpf +++ b/data/presets/TripleOscillator/ArpeggioPing.xpf @@ -5,7 +5,7 @@ - + diff --git a/data/presets/TripleOscillator/BlandModBass.xpf b/data/presets/TripleOscillator/BlandModBass.xpf index 3160bd09725..593d1f4a117 100644 --- a/data/presets/TripleOscillator/BlandModBass.xpf +++ b/data/presets/TripleOscillator/BlandModBass.xpf @@ -3,7 +3,7 @@ - + diff --git a/data/presets/TripleOscillator/BrokenToy.xpf b/data/presets/TripleOscillator/BrokenToy.xpf index ed0ac370e1d..6a8eea0dd31 100644 --- a/data/presets/TripleOscillator/BrokenToy.xpf +++ b/data/presets/TripleOscillator/BrokenToy.xpf @@ -3,12 +3,12 @@ - + - + - + diff --git a/data/presets/TripleOscillator/DetunedGhost.xpf b/data/presets/TripleOscillator/DetunedGhost.xpf index 4f180b6e380..d19280b28a6 100644 --- a/data/presets/TripleOscillator/DetunedGhost.xpf +++ b/data/presets/TripleOscillator/DetunedGhost.xpf @@ -9,8 +9,7 @@ - - + diff --git a/data/presets/TripleOscillator/DirtyReece.xpf b/data/presets/TripleOscillator/DirtyReece.xpf index d574c72997e..8a0dea3add5 100644 --- a/data/presets/TripleOscillator/DirtyReece.xpf +++ b/data/presets/TripleOscillator/DirtyReece.xpf @@ -5,7 +5,7 @@ - + diff --git a/data/presets/TripleOscillator/Drums_HardKick.xpf b/data/presets/TripleOscillator/Drums_HardKick.xpf index 64bd319493b..6b322280b38 100644 --- a/data/presets/TripleOscillator/Drums_HardKick.xpf +++ b/data/presets/TripleOscillator/Drums_HardKick.xpf @@ -94,7 +94,7 @@ - + diff --git a/data/presets/TripleOscillator/Drums_HihatO.xpf b/data/presets/TripleOscillator/Drums_HihatO.xpf index 19258c57a04..51b2b457a2a 100644 --- a/data/presets/TripleOscillator/Drums_HihatO.xpf +++ b/data/presets/TripleOscillator/Drums_HihatO.xpf @@ -5,7 +5,7 @@ - + diff --git a/data/presets/TripleOscillator/Drums_Kick.xpf b/data/presets/TripleOscillator/Drums_Kick.xpf index d18e0ed1756..7ef4d234ac8 100644 --- a/data/presets/TripleOscillator/Drums_Kick.xpf +++ b/data/presets/TripleOscillator/Drums_Kick.xpf @@ -1,21 +1,26 @@ - + - - + + - + - - - - + + + + - - - - + + + + + + + + + diff --git a/data/presets/TripleOscillator/Drums_Snare.xpf b/data/presets/TripleOscillator/Drums_Snare.xpf index 50731bf56ab..08059d7b16e 100644 --- a/data/presets/TripleOscillator/Drums_Snare.xpf +++ b/data/presets/TripleOscillator/Drums_Snare.xpf @@ -1,21 +1,26 @@ - + - - + + - + - - - - + + + + - - - - + + + + + + + + + diff --git a/data/presets/TripleOscillator/FuzzyAnalogBass.xpf b/data/presets/TripleOscillator/FuzzyAnalogBass.xpf index 78b176dfdca..c0cf170378a 100644 --- a/data/presets/TripleOscillator/FuzzyAnalogBass.xpf +++ b/data/presets/TripleOscillator/FuzzyAnalogBass.xpf @@ -1,21 +1,30 @@ - + - - + + - + + + - - - - + + + + - - - - + + + + + + + + + + + diff --git a/data/presets/TripleOscillator/GhostBoy.xpf b/data/presets/TripleOscillator/GhostBoy.xpf index 0742a1c3c35..bbf07b1562b 100644 --- a/data/presets/TripleOscillator/GhostBoy.xpf +++ b/data/presets/TripleOscillator/GhostBoy.xpf @@ -3,9 +3,9 @@ - + - + diff --git a/data/presets/TripleOscillator/Harp-of-a-Fairy.xpf b/data/presets/TripleOscillator/Harp-of-a-Fairy.xpf index c248b9c4811..f1c7360f20b 100644 --- a/data/presets/TripleOscillator/Harp-of-a-Fairy.xpf +++ b/data/presets/TripleOscillator/Harp-of-a-Fairy.xpf @@ -4,7 +4,7 @@ - + diff --git a/data/presets/TripleOscillator/Jupiter.xpf b/data/presets/TripleOscillator/Jupiter.xpf index 86b59aac599..3289f922258 100644 --- a/data/presets/TripleOscillator/Jupiter.xpf +++ b/data/presets/TripleOscillator/Jupiter.xpf @@ -3,9 +3,9 @@ - + - + diff --git a/data/presets/TripleOscillator/LFO-party.xpf b/data/presets/TripleOscillator/LFO-party.xpf index f5d9b1baa7a..30228d11746 100644 --- a/data/presets/TripleOscillator/LFO-party.xpf +++ b/data/presets/TripleOscillator/LFO-party.xpf @@ -8,7 +8,7 @@ - + diff --git a/data/presets/TripleOscillator/LovelyDream.xpf b/data/presets/TripleOscillator/LovelyDream.xpf index 589640975cd..52769caf83b 100644 --- a/data/presets/TripleOscillator/LovelyDream.xpf +++ b/data/presets/TripleOscillator/LovelyDream.xpf @@ -6,7 +6,7 @@ - + diff --git a/data/presets/TripleOscillator/MoogArpeggio.xpf b/data/presets/TripleOscillator/MoogArpeggio.xpf index d2f280c1b5b..987e7100d00 100644 --- a/data/presets/TripleOscillator/MoogArpeggio.xpf +++ b/data/presets/TripleOscillator/MoogArpeggio.xpf @@ -5,7 +5,7 @@ - + diff --git a/data/presets/TripleOscillator/OldComputerGames.xpf b/data/presets/TripleOscillator/OldComputerGames.xpf index 674bef67470..8a8534b4424 100644 --- a/data/presets/TripleOscillator/OldComputerGames.xpf +++ b/data/presets/TripleOscillator/OldComputerGames.xpf @@ -3,7 +3,7 @@ - + @@ -73,24 +73,6 @@ - - - - - - - - - - - - - - - - - - diff --git a/data/presets/TripleOscillator/PMFMFTWbass.xpf b/data/presets/TripleOscillator/PMFMFTWbass.xpf index d81b5560166..a707d2460ab 100644 --- a/data/presets/TripleOscillator/PMFMFTWbass.xpf +++ b/data/presets/TripleOscillator/PMFMFTWbass.xpf @@ -5,10 +5,10 @@ - + - + diff --git a/data/presets/TripleOscillator/PluckArpeggio.xpf b/data/presets/TripleOscillator/PluckArpeggio.xpf index 44ce26c8e20..efc47b51604 100644 --- a/data/presets/TripleOscillator/PluckArpeggio.xpf +++ b/data/presets/TripleOscillator/PluckArpeggio.xpf @@ -5,7 +5,7 @@ - + diff --git a/data/presets/TripleOscillator/PluckBass.xpf b/data/presets/TripleOscillator/PluckBass.xpf index 51c5de329a2..4d4052dfa84 100644 --- a/data/presets/TripleOscillator/PluckBass.xpf +++ b/data/presets/TripleOscillator/PluckBass.xpf @@ -15,31 +15,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data/presets/TripleOscillator/PowerStrings.xpf b/data/presets/TripleOscillator/PowerStrings.xpf index 0ef3750976e..b5ab04178e4 100644 --- a/data/presets/TripleOscillator/PowerStrings.xpf +++ b/data/presets/TripleOscillator/PowerStrings.xpf @@ -3,7 +3,7 @@ - + @@ -16,10 +16,6 @@ - - - - diff --git a/data/presets/TripleOscillator/RaveBass.xpf b/data/presets/TripleOscillator/RaveBass.xpf index 21fc6e90c06..2285dc370b7 100644 --- a/data/presets/TripleOscillator/RaveBass.xpf +++ b/data/presets/TripleOscillator/RaveBass.xpf @@ -5,10 +5,10 @@ - + - + diff --git a/data/presets/TripleOscillator/SawReso.xpf b/data/presets/TripleOscillator/SawReso.xpf index 2c631d66372..d9873e5f813 100644 --- a/data/presets/TripleOscillator/SawReso.xpf +++ b/data/presets/TripleOscillator/SawReso.xpf @@ -5,7 +5,7 @@ - + diff --git a/data/presets/TripleOscillator/SpaceBass.xpf b/data/presets/TripleOscillator/SpaceBass.xpf index aeb43286db7..5a13266fd6a 100644 --- a/data/presets/TripleOscillator/SpaceBass.xpf +++ b/data/presets/TripleOscillator/SpaceBass.xpf @@ -3,8 +3,8 @@ - - + + diff --git a/data/presets/TripleOscillator/Square.xpf b/data/presets/TripleOscillator/Square.xpf index cbd455e0f52..49859adbc81 100644 --- a/data/presets/TripleOscillator/Square.xpf +++ b/data/presets/TripleOscillator/Square.xpf @@ -3,12 +3,12 @@ - + - + - + diff --git a/data/presets/TripleOscillator/TINTNpad.xpf b/data/presets/TripleOscillator/TINTNpad.xpf index 6f04ca4f221..9c4e27be05e 100644 --- a/data/presets/TripleOscillator/TINTNpad.xpf +++ b/data/presets/TripleOscillator/TINTNpad.xpf @@ -3,7 +3,7 @@ - + diff --git a/data/presets/TripleOscillator/TheMaster.xpf b/data/presets/TripleOscillator/TheMaster.xpf index c54787a19f6..2de7125277e 100644 --- a/data/presets/TripleOscillator/TheMaster.xpf +++ b/data/presets/TripleOscillator/TheMaster.xpf @@ -3,9 +3,9 @@ - + - + @@ -15,17 +15,6 @@ - - - - - - - - - - - diff --git a/data/presets/TripleOscillator/TranceLead.xpf b/data/presets/TripleOscillator/TranceLead.xpf index cd1d3526a97..003739d39a7 100644 --- a/data/presets/TripleOscillator/TranceLead.xpf +++ b/data/presets/TripleOscillator/TranceLead.xpf @@ -1,18 +1,22 @@ - - + + - - - - - - - - - + + + + + + + + + + + - - - - + + + + + + diff --git a/data/presets/TripleOscillator/WarmStack.xpf b/data/presets/TripleOscillator/WarmStack.xpf index fb903295c4e..d3ab54bf0ca 100644 --- a/data/presets/TripleOscillator/WarmStack.xpf +++ b/data/presets/TripleOscillator/WarmStack.xpf @@ -5,7 +5,7 @@ - + diff --git a/data/presets/TripleOscillator/Whistle.xpf b/data/presets/TripleOscillator/Whistle.xpf index 3d03f5e56a3..545abd3781e 100644 --- a/data/presets/TripleOscillator/Whistle.xpf +++ b/data/presets/TripleOscillator/Whistle.xpf @@ -3,8 +3,8 @@ - - + + diff --git a/data/presets/Vibed/Harpsichord.xpf b/data/presets/Vibed/Harpsichord.xpf index b7c617c9bb9..2d22169bc4b 100644 --- a/data/presets/Vibed/Harpsichord.xpf +++ b/data/presets/Vibed/Harpsichord.xpf @@ -3,8 +3,8 @@ - - + + diff --git a/data/presets/Vibed/SadPad.xpf b/data/presets/Vibed/SadPad.xpf index 2ef17698bb7..b702d1896f9 100644 --- a/data/presets/Vibed/SadPad.xpf +++ b/data/presets/Vibed/SadPad.xpf @@ -3,8 +3,8 @@ - - + + diff --git a/data/presets/Xpressive/Ambition.xpf b/data/presets/Xpressive/Ambition.xpf index dd64489779c..fa3bc736d16 100644 --- a/data/presets/Xpressive/Ambition.xpf +++ b/data/presets/Xpressive/Ambition.xpf @@ -10,7 +10,7 @@ - + diff --git a/data/presets/Xpressive/Creature.xpf b/data/presets/Xpressive/Creature.xpf index bee39f224fb..8ae8a2794ff 100644 --- a/data/presets/Xpressive/Creature.xpf +++ b/data/presets/Xpressive/Creature.xpf @@ -10,7 +10,7 @@ - + diff --git a/data/presets/Xpressive/Low Battery.xpf b/data/presets/Xpressive/Low Battery.xpf index 78f1fc78f72..009c036cd74 100644 --- a/data/presets/Xpressive/Low Battery.xpf +++ b/data/presets/Xpressive/Low Battery.xpf @@ -3,7 +3,7 @@ - + diff --git a/data/presets/Xpressive/Rubber Bass.xpf b/data/presets/Xpressive/Rubber Bass.xpf index 4b1409e224f..db4026c5ceb 100644 --- a/data/presets/Xpressive/Rubber Bass.xpf +++ b/data/presets/Xpressive/Rubber Bass.xpf @@ -10,7 +10,7 @@ - + diff --git a/data/presets/Xpressive/Untuned Bell.xpf b/data/presets/Xpressive/Untuned Bell.xpf index 5dd61ec18d1..53de2358bdb 100644 --- a/data/presets/Xpressive/Untuned Bell.xpf +++ b/data/presets/Xpressive/Untuned Bell.xpf @@ -10,7 +10,7 @@ - + @@ -19,4 +19,4 @@ - + \ No newline at end of file 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 9ea29b34d3f..d08ca6e04c1 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/themes/classic/clone_bb_track_pattern.png b/data/themes/classic/clone_bb_track_pattern.png new file mode 100644 index 00000000000..bf4b3669d81 Binary files /dev/null and b/data/themes/classic/clone_bb_track_pattern.png differ diff --git a/data/themes/classic/effect_plugin.png b/data/themes/classic/effect_plugin.png index 567bc31ae52..6a759672ff5 100644 Binary files a/data/themes/classic/effect_plugin.png and b/data/themes/classic/effect_plugin.png differ diff --git a/data/themes/classic/midi_cc_rack.png b/data/themes/classic/midi_cc_rack.png new file mode 100644 index 00000000000..1fe8bb9cb24 Binary files /dev/null and b/data/themes/classic/midi_cc_rack.png differ diff --git a/data/themes/classic/style.css b/data/themes/classic/style.css index 3fbb2e6fb7b..860aa0da1ea 100644 --- a/data/themes/classic/style.css +++ b/data/themes/classic/style.css @@ -11,6 +11,11 @@ QMdiArea { background-image: url(resources:background_artwork.png); } +Knob { + qproperty-lineInactiveColor: rgb(120, 120, 120); + qproperty-arcInactiveColor: rgba(120, 120, 120, 70); +} + AutomationEditor { background-color: rgb(0, 0, 0); color: #e0e0e0; @@ -34,7 +39,6 @@ QLineEdit { border-radius: 4px; border: 2px inset rgba(91,101,113,128); background: #49515b; - color: #e0e0e0; } @@ -49,6 +53,13 @@ QLineEdit:focus { border: 1px solid rgba(0,0,0, 128); } +/* Set color and selection background color for various inputs. + SpinBoxes are used in QInputDialogs */ + +QTextEdit, QLineEdit:focus, QComboBox:focus, QSpinBox:focus, QDoubleSpinBox:focus { + color: #e0e0e0; + selection-background-color: #202020; +} QToolTip { border-radius: 4px; @@ -118,6 +129,17 @@ QMenu::indicator:selected { background-color: #747474; } +FileBrowser QCheckBox +{ + font-size: 10px; + color: white; +} + +PositionLine { + qproperty-tailGradient: false; + qproperty-lineColor: rgb(255, 255, 255); +} + PianoRoll { background-color: rgb(0, 0, 0); qproperty-backgroundShade: rgba( 255, 255, 255, 10 ); @@ -133,6 +155,17 @@ PianoRoll { qproperty-ghostNoteBorders: true; qproperty-barColor: #4afd85; qproperty-markedSemitoneColor: rgba( 0, 255, 200, 60 ); + /* Piano keys */ + qproperty-whiteKeyWidth: 64; + qproperty-whiteKeyActiveTextColor: #000; + qproperty-whiteKeyActiveTextShadow: rgb( 240, 240, 240 ); + qproperty-whiteKeyActiveBackground: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #43e97b, stop:1 #3bcd6c); + qproperty-whiteKeyInactiveTextColor: rgb( 128, 128, 128); + qproperty-whiteKeyInactiveTextShadow: rgb( 240, 240, 240 ); + qproperty-whiteKeyInactiveBackground: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #eeeeee, stop:1 #ffffff); + qproperty-blackKeyWidth: 48; + qproperty-blackKeyActiveBackground: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #43e97b, stop:1 #3bcd6c); + qproperty-blackKeyInactiveBackground: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #333, stop:1 #000); /* Grid colors */ qproperty-lineColor: rgba( 128, 128, 128, 80 ); qproperty-beatLineColor: rgba( 128, 128, 128, 160 ); @@ -163,7 +196,6 @@ Oscilloscope { background: none; border: none; qproperty-normalColor: rgb(71, 253, 133); - qproperty-warningColor: rgb(255, 192, 64); qproperty-clippingColor: rgb(255, 64, 64); } @@ -622,6 +654,8 @@ TrackContentObjectView { qproperty-textBackgroundColor: rgba(0, 0, 0, 75); qproperty-textShadowColor: rgb( 0, 0, 0 ); qproperty-gradient: true; /* boolean property, set true to have a gradient */ + /* finger tip offset of cursor */ + qproperty-mouseHotspotHand: 3px 3px; font-size: 11px; } diff --git a/data/themes/default/clear_ghost_note.png b/data/themes/default/clear_ghost_note.png index c9f85a2b4ab..b9565269f1a 100644 Binary files a/data/themes/default/clear_ghost_note.png and b/data/themes/default/clear_ghost_note.png differ diff --git a/data/themes/default/clone_bb_track_pattern.png b/data/themes/default/clone_bb_track_pattern.png new file mode 100644 index 00000000000..ed7d40fa191 Binary files /dev/null and b/data/themes/default/clone_bb_track_pattern.png differ diff --git a/data/themes/default/effect_plugin.png b/data/themes/default/effect_plugin.png index b805415c314..4c312037984 100644 Binary files a/data/themes/default/effect_plugin.png and b/data/themes/default/effect_plugin.png differ diff --git a/data/themes/default/fullscreen.png b/data/themes/default/fullscreen.png new file mode 100755 index 00000000000..56f552e104a Binary files /dev/null and b/data/themes/default/fullscreen.png differ diff --git a/data/themes/default/ghost_note.png b/data/themes/default/ghost_note.png index 07344265978..9871fcf0a7e 100644 Binary files a/data/themes/default/ghost_note.png and b/data/themes/default/ghost_note.png differ diff --git a/data/themes/default/glue.png b/data/themes/default/glue.png new file mode 100644 index 00000000000..de611b4bc34 Binary files /dev/null and b/data/themes/default/glue.png differ diff --git a/data/themes/default/insert_bar.png b/data/themes/default/insert_bar.png new file mode 100644 index 00000000000..c7b7ddc7907 Binary files /dev/null and b/data/themes/default/insert_bar.png differ diff --git a/data/themes/default/loop_points_off.png b/data/themes/default/loop_points_off.png index 23ba7c6babb..a08b304dd87 100644 Binary files a/data/themes/default/loop_points_off.png and b/data/themes/default/loop_points_off.png differ diff --git a/data/themes/default/loop_points_on.png b/data/themes/default/loop_points_on.png index ee6cf0d20f0..908eccd9cb9 100644 Binary files a/data/themes/default/loop_points_on.png and b/data/themes/default/loop_points_on.png differ diff --git a/data/themes/default/midi_cc_rack.png b/data/themes/default/midi_cc_rack.png new file mode 100644 index 00000000000..1fe8bb9cb24 Binary files /dev/null and b/data/themes/default/midi_cc_rack.png differ diff --git a/data/themes/default/record_step_off.png b/data/themes/default/record_step_off.png index 8da17a91009..8f81605f40a 100644 Binary files a/data/themes/default/record_step_off.png and b/data/themes/default/record_step_off.png differ diff --git a/data/themes/default/record_step_on.png b/data/themes/default/record_step_on.png index 700ba97f305..051a2baf7f6 100644 Binary files a/data/themes/default/record_step_on.png and b/data/themes/default/record_step_on.png differ diff --git a/data/themes/default/remove_bar.png b/data/themes/default/remove_bar.png new file mode 100644 index 00000000000..46845e5991c Binary files /dev/null and b/data/themes/default/remove_bar.png differ diff --git a/data/themes/default/style.css b/data/themes/default/style.css index bedb8ea32ff..ce476f5a9ce 100644 --- a/data/themes/default/style.css +++ b/data/themes/default/style.css @@ -40,6 +40,17 @@ QMdiArea { background-color: #111314; } +FileBrowser QCheckBox +{ + font-size: 10px; + color: white; +} + +Knob { + qproperty-lineInactiveColor: rgb(120, 120, 120); + qproperty-arcInactiveColor: rgba(120, 120, 120, 70); +} + AutomationEditor { color: #ffffff; background-color: #141616; @@ -61,7 +72,6 @@ QLineEdit { border-radius: 4px; border: 1px; background: #101213; - color: #d1d8e4; } QLineEdit:read-only { @@ -75,6 +85,13 @@ QLineEdit:focus { border: 1px solid #0bd556; } +/* Set color and selection background color for various inputs. + SpinBoxes are used in QInputDialogs */ + +QTextEdit, QLineEdit:focus, QComboBox:focus, QSpinBox:focus, QDoubleSpinBox:focus { + color: #d1d8e4; + selection-background-color: #17793b; +} QToolTip { border-radius: 4px; @@ -150,6 +167,11 @@ QMenu::indicator:selected { background-color: #101213; } +PositionLine { + qproperty-tailGradient: true; + qproperty-lineColor: rgb(255, 255, 255); +} + PianoRoll { background-color: #141616; qproperty-backgroundShade: rgba(255, 255, 255, 10); @@ -165,6 +187,17 @@ PianoRoll { qproperty-ghostNoteBorders: false; qproperty-barColor: #078f3a; qproperty-markedSemitoneColor: rgba(255, 255, 255, 30); + /* Piano keys */ + qproperty-whiteKeyWidth: 64; + qproperty-whiteKeyActiveTextColor: #000; + qproperty-whiteKeyActiveTextShadow: #fff; + qproperty-whiteKeyActiveBackground: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #43e97b, stop:1 #3bcd6c); + qproperty-whiteKeyInactiveTextColor: #000; + qproperty-whiteKeyInactiveTextShadow: #fff; + qproperty-whiteKeyInactiveBackground: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #eeeeee, stop:1 #ffffff); + qproperty-blackKeyWidth: 48; + qproperty-blackKeyActiveBackground: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #43e97b, stop:1 #3bcd6c); + qproperty-blackKeyInactiveBackground: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #333, stop:1 #000); /* Grid colors */ qproperty-lineColor: #292929; qproperty-beatLineColor: #2d6b45; @@ -195,7 +228,6 @@ Oscilloscope { background: none; border: none; qproperty-normalColor: rgb(71, 253, 133); - qproperty-warningColor: rgb(255, 192, 64); qproperty-clippingColor: rgb(255, 64, 64); } @@ -271,6 +303,12 @@ QScrollBar::handle:horizontal:disabled, QScrollBar::handle:vertical:disabled { border: none; } +EffectRackView QScrollBar::handle:vertical:disabled { + background: #3f4750; + border: none; + border-radius: 4px; +} + /* arrow buttons */ QScrollBar::add-line, QScrollBar::sub-line { @@ -323,6 +361,8 @@ QScrollBar::left-arrow:horizontal:disabled { background-image: url(resources:sba QScrollBar::right-arrow:horizontal:disabled { background-image: url(resources:sbarrow_right_d.png);} QScrollBar::up-arrow:vertical:disabled { background-image: url(resources:sbarrow_up_d.png);} QScrollBar::down-arrow:vertical:disabled { background-image: url(resources:sbarrow_down_d.png);} +EffectRackView QScrollBar::up-arrow:vertical:disabled { background-image: url(resources:sbarrow_up.png);} +EffectRackView QScrollBar::down-arrow:vertical:disabled { background-image: url(resources:sbarrow_down.png);} /* background for song editor and bb-editor */ @@ -660,6 +700,8 @@ TrackContentObjectView { qproperty-textBackgroundColor: rgba(0, 0, 0, 75); qproperty-textShadowColor: rgba(0,0,0,200); qproperty-gradient: false; /* boolean property, set true to have a gradient */ + /* finger tip offset of cursor */ + qproperty-mouseHotspotHand: 7px 2px; font-size: 11px; } diff --git a/data/themes/default/tool.png b/data/themes/default/tool.png new file mode 100644 index 00000000000..6d818a53efc Binary files /dev/null and b/data/themes/default/tool.png differ diff --git a/data/themes/default/trackop.png b/data/themes/default/trackop.png index b26dd6ef26a..dd200d095f2 100644 Binary files a/data/themes/default/trackop.png and b/data/themes/default/trackop.png differ diff --git a/doc/CONTRIBUTORS b/doc/CONTRIBUTORS index 4a791028fe3..eb030ad7106 100644 --- a/doc/CONTRIBUTORS +++ b/doc/CONTRIBUTORS @@ -9,24 +9,26 @@ Colin Wallace Oskar Wallgren Raine M. Ekman Umcaruje -Michael Gregorius +Hyunjin Song Javier Serrano Polo +Michael Gregorius grejppi Javier Serrano Polo -Hyunjin Song Wong Cho Ching Alexandre Almeida Daniel Winzen LMMS Service Account Steffen Baranowsky Danny McRae +Johannes Lorenz Garrett -Hyunin Song liushuyu +Dominic Clark +Hyunin Song Andrew Kelley +Spekular Andreas Brandmaier Fastigium -Spekular Amadeus Folego Jonas Trappenberg M374LX @@ -35,18 +37,17 @@ grindhold Mike Choi Karmo Rosental Christopher L. Simons -Dominic Clark NoiseByNorthwest -falkTX -Johannes Lorenz Rebecca DeField +falkTX Stian Jørgensrud +David Carlier Ryan Roden-Corrent +Shmuel H midi-pascal Augustin Cavalier BaraMGB Csaba Hruska -David Carlier DeRobyJ Hussam Eddin Alhomsi Rüdiger Ranft @@ -66,11 +67,15 @@ Jonathan Aquilina Mohammad Amin Sameti ra wongcc966422 +Cyp David CARLIER +Douglas <34612565+DouglasDGI@users.noreply.github.com> Gurjot Singh Janne Sinisalo Krzysztof Foltman Lou Herard +Noah Brecht +Olivier Humbert Paul Batchelor Paul Wayper Petter Reinholdtsen @@ -86,9 +91,8 @@ Cyrille Bollu Dan Williams Ian Sannar Jaroslav Petrnoušek -Johannes Lorenz <1042576+JohannesLorenz@users.noreply.github.com> -Johannes Lorenz Kenneth Perry (thothonegan) +Kevin Zander LYF610400210 Lukas W Mark-Agent003 @@ -101,29 +105,37 @@ Rebecca LaVie Roberto Giaconia SecondFlight Steffen Baranowsky +T0NIT0 RMX TheTravelingSpaceman Thomas Clark gnudles liushuyu +makepost miketurn psyomn quadro sarahkeefe +thmueller64 <64359888+thmueller64@users.noreply.github.com> Achim Settelmeier +Alexandra Dutton +Andreas Müller André Hentschel Armin Kazmi +Artur Twardowski <32247490+artur-twardowski@users.noreply.github.com> Attila Herman Bastian Kummer Christopher A. Oliver +Cyp <48363+Cyp@users.noreply.github.com> Devin Venable Diego Ramos Ruggeri -Douglas <34612565+DouglasDGI@users.noreply.github.com> DragonEagle Filip Hron Frank Mather Frederik +Gingka Akiyama <33764485+GingkathFox@users.noreply.github.com> Greg Simpson Hexasoft +Hubert Figuière IvanMaldonado Ivo Wetzel Jens Lang @@ -138,17 +150,17 @@ Lee Avital LocoMatt Léo Andrès Markus Elfring +Martin Pavelek Maurizio Lo Bosco Mehdi Mikobuntu Mingcong Bai Nikos Chantziaras -Noah Brecht Ododo -Olivier Humbert Paul Nasca Peter Nelson Ra +Ron U Ryan Schmidt Shane Ambler Simon Jackson (Netbook) @@ -170,13 +182,15 @@ follower fundamental gandalf3 groboclown +https://gitlab.com/users/CYBERDEViLNL <1148379+CYBERDEViLNL@users.noreply.github.com> irrenhaus3 jasp00 justnope kamnxt +knittl lmmsservice m-xbutterfly -noahb01 +necrashter projectpitchin rgwan xhe diff --git a/doc/bash-completion/lmms b/doc/bash-completion/lmms index ccff8f249d9..b582612bddc 100644 --- a/doc/bash-completion/lmms +++ b/doc/bash-completion/lmms @@ -89,7 +89,7 @@ _lmms() pars_render=(--float --bitrate --format --interpolation) pars_render+=(--loop --mode --output --profile) pars_render+=(--samplerate --oversampling) - actions=(dump render rendertracks upgrade) + actions=(dump compress render rendertracks upgrade) actions_old=(-d --dump -r --render --rendertracks -u --upgrade) shortargs+=(-a -b -c -f -h -i -l -m -o -p -s -v -x) diff --git a/include/AudioAlsa.h b/include/AudioAlsa.h index b1aa9647a61..4bfd0217e31 100644 --- a/include/AudioAlsa.h +++ b/include/AudioAlsa.h @@ -71,7 +71,7 @@ class AudioAlsa : public QThread, public AudioDevice inline static QString name() { - return QT_TRANSLATE_NOOP( "setupWidget", + return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "ALSA (Advanced Linux Sound Architecture)" ); } diff --git a/include/AudioDevice.h b/include/AudioDevice.h index 35f5ec6207f..c9ad7f4b3cd 100644 --- a/include/AudioDevice.h +++ b/include/AudioDevice.h @@ -115,7 +115,7 @@ class AudioDevice const fpp_t _frames ); // resample given buffer from samplerate _src_sr to samplerate _dst_sr - void resample( const surroundSampleFrame * _src, + fpp_t resample( const surroundSampleFrame * _src, const fpp_t _frames, surroundSampleFrame * _dst, const sample_rate_t _src_sr, diff --git a/include/AudioDummy.h b/include/AudioDummy.h index 0772c69eb36..cf77491bc3f 100644 --- a/include/AudioDummy.h +++ b/include/AudioDummy.h @@ -48,7 +48,7 @@ class AudioDummy : public QThread, public AudioDevice inline static QString name() { - return QT_TRANSLATE_NOOP( "setupWidget", "Dummy (no sound output)" ); + return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "Dummy (no sound output)" ); } diff --git a/include/AudioJack.h b/include/AudioJack.h index c3207c82984..844aa886d87 100644 --- a/include/AudioJack.h +++ b/include/AudioJack.h @@ -34,6 +34,7 @@ #include "weak_libjack.h" #endif +#include #include #include #include @@ -57,11 +58,12 @@ class AudioJack : public QObject, public AudioDevice // the jack callback is handled here, we call the midi client so that it can read // it's midi data during the callback AudioJack * addMidiClient(MidiJack *midiClient); + void removeMidiClient(void) { m_midiClient = nullptr; } jack_client_t * jackClient() {return m_client;}; inline static QString name() { - return QT_TRANSLATE_NOOP( "setupWidget", + return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "JACK (JACK Audio Connection Kit)" ); } @@ -106,9 +108,9 @@ private slots: jack_client_t * m_client; bool m_active; - bool m_stopped; + std::atomic m_stopped; - MidiJack *m_midiClient; + std::atomic m_midiClient; QVector m_outputPorts; jack_default_audio_sample_t * * m_tempOutBufs; surroundSampleFrame * m_outBuf; diff --git a/include/AudioOss.h b/include/AudioOss.h index 9e4787ff202..c631bcedddc 100644 --- a/include/AudioOss.h +++ b/include/AudioOss.h @@ -48,7 +48,7 @@ class AudioOss : public QThread, public AudioDevice inline static QString name() { - return QT_TRANSLATE_NOOP( "setupWidget", "OSS (Open Sound System)" ); + return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "OSS (Open Sound System)" ); } static QString probeDevice(); diff --git a/include/AudioPortAudio.h b/include/AudioPortAudio.h index e1288c3a45d..5279492cee7 100644 --- a/include/AudioPortAudio.h +++ b/include/AudioPortAudio.h @@ -72,7 +72,7 @@ class AudioPortAudio : public AudioDevice inline static QString name() { - return QT_TRANSLATE_NOOP( "setupWidget", "PortAudio" ); + return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "PortAudio" ); } diff --git a/include/AudioPulseAudio.h b/include/AudioPulseAudio.h index e65180a74a3..b92a386b99f 100644 --- a/include/AudioPulseAudio.h +++ b/include/AudioPulseAudio.h @@ -50,7 +50,7 @@ class AudioPulseAudio : public QThread, public AudioDevice inline static QString name() { - return QT_TRANSLATE_NOOP( "setupWidget", "PulseAudio" ); + return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "PulseAudio" ); } static QString probeDevice(); diff --git a/include/AudioSdl.h b/include/AudioSdl.h index 93f23abed22..1bda446b290 100644 --- a/include/AudioSdl.h +++ b/include/AudioSdl.h @@ -51,7 +51,7 @@ class AudioSdl : public AudioDevice inline static QString name() { - return QT_TRANSLATE_NOOP( "setupWidget", + return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "SDL (Simple DirectMedia Layer)" ); } diff --git a/include/AudioSndio.h b/include/AudioSndio.h index f8cf56848a6..0cc88facfa4 100644 --- a/include/AudioSndio.h +++ b/include/AudioSndio.h @@ -49,7 +49,7 @@ class AudioSndio : public QThread, public AudioDevice inline static QString name( void ) { - return QT_TRANSLATE_NOOP( "setupWidget", "sndio" ); + return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "sndio" ); } class setupWidget : public AudioDeviceSetupWidget diff --git a/include/AudioSoundIo.h b/include/AudioSoundIo.h index f743ad67629..6a740a02400 100644 --- a/include/AudioSoundIo.h +++ b/include/AudioSoundIo.h @@ -61,7 +61,7 @@ class AudioSoundIo : public AudioDevice inline static QString name() { - return QT_TRANSLATE_NOOP( "setupWidget", "soundio" ); + return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "soundio" ); } class setupWidget : public AudioDeviceSetupWidget @@ -110,6 +110,7 @@ class AudioSoundIo : public AudioDevice fpp_t m_outBufFrameIndex; bool m_stopped; + bool m_outstreamStarted; int m_disconnectErr; void onBackendDisconnect(int err); diff --git a/include/AutomatableModel.h b/include/AutomatableModel.h index a86430938e3..0289a8d2d56 100644 --- a/include/AutomatableModel.h +++ b/include/AutomatableModel.h @@ -30,7 +30,7 @@ #include "JournallingObject.h" #include "Model.h" -#include "MidiTime.h" +#include "TimePos.h" #include "ValueBuffer.h" #include "Memory.h" #include "ModelVisitor.h" @@ -148,7 +148,7 @@ class LMMS_EXPORT AutomatableModel : public Model, public JournallingObject template inline T value( int frameOffset = 0 ) const { - if( unlikely( hasLinkedModels() || m_controllerConnection != NULL ) ) + if( hasLinkedModels() || m_controllerConnection != NULL ) { return castValue( controllerValue( frameOffset ) ); } @@ -281,7 +281,7 @@ class LMMS_EXPORT AutomatableModel : public Model, public JournallingObject return false; } - float globalAutomationValueAt( const MidiTime& time ); + float globalAutomationValueAt( const TimePos& time ); void setStrictStepSize( const bool b ) { diff --git a/include/AutomatableModelView.h b/include/AutomatableModelView.h index 1bcbd97d6fe..a5996118595 100644 --- a/include/AutomatableModelView.h +++ b/include/AutomatableModelView.h @@ -50,6 +50,7 @@ class LMMS_EXPORT AutomatableModelView : public ModelView } void setModel( Model* model, bool isOldModelValid = true ) override; + void unsetModel() override; template inline T value() const @@ -69,12 +70,16 @@ class LMMS_EXPORT AutomatableModelView : public ModelView void addDefaultActions( QMenu* menu ); + void setConversionFactor( float factor ); + float getConversionFactor(); + protected: virtual void mousePressEvent( QMouseEvent* event ); QString m_description; QString m_unit; + float m_conversionFactor; // Factor to be applied when the m_model->value is displayed } ; diff --git a/include/AutomationEditor.h b/include/AutomationEditor.h index 520416be80d..a4e9d528634 100644 --- a/include/AutomationEditor.h +++ b/include/AutomationEditor.h @@ -34,7 +34,7 @@ #include "lmms_basics.h" #include "JournallingObject.h" -#include "MidiTime.h" +#include "TimePos.h" #include "AutomationPattern.h" #include "ComboBoxModel.h" #include "Knob.h" @@ -70,7 +70,7 @@ class AutomationEditor : public QWidget, public JournallingObject inline bool validPattern() const { - return m_pattern != nullptr; + return m_pattern != nullptr && m_pattern->hasAutomation(); } void saveSettings(QDomDocument & doc, QDomElement & parent) override; @@ -153,7 +153,7 @@ protected slots: void pasteValues(); void deleteSelectedValues(); - void updatePosition( const MidiTime & t ); + void updatePosition( const TimePos & t ); void zoomingXChanged(); void zoomingYChanged(); @@ -209,12 +209,13 @@ protected slots: float m_bottomLevel; float m_topLevel; + void centerTopBottomScroll(); void updateTopBottomLevels(); QScrollBar * m_leftRightScroll; QScrollBar * m_topBottomScroll; - MidiTime m_currentPosition; + TimePos m_currentPosition; Actions m_action; @@ -264,7 +265,7 @@ protected slots: signals: void currentPatternChanged(); - void positionChanged( const MidiTime & ); + void positionChanged( const TimePos & ); } ; diff --git a/include/AutomationPattern.h b/include/AutomationPattern.h index cad9d0a1d00..aff1f26bf86 100644 --- a/include/AutomationPattern.h +++ b/include/AutomationPattern.h @@ -30,11 +30,11 @@ #include #include -#include "Track.h" +#include "TrackContentObject.h" class AutomationTrack; -class MidiTime; +class TimePos; @@ -74,19 +74,19 @@ class LMMS_EXPORT AutomationPattern : public TrackContentObject } void setTension( QString _new_tension ); - MidiTime timeMapLength() const; + TimePos timeMapLength() const; void updateLength(); - MidiTime putValue( const MidiTime & time, + TimePos putValue( const TimePos & time, const float value, const bool quantPos = true, const bool ignoreSurroundingPoints = true ); - void removeValue( const MidiTime & time ); + void removeValue( const TimePos & time ); - void recordValue(MidiTime time, float value); + void recordValue(TimePos time, float value); - MidiTime setDragValue( const MidiTime & time, + TimePos setDragValue( const TimePos & time, const float value, const bool quantPos = true, const bool controlKey = false ); @@ -134,8 +134,8 @@ class LMMS_EXPORT AutomationPattern : public TrackContentObject return m_timeMap.isEmpty() == false; } - float valueAt( const MidiTime & _time ) const; - float *valuesAfter( const MidiTime & _time ) const; + float valueAt( const TimePos & _time ) const; + float *valuesAfter( const TimePos & _time ) const; const QString name() const; diff --git a/include/AutomationPatternView.h b/include/AutomationPatternView.h index 3f019483a10..5e7b12977af 100644 --- a/include/AutomationPatternView.h +++ b/include/AutomationPatternView.h @@ -27,9 +27,10 @@ #include -#include "Track.h" - -class AutomationPattern; +#include "AutomationPattern.h" +#include "Song.h" +#include "SongEditor.h" +#include "TrackContentObjectView.h" class AutomationPatternView : public TrackContentObjectView diff --git a/include/AutomationTrack.h b/include/AutomationTrack.h index cdf1086678e..28be7a62365 100644 --- a/include/AutomationTrack.h +++ b/include/AutomationTrack.h @@ -28,6 +28,7 @@ #define AUTOMATION_TRACK_H #include "Track.h" +#include "TrackView.h" class LMMS_EXPORT AutomationTrack : public Track @@ -37,7 +38,7 @@ class LMMS_EXPORT AutomationTrack : public Track AutomationTrack( TrackContainer* tc, bool _hidden = false ); virtual ~AutomationTrack() = default; - virtual bool play( const MidiTime & _start, const fpp_t _frames, + virtual bool play( const TimePos & _start, const fpp_t _frames, const f_cnt_t _frame_base, int _tco_num = -1 ) override; QString nodeName() const override @@ -46,7 +47,7 @@ class LMMS_EXPORT AutomationTrack : public Track } TrackView * createView( TrackContainerView* ) override; - TrackContentObject * createTCO( const MidiTime & _pos ) override; + TrackContentObject* createTCO(const TimePos & pos) override; virtual void saveTrackSpecificSettings( QDomDocument & _doc, QDomElement & _parent ) override; diff --git a/include/BBEditor.h b/include/BBEditor.h index ed54beaf16d..d02dc198b64 100644 --- a/include/BBEditor.h +++ b/include/BBEditor.h @@ -26,6 +26,7 @@ #ifndef BB_EDITOR_H #define BB_EDITOR_H + #include "Editor.h" #include "TrackContainerView.h" @@ -86,6 +87,7 @@ public slots: void removeSteps(); void addSampleTrack(); void addAutomationTrack(); + void clonePattern(); protected slots: void dropEvent(QDropEvent * de ) override; diff --git a/include/BBTrack.h b/include/BBTrack.h index 02d9d669283..f6567715ff0 100644 --- a/include/BBTrack.h +++ b/include/BBTrack.h @@ -32,7 +32,9 @@ #include #include "lmms_export.h" +#include "TrackContentObjectView.h" #include "Track.h" +#include "TrackView.h" class TrackLabelButton; class TrackContainer; @@ -51,33 +53,11 @@ class LMMS_EXPORT BBTCO : public TrackContentObject return( "bbtco" ); } - unsigned int color() const - { - return( m_color.rgb() ); - } - - QColor colorObj() const - { - return m_color; - } - - void setColor( const QColor & c ) - { - m_color = QColor( c ); - } - - void setUseStyleColor( bool b ) - { - m_useStyleColor = b; - } - int bbTrackIndex(); TrackContentObjectView * createView( TrackView * _tv ) override; private: - QColor m_color; - bool m_useStyleColor; friend class BBTCOView; @@ -93,11 +73,6 @@ class BBTCOView : public TrackContentObjectView BBTCOView( TrackContentObject * _tco, TrackView * _tv ); virtual ~BBTCOView() = default; - QColor color() const - { - return( m_bbTCO->m_color ); - } - void setColor( QColor _new_color ); public slots: void update() override; @@ -106,8 +81,6 @@ protected slots: void openInBBEditor(); void resetName(); void changeName(); - void changeColor(); - void resetColor(); protected: @@ -133,10 +106,10 @@ class LMMS_EXPORT BBTrack : public Track BBTrack( TrackContainer* tc ); virtual ~BBTrack(); - virtual bool play( const MidiTime & _start, const fpp_t _frames, + virtual bool play( const TimePos & _start, const fpp_t _frames, const f_cnt_t _frame_base, int _tco_num = -1 ) override; TrackView * createView( TrackContainerView* tcv ) override; - TrackContentObject * createTCO( const MidiTime & _pos ) override; + TrackContentObject* createTCO(const TimePos & pos) override; virtual void saveTrackSpecificSettings( QDomDocument & _doc, QDomElement & _parent ) override; @@ -163,27 +136,6 @@ class LMMS_EXPORT BBTrack : public Track m_disabledTracks.removeAll( _track ); } - static void setLastTCOColor( const QColor & c ) - { - if( ! s_lastTCOColor ) - { - s_lastTCOColor = new QColor( c ); - } - else - { - *s_lastTCOColor = QColor( c ); - } - } - - static void clearLastTCOColor() - { - if( s_lastTCOColor ) - { - delete s_lastTCOColor; - } - s_lastTCOColor = NULL; - } - protected: inline QString nodeName() const override { @@ -197,8 +149,6 @@ class LMMS_EXPORT BBTrack : public Track typedef QMap infoMap; static infoMap s_infoMap; - static QColor * s_lastTCOColor; - friend class BBTrackView; } ; diff --git a/include/BBTrackContainer.h b/include/BBTrackContainer.h index 17d6eb5fed1..79bf2e31565 100644 --- a/include/BBTrackContainer.h +++ b/include/BBTrackContainer.h @@ -38,8 +38,7 @@ class LMMS_EXPORT BBTrackContainer : public TrackContainer BBTrackContainer(); virtual ~BBTrackContainer(); - virtual bool play( MidiTime _start, const fpp_t _frames, - const f_cnt_t _frame_base, int _tco_num = -1 ); + virtual bool play(TimePos start, const fpp_t frames, const f_cnt_t frameBase, int tcoNum = -1); void updateAfterTrackAdd() override; @@ -48,21 +47,21 @@ class LMMS_EXPORT BBTrackContainer : public TrackContainer return "bbtrackcontainer"; } - bar_t lengthOfBB( int _bb ) const; + bar_t lengthOfBB(int bb) const; inline bar_t lengthOfCurrentBB() { - return lengthOfBB( currentBB() ); + return lengthOfBB(currentBB()); } int numOfBBs() const; - void removeBB( int _bb ); + void removeBB(int bb); - void swapBB( int _bb1, int _bb2 ); + void swapBB(int bb1, int bb2); - void updateBBTrack( TrackContentObject * _tco ); + void updateBBTrack(TrackContentObject * tco); void fixIncorrectPositions(); - void createTCOsForBB( int _bb ); + void createTCOsForBB(int bb); - AutomatedValueMap automatedValuesAt(MidiTime time, int tcoNum) const override; + AutomatedValueMap automatedValuesAt(TimePos time, int tcoNum) const override; public slots: void play(); diff --git a/include/Clipboard.h b/include/Clipboard.h index fa4d5c5404e..a2dced9a6b7 100644 --- a/include/Clipboard.h +++ b/include/Clipboard.h @@ -29,25 +29,40 @@ #include -class JournallingObject; - -class Clipboard +namespace Clipboard { -public: - typedef QMap Map; - - static void copy( JournallingObject * _object ); - static const QDomElement * getContent( const QString & _node_name ); - - static const char * mimeType() + enum class MimeType { - return( "application/x-lmms-clipboard" ); - } + StringPair, + Default + }; + // Convenience Methods + const QMimeData * getMimeData(); + bool hasFormat( MimeType mT ); -private: - static Map content; + // Helper methods for String data + void copyString( const QString & str, MimeType mT ); + QString getString( MimeType mT ); + // Helper methods for String Pair data + void copyStringPair( const QString & key, const QString & value ); + QString decodeKey( const QMimeData * mimeData ); + QString decodeValue( const QMimeData * mimeData ); + + inline const char * mimeType( MimeType type ) + { + switch( type ) + { + case MimeType::StringPair: + return "application/x-lmms-stringpair"; + break; + case MimeType::Default: + default: + return "application/x-lmms-clipboard"; + break; + } + } } ; #endif diff --git a/include/ColorChooser.h b/include/ColorChooser.h index fe5b7a22a4e..ac2a1b62d4a 100644 --- a/include/ColorChooser.h +++ b/include/ColorChooser.h @@ -21,21 +21,39 @@ * */ -#include #include +#include +#include #include +#include class ColorChooser: public QColorDialog { public: ColorChooser(const QColor &initial, QWidget *parent): QColorDialog(initial, parent) {}; ColorChooser(QWidget *parent): QColorDialog(parent) {}; + //! For getting a color without having to initialise a color dialog + ColorChooser() {}; + enum class Palette {Default, Track, Mixer}; + //! Set global palette via array, checking bounds + void setPalette (QVector); + //! Set global paletter via enum + void setPalette (Palette); + //! Set palette via enum, return self pointer for chaining + ColorChooser* withPalette (Palette); + //! Return a certain palette + static QVector getPalette (Palette); protected: - // Forward key events to the parent to prevent stuck notes when the dialog gets focus + //! Forward key events to the parent to prevent stuck notes when the dialog gets focus void keyReleaseEvent(QKeyEvent *event) override { QKeyEvent ke(*event); QApplication::sendEvent(parentWidget(), &ke); } +private: + //! Copy the current QColorDialog palette into an array + static QVector defaultPalette(); + //! Generate a nice palette, with adjustable value + static QVector nicePalette (int); }; diff --git a/include/ComboBox.h b/include/ComboBox.h index d530c9d92f7..1ab1c240d80 100644 --- a/include/ComboBox.h +++ b/include/ComboBox.h @@ -32,8 +32,6 @@ #include "ComboBoxModel.h" #include "AutomatableModelView.h" - - class LMMS_EXPORT ComboBox : public QWidget, public IntModelView { Q_OBJECT @@ -51,6 +49,8 @@ class LMMS_EXPORT ComboBox : public QWidget, public IntModelView return castModel(); } + static constexpr int DEFAULT_HEIGHT = 22; + public slots: void selectNext(); void selectPrevious(); diff --git a/include/ConfigManager.h b/include/ConfigManager.h index 556c455a0c7..e5df02ff5e9 100644 --- a/include/ConfigManager.h +++ b/include/ConfigManager.h @@ -39,7 +39,6 @@ class LmmsCore; - const QString PROJECTS_PATH = "projects/"; const QString TEMPLATE_PATH = "templates/"; const QString PRESETS_PATH = "presets/"; @@ -50,11 +49,14 @@ const QString LADSPA_PATH ="plugins/ladspa/"; const QString DEFAULT_THEME_PATH = "themes/default/"; const QString TRACK_ICON_PATH = "track_icons/"; const QString LOCALE_PATH = "locale/"; - +const QString PORTABLE_MODE_FILE = "/portable_mode.txt"; class LMMS_EXPORT ConfigManager : public QObject { Q_OBJECT + + using UpgradeMethod = void(ConfigManager::*)(); + public: static inline ConfigManager * inst() { @@ -71,6 +73,12 @@ class LMMS_EXPORT ConfigManager : public QObject return m_workingDir; } + void initPortableWorkingDir(); + + void initInstalledWorkingDir(); + + void initDevelopmentWorkingDir(); + const QString & dataDir() const { return m_dataDir; @@ -213,10 +221,14 @@ class LMMS_EXPORT ConfigManager : public QObject return m_version; } + // Used when the configversion attribute is not present in a configuration file. + // Returns the appropriate config file version based on the LMMS version. + unsigned int legacyConfigVersion(); + QString defaultVersion() const; - static QStringList availabeVstEmbedMethods(); + static QStringList availableVstEmbedMethods(); QString vstEmbedMethod() const; // Returns true if the working dir (e.g. ~/lmms) exists on disk. @@ -264,6 +276,9 @@ class LMMS_EXPORT ConfigManager : public QObject void upgrade_1_1_91(); void upgrade(); + // List of all upgrade methods + static const std::vector UPGRADE_METHODS; + QString m_workingDir; QString m_dataDir; QString m_vstDir; @@ -280,6 +295,7 @@ class LMMS_EXPORT ConfigManager : public QObject QString m_backgroundPicFile; QString m_lmmsRcFile; QString m_version; + unsigned int m_configVersion; QStringList m_recentlyOpenedProjects; typedef QVector > stringPairVector; diff --git a/include/ControlLayout.h b/include/ControlLayout.h index 625b3f4681d..60182010792 100644 --- a/include/ControlLayout.h +++ b/include/ControlLayout.h @@ -110,6 +110,9 @@ class ControlLayout : public QLayout void setGeometry(const QRect &rect) override; QSize sizeHint() const override; QLayoutItem *takeAt(int index) override; + //! remove focus from QLineEdit search bar + //! this may be useful if the mouse is outside the layout + void removeFocusFromSearchBar(); private slots: void onTextChanged(const QString&); diff --git a/include/CustomTextKnob.h b/include/CustomTextKnob.h new file mode 100644 index 00000000000..baaf8820599 --- /dev/null +++ b/include/CustomTextKnob.h @@ -0,0 +1,30 @@ +/* Text customizable knob */ +#ifndef CUSTOM_TEXT_KNOB_H +#define CUSTOM_TEXT_KNOB_H + +#include "Knob.h" + +class LMMS_EXPORT CustomTextKnob : public Knob +{ +protected: + inline void setHintText( const QString & _txt_before, const QString & _txt_after ) {} // inaccessible +public: + CustomTextKnob( knobTypes _knob_num, QWidget * _parent = NULL, const QString & _name = QString(), const QString & _value_text = QString() ); + + CustomTextKnob( QWidget * _parent = NULL, const QString & _name = QString(), const QString & _value_text = QString() ); //!< default ctor + + CustomTextKnob( const Knob& other ) = delete; + + inline void setValueText(const QString & _value_text) + { + m_value_text = _value_text; + } + +private: + virtual QString displayValue() const; + +protected: + QString m_value_text; +} ; + +#endif diff --git a/include/DataFile.h b/include/DataFile.h index 59e50b028b2..ed947eef2be 100644 --- a/include/DataFile.h +++ b/include/DataFile.h @@ -31,12 +31,16 @@ #include "lmms_export.h" #include "Memory.h" +#include "ProjectVersion.h" class QTextStream; class LMMS_EXPORT DataFile : public QDomDocument { MM_OPERATORS + + using UpgradeMethod = void(DataFile::*)(); + public: enum Types { @@ -84,6 +88,8 @@ class LMMS_EXPORT DataFile : public QDomDocument return m_type; } + unsigned int legacyFileVersion(); + private: static Type type( const QString& typeName ); static QString typeName( Type type ); @@ -107,8 +113,13 @@ class LMMS_EXPORT DataFile : public QDomDocument void upgrade_1_1_0(); void upgrade_1_1_91(); void upgrade_1_2_0_rc3(); - void upgrade_1_2_0_rc2_42(); void upgrade_1_3_0(); + void upgrade_noHiddenClipNames(); + + // List of all upgrade methods + static const std::vector UPGRADE_METHODS; + // List of ProjectVersions for the legacyFileVersion method + static const std::vector UPGRADE_VERSIONS; void upgrade(); @@ -125,14 +136,9 @@ class LMMS_EXPORT DataFile : public QDomDocument QDomElement m_content; QDomElement m_head; Type m_type; + unsigned int m_fileVersion; } ; -const int LDF_MAJOR_VERSION = 1; -const int LDF_MINOR_VERSION = 0; -const QString LDF_VERSION_STRING = QString::number( LDF_MAJOR_VERSION ) + "." + QString::number( LDF_MINOR_VERSION ); - - #endif - diff --git a/include/DeprecationHelper.h b/include/DeprecationHelper.h new file mode 100644 index 00000000000..bef4ea9b954 --- /dev/null +++ b/include/DeprecationHelper.h @@ -0,0 +1,63 @@ +/* + * DeprecationHelper.h - This file contains the declarations of helper functions + * which helps centralize the #ifdefs preprocessors regarding deprecation based on Qt versions. + * The functions are defined differently based on the callers' Qt versions. + * + * Copyright (c) 2020 Tien Dat Nguyen + * + * 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 DEPRECATIONHELPER_H +#define DEPRECATIONHELPER_H + +#include +#include + +/** + * @brief horizontalAdvance is a backwards-compatible adapter for + * QFontMetrics::horizontalAdvance and width functions. + * @param metrics + * @param text + * @return text's horizontal advance based on metrics. + */ +inline int horizontalAdvance(const QFontMetrics& metrics, const QString& text) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)) + return metrics.horizontalAdvance(text); +#else + return metrics.width(text); +#endif +} + +/** + * @brief position is a backwards-compatible adapter for + * QWheelEvent::position and pos functions. + * @param wheelEvent + * @return the position of wheelEvent + */ +inline QPoint position(QWheelEvent *wheelEvent) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + return wheelEvent->position().toPoint(); +#else + return wheelEvent->pos(); +#endif +} +#endif // DEPRECATIONHELPER_H diff --git a/include/Editor.h b/include/Editor.h index 1c80e9f2f85..d755608a6c9 100644 --- a/include/Editor.h +++ b/include/Editor.h @@ -28,6 +28,12 @@ #include #include +static const int Quantizations[] = { + 1, 2, 4, 8, 16, 32, 64, + 3, 6, 12, 24, 48, 96, 192 +}; + + class QAction; class DropToolBar; @@ -58,6 +64,11 @@ protected slots: private slots: /// Called by pressing the space key. Plays or stops. void togglePlayStop(); + + /// Called by pressing shift+space. Toggles pause state. + void togglePause(); + + void toggleMaximize(); signals: diff --git a/include/EffectRackView.h b/include/EffectRackView.h index 698bad7fb25..d2a9dd52840 100644 --- a/include/EffectRackView.h +++ b/include/EffectRackView.h @@ -46,6 +46,7 @@ class EffectRackView : public QWidget, public ModelView EffectRackView( EffectChain* model, QWidget* parent = NULL ); virtual ~EffectRackView(); + static constexpr int DEFAULT_WIDTH = 245; public slots: void clearViews(); diff --git a/include/EffectView.h b/include/EffectView.h index 6e994dd7e5b..a2509dc5b1f 100644 --- a/include/EffectView.h +++ b/include/EffectView.h @@ -57,6 +57,7 @@ class EffectView : public PluginView return castModel(); } + static constexpr int DEFAULT_WIDTH = 215; public slots: void editControls(); diff --git a/include/Engine.h b/include/Engine.h index f4ff72fb2fb..4ec146b2bbd 100644 --- a/include/Engine.h +++ b/include/Engine.h @@ -30,11 +30,11 @@ #include +#include "lmmsconfig.h" #include "lmms_export.h" #include "lmms_basics.h" class BBTrackContainer; -class DummyTrackContainer; class FxMixer; class ProjectJournal; class Mixer; @@ -87,14 +87,18 @@ class LMMS_EXPORT LmmsCore : public QObject return s_projectJournal; } - static Ladspa2LMMS * getLADSPAManager() + static bool ignorePluginBlacklist(); + +#ifdef LMMS_HAVE_LV2 + static class Lv2Manager * getLv2Manager() { - return s_ladspaManager; + return s_lv2Manager; } +#endif - static DummyTrackContainer * dummyTrackContainer() + static Ladspa2LMMS * getLADSPAManager() { - return s_dummyTC; + return s_ladspaManager; } static float framesPerTick() @@ -141,8 +145,10 @@ class LMMS_EXPORT LmmsCore : public QObject static Song * s_song; static BBTrackContainer * s_bbTrackContainer; static ProjectJournal * s_projectJournal; - static DummyTrackContainer * s_dummyTC; +#ifdef LMMS_HAVE_LV2 + static class Lv2Manager* s_lv2Manager; +#endif static Ladspa2LMMS * s_ladspaManager; static void* s_dndPluginKey; diff --git a/include/FadeButton.h b/include/FadeButton.h index 54703d19476..dfffe93a284 100644 --- a/include/FadeButton.h +++ b/include/FadeButton.h @@ -26,9 +26,9 @@ #ifndef FADE_BUTTON_H #define FADE_BUTTON_H -#include #include #include +#include class FadeButton : public QAbstractButton @@ -55,8 +55,8 @@ public slots: private: - QTime m_stateTimer; - QTime m_releaseTimer; + QElapsedTimer m_stateTimer; + QElapsedTimer m_releaseTimer; // the default color of the widget QColor m_normalColor; @@ -66,7 +66,7 @@ public slots: QColor m_holdColor; int activeNotes; - QColor fadeToColor(QColor, QColor, QTime, float); + QColor fadeToColor(QColor, QColor, QElapsedTimer, float); } ; diff --git a/include/Fader.h b/include/Fader.h index 2072154459d..10f8c92ef05 100644 --- a/include/Fader.h +++ b/include/Fader.h @@ -48,9 +48,10 @@ #ifndef FADER_H #define FADER_H -#include -#include +#include #include +#include + #include "AutomatableModelView.h" @@ -98,7 +99,7 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView void setDisplayConversion( bool b ) { - m_displayConversion = b; + m_conversionFactor = b ? 100.0 : 1.0; } inline void setHintText( const QString & _txt_before, @@ -130,7 +131,7 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView return height() - ( ( height() - m_knob->height() ) * ( realVal / fRange ) ); } - void setPeak( float fPeak, float &targetPeak, float &persistentPeak, QTime &lastPeakTime ); + void setPeak( float fPeak, float &targetPeak, float &persistentPeak, QElapsedTimer &lastPeakTimer ); int calculateDisplayPeak( float fPeak ); void updateTextFloat(); @@ -144,8 +145,8 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView float m_fMinPeak; float m_fMaxPeak; - QTime m_lastPeakTime_L; - QTime m_lastPeakTime_R; + QElapsedTimer m_lastPeakTimer_L; + QElapsedTimer m_lastPeakTimer_R; static QPixmap * s_back; static QPixmap * s_leds; @@ -154,8 +155,7 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView QPixmap * m_back; QPixmap * m_leds; QPixmap * m_knob; - - bool m_displayConversion; + bool m_levelsDisplayedInDBFS; int m_moveStartPoint; diff --git a/include/FileBrowser.h b/include/FileBrowser.h index d36eacf0775..2e26199fcec 100644 --- a/include/FileBrowser.h +++ b/include/FileBrowser.h @@ -26,6 +26,7 @@ #ifndef FILE_BROWSER_H #define FILE_BROWSER_H +#include #include #include #include @@ -58,14 +59,17 @@ class FileBrowser : public SideBarWidget */ FileBrowser( const QString & directories, const QString & filter, const QString & title, const QPixmap & pm, - QWidget * parent, bool dirs_as_items = false, bool recurse = false ); + QWidget * parent, bool dirs_as_items = false, bool recurse = false, + const QString& userDir = "", + const QString& factoryDir = ""); + virtual ~FileBrowser() = default; private slots: void reloadTree( void ); - void expandItems( QTreeWidgetItem * item=NULL, QList expandedDirs = QList() ); + void expandItems( QTreeWidgetItem * item=nullptr, QList expandedDirs = QList() ); // call with item=NULL to filter the entire tree - bool filterItems( const QString & filter, QTreeWidgetItem * item=NULL ); + bool filterItems( const QString & filter, QTreeWidgetItem * item=nullptr ); void giveFocusToFilter(); private: @@ -83,6 +87,11 @@ private slots: bool m_dirsAsItems; bool m_recurse; + void addContentCheckBox(); + QCheckBox* m_showUserContent = nullptr; + QCheckBox* m_showFactoryContent = nullptr; + QString m_userDir; + QString m_factoryDir; } ; @@ -105,29 +114,39 @@ class FileBrowserTreeWidget : public QTreeWidget void mousePressEvent( QMouseEvent * me ) override; void mouseMoveEvent( QMouseEvent * me ) override; void mouseReleaseEvent( QMouseEvent * me ) override; + void keyPressEvent( QKeyEvent * ke ) override; + void keyReleaseEvent( QKeyEvent * ke ) override; + void hideEvent( QHideEvent * he ) override; + void focusOutEvent( QFocusEvent * fe ) override; private: + //! Start a preview of a file item + void previewFileItem(FileItem* file); + //! If a preview is playing, stop it. + void stopPreview(); + void handleFile( FileItem * fi, InstrumentTrack * it ); - void openInNewInstrumentTrack( TrackContainer* tc ); + void openInNewInstrumentTrack( TrackContainer* tc, FileItem* item ); bool m_mousePressed; QPoint m_pressPos; + //! This should only be accessed or modified when m_pphMutex is held PlayHandle* m_previewPlayHandle; QMutex m_pphMutex; - FileItem * m_contextMenuItem; + QList getContextActions(FileItem* item, bool songEditor); private slots: void activateListItem( QTreeWidgetItem * item, int column ); - void openInNewInstrumentTrackBBE( void ); - void openInNewInstrumentTrackSE( void ); - void sendToActiveInstrumentTrack( void ); + void openInNewInstrumentTrack( FileItem* item, bool songEditor ); + bool openInNewSampleTrack( FileItem* item ); + void sendToActiveInstrumentTrack( FileItem* item ); void updateDirectory( QTreeWidgetItem * item ); - void openContainingFolder(); + void openContainingFolder( FileItem* item ); } ; @@ -234,6 +253,11 @@ class FileItem : public QTreeWidgetItem return( m_handling ); } + inline bool isTrack( void ) const + { + return m_handling == LoadAsPreset || m_handling == LoadByPlugin; + } + QString extension( void ); static QString extension( const QString & file ); diff --git a/include/FileDialog.h b/include/FileDialog.h index c3db2393d45..6e29703b8a1 100644 --- a/include/FileDialog.h +++ b/include/FileDialog.h @@ -46,8 +46,7 @@ class LMMS_EXPORT FileDialog : public QFileDialog const QString &caption = QString(), const QString &directory = QString(), const QString &filter = QString(), - QString *selectedFilter = 0, - QFileDialog::Options options = 0); + QString *selectedFilter = 0); void clearSelection(); }; diff --git a/include/FxLine.h b/include/FxLine.h index c16dcd5f598..e9ee248b811 100644 --- a/include/FxLine.h +++ b/include/FxLine.h @@ -26,10 +26,12 @@ #ifndef FX_LINE_H #define FX_LINE_H +#include #include #include #include +#include "ColorChooser.h" #include "Knob.h" #include "LcdWidget.h" #include "SendButtonIndicator.h" @@ -101,6 +103,9 @@ class FxLine : public QWidget public slots: void renameChannel(); + void resetColor(); + void changeColor(); + void randomColor(); private slots: void renameFinished(); diff --git a/include/FxMixer.h b/include/FxMixer.h index 68b69d9bc88..e7af1d50e1c 100644 --- a/include/FxMixer.h +++ b/include/FxMixer.h @@ -32,6 +32,8 @@ #include +#include + class FxRoute; typedef QVector FxRouteVector; @@ -70,6 +72,17 @@ class FxChannel : public ThreadableJob bool requiresProcessing() const override { return true; } void unmuteForSolo(); + + void setColor (QColor newColor) + { + m_color = newColor; + m_hasColor = true; + } + + // TODO C++17 and above: use std::optional instead + QColor m_color; + bool m_hasColor; + std::atomic_int m_dependenciesMet; void incrementDeps(); diff --git a/include/GuiApplication.h b/include/GuiApplication.h index 8b4284c026b..825c258372e 100644 --- a/include/GuiApplication.h +++ b/include/GuiApplication.h @@ -28,6 +28,7 @@ #include #include "lmms_export.h" +#include "lmmsconfig.h" class QLabel; @@ -48,6 +49,9 @@ class LMMS_EXPORT GuiApplication : public QObject ~GuiApplication(); static GuiApplication* instance(); +#ifdef LMMS_BUILD_WIN32 + static QFont getWin32SystemFont(); +#endif MainWindow* mainWindow() { return m_mainWindow; } FxMixerView* fxMixerView() { return m_fxMixerView; } diff --git a/include/Instrument.h b/include/Instrument.h index 38c25fb0f77..90364e84b30 100644 --- a/include/Instrument.h +++ b/include/Instrument.h @@ -30,8 +30,8 @@ #include "lmms_export.h" #include "lmms_basics.h" #include "Memory.h" -#include "MidiTime.h" #include "Plugin.h" +#include "TimePos.h" // forward-declarations @@ -105,7 +105,7 @@ class LMMS_EXPORT Instrument : public Plugin // sub-classes can re-implement this for receiving all incoming // MIDI-events - inline virtual bool handleMidiEvent( const MidiEvent&, const MidiTime& = MidiTime(), f_cnt_t offset = 0 ) + inline virtual bool handleMidiEvent( const MidiEvent&, const TimePos& = TimePos(), f_cnt_t offset = 0 ) { return true; } @@ -132,6 +132,9 @@ class LMMS_EXPORT Instrument : public Plugin protected: + // fade in to prevent clicks + void applyFadeIn(sampleFrame * buf, NotePlayHandle * n); + // instruments may use this to apply a soft fade out at the end of // notes - method does this only if really less or equal // desiredReleaseFrames() frames are left diff --git a/include/InstrumentSoundShaping.h b/include/InstrumentSoundShaping.h index 1b8df38d3f1..b037f615a77 100644 --- a/include/InstrumentSoundShaping.h +++ b/include/InstrumentSoundShaping.h @@ -74,7 +74,7 @@ class InstrumentSoundShaping : public Model, public JournallingObject FloatModel m_filterCutModel; FloatModel m_filterResModel; - static const QString targetNames[InstrumentSoundShaping::NumTargets][3]; + static const char *const targetNames[InstrumentSoundShaping::NumTargets][3]; friend class InstrumentSoundShapingView; diff --git a/include/InstrumentTrack.h b/include/InstrumentTrack.h index b30d5cb21c9..ec278996fec 100644 --- a/include/InstrumentTrack.h +++ b/include/InstrumentTrack.h @@ -30,6 +30,8 @@ #include "GroupBox.h" #include "InstrumentFunctions.h" #include "InstrumentSoundShaping.h" +#include "Midi.h" +#include "MidiCCRackView.h" #include "MidiEventProcessor.h" #include "MidiPort.h" #include "NotePlayHandle.h" @@ -38,11 +40,11 @@ #include "Pitch.h" #include "Plugin.h" #include "Track.h" +#include "TrackView.h" class QLineEdit; -template class QQueue; class InstrumentFunctionArpeggioView; class InstrumentFunctionNoteStackingView; class EffectRackView; @@ -80,8 +82,8 @@ class LMMS_EXPORT InstrumentTrack : public Track, public MidiEventProcessor MidiEvent applyMasterKey( const MidiEvent& event ); - 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; + void processInEvent( const MidiEvent& event, const TimePos& time = TimePos(), f_cnt_t offset = 0 ) override; + void processOutEvent( const MidiEvent& event, const TimePos& time = TimePos(), f_cnt_t offset = 0 ) override; // silence all running notes played by this track void silenceAllNotes( bool removeIPH = false ); @@ -130,13 +132,13 @@ class LMMS_EXPORT InstrumentTrack : public Track, public MidiEventProcessor } // play everything in given frame-range - creates note-play-handles - virtual bool play( const MidiTime & _start, const fpp_t _frames, + virtual bool play( const TimePos & _start, const fpp_t _frames, const f_cnt_t _frame_base, int _tco_num = -1 ) override; // create new view for me TrackView * createView( TrackContainerView* tcv ) override; // create new track-content-object = pattern - TrackContentObject * createTCO( const MidiTime & _pos ) override; + TrackContentObject* createTCO(const TimePos & pos) override; // called by track @@ -219,6 +221,8 @@ class LMMS_EXPORT InstrumentTrack : public Track, public MidiEventProcessor return m_previewMode; } + void autoAssignMidiDevice( bool ); + signals: void instrumentChanged(); void midiNoteOn( const Note& ); @@ -227,7 +231,6 @@ class LMMS_EXPORT InstrumentTrack : public Track, public MidiEventProcessor void newNote(); void endNote(); - protected: QString nodeName() const override { @@ -246,6 +249,8 @@ protected slots: private: + void processCCEvent(int controller); + MidiPort m_midiPort; NotePlayHandle* m_notes[NumKeys]; @@ -260,6 +265,9 @@ protected slots: bool m_previewMode; + bool m_hasAutoMidiDev; + static InstrumentTrack *s_autoAssignedTrack; + IntModel m_baseNoteModel; NotePlayHandleList m_processHandles; @@ -282,11 +290,14 @@ protected slots: Piano m_piano; + std::unique_ptr m_midiCCEnable; + std::unique_ptr m_midiCCModel[MidiControllerCount]; friend class InstrumentTrackView; friend class InstrumentTrackWindow; friend class NotePlayHandle; friend class InstrumentMiscView; + friend class MidiCCRackView; } ; @@ -319,10 +330,6 @@ class InstrumentTrackView : public TrackView return m_midiMenu; } - void freeInstrumentTrackWindow(); - - static void cleanupWindowCache(); - // Create a menu for assigning/creating channels for this track QMenu * createFxMenu( QString title, QString newFxLabel ) override; @@ -334,6 +341,7 @@ class InstrumentTrackView : public TrackView private slots: void toggleInstrumentWindow( bool _on ); + void toggleMidiCCRack(); void activityIndicatorPressed(); void activityIndicatorReleased(); @@ -344,12 +352,12 @@ private slots: void assignFxLine( int channelIndex ); void createFxLine(); + void handleConfigChange(QString cls, QString attr, QString value); + private: InstrumentTrackWindow * m_window; - static QQueue s_windowCache; - // widgets in track-settings-widget TrackLabelButton * m_tlb; Knob * m_volumeKnob; @@ -361,9 +369,11 @@ private slots: QAction * m_midiInputAction; QAction * m_midiOutputAction; + std::unique_ptr m_midiCCRackView; + QPoint m_lastPos; - FadeButton * getActivityIndicator() + FadeButton * getActivityIndicator() override { return m_activityIndicator; } @@ -477,6 +487,7 @@ protected slots: PianoView * m_pianoView; friend class InstrumentView; + friend class InstrumentTrackView; } ; diff --git a/include/Knob.h b/include/Knob.h index 4f806473118..3c730e3dd60 100644 --- a/include/Knob.h +++ b/include/Knob.h @@ -26,6 +26,8 @@ #ifndef KNOB_H #define KNOB_H +#include +#include #include #include @@ -41,6 +43,7 @@ enum knobTypes } ; +void convertPixmapToGrayScale(QPixmap &pixMap); class LMMS_EXPORT Knob : public QWidget, public FloatModelView { @@ -58,8 +61,12 @@ class LMMS_EXPORT Knob : public QWidget, public FloatModelView // Unfortunately, the gradient syntax doesn't create our gradient // correctly so we need to do this: Q_PROPERTY(QColor outerColor READ outerColor WRITE setOuterColor) - Q_PROPERTY(QColor lineColor READ lineColor WRITE setlineColor) - Q_PROPERTY(QColor arcColor READ arcColor WRITE setarcColor) + + Q_PROPERTY(QColor lineActiveColor MEMBER m_lineActiveColor) + Q_PROPERTY(QColor lineInactiveColor MEMBER m_lineInactiveColor) + Q_PROPERTY(QColor arcActiveColor MEMBER m_arcActiveColor) + Q_PROPERTY(QColor arcInactiveColor MEMBER m_arcInactiveColor) + mapPropertyFromModel(bool,isVolumeKnob,setVolumeKnob,m_volumeKnob); mapPropertyFromModel(float,volumeRatio,setVolumeRatio,m_volumeRatio); @@ -74,7 +81,6 @@ class LMMS_EXPORT Knob : public QWidget, public FloatModelView Knob( knobTypes _knob_num, QWidget * _parent = NULL, const QString & _name = QString() ); Knob( QWidget * _parent = NULL, const QString & _name = QString() ); //!< default ctor Knob( const Knob& other ) = delete; - virtual ~Knob(); // TODO: remove inline void setHintText( const QString & _txt_before, @@ -108,10 +114,6 @@ class LMMS_EXPORT Knob : public QWidget, public FloatModelView QColor outerColor() const; void setOuterColor( const QColor & c ); - QColor lineColor() const; - void setlineColor( const QColor & c ); - QColor arcColor() const; - void setarcColor( const QColor & c ); QColor textColor() const; void setTextColor( const QColor & c ); @@ -134,6 +136,7 @@ class LMMS_EXPORT Knob : public QWidget, public FloatModelView void mouseDoubleClickEvent( QMouseEvent * _me ) override; void paintEvent( QPaintEvent * _me ) override; void wheelEvent( QWheelEvent * _me ) override; + void changeEvent(QEvent * ev) override; virtual float getValue( const QPoint & _p ); @@ -143,7 +146,7 @@ private slots: void toggleScale(); private: - QString displayValue() const; + virtual QString displayValue() const; void doConnections() override; @@ -169,12 +172,11 @@ private slots: QString m_label; - QPixmap * m_knobPixmap; + std::unique_ptr m_knobPixmap; BoolModel m_volumeKnob; FloatModel m_volumeRatio; - QPoint m_mouseOffset; - QPoint m_origMousePos; + QPoint m_lastMousePos; //!< mouse position in last mouseMoveEvent float m_leftOver; bool m_buttonPressed; @@ -188,8 +190,11 @@ private slots: float m_outerRadius; float m_lineWidth; QColor m_outerColor; - QColor m_lineColor; //!< unused yet - QColor m_arcColor; //!< unused yet + + QColor m_lineActiveColor; + QColor m_lineInactiveColor; + QColor m_arcActiveColor; + QColor m_arcInactiveColor; QColor m_textColor; diff --git a/include/LcdSpinBox.h b/include/LcdSpinBox.h index 379b743ace4..91ac8b4a78c 100644 --- a/include/LcdSpinBox.h +++ b/include/LcdSpinBox.h @@ -73,8 +73,9 @@ public slots: void mouseDoubleClickEvent( QMouseEvent * _me ) override; private: + float m_remainder; //!< floating offset of spinbox in [-0.5, 0.5] bool m_mouseMoving; - QPoint m_origMousePos; + QPoint m_lastMousePos; //!< mouse position in last mouseMoveEvent int m_displayOffset; void enterValue(); diff --git a/include/LinkedModelGroupViews.h b/include/LinkedModelGroupViews.h index 79fab76afd5..46ba4c3ab55 100644 --- a/include/LinkedModelGroupViews.h +++ b/include/LinkedModelGroupViews.h @@ -71,6 +71,8 @@ class LinkedModelGroupView : public QWidget void removeControl(const QString &key); + void removeFocusFromSearchBar(); + private: class LinkedModelGroup* m_model; @@ -96,7 +98,7 @@ class LinkedModelGroupsView void modelChanged(class LinkedModelGroups* ctrlBase); private: - //! The base class must return the adressed group view, + //! The base class must return the addressed group view, //! which has the same value as "this" virtual LinkedModelGroupView* getGroupView() = 0; }; diff --git a/include/LinkedModelGroups.h b/include/LinkedModelGroups.h index 355290d9aee..686f09cba36 100644 --- a/include/LinkedModelGroups.h +++ b/include/LinkedModelGroups.h @@ -42,7 +42,7 @@ /** Base class for a group of linked models - See the LinkedModelGroup class for explenations + See the LinkedModelGroup class for explanations Features: * Models are stored by their QObject::objectName diff --git a/include/LocklessRingBuffer.h b/include/LocklessRingBuffer.h index d313fd72288..617f7727a89 100644 --- a/include/LocklessRingBuffer.h +++ b/include/LocklessRingBuffer.h @@ -28,84 +28,36 @@ #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. +//! A convenience layer for a realtime-safe and thread-safe multi-reader ringbuffer template -class LocklessRingBufferBase +class LocklessRingBuffer { template friend class LocklessRingBufferReader; public: - LocklessRingBufferBase(std::size_t sz) : m_buffer(sz) + LocklessRingBuffer(std::size_t sz) : m_buffer(sz) { m_buffer.touch(); // reserve storage space before realtime operation starts } - ~LocklessRingBufferBase() {}; + ~LocklessRingBuffer() {}; 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); + std::size_t written = LocklessRingBuffer::m_buffer.write(src, cnt); // Let all waiting readers know new data are available. - if (notify) {LocklessRingBufferBase::m_notifier.wakeAll();} + if (notify) {LocklessRingBuffer::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; - } +protected: + ringbuffer_t m_buffer; + QWaitCondition m_notifier; }; diff --git a/include/Lv2Basics.h b/include/Lv2Basics.h new file mode 100644 index 00000000000..0003f83e814 --- /dev/null +++ b/include/Lv2Basics.h @@ -0,0 +1,67 @@ +/* + * Lv2Basics.h - basic Lv2 utils + * + * Copyright (c) 2018-2020 Johannes Lorenz + * + * 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 LV2BASICS_H +#define LV2BASICS_H + + +#include "lmmsconfig.h" + +#ifdef LMMS_HAVE_LV2 + +#include +#include +#include +#include + +struct LilvNodeDeleter +{ + void operator()(LilvNode* n) { lilv_node_free(n); } +}; + +struct LilvNodesDeleter +{ + void operator()(LilvNodes* n) { lilv_nodes_free(n); } +}; + +using AutoLilvNode = std::unique_ptr; +using AutoLilvNodes = std::unique_ptr; + +/** + Return QString from a plugin's node, everything will be freed automatically + @param plug The plugin where the node is + @param getFunc The function to return the node from the plugin +*/ +QString qStringFromPluginNode(const LilvPlugin* plug, + LilvNode * (*getFunc)(const LilvPlugin*)); + +//! Return port name as QString, everything will be freed automatically +QString qStringFromPortName(const LilvPlugin* plug, const LilvPort* port); + +//! Return port name as std::string, everything will be freed automatically +std::string stdStringFromPortName(const LilvPlugin* plug, const LilvPort* port); + +#endif // LMMS_HAVE_LV2 +#endif // LV2BASICS_H diff --git a/include/Lv2ControlBase.h b/include/Lv2ControlBase.h new file mode 100644 index 00000000000..de90960dcd7 --- /dev/null +++ b/include/Lv2ControlBase.h @@ -0,0 +1,158 @@ +/* + * Lv2ControlBase.h - Lv2 control base class + * + * Copyright (c) 2018-2020 Johannes Lorenz + * + * 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 LV2_CONTROL_BASE_H +#define LV2_CONTROL_BASE_H + +#include "lmmsconfig.h" + +#ifdef LMMS_HAVE_LV2 + +#include + +#include "DataFile.h" +#include "LinkedModelGroups.h" +#include "lmms_export.h" +#include "Plugin.h" + +class Lv2Proc; +class PluginIssue; + +/** + Common base class for Lv2 plugins + + This class contains a vector of Lv2Proc, usually 1 (for stereo plugins) or + 2 (for mono plugins). Most of the logic is done there, this class primarily + forwards work to the Lv2Proc and collects the results. + + This class provides everything Lv2 plugins have in common. It's not + named Lv2Plugin, because + * it does not inherit Instrument + * the Plugin subclass Effect does not inherit this class + + This class would usually be a Model subclass. However, Qt doesn't allow + this: + * inheriting only from Model will cause diamond inheritance for QObject, + which will cause errors with Q_OBJECT + * making this a direct subclass of Instrument resp. EffectControls would + require CRTP, which would make this class a template class, which would + conflict with Q_OBJECT + + The consequence is that this class can neither inherit QObject or Model, nor + Instrument or EffectControls, which means in fact: + * this class contains no signals or slots, but it offers stubs for slots + that shall be called by child classes + * this class can not override virtuals of Instrument or EffectControls, so + it will offer functions that must be called by virtuals in its child class +*/ +class LMMS_EXPORT Lv2ControlBase : public LinkedModelGroups +{ +public: + static Plugin::PluginTypes check(const LilvPlugin* m_plugin, + std::vector &issues); + + const LilvPlugin* getPlugin() const { return m_plugin; } + + Lv2Proc *control(std::size_t idx) { return m_procs[idx].get(); } + const Lv2Proc *control(std::size_t idx) const { return m_procs[idx].get(); } + + bool hasGui() const { return m_hasGUI; } + void setHasGui(bool val) { m_hasGUI = val; } + +protected: + /* + ctor/dtor + */ + //! @param that the class inheriting this class and inheriting Model; + //! this is the same pointer as this, but a different type + //! @param uri the Lv2 URI telling this class what plugin to construct + Lv2ControlBase(class Model *that, const QString& uri); + Lv2ControlBase(const Lv2ControlBase&) = delete; + ~Lv2ControlBase() override; + + Lv2ControlBase& operator=(const Lv2ControlBase&) = delete; + + //! Must be checked after ctor or reload + bool isValid() const { return m_valid; } + + /* + overrides + */ + LinkedModelGroup* getGroup(std::size_t idx) override; + const LinkedModelGroup* getGroup(std::size_t idx) const override; + + /* + utils for the run thread + */ + //! Copy values from the LMMS core (connected models, MIDI events, ...) into + //! the respective ports + void copyModelsFromLmms(); + //! Bring values from all ports to the LMMS core + void copyModelsToLmms() const; + + //! Copy buffer passed by LMMS into our ports + void copyBuffersFromLmms(const sampleFrame *buf, fpp_t frames); + //! Copy our ports into buffers passed by LMMS + void copyBuffersToLmms(sampleFrame *buf, fpp_t frames) const; + //! Run the Lv2 plugin instance for @param frames frames + void run(fpp_t frames); + + /* + load/save, must be called from virtuals + */ + void saveSettings(QDomDocument &doc, QDomElement &that); + void loadSettings(const QDomElement &that); + void loadFile(const QString &file); + //! TODO: not implemented + void reloadPlugin(); + + /* + more functions that must be called from virtuals + */ + std::size_t controlCount() const; + QString nodeName() const { return "lv2controls"; } + bool hasNoteInput() const; + void handleMidiInputEvent(const class MidiEvent &event, + const class TimePos &time, f_cnt_t offset); + +private: + //! Return the DataFile settings type + virtual DataFile::Types settingsType() = 0; + //! Inform the plugin about a file name change + virtual void setNameFromFile(const QString &fname) = 0; + + //! Independent processors + //! If this is a mono effect, the vector will have size 2 in order to + //! fulfill LMMS' requirement of having stereo input and output + std::vector> m_procs; + + bool m_valid = true; + bool m_hasGUI = false; + unsigned m_channelsPerProc; + + const LilvPlugin* m_plugin; +}; + +#endif // LMMS_HAVE_LV2 +#endif // LV2_CONTROL_BASE_H diff --git a/include/Lv2Evbuf.h b/include/Lv2Evbuf.h new file mode 100644 index 00000000000..9cf6a6801fe --- /dev/null +++ b/include/Lv2Evbuf.h @@ -0,0 +1,149 @@ +/* + * lv2_evbuf.h - Lv2 event buffer definitions + * + * Copyright (c) 2019-2020 Johannes Lorenz + * + * 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. + * + */ + +/* + * The original code was written by David Robillard + * Original version: 6f22ee0 from https://github.com/drobilla/jalv.git + * Minor changes have been done, but no functional changes. + * Considering this as an "external library", the identifiers do not need to + * match the LMMS coding conventions. + */ + +#ifndef LV2_EVBUF_H +#define LV2_EVBUF_H + +#include "lmmsconfig.h" + +#ifdef LMMS_HAVE_LV2 + +#include + +/** + An abstract/opaque LV2 event buffer. +*/ +typedef struct LV2_Evbuf_Impl LV2_Evbuf; + +/** + An iterator over an LV2_Evbuf. +*/ +typedef struct { + LV2_Evbuf* evbuf; + uint32_t offset; +} LV2_Evbuf_Iterator; + +/** + Allocate a new, empty event buffer. + URIDs for atom:Chunk and atom:Sequence must be passed for LV2_EVBUF_ATOM. +*/ +LV2_Evbuf* +lv2_evbuf_new(uint32_t capacity, uint32_t atom_Chunk, uint32_t atom_Sequence); + +/** + Free an event buffer allocated with lv2_evbuf_new. +*/ +void +lv2_evbuf_free(LV2_Evbuf* evbuf); + +/** + Clear and initialize an existing event buffer. + The contents of buf are ignored entirely and overwritten, except capacity + which is unmodified. + If input is false and this is an atom buffer, the buffer will be prepared + for writing by the plugin. This MUST be called before every run cycle. +*/ +void +lv2_evbuf_reset(LV2_Evbuf* evbuf, bool input); + +/** + Return the total padded size of the events stored in the buffer. +*/ +uint32_t +lv2_evbuf_get_size(LV2_Evbuf* evbuf); + +/** + Return the actual buffer implementation. + The format of the buffer returned depends on the buffer type. +*/ +void* +lv2_evbuf_get_buffer(LV2_Evbuf* evbuf); + +/** + Return an iterator to the start of `evbuf`. +*/ +LV2_Evbuf_Iterator +lv2_evbuf_begin(LV2_Evbuf* evbuf); + +/** + Return an iterator to the end of `evbuf`. +*/ +LV2_Evbuf_Iterator +lv2_evbuf_end(LV2_Evbuf* evbuf); + +/** + Check if `iter` is valid. + @return True if `iter` is valid, otherwise false (past end of buffer) +*/ +bool +lv2_evbuf_is_valid(LV2_Evbuf_Iterator iter); + +/** + Advance `iter` forward one event. + `iter` must be valid. + @return True if `iter` is valid, otherwise false (reached end of buffer) +*/ +LV2_Evbuf_Iterator +lv2_evbuf_next(LV2_Evbuf_Iterator iter); + +/** + Dereference an event iterator (i.e. get the event currently pointed to). + `iter` must be valid. + `type` Set to the type of the event. + `size` Set to the size of the event. + `data` Set to the contents of the event. + @return True on success. +*/ +bool +lv2_evbuf_get( LV2_Evbuf_Iterator iter, + uint32_t* frames, + uint32_t* type, + uint32_t* size, + uint8_t** data); + +/** + Write an event at `iter`. + The event (if any) pointed to by `iter` will be overwritten, and `iter` + incremented to point to the following event (i.e. several calls to this + function can be done in sequence without twiddling iter in-between). + @return True if event was written, otherwise false (buffer is full). +*/ +bool +lv2_evbuf_write( LV2_Evbuf_Iterator* iter, + uint32_t frames, + uint32_t type, + uint32_t size, + const uint8_t* data); + +#endif // LMMS_HAVE_LV2 + +#endif // LV2_EVBUF_H diff --git a/include/Lv2Features.h b/include/Lv2Features.h new file mode 100644 index 00000000000..f036c6d1f67 --- /dev/null +++ b/include/Lv2Features.h @@ -0,0 +1,81 @@ +/* + * Lv2Features.h - Lv2Features class + * + * Copyright (c) 2020-2020 Johannes Lorenz + * + * 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 LV2FEATURES_H +#define LV2FEATURES_H + +#include "lmmsconfig.h" + +#ifdef LMMS_HAVE_LV2 + +#include +#include +#include +#include "Lv2Manager.h" + +/** + Feature container + + References all available features for a plugin and maps them to their URIs. + + The public member functions should be called in descending order: + + 1. initCommon: map plugin-common features + 2. operator[]: map plugin-specific features + 3. createFeatureVectors: create the feature vectors required for + lilv_plugin_instantiate + 4. access the latter +*/ +class Lv2Features +{ +public: + //! Return if a feature is supported by LMMS + static bool isFeatureSupported(const char *featName); + + Lv2Features(); + + //! Register only plugin-common features + void initCommon(); + //! Return reference to feature data with given URI featName + void*& operator[](const char* featName); + //! Fill m_features and m_featurePointers with all features + void createFeatureVectors(); + //! Return LV2_Feature pointer vector, suited for lilv_plugin_instantiate + const LV2_Feature* const* featurePointers() const + { + return m_featurePointers.data(); + } + +private: + //! feature storage + std::vector m_features; + //! pointers to m_features, required for lilv_plugin_instantiate + std::vector m_featurePointers; + //! features + data, ordered by URI + std::map m_featureByUri; +}; + +#endif // LMMS_HAVE_LV2 + +#endif // LV2FEATURES_H diff --git a/include/Lv2Manager.h b/include/Lv2Manager.h new file mode 100644 index 00000000000..dbea510ce39 --- /dev/null +++ b/include/Lv2Manager.h @@ -0,0 +1,163 @@ +/* + * Lv2Manager.h - Implementation of Lv2Manager class + * + * Copyright (c) 2018-2020 Johannes Lorenz + * + * 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 LV2MANAGER_H +#define LV2MANAGER_H + +#include "lmmsconfig.h" + +#ifdef LMMS_HAVE_LV2 + +#include +#include +#include + +#include "Lv2Basics.h" +#include "Lv2UridCache.h" +#include "Lv2UridMap.h" +#include "Plugin.h" + + +/* + all Lv2 classes in relation (use our "4 spaces per tab rule" to view): + + explanation: + "x = {y z}" means class "x" consists of classes "y" and "z" + (and probably other classes not mentioned) + "x = {y*}" means class "x" references/uses class "y" + + core: + Lv2Proc = {LilvInstance} + Lv2ControlBase = {Lv2Proc, Lv2Proc... (2 for mono, 1 for stereo)} + Lv2Manager = {LilvPlugin*, LilvPlugin* ...} + (creates Lv2ControlBase, Lv2ControlBase...) + + Lv2FxControls = {Lv2ControlBase} + Lv2Effect = {Effect + Lv2FxControls} + (takes Lv2SubPluginFeatures in ctor) + Lv2Instrument = {Instrument + Lv2ControlBase} + (takes Lv2SubPluginFeatures in ctor) + + gui: + Lv2ViewProc = {Lv2Proc*} + Lv2ViewBase = {Lv2ViewProc, Lv2ViewProc... + (2 for mono, 1 for stereo)} + Lv2FxControlDialog = {EffectControlDialog + Lv2ViewBase} + Lv2InsView = {InstrumentView + Lv2ViewBase} + + Lv2SubPluginFeatures: + Lv2SubPluginFeatures = {Lv2Manager*} + Lv2Effect::Descriptor = {Lv2SubPluginFeatures} + Lv2Instrument::Descriptor = {Lv2SubPluginFeatures} +*/ + + +//! Class to keep track of all LV2 plugins +class Lv2Manager +{ +public: + void initPlugins(); + + Lv2Manager(); + ~Lv2Manager(); + + + AutoLilvNode uri(const char* uriStr); + + //! Class representing info for one plugin + struct Lv2Info + { + public: + //! use only for std::map internals + Lv2Info() : m_plugin(nullptr) {} + //! ctor used inside Lv2Manager + Lv2Info(const LilvPlugin* plug, Plugin::PluginTypes type, bool valid) : + m_plugin(plug), m_type(type), m_valid(valid) {} + Lv2Info(Lv2Info&& other) = default; + Lv2Info& operator=(Lv2Info&& other) = default; + + const LilvPlugin* plugin() const { return m_plugin; } + Plugin::PluginTypes type() const { return m_type; } + bool isValid() const { return m_valid; } + + private: + const LilvPlugin* m_plugin; + Plugin::PluginTypes m_type; + bool m_valid = false; + }; + + //! Return descriptor with URI @p uri or nullptr if none exists + const LilvPlugin *getPlugin(const std::string &uri); + //! Return descriptor with URI @p uri or nullptr if none exists + const LilvPlugin *getPlugin(const QString& uri); + + using Lv2InfoMap = std::map; + using Iterator = Lv2InfoMap::iterator; + Iterator begin() { return m_lv2InfoMap.begin(); } + Iterator end() { return m_lv2InfoMap.end(); } + + //! strcmp based key comparator for std::set and std::map + struct CmpStr + { + bool operator()(char const *a, char const *b) const; + }; + + UridMap& uridMap() { return m_uridMap; } + const Lv2UridCache& uridCache() const { return m_uridCache; } + const std::set& supportedFeatureURIs() const + { + return m_supportedFeatureURIs; + } + bool isFeatureSupported(const char* featName) const; + AutoLilvNodes findNodes(const LilvNode *subject, + const LilvNode *predicate, const LilvNode *object); + + static const std::set& getPluginBlacklist() + { + return pluginBlacklist; + } + +private: + // general data + bool m_debug; //!< if set, debug output will be printed + LilvWorld* m_world; + Lv2InfoMap m_lv2InfoMap; + std::set m_supportedFeatureURIs; + + // feature data that are common for all Lv2Proc + UridMap m_uridMap; + + // URID cache for fast URID access + Lv2UridCache m_uridCache; + + // static + static const std::set pluginBlacklist; + + // functions + bool isSubclassOf(const LilvPluginClass *clvss, const char *uriStr); +}; + +#endif // LMMS_HAVE_LV2 + +#endif // LV2MANAGER_H diff --git a/include/Lv2Options.h b/include/Lv2Options.h new file mode 100644 index 00000000000..1453de2ea10 --- /dev/null +++ b/include/Lv2Options.h @@ -0,0 +1,104 @@ +/* + * Lv2Options.h - Lv2Options class + * + * Copyright (c) 2020-2020 Johannes Lorenz + * + * 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 LV2OPTIONS_H +#define LV2OPTIONS_H + +#include "lmmsconfig.h" + +#ifdef LMMS_HAVE_LV2 + +#include +#include +#include +#include +#include +#include +#include + +#include "Engine.h" +#include "Lv2Manager.h" +#include "Lv2UridCache.h" + +/** + Option container + + References all available options for a plugin and maps them to their URIDs. + This class is used per Lv2 processor (justification in Lv2Proc::initMOptions()) + + The public member functions should be called in descending order: + + 1. supportOption: set all supported option URIDs + 2. initOption: initialize options with values + 3. createOptionVectors: create the option vectors required for + the feature + 4. access the latter using feature() +*/ +class Lv2Options +{ +public: + //! Return if an option is supported by LMMS + static bool isOptionSupported(LV2_URID key); + //! Mark option as supported + static void supportOption(LV2_URID key); + + //! Initialize an option + template + void initOption(Lv2UridCache::Id key, Arg&& value, + LV2_Options_Context context = LV2_OPTIONS_INSTANCE, + std::uint32_t subject = 0) + { + const Lv2UridCache& cache = Engine::getLv2Manager()->uridCache(); + initOption(cache[key], sizeof(Opt), cache[Lv2UridCache::IdForType::value], + std::make_shared(std::forward(value)), context, subject); + } + //! Fill m_options and m_optionPointers with all options + void createOptionVectors(); + //! Return the feature + const LV2_Options_Option* feature() const + { + return m_options.data(); + } + +private: + //! Initialize an option internally + void initOption(LV2_URID key, + uint32_t size, + LV2_URID type, + std::shared_ptr value, + LV2_Options_Context context = LV2_OPTIONS_INSTANCE, + uint32_t subject = 0); + //! options that are supported by every processor + static std::set s_supportedOptions; + //! options + data, ordered by URID + std::map m_optionByUrid; + //! option storage + std::vector m_options; + //! option value storage + std::map> m_optionValues; +}; + +#endif // LMMS_HAVE_LV2 + +#endif // LV2OPTIONS_H diff --git a/include/Lv2Ports.h b/include/Lv2Ports.h new file mode 100644 index 00000000000..529200793ad --- /dev/null +++ b/include/Lv2Ports.h @@ -0,0 +1,265 @@ +/* + * Lv2Ports.h - Lv2 port classes definitions + * + * Copyright (c) 2019-2020 Johannes Lorenz + * + * 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 LV2PORTS_H +#define LV2PORTS_H + +#include "lmmsconfig.h" + +#ifdef LMMS_HAVE_LV2 + +#include +#include +#include + +#include "lmms_basics.h" +#include "PluginIssue.h" + +struct ConnectPortVisitor; +typedef struct LV2_Evbuf_Impl LV2_Evbuf; + +namespace Lv2Ports { + +/* + port structs +*/ +enum class Flow { + Unknown, + Input, + Output +}; + +enum class Type { + Unknown, + Control, + Audio, + AtomSeq, + Cv //!< TODO: unused, describe +}; + +//! Port visualization +//! @note All Lv2 audio ports are float, this is only the visualisation +enum class Vis { + Generic, //!< nothing specific, a generic knob or slider shall be used + Integer, //!< counter + Enumeration, //!< selection from enumerated values + Toggled //!< boolean widget +}; + +const char* toStr(Lv2Ports::Flow pf); +const char* toStr(Lv2Ports::Type pt); +const char* toStr(Lv2Ports::Vis pv); + +struct ControlPortBase; +struct Control; +struct Audio; +struct Cv; +struct AtomSeq; +struct Unknown; + +struct ConstVisitor +{ + virtual void visit(const Lv2Ports::ControlPortBase& ) {} + virtual void visit(const Lv2Ports::Control& ) {} + virtual void visit(const Lv2Ports::Audio& ) {} + virtual void visit(const Lv2Ports::Cv& ) {} + virtual void visit(const Lv2Ports::AtomSeq& ) {} + virtual void visit(const Lv2Ports::Unknown& ) {} + + virtual ~ConstVisitor(); +}; + +struct Visitor +{ + virtual void visit(Lv2Ports::ControlPortBase& ) {} + virtual void visit(Lv2Ports::Control& ) {} + virtual void visit(Lv2Ports::Audio& ) {} + virtual void visit(Lv2Ports::Cv& ) {} + virtual void visit(Lv2Ports::AtomSeq& ) {} + virtual void visit(Lv2Ports::Unknown& ) {} + + virtual ~Visitor(); +}; + +struct Meta +{ + Type m_type = Type::Unknown; + Flow m_flow = Flow::Unknown; + Vis m_vis = Vis::Generic; + + bool m_logarithmic = false; + + bool m_optional = false; + bool m_used = true; + + std::vector get(const LilvPlugin* plugin, std::size_t portNum); + + float def() const { return m_def; } + float min(sample_rate_t sr) const { return m_sampleRate ? sr * m_min : m_min; } + float max(sample_rate_t sr) const { return m_sampleRate ? sr * m_max : m_max; } +private: + float m_def = .0f, m_min = .0f, m_max = .0f; + bool m_sampleRate = false; +}; + +struct PortBase : public Meta +{ + const LilvPort* m_port = nullptr; + const LilvPlugin* m_plugin = nullptr; + + virtual void accept(Visitor& v) = 0; + virtual void accept(ConstVisitor& v) const = 0; + + QString name() const; + QString uri() const; + + virtual ~PortBase(); +}; + +template +struct VisitablePort : public Base +{ + void accept(Visitor& v) override { v.visit(static_cast(*this)); } + void accept(ConstVisitor& v) const override { v.visit(static_cast(*this)); } +}; + +struct ControlPortBase : public VisitablePort +{ + //! LMMS models + //! Always up-to-date, except during runs + std::unique_ptr m_connectedModel; + + //! Enumerate float values + //! lv2 defines scale points as + //! "single float Points (for control inputs)" + std::vector m_scalePointMap; +}; + +struct Control : public VisitablePort +{ + //! Data location which Lv2 plugins see + //! Model values are being copied here every run + //! Between runs, this data is not up-to-date + float m_val; +}; + +struct Cv : public VisitablePort +{ + //! Data location which Lv2 plugins see + //! Model values are being copied here every run + //! Between runs, this data is not up-to-date + std::vector m_buffer; +}; + +struct Audio : public VisitablePort +{ + Audio(std::size_t bufferSize, bool isSidechain); + + //! Copy buffer passed by LMMS into our ports + //! @param channel channel index into each sample frame + void copyBuffersFromCore(const sampleFrame *lmmsBuf, + unsigned channel, fpp_t frames); + //! Add buffer passed by LMMS into our ports, and halve the result + //! @param channel channel index into each sample frame + void averageWithBuffersFromCore(const sampleFrame *lmmsBuf, + unsigned channel, fpp_t frames); + //! Copy our ports into buffers passed by LMMS + //! @param channel channel index into each sample frame + void copyBuffersToCore(sampleFrame *lmmsBuf, + unsigned channel, fpp_t frames) const; + + bool isSideChain() const { return m_sidechain; } + bool isOptional() const { return m_optional; } + bool mustBeUsed() const { return !isSideChain() && !isOptional(); } + std::size_t bufferSize() const { return m_buffer.size(); } + +private: + //! the buffer where Lv2 reads/writes the data from/to + std::vector m_buffer; + bool m_sidechain; + + // the only case when data of m_buffer may be referenced: + friend struct ::ConnectPortVisitor; +}; + +struct AtomSeq : public VisitablePort +{ + enum FlagType + { + None = 0, + Midi = 1 + }; + unsigned flags = FlagType::None; + + struct Lv2EvbufDeleter + { + void operator()(LV2_Evbuf* n); + }; + using AutoLv2Evbuf = std::unique_ptr; + AutoLv2Evbuf m_buf; +}; + +struct Unknown : public VisitablePort +{ +}; + +/* + port casts +*/ +template +struct DCastVisitor : public Visitor +{ + Target* m_result = nullptr; + void visit(Target& tar) { m_result = &tar; } +}; + +template +struct ConstDCastVisitor : public ConstVisitor +{ + const Target* m_result = nullptr; + void visit(const Target& tar) { m_result = &tar; } +}; + +//! If you don't want to use a whole visitor, you can use dcast +template +Target* dcast(PortBase* base) +{ + DCastVisitor vis; + base->accept(vis); + return vis.m_result; +} + +//! const overload +template +const Target* dcast(const PortBase* base) +{ + ConstDCastVisitor vis; + base->accept(vis); + return vis.m_result; +} + +} // namespace Lv2Ports + +#endif // LMMS_HAVE_LV2 +#endif // LV2PORTS_H diff --git a/include/Lv2Proc.h b/include/Lv2Proc.h new file mode 100644 index 00000000000..a80c10e3f18 --- /dev/null +++ b/include/Lv2Proc.h @@ -0,0 +1,217 @@ +/* + * Lv2Proc.h - Lv2 processor class + * + * Copyright (c) 2019-2020 Johannes Lorenz + * + * 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 LV2PROC_H +#define LV2PROC_H + +#include "lmmsconfig.h" + +#ifdef LMMS_HAVE_LV2 + +#include +#include +#include + +#include "Lv2Basics.h" +#include "Lv2Features.h" +#include "Lv2Options.h" +#include "LinkedModelGroups.h" +#include "MidiEvent.h" +#include "Plugin.h" +#include "PluginIssue.h" +#include "../src/3rdparty/ringbuffer/include/ringbuffer/ringbuffer.h" +#include "TimePos.h" + +// forward declare port structs/enums +namespace Lv2Ports +{ + struct Audio; + struct PortBase; + struct AtomSeq; + + enum class Type; + enum class Flow; + enum class Vis; +} + + +//! Class representing one Lv2 processor, i.e. one Lv2 handle +//! For Mono effects, 1 Lv2ControlBase references 2 Lv2Proc +class Lv2Proc : public LinkedModelGroup +{ +public: + static Plugin::PluginTypes check(const LilvPlugin* plugin, + std::vector &issues); + + /* + ctor/dtor + */ + Lv2Proc(const LilvPlugin* plugin, Model *parent); + ~Lv2Proc() override; + //! Must be checked after ctor or reload + bool isValid() const { return m_valid; } + + /* + port access + */ + struct StereoPortRef + { + //! mono port or left port in case of stereo + Lv2Ports::Audio* m_left = nullptr; + //! unused, or right port in case of stereo + Lv2Ports::Audio* m_right = nullptr; + }; + + StereoPortRef& inPorts() { return m_inPorts; } + const StereoPortRef& inPorts() const { return m_inPorts; } + StereoPortRef& outPorts() { return m_outPorts; } + const StereoPortRef& outPorts() const { return m_outPorts; } + template + void foreach_port(const Functor& ftor) + { + for (std::unique_ptr& port : m_ports) + { + ftor(port.get()); + } + } + template + void foreach_port(const Functor& ftor) const + { + for (const std::unique_ptr& port : m_ports) + { + ftor(port.get()); + } + } + + //! Debug function to print ports to stdout + void dumpPorts(); + + /* + utils for the run thread + */ + //! Copy values from the LMMS core (connected models, MIDI events, ...) into + //! the respective ports + void copyModelsFromCore(); + //! Bring values from all ports to the LMMS core + void copyModelsToCore(); + /** + * Copy buffer passed by the core into our ports + * @param buf buffer of sample frames, each sample frame is something like + * a `float[ * ]` array. + * @param firstChan The offset for @p buf where we have to read our + * first channel. + * This marks the first sample in each sample frame where we read from. + * If we are the 2nd of 2 mono procs, this can be greater than 0. + * @param num Number of channels we must read from @param buf (starting at + * @p offset) + */ + void copyBuffersFromCore(const sampleFrame *buf, + unsigned firstChan, unsigned num, fpp_t frames); + /** + * Copy our ports into buffers passed by the core + * @param buf buffer of sample frames, each sample frame is something like + * a `float[ * ]` array. + * @param firstChan The offset for @p buf where we have to write our + * first channel. + * This marks the first sample in each sample frame where we write to. + * If we are the 2nd of 2 mono procs, this can be greater than 0. + * @param num Number of channels we must write to @param buf (starting at + * @p offset) + */ + void copyBuffersToCore(sampleFrame *buf, unsigned firstChan, unsigned num, + fpp_t frames) const; + //! Run the Lv2 plugin instance for @param frames frames + void run(fpp_t frames); + + void handleMidiInputEvent(const class MidiEvent &event, + const TimePos &time, f_cnt_t offset); + + /* + misc + */ + class AutomatableModel *modelAtPort(const QString &uri); // unused currently + std::size_t controlCount() const { return LinkedModelGroup::modelNum(); } + bool hasNoteInput() const; + +protected: + /* + load and save + */ + //! Create ports and instance, connect ports, activate plugin + void initPlugin(); + //! Deactivate instance + void shutdownPlugin(); + +private: + bool m_valid = true; + + const LilvPlugin* m_plugin; + LilvInstance* m_instance; + Lv2Features m_features; + Lv2Options m_options; + + // full list of ports + std::vector> m_ports; + // quick reference to specific, unique ports + StereoPortRef m_inPorts, m_outPorts; + Lv2Ports::AtomSeq *m_midiIn = nullptr, *m_midiOut = nullptr; + + // MIDI + // many things here may be moved into the `Instrument` class + constexpr const static std::size_t m_maxMidiInputEvents = 1024; + //! spinlock for the MIDI ringbuffer (for MIDI events going to the plugin) + std::atomic_flag m_ringLock = ATOMIC_FLAG_INIT; + + //! MIDI ringbuffer (for MIDI events going to the plugin) + ringbuffer_t m_midiInputBuf; + //! MIDI ringbuffer reader + ringbuffer_reader_t m_midiInputReader; + + // other + static int32_t defaultEvbufSize() { return 1 << 15; /* ardour uses this*/ } + + //! models for the controls, sorted by port symbols + std::map m_connectedModels; + + void initMOptions(); //!< initialize m_options + void initPluginSpecificFeatures(); + + //! load a file in the plugin, but don't do anything in LMMS + void loadFileInternal(const QString &file); + //! allocate m_ports, fill all with metadata, and assign meaning of ports + void createPorts(); + //! fill m_ports[portNum] with metadata + void createPort(std::size_t portNum); + //! connect m_ports[portNum] with Lv2 + void connectPort(std::size_t num); + + void dumpPort(std::size_t num); + + static bool portIsSideChain(const LilvPlugin* plugin, const LilvPort *port); + static bool portIsOptional(const LilvPlugin* plugin, const LilvPort *port); + static AutoLilvNode uri(const char* uriStr); +}; + +#endif // LMMS_HAVE_LV2 +#endif // LV2PROC_H diff --git a/include/Lv2SubPluginFeatures.h b/include/Lv2SubPluginFeatures.h new file mode 100644 index 00000000000..fee3c381216 --- /dev/null +++ b/include/Lv2SubPluginFeatures.h @@ -0,0 +1,62 @@ +/* + * Lv2SubPluginFeatures.h - derivation from + * Plugin::Descriptor::SubPluginFeatures for + * hosting LV2 plugins + * + * Copyright (c) 2018-2020 Johannes Lorenz + * + * 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 LV2_SUBPLUGIN_FEATURES_H +#define LV2_SUBPLUGIN_FEATURES_H + +#include "lmmsconfig.h" + +#ifdef LMMS_HAVE_LV2 + +#include + +#include "lmms_export.h" +#include "Plugin.h" + +class LMMS_EXPORT Lv2SubPluginFeatures : public Plugin::Descriptor::SubPluginFeatures +{ +private: + static const LilvPlugin *getPlugin(const Key &k); + static QString pluginName(const LilvPlugin *plug); + +public: + Lv2SubPluginFeatures(Plugin::PluginTypes type); + + void fillDescriptionWidget( + QWidget *parent, const Key *k) const override; + + QString additionalFileExtensions(const Key &k) const override; + QString displayName(const Key &k) const override; + QString description(const Key &k) const override; + const PixmapLoader *logo(const Key &k) const override; + + void listSubPluginKeys( + const Plugin::Descriptor *desc, KeyList &kl) const override; +}; + +#endif // LMMS_HAVE_LV2 + +#endif diff --git a/include/Lv2UridCache.h b/include/Lv2UridCache.h new file mode 100644 index 00000000000..1921bdfd70b --- /dev/null +++ b/include/Lv2UridCache.h @@ -0,0 +1,70 @@ +/* + * Lv2UridCache.h - Lv2UridCache definition + * + * Copyright (c) 2020-2020 Johannes Lorenz + * + * 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 LV2URIDCACHE_H +#define LV2URIDCACHE_H + +#include "lmmsconfig.h" + +#ifdef LMMS_HAVE_LV2 + +#include +#include + +//! Cached URIDs for fast access (for use in real-time code) +class Lv2UridCache +{ +public: + enum class Id //!< ID for m_uridCache array + { + // keep it alphabetically (except "size" at the end) + atom_Float, + atom_Int, + bufsz_minBlockLength, + bufsz_maxBlockLength, + bufsz_nominalBlockLength, + bufsz_sequenceSize, + midi_MidiEvent, + param_sampleRate, + // exception to alphabetic ordering - keep at the end: + size + }; + + template + struct IdForType; + + //! Return URID for a cache ID + uint32_t operator[](Id id) const; + + Lv2UridCache(class UridMap& mapper); + +private: + uint32_t m_cache[static_cast(Id::size)]; +}; + +template<> struct Lv2UridCache::IdForType { static constexpr auto value = Id::atom_Float; }; +template<> struct Lv2UridCache::IdForType { static constexpr auto value = Id::atom_Int; }; + +#endif // LMMS_HAVE_LV2 +#endif // LV2URIDCACHE_H diff --git a/include/Lv2UridMap.h b/include/Lv2UridMap.h new file mode 100644 index 00000000000..39cfcc44fb2 --- /dev/null +++ b/include/Lv2UridMap.h @@ -0,0 +1,70 @@ +/* + * Lv2UridMap.cpp - Lv2UridMap class + * + * Copyright (c) 2019 Johannes Lorenz + * + * 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 LV2URIDMAP_H +#define LV2URIDMAP_H + +#include "lmmsconfig.h" + +#ifdef LMMS_HAVE_LV2 + +#include +#include // TODO: use semaphore, even though this is not realtime critical +#include +#include +#include + +/** + * Complete implementation of the Lv2 Urid Map extension + */ +class UridMap +{ + std::unordered_map m_map; + std::vector m_unMap; + + //! mutex for both m_map and m_unMap + //! the URID map is global, which is why a mutex is required here + std::mutex m_MapMutex; + + LV2_URID_Map m_mapFeature; + LV2_URID_Unmap m_unmapFeature; + + LV2_URID m_lastUrid = 0; + +public: + //! constructor; will set up the features + UridMap(); + + //! map feature function + LV2_URID map(const char* uri); + //! unmap feature function + const char* unmap(LV2_URID urid); + + // access the features + LV2_URID_Map* mapFeature() { return &m_mapFeature; } + LV2_URID_Unmap* unmapFeature() { return &m_unmapFeature; } +}; + +#endif // LMMS_HAVE_LV2 +#endif // LV2URIDMAP_H diff --git a/include/Lv2ViewBase.h b/include/Lv2ViewBase.h new file mode 100644 index 00000000000..5ccbbb75be1 --- /dev/null +++ b/include/Lv2ViewBase.h @@ -0,0 +1,98 @@ +/* + * Lv2ViewBase.h - base class for Lv2 plugin views + * + * Copyright (c) 2018-2020 Johannes Lorenz + * + * 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 LV2VIEWBASE_H +#define LV2VIEWBASE_H + +#include "lmmsconfig.h" + +#ifdef LMMS_HAVE_LV2 + + +#include +#include + +#include "LinkedModelGroupViews.h" +#include "lmms_export.h" +#include "Lv2Basics.h" + +class Lv2Proc; +class Lv2ControlBase; + + +//! View for one processor, Lv2ViewBase contains 2 of those for mono plugins +class Lv2ViewProc : public LinkedModelGroupView +{ +public: + //! @param colNum numbers of columns for the controls + Lv2ViewProc(QWidget *parent, Lv2Proc *ctrlBase, int colNum); + ~Lv2ViewProc(); + +private: + static AutoLilvNode uri(const char *uriStr); +}; + + +//! Base class for view for one Lv2 plugin +class LMMS_EXPORT Lv2ViewBase : public LinkedModelGroupsView +{ +protected: + //! @param pluginWidget A child class which inherits QWidget + Lv2ViewBase(class QWidget *pluginWidget, Lv2ControlBase *ctrlBase); + ~Lv2ViewBase(); + + // these widgets must be connected by child widgets + class QPushButton *m_reloadPluginButton = nullptr; + class QPushButton *m_toggleUIButton = nullptr; + class QPushButton *m_helpButton = nullptr; + + void toggleUI(); + void toggleHelp(bool visible); + + // to be called by child virtuals + //! Reconnect models if model changed + void modelChanged(Lv2ControlBase* ctrlBase); + +private: + enum Rows + { + ButtonRow, + ProcRow, + LinkChannelsRow + }; + + static AutoLilvNode uri(const char *uriStr); + LinkedModelGroupView* getGroupView() override { return m_procView; } + + Lv2ViewProc* m_procView; + + //! Numbers of controls per row; must be multiple of 2 for mono effects + const int m_colNum = 6; + class QMdiSubWindow* m_helpWindow = nullptr; + class LedCheckBox *m_multiChannelLink; +}; + + +#endif // LMMS_HAVE_LV2 +#endif // LV2VIEWBASE_H diff --git a/include/MainWindow.h b/include/MainWindow.h index f7325395928..5acbbac2fb1 100644 --- a/include/MainWindow.h +++ b/include/MainWindow.h @@ -63,7 +63,7 @@ class LMMS_EXPORT MainWindow : public QMainWindow void addSpacingToToolBar( int _size ); // wrap the widget with a window decoration and add it to the workspace - SubWindow* addWindowedWidget(QWidget *w, Qt::WindowFlags windowFlags=0); + SubWindow* addWindowedWidget(QWidget *w, Qt::WindowFlags windowFlags = QFlag(0)); /// @@ -157,6 +157,7 @@ public slots: void toggleFxMixerWin(); void togglePianoRollWin(); void toggleControllerRack(); + void toggleFullscreen(); void updatePlayPauseIcons(); @@ -226,6 +227,8 @@ private slots: ToolButton * m_metronomeToggle; SessionState m_session; + + bool maximized; private slots: void browseHelp(); diff --git a/include/MidiAlsaSeq.h b/include/MidiAlsaSeq.h index b6e4987210b..5db5357d829 100644 --- a/include/MidiAlsaSeq.h +++ b/include/MidiAlsaSeq.h @@ -66,7 +66,7 @@ class MidiAlsaSeq : public QThread, public MidiClient virtual void processOutEvent( const MidiEvent & _me, - const MidiTime & _time, + const TimePos & _time, const MidiPort * _port ) override; void applyPortMode( MidiPort * _port ) override; diff --git a/include/MidiApple.h b/include/MidiApple.h index 21b88073b08..4ea4805e5a8 100644 --- a/include/MidiApple.h +++ b/include/MidiApple.h @@ -60,7 +60,7 @@ class MidiApple : public QObject, public MidiClient } virtual void processOutEvent( const MidiEvent & _me, - const MidiTime & _time, + const TimePos & _time, const MidiPort * _port ); virtual void applyPortMode( MidiPort * _port ); diff --git a/include/MidiCCRackView.h b/include/MidiCCRackView.h new file mode 100644 index 00000000000..9d015e4e8fb --- /dev/null +++ b/include/MidiCCRackView.h @@ -0,0 +1,40 @@ +#ifndef MIDI_CC_RACK_VIEW_H +#define MIDI_CC_RACK_VIEW_H + +#include + +#include "GroupBox.h" +#include "Knob.h" +#include "Midi.h" +#include "SerializingObject.h" + +class InstrumentTrack; + +class MidiCCRackView : public QWidget, public SerializingObject +{ + Q_OBJECT +public: + MidiCCRackView(InstrumentTrack * track); + ~MidiCCRackView() override; + + void saveSettings(QDomDocument & doc, QDomElement & parent) override; + void loadSettings(const QDomElement &) override; + + inline QString nodeName() const override + { + return "MidiCCRackView"; + } + +private slots: + void renameWindow(); + +private: + InstrumentTrack *m_track; + + GroupBox *m_midiCCGroupBox; // MIDI CC GroupBox (used to enable disable MIDI CC) + + Knob *m_controllerKnob[MidiControllerCount]; // Holds the knob widgets for each controller + +}; + +#endif diff --git a/include/MidiClient.h b/include/MidiClient.h index f06cac89394..ff441e24f1d 100644 --- a/include/MidiClient.h +++ b/include/MidiClient.h @@ -46,7 +46,7 @@ class MidiClient // to be implemented by sub-classes virtual void processOutEvent( const MidiEvent & _me, - const MidiTime & _time, + const TimePos & _time, const MidiPort * _port ) = 0; // inheriting classes can re-implement this for being able to update @@ -141,7 +141,7 @@ class MidiClientRaw : public MidiClient private: // this does MIDI-event-process void processParsedEvent(); - void processOutEvent( const MidiEvent& event, const MidiTime& time, const MidiPort* port ) override; + void processOutEvent( const MidiEvent& event, const TimePos& 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 43f928a25cb..74b408f867d 100644 --- a/include/MidiController.h +++ b/include/MidiController.h @@ -44,10 +44,10 @@ class MidiController : public Controller, public MidiEventProcessor virtual ~MidiController(); virtual void processInEvent( const MidiEvent & _me, - const MidiTime & _time, f_cnt_t offset = 0 ) override; + const TimePos & _time, f_cnt_t offset = 0 ) override; virtual void processOutEvent( const MidiEvent& _me, - const MidiTime & _time, f_cnt_t offset = 0 ) override + const TimePos & _time, f_cnt_t offset = 0 ) override { // No output yet } diff --git a/include/MidiEvent.h b/include/MidiEvent.h index 907314b4866..a82c5d4645c 100644 --- a/include/MidiEvent.h +++ b/include/MidiEvent.h @@ -33,27 +33,32 @@ class MidiEvent { public: - MidiEvent( MidiEventTypes type = MidiActiveSensing, + enum class Source { Internal, External }; + + MidiEvent(MidiEventTypes type = MidiActiveSensing, int8_t channel = 0, int16_t param1 = 0, int16_t param2 = 0, - const void* sourcePort = NULL ) : + const void* sourcePort = nullptr, + Source source = Source::External) : m_type( type ), m_metaEvent( MidiMetaInvalid ), m_channel( channel ), m_sysExData( NULL ), - m_sourcePort( sourcePort ) + m_sourcePort(sourcePort), + m_source(source) { m_data.m_param[0] = param1; m_data.m_param[1] = param2; } - MidiEvent( MidiEventTypes type, const char* sysExData, int dataLen ) : + MidiEvent(MidiEventTypes type, const char* sysExData, std::size_t dataLen, Source source = Source::External) : m_type( type ), m_metaEvent( MidiMetaInvalid ), m_channel( 0 ), m_sysExData( sysExData ), - m_sourcePort( NULL ) + m_sourcePort(nullptr), + m_source(source) { m_data.m_sysExDataLen = dataLen; } @@ -64,7 +69,8 @@ class MidiEvent m_channel( other.m_channel ), m_data( other.m_data ), m_sysExData( other.m_sysExData ), - m_sourcePort( other.m_sourcePort ) + m_sourcePort(other.m_sourcePort), + m_source(other.m_source) { } @@ -190,6 +196,16 @@ class MidiEvent setParam( 0, pitchBend ); } + Source source() const + { + return m_source; + } + + void setSource(Source value) + { + m_source = value; + } + private: MidiEventTypes m_type; // MIDI event type @@ -198,13 +214,15 @@ class MidiEvent union { int16_t m_param[2]; // first/second parameter (key/velocity) - uint8_t m_bytes[4]; // raw bytes + uint8_t m_bytes[4]; // raw bytes int32_t m_sysExDataLen; // len of m_sysExData } m_data; const char* m_sysExData; const void* m_sourcePort; + // Stores the source of the MidiEvent: Internal or External (hardware controllers). + Source m_source; } ; #endif diff --git a/include/MidiEventProcessor.h b/include/MidiEventProcessor.h index 7022eaf3a81..ba94beea5e9 100644 --- a/include/MidiEventProcessor.h +++ b/include/MidiEventProcessor.h @@ -26,8 +26,8 @@ #define MIDI_EVENT_PROCESSOR_H #include "MidiEvent.h" -#include "MidiTime.h" #include "Memory.h" +#include "TimePos.h" // all classes being able to process MIDI-events should inherit from this class MidiEventProcessor @@ -43,8 +43,8 @@ class MidiEventProcessor } // to be implemented by inheriting classes - virtual void processInEvent( const MidiEvent& event, const MidiTime& time = MidiTime(), f_cnt_t offset = 0 ) = 0; - virtual void processOutEvent( const MidiEvent& event, const MidiTime& time = MidiTime(), f_cnt_t offset = 0 ) = 0; + virtual void processInEvent( const MidiEvent& event, const TimePos& time = TimePos(), f_cnt_t offset = 0 ) = 0; + virtual void processOutEvent( const MidiEvent& event, const TimePos& time = TimePos(), f_cnt_t offset = 0 ) = 0; } ; diff --git a/include/MidiEventToByteSeq.h b/include/MidiEventToByteSeq.h new file mode 100644 index 00000000000..fba8cdeb414 --- /dev/null +++ b/include/MidiEventToByteSeq.h @@ -0,0 +1,47 @@ +/* + * MidiEventToByteSeq.h - writeToByteSeq declaration + * + * Copyright (c) 2020-2020 Johannes Lorenz + * + * 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 MIDIEVENTTOBYTESEQ_H +#define MIDIEVENTTOBYTESEQ_H + +#include +#include + +#include "lmms_export.h" + +/** + Write MIDI event into byte sequence. + + Conforming to http://lv2plug.in/ns/ext/midi#MidiEvent + + @param data Pointer to the target buffer for the byte sequence. Must + point to existing memory with at least 3 bytes size. + @param bufsize Available size of the target buffer. + @return Used size of the target buffer, or 0 if the MidiEvent could not + be converted. +*/ +std::size_t LMMS_EXPORT writeToByteSeq( const class MidiEvent& ev, + uint8_t* data, std::size_t bufsize ); + +#endif // MIDIEVENTTOBYTESEQ_H diff --git a/include/MidiPort.h b/include/MidiPort.h index e9cba39ed2f..9592147da5e 100644 --- a/include/MidiPort.h +++ b/include/MidiPort.h @@ -31,7 +31,7 @@ #include #include "Midi.h" -#include "MidiTime.h" +#include "TimePos.h" #include "AutomatableModel.h" @@ -96,11 +96,14 @@ class MidiPort : public Model, public SerializingObject int realOutputChannel() const { - return outputChannel() - 1; + // There's a possibility of outputChannel being 0 ("--"), which is used to keep all + // midi channels when forwarding. In that case, realOutputChannel will return the + // default channel 1 (whose value is 0). + return outputChannel() ? outputChannel() - 1 : 0; } - void processInEvent( const MidiEvent& event, const MidiTime& time = MidiTime() ); - void processOutEvent( const MidiEvent& event, const MidiTime& time = MidiTime() ); + void processInEvent( const MidiEvent& event, const TimePos& time = TimePos() ); + void processOutEvent( const MidiEvent& event, const TimePos& time = TimePos() ); void saveSettings( QDomDocument& doc, QDomElement& thisElement ) override; diff --git a/include/MidiWinMM.h b/include/MidiWinMM.h index a51fa7ed669..cbb13998313 100644 --- a/include/MidiWinMM.h +++ b/include/MidiWinMM.h @@ -64,7 +64,7 @@ class MidiWinMM : public QObject, public MidiClient virtual void processOutEvent( const MidiEvent & _me, - const MidiTime & _time, + const TimePos & _time, const MidiPort * _port ); virtual void applyPortMode( MidiPort * _port ); diff --git a/include/Mixer.h b/include/Mixer.h index 32eeb8977bf..c561aa3c94d 100644 --- a/include/Mixer.h +++ b/include/Mixer.h @@ -98,9 +98,9 @@ class LMMS_EXPORT Mixer : public QObject Interpolation interpolation; Oversampling oversampling; - qualitySettings( Mode _m ) + qualitySettings(Mode m) { - switch( _m ) + switch (m) { case Mode_Draft: interpolation = Interpolation_Linear; @@ -118,9 +118,9 @@ class LMMS_EXPORT Mixer : public QObject } } - qualitySettings( Interpolation _i, Oversampling _o ) : - interpolation( _i ), - oversampling( _o ) + qualitySettings(Interpolation i, Oversampling o) : + interpolation(i), + oversampling(o) { } @@ -173,8 +173,6 @@ class LMMS_EXPORT Mixer : public QObject //! Set new audio device. Old device will be deleted, //! unless it's stored using storeAudioDevice - void setAudioDevice( AudioDevice * _dev , bool startNow ); - //! See overloaded function void setAudioDevice( AudioDevice * _dev, const struct qualitySettings & _qs, bool _needs_fifo, @@ -188,14 +186,14 @@ class LMMS_EXPORT Mixer : public QObject // audio-port-stuff - inline void addAudioPort( AudioPort * _port ) + inline void addAudioPort(AudioPort * port) { requestChangeInModel(); - m_audioPorts.push_back( _port ); + m_audioPorts.push_back(port); doneChangeInModel(); } - void removeAudioPort( AudioPort * _port ); + void removeAudioPort(AudioPort * port); // MIDI-client-stuff @@ -220,7 +218,7 @@ class LMMS_EXPORT Mixer : public QObject return m_playHandles; } - void removePlayHandlesOfTypes( Track * _track, const quint8 types ); + void removePlayHandlesOfTypes(Track * track, const quint8 types); // methods providing information for other classes @@ -257,23 +255,23 @@ class LMMS_EXPORT Mixer : public QObject return m_masterGain; } - inline void setMasterGain( const float _mo ) + inline void setMasterGain(const float mo) { - m_masterGain = _mo; + m_masterGain = mo; } - static inline sample_t clip( const sample_t _s ) + static inline sample_t clip(const sample_t s) { - if( _s > 1.0f ) + if (s > 1.0f) { return 1.0f; } - else if( _s < -1.0f ) + else if (s < -1.0f) { return -1.0f; } - return _s; + return s; } @@ -283,7 +281,7 @@ class LMMS_EXPORT Mixer : public QObject sample_t left; sample_t right; }; - StereoSample getPeakValues(sampleFrame * _ab, const f_cnt_t _frames) const; + StereoSample getPeakValues(sampleFrame * ab, const f_cnt_t _frames) const; bool criticalXRuns() const; @@ -310,7 +308,7 @@ class LMMS_EXPORT Mixer : public QObject return hasFifoWriter() ? m_fifo->read() : renderNextBuffer(); } - void changeQuality( const struct qualitySettings & _qs ); + void changeQuality(const struct qualitySettings & qs); inline bool isMetronomeActive() const { return m_metronomeActive; } inline void setMetronomeActive(bool value = true) { m_metronomeActive = value; } @@ -335,7 +333,7 @@ class LMMS_EXPORT Mixer : public QObject class fifoWriter : public QThread { public: - fifoWriter( Mixer * _mixer, fifo * _fifo ); + fifoWriter(Mixer * mixer, fifo * _fifo); void finish(); @@ -355,7 +353,7 @@ class LMMS_EXPORT Mixer : public QObject Mixer( bool renderOnly ); virtual ~Mixer(); - void startProcessing( bool _needs_fifo = true ); + void startProcessing(bool needsFifo = true); void stopProcessing(); @@ -365,6 +363,10 @@ class LMMS_EXPORT Mixer : public QObject const surroundSampleFrame * renderNextBuffer(); + void swapBuffers(); + + void handleMetronome(); + void clearInternal(); //! Called by the audio thread to give control to other threads, @@ -383,13 +385,8 @@ class LMMS_EXPORT Mixer : public QObject int m_inputBufferRead; int m_inputBufferWrite; - surroundSampleFrame * m_readBuf; - surroundSampleFrame * m_writeBuf; - - QVector m_bufferPool; - int m_readBuffer; - int m_writeBuffer; - int m_poolDepth; + surroundSampleFrame * m_outputBufferRead; + surroundSampleFrame * m_outputBufferWrite; // worker thread stuff QVector m_workers; diff --git a/include/ModelView.h b/include/ModelView.h index 907cd14efdf..04229ed0d2f 100644 --- a/include/ModelView.h +++ b/include/ModelView.h @@ -36,6 +36,7 @@ class LMMS_EXPORT ModelView virtual ~ModelView(); virtual void setModel( Model* model, bool isOldModelValid = true ); + virtual void unsetModel(); Model* model() { diff --git a/include/Note.h b/include/Note.h index 30969b4c8f9..c08a3e24e55 100644 --- a/include/Note.h +++ b/include/Note.h @@ -30,8 +30,8 @@ #include "volume.h" #include "panning.h" -#include "MidiTime.h" #include "SerializingObject.h" +#include "TimePos.h" class DetuningHelper; @@ -81,8 +81,8 @@ const float MaxDetuning = 4 * 12.0f; class LMMS_EXPORT Note : public SerializingObject { public: - Note( const MidiTime & length = MidiTime( 0 ), - const MidiTime & pos = MidiTime( 0 ), + Note( const TimePos & length = TimePos( 0 ), + const TimePos & pos = TimePos( 0 ), int key = DefaultKey, volume_t volume = DefaultVolume, panning_t panning = DefaultPanning, @@ -93,9 +93,9 @@ class LMMS_EXPORT Note : public SerializingObject // used by GUI inline void setSelected( const bool selected ) { m_selected = selected; } inline void setOldKey( const int oldKey ) { m_oldKey = oldKey; } - inline void setOldPos( const MidiTime & oldPos ) { m_oldPos = oldPos; } + inline void setOldPos( const TimePos & oldPos ) { m_oldPos = oldPos; } - inline void setOldLength( const MidiTime & oldLength ) + inline void setOldLength( const TimePos & oldLength ) { m_oldLength = oldLength; } @@ -105,8 +105,8 @@ class LMMS_EXPORT Note : public SerializingObject } - void setLength( const MidiTime & length ); - void setPos( const MidiTime & pos ); + void setLength( const TimePos & length ); + void setPos( const TimePos & pos ); void setKey( const int key ); virtual void setVolume( volume_t volume ); virtual void setPanning( panning_t panning ); @@ -138,12 +138,12 @@ class LMMS_EXPORT Note : public SerializingObject return m_oldKey; } - inline MidiTime oldPos() const + inline TimePos oldPos() const { return m_oldPos; } - inline MidiTime oldLength() const + inline TimePos oldLength() const { return m_oldLength; } @@ -153,23 +153,23 @@ class LMMS_EXPORT Note : public SerializingObject return m_isPlaying; } - inline MidiTime endPos() const + inline TimePos endPos() const { const int l = length(); return pos() + l; } - inline const MidiTime & length() const + inline const TimePos & length() const { return m_length; } - inline const MidiTime & pos() const + inline const TimePos & pos() const { return m_pos; } - inline MidiTime pos( MidiTime basePos ) const + inline TimePos pos( TimePos basePos ) const { const int bp = basePos; return m_pos - bp; @@ -205,7 +205,7 @@ class LMMS_EXPORT Note : public SerializingObject return classNodeName(); } - static MidiTime quantized( const MidiTime & m, const int qGrid ); + static TimePos quantized( const TimePos & m, const int qGrid ); DetuningHelper * detuning() const { @@ -226,15 +226,15 @@ class LMMS_EXPORT Note : public SerializingObject // for piano roll editing bool m_selected; int m_oldKey; - MidiTime m_oldPos; - MidiTime m_oldLength; + TimePos m_oldPos; + TimePos m_oldLength; bool m_isPlaying; int m_key; volume_t m_volume; panning_t m_panning; - MidiTime m_length; - MidiTime m_pos; + TimePos m_length; + TimePos m_pos; DetuningHelper * m_detuning; }; diff --git a/include/NotePlayHandle.h b/include/NotePlayHandle.h index 28452b19048..692ae3038ec 100644 --- a/include/NotePlayHandle.h +++ b/include/NotePlayHandle.h @@ -48,6 +48,9 @@ class LMMS_EXPORT NotePlayHandle : public PlayHandle, public Note void * m_pluginData; std::unique_ptr> m_filter; + // length of the declicking fade in + fpp_t m_fadeInLength; + // specifies origin of NotePlayHandle enum Origins { @@ -240,19 +243,19 @@ class LMMS_EXPORT NotePlayHandle : public PlayHandle, public Note } /*! Process note detuning automation */ - void processMidiTime( const MidiTime& time ); + void processTimePos( const TimePos& time ); /*! Updates total length (m_frames) depending on a new tempo */ void resize( const bpm_t newTempo ); /*! Set song-global offset (relative to containing pattern) in order to properly perform the note detuning */ - void setSongGlobalParentOffset( const MidiTime& offset ) + void setSongGlobalParentOffset( const TimePos& offset ) { m_songGlobalParentOffset = offset; } /*! Returns song-global offset */ - const MidiTime& songGlobalParentOffset() const + const TimePos& songGlobalParentOffset() const { return m_songGlobalParentOffset; } @@ -319,7 +322,7 @@ class LMMS_EXPORT NotePlayHandle : public PlayHandle, public Note float m_unpitchedFrequency; BaseDetuning* m_baseDetuning; - MidiTime m_songGlobalParentOffset; + TimePos m_songGlobalParentOffset; int m_midiChannel; Origin m_origin; diff --git a/include/Oscillator.h b/include/Oscillator.h index 408e69dbc6c..912bcdc0977 100644 --- a/include/Oscillator.h +++ b/include/Oscillator.h @@ -97,7 +97,7 @@ class LMMS_EXPORT Oscillator static inline sample_t triangleSample( const float _sample ) { - const float ph = fraction( _sample ); + const float ph = absFraction( _sample ); if( ph <= 0.25f ) { return ph * 4.0f; @@ -111,17 +111,17 @@ class LMMS_EXPORT Oscillator static inline sample_t sawSample( const float _sample ) { - return -1.0f + fraction( _sample ) * 2.0f; + return -1.0f + absFraction( _sample ) * 2.0f; } static inline sample_t squareSample( const float _sample ) { - return ( fraction( _sample ) > 0.5f ) ? -1.0f : 1.0f; + return ( absFraction( _sample ) > 0.5f ) ? -1.0f : 1.0f; } static inline sample_t moogSawSample( const float _sample ) { - const float ph = fraction( _sample ); + const float ph = absFraction( _sample ); if( ph < 0.5f ) { return -1.0f + ph * 4.0f; @@ -131,7 +131,7 @@ class LMMS_EXPORT Oscillator static inline sample_t expSample( const float _sample ) { - float ph = fraction( _sample ); + float ph = absFraction( _sample ); if( ph > 0.5f ) { ph = 1.0f - ph; diff --git a/include/Oscilloscope.h b/include/Oscilloscope.h index 49db1393b3e..45e04832a02 100644 --- a/include/Oscilloscope.h +++ b/include/Oscilloscope.h @@ -37,7 +37,6 @@ class Oscilloscope : public QWidget Q_OBJECT public: Q_PROPERTY( QColor normalColor READ normalColor WRITE setNormalColor ) - Q_PROPERTY( QColor warningColor READ warningColor WRITE setWarningColor ) Q_PROPERTY( QColor clippingColor READ clippingColor WRITE setClippingColor ) Oscilloscope( QWidget * _parent ); @@ -48,9 +47,6 @@ class Oscilloscope : public QWidget QColor const & normalColor() const; void setNormalColor(QColor const & normalColor); - QColor const & warningColor() const; - void setWarningColor(QColor const & warningColor); - QColor const & clippingColor() const; void setClippingColor(QColor const & clippingColor); @@ -74,7 +70,6 @@ protected slots: bool m_active; QColor m_normalColor; - QColor m_warningColor; QColor m_clippingColor; } ; diff --git a/include/PathUtil.h b/include/PathUtil.h new file mode 100644 index 00000000000..cc6b982a114 --- /dev/null +++ b/include/PathUtil.h @@ -0,0 +1,41 @@ +#ifndef PATHUTIL_H +#define PATHUTIL_H + +#include "lmms_export.h" + +#include + +namespace PathUtil +{ + enum class Base { Absolute, ProjectDir, FactorySample, UserSample, UserVST, Preset, + UserLADSPA, DefaultLADSPA, UserSoundfont, DefaultSoundfont, UserGIG, DefaultGIG }; + + //! Return the directory associated with a given base as a QString + QString LMMS_EXPORT baseLocation(const Base base); + //! Return the directory associated with a given base as a QDir + QDir LMMS_EXPORT baseQDir (const Base base); + //! Return the prefix used to denote this base in path strings + QString LMMS_EXPORT basePrefix(const Base base); + //! Check the prefix of a path and return the base it corresponds to + //! Defaults to Base::Absolute + Base LMMS_EXPORT baseLookup(const QString & path); + + //! Remove the prefix from a path, iff there is one + QString LMMS_EXPORT stripPrefix(const QString & path); + //! Get the filename for a path, handling prefixed paths correctly + QString LMMS_EXPORT cleanName(const QString & path); + + //! Upgrade prefix-less relative paths to the new format + QString LMMS_EXPORT oldRelativeUpgrade(const QString & input); + + //! Make this path absolute + QString LMMS_EXPORT toAbsolute(const QString & input); + //! Make this path relative to a given base, return an absolute path if that fails + QString LMMS_EXPORT relativeOrAbsolute(const QString & input, const Base base); + //! Make this path relative to any base, choosing the shortest if there are + //! multiple options. Defaults to an absolute path if all bases fail. + QString LMMS_EXPORT toShortestRelative(const QString & input); + +} + +#endif diff --git a/include/Pattern.h b/include/Pattern.h index 5192da9faf8..0bc1f61f37a 100644 --- a/include/Pattern.h +++ b/include/Pattern.h @@ -34,16 +34,10 @@ #include "Note.h" -#include "Track.h" +#include "TrackContentObjectView.h" -class QAction; -class QProgressBar; -class QPushButton; - class InstrumentTrack; -class SampleBuffer; - class LMMS_EXPORT Pattern : public TrackContentObject @@ -128,7 +122,7 @@ protected slots: private: - MidiTime beatPatternLength() const; + TimePos beatPatternLength() const; void setType( PatternTypes _new_pattern_type ); void checkType(); diff --git a/include/PianoRoll.h b/include/PianoRoll.h index 5859594f6dc..5e0ea0762c9 100644 --- a/include/PianoRoll.h +++ b/include/PianoRoll.h @@ -40,6 +40,7 @@ #include "ToolTip.h" #include "StepRecorder.h" #include "StepRecorderWidget.h" +#include "PositionLine.h" class QPainter; class QPixmap; @@ -55,25 +56,38 @@ class TimeLineWidget; class PianoRoll : public QWidget { Q_OBJECT - Q_PROPERTY( QColor barLineColor READ barLineColor WRITE setBarLineColor ) - Q_PROPERTY( QColor beatLineColor READ beatLineColor WRITE setBeatLineColor ) - Q_PROPERTY( QColor lineColor READ lineColor WRITE setLineColor ) - Q_PROPERTY( QColor noteModeColor READ noteModeColor WRITE setNoteModeColor ) - Q_PROPERTY( QColor noteColor READ noteColor WRITE setNoteColor ) - Q_PROPERTY( QColor ghostNoteColor READ ghostNoteColor WRITE setGhostNoteColor ) - Q_PROPERTY( QColor noteTextColor READ noteTextColor WRITE setNoteTextColor ) - Q_PROPERTY( QColor ghostNoteTextColor READ ghostNoteTextColor WRITE setGhostNoteTextColor ) - Q_PROPERTY( QColor barColor READ barColor WRITE setBarColor ) - Q_PROPERTY( QColor selectedNoteColor READ selectedNoteColor WRITE setSelectedNoteColor ) - Q_PROPERTY( QColor textColor READ textColor WRITE setTextColor ) - Q_PROPERTY( QColor textColorLight READ textColorLight WRITE setTextColorLight ) - Q_PROPERTY( QColor textShadow READ textShadow WRITE setTextShadow ) - Q_PROPERTY( QColor markedSemitoneColor READ markedSemitoneColor WRITE setMarkedSemitoneColor ) - Q_PROPERTY( int noteOpacity READ noteOpacity WRITE setNoteOpacity ) - Q_PROPERTY( bool noteBorders READ noteBorders WRITE setNoteBorders ) - Q_PROPERTY( int ghostNoteOpacity READ ghostNoteOpacity WRITE setGhostNoteOpacity ) - Q_PROPERTY( bool ghostNoteBorders READ ghostNoteBorders WRITE setGhostNoteBorders ) - Q_PROPERTY( QColor backgroundShade READ backgroundShade WRITE setBackgroundShade ) + Q_PROPERTY(QColor barLineColor MEMBER m_barLineColor) + Q_PROPERTY(QColor beatLineColor MEMBER m_beatLineColor) + Q_PROPERTY(QColor lineColor MEMBER m_lineColor) + Q_PROPERTY(QColor noteModeColor MEMBER m_noteModeColor) + Q_PROPERTY(QColor noteColor MEMBER m_noteColor) + Q_PROPERTY(QColor ghostNoteColor MEMBER m_ghostNoteColor) + Q_PROPERTY(QColor noteTextColor MEMBER m_noteTextColor) + Q_PROPERTY(QColor ghostNoteTextColor MEMBER m_ghostNoteTextColor) + Q_PROPERTY(QColor barColor MEMBER m_barColor) + Q_PROPERTY(QColor selectedNoteColor MEMBER m_selectedNoteColor) + Q_PROPERTY(QColor textColor MEMBER m_textColor) + Q_PROPERTY(QColor textColorLight MEMBER m_textColorLight) + Q_PROPERTY(QColor textShadow MEMBER m_textShadow) + Q_PROPERTY(QColor markedSemitoneColor MEMBER m_markedSemitoneColor) + Q_PROPERTY(int noteOpacity MEMBER m_noteOpacity) + Q_PROPERTY(bool noteBorders MEMBER m_noteBorders) + Q_PROPERTY(int ghostNoteOpacity MEMBER m_ghostNoteOpacity) + Q_PROPERTY(bool ghostNoteBorders MEMBER m_ghostNoteBorders) + Q_PROPERTY(QColor backgroundShade MEMBER m_backgroundShade) + + /* white key properties */ + Q_PROPERTY(int whiteKeyWidth MEMBER m_whiteKeyWidth) + Q_PROPERTY(QColor whiteKeyInactiveTextColor MEMBER m_whiteKeyInactiveTextColor) + Q_PROPERTY(QColor whiteKeyInactiveTextShadow MEMBER m_whiteKeyInactiveTextShadow) + Q_PROPERTY(QBrush whiteKeyInactiveBackground MEMBER m_whiteKeyInactiveBackground) + Q_PROPERTY(QColor whiteKeyActiveTextColor MEMBER m_whiteKeyActiveTextColor) + Q_PROPERTY(QColor whiteKeyActiveTextShadow MEMBER m_whiteKeyActiveTextShadow) + Q_PROPERTY(QBrush whiteKeyActiveBackground MEMBER m_whiteKeyActiveBackground) + /* black key properties */ + Q_PROPERTY(int blackKeyWidth MEMBER m_blackKeyWidth) + Q_PROPERTY(QBrush blackKeyInactiveBackground MEMBER m_blackKeyInactiveBackground) + Q_PROPERTY(QBrush blackKeyActiveBackground MEMBER m_blackKeyActiveBackground) public: enum EditModes { @@ -125,47 +139,6 @@ class PianoRoll : public QWidget int quantization() const; - // qproperty access functions - QColor barLineColor() const; - void setBarLineColor( const QColor & c ); - QColor beatLineColor() const; - void setBeatLineColor( const QColor & c ); - QColor lineColor() const; - void setLineColor( const QColor & c ); - QColor noteModeColor() const; - void setNoteModeColor( const QColor & c ); - QColor noteColor() const; - void setNoteColor( const QColor & c ); - QColor noteTextColor() const; - void setNoteTextColor( const QColor & c ); - QColor barColor() const; - void setBarColor( const QColor & c ); - QColor selectedNoteColor() const; - void setSelectedNoteColor( const QColor & c ); - QColor textColor() const; - void setTextColor( const QColor & c ); - QColor textColorLight() const; - void setTextColorLight( const QColor & c ); - QColor textShadow() const; - void setTextShadow( const QColor & c ); - QColor markedSemitoneColor() const; - void setMarkedSemitoneColor( const QColor & c ); - int noteOpacity() const; - void setNoteOpacity( const int i ); - bool noteBorders() const; - void setNoteBorders( const bool b ); - QColor ghostNoteColor() const; - void setGhostNoteColor( const QColor & c ); - QColor ghostNoteTextColor() const; - void setGhostNoteTextColor( const QColor & c ); - int ghostNoteOpacity() const; - void setGhostNoteOpacity( const int i ); - bool ghostNoteBorders() const; - void setGhostNoteBorders( const bool b ); - QColor backgroundShade() const; - void setBackgroundShade( const QColor & c ); - - protected: void keyPressEvent( QKeyEvent * ke ) override; void keyReleaseEvent( QKeyEvent * ke ) override; @@ -178,6 +151,7 @@ class PianoRoll : public QWidget void resizeEvent( QResizeEvent * re ) override; void wheelEvent( QWheelEvent * we ) override; void focusOutEvent( QFocusEvent * ) override; + void focusInEvent( QFocusEvent * ) override; int getKey( int y ) const; void drawNoteRect( QPainter & p, int x, int y, @@ -185,9 +159,8 @@ class PianoRoll : public QWidget const QColor & selCol, const int noteOpc, const bool borderless, bool drawNoteName ); void removeSelection(); void selectAll(); - NoteVector getSelectedNotes(); + NoteVector getSelectedNotes() const; void selectNotesOnKey(); - int xCoordOfTick( int tick ); // for entering values with dblclick in the vol/pan bars void enterValue( NoteVector* nv ); @@ -212,28 +185,30 @@ protected slots: void copySelectedNotes(); void cutSelectedNotes(); void pasteNotes(); - void deleteSelectedNotes(); + bool deleteSelectedNotes(); - void updatePosition(const MidiTime & t ); - void updatePositionAccompany(const MidiTime & t ); - void updatePositionStepRecording(const MidiTime & t ); + void updatePosition(const TimePos & t ); + void updatePositionAccompany(const TimePos & t ); + void updatePositionStepRecording(const TimePos & t ); void zoomingChanged(); void zoomingYChanged(); void quantizeChanged(); void noteLengthChanged(); + void keyChanged(); void quantizeNotes(); void updateSemiToneMarkerMenu(); void changeNoteEditMode( int i ); - void markSemiTone( int i ); + void markSemiTone(int i, bool fromMenu = true); void hidePattern( Pattern* pattern ); void selectRegionFromPixels( int xStart, int xEnd ); void clearGhostPattern(); + void glueNotes(); signals: @@ -278,6 +253,8 @@ protected slots: PR_BLACK_KEY }; + PositionLine * m_positionLine; + QVector m_nemStr; // gui names of each edit mode QMenu * m_noteEditMenu; // when you right click below the key area @@ -289,12 +266,14 @@ protected slots: PianoRoll( const PianoRoll & ); virtual ~PianoRoll(); - void autoScroll(const MidiTime & t ); + void autoScroll(const TimePos & t ); - MidiTime newNoteLen() const; + TimePos newNoteLen() const; void shiftPos(int amount); + void shiftPos(NoteVector notes, int amount); void shiftSemiTone(int amount); + void shiftSemiTone(NoteVector notes, int amount); bool isSelection() const; int selectionCount() const; void testPlayNote( Note * n ); @@ -303,6 +282,9 @@ protected slots: void playChordNotes(int key, int velocity=-1); void pauseChordNotes(int key); + void updateScrollbars(); + void updatePositionLineHeight(); + QList getAllOctavesForKey( int keyToMirror ) const; int noteEditTop() const; @@ -317,12 +299,6 @@ protected slots: static const int cm_scrollAmtHoriz = 10; static const int cm_scrollAmtVert = 1; - static QPixmap * s_whiteKeyBigPm; - static QPixmap * s_whiteKeyBigPressedPm; - static QPixmap * s_whiteKeySmallPm; - static QPixmap * s_whiteKeySmallPressedPm; - static QPixmap * s_blackKeyPm; - static QPixmap * s_blackKeyPressedPm; static QPixmap * s_toolDraw; static QPixmap * s_toolErase; static QPixmap * s_toolSelect; @@ -337,6 +313,7 @@ protected slots: ComboBoxModel m_zoomingYModel; ComboBoxModel m_quantizeModel; ComboBoxModel m_noteLenModel; + ComboBoxModel m_keyModel; ComboBoxModel m_scaleModel; ComboBoxModel m_chordModel; @@ -354,7 +331,7 @@ protected slots: QScrollBar * m_leftRightScroll; QScrollBar * m_topBottomScroll; - MidiTime m_currentPosition; + TimePos m_currentPosition; bool m_recording; QList m_recordingNotes; @@ -386,10 +363,11 @@ protected slots: int m_moveStartX; int m_moveStartY; - int m_oldNotesEditHeight; int m_notesEditHeight; + int m_userSetNotesEditHeight; int m_ppb; // pixels per bar int m_totalKeysToScroll; + int m_pianoKeysVisible; int m_keyLineHeight; int m_octaveHeight; @@ -399,10 +377,13 @@ protected slots: // remember these values to use them // for the next note that is set - MidiTime m_lenOfNewNotes; + TimePos m_lenOfNewNotes; volume_t m_lastNoteVolume; panning_t m_lastNotePanning; + //When resizing several notes, we want to calculate a common minimum length + TimePos m_minResizeLen; + int m_startKey; // first key when drawing int m_lastKey; @@ -452,9 +433,21 @@ protected slots: bool m_noteBorders; bool m_ghostNoteBorders; QColor m_backgroundShade; + /* white key properties */ + int m_whiteKeyWidth; + QColor m_whiteKeyActiveTextColor; + QColor m_whiteKeyActiveTextShadow; + QBrush m_whiteKeyActiveBackground; + QColor m_whiteKeyInactiveTextColor; + QColor m_whiteKeyInactiveTextShadow; + QBrush m_whiteKeyInactiveBackground; + /* black key properties */ + int m_blackKeyWidth; + QBrush m_blackKeyActiveBackground; + QBrush m_blackKeyInactiveBackground; signals: - void positionChanged( const MidiTime & ); + void positionChanged( const TimePos & ); } ; @@ -495,6 +488,7 @@ class PianoRollWindow : public Editor, SerializingObject } QSize sizeHint() const override; + bool hasFocus() const; signals: void currentPatternChanged(); @@ -516,6 +510,7 @@ private slots: ComboBox * m_zoomingYComboBox; ComboBox * m_quantizeComboBox; ComboBox * m_noteLenComboBox; + ComboBox * m_keyComboBox; ComboBox * m_scaleComboBox; ComboBox * m_chordComboBox; QPushButton * m_clearGhostButton; diff --git a/include/PianoView.h b/include/PianoView.h index b793ee76813..2f2fea2c935 100644 --- a/include/PianoView.h +++ b/include/PianoView.h @@ -56,6 +56,7 @@ class PianoView : public QWidget, public ModelView void mouseReleaseEvent( QMouseEvent * me ) override; void mouseMoveEvent( QMouseEvent * me ) override; void focusOutEvent( QFocusEvent * _fe ) override; + void focusInEvent( QFocusEvent * fe ) override; void resizeEvent( QResizeEvent * _event ) override; diff --git a/include/PluginBrowser.h b/include/PluginBrowser.h index 3cc54c6e47a..fa13f246916 100644 --- a/include/PluginBrowser.h +++ b/include/PluginBrowser.h @@ -33,7 +33,6 @@ class QLineEdit; class QTreeWidget; -class QTreeWidgetItem; class PluginBrowser : public SideBarWidget @@ -53,8 +52,6 @@ private slots: QWidget * m_view; QTreeWidget * m_descTree; - QTreeWidgetItem * m_lmmsRoot; - QTreeWidgetItem * m_lv2Root; }; diff --git a/include/PluginIssue.h b/include/PluginIssue.h index c009458056e..8bfad5bf10f 100644 --- a/include/PluginIssue.h +++ b/include/PluginIssue.h @@ -32,16 +32,29 @@ //! LMMS Plugins should use this to indicate errors enum PluginIssueType { + // port flow & type unknownPortFlow, unknownPortType, + // channel count tooManyInputChannels, tooManyOutputChannels, + tooManyMidiInputChannels, + tooManyMidiOutputChannels, noOutputChannel, + // port metadata portHasNoDef, portHasNoMin, portHasNoMax, + minGreaterMax, + defaultValueNotInRange, + logScaleMinMissing, + logScaleMaxMissing, + logScaleMinMaxDifferentSigns, + // features featureNotSupported, //!< plugin requires functionality LMMS can't offer + // misc badPortType, //!< port type not supported + blacklisted, noIssue }; @@ -58,6 +71,9 @@ class PluginIssue : m_issueType(it), m_info(msg) { } + PluginIssueType type() const { return m_issueType; } + bool operator==(const PluginIssue& other) const; + bool operator<(const PluginIssue& other) const; friend QDebug operator<<(QDebug stream, const PluginIssue& iss); }; diff --git a/include/PositionLine.h b/include/PositionLine.h new file mode 100644 index 00000000000..d48fd3df1cb --- /dev/null +++ b/include/PositionLine.h @@ -0,0 +1,49 @@ +/* + * PositionLine.h - declaration of class PositionLine, a simple widget that + * draws a line, mainly works with TimeLineWidget + * + * Copyright (c) 2004-2014 Tobias Doerffel + * + * 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 POSITION_LINE_H +#define POSITION_LINE_H + +#include + +class PositionLine : public QWidget +{ + Q_OBJECT + Q_PROPERTY(bool tailGradient MEMBER m_hasTailGradient) + Q_PROPERTY(QColor lineColor MEMBER m_lineColor) +public: + PositionLine(QWidget* parent); + +public slots: + void zoomChange(double zoom); + +private: + void paintEvent(QPaintEvent* pe) override; + + bool m_hasTailGradient; + QColor m_lineColor; +}; + +#endif \ No newline at end of file diff --git a/include/PresetPreviewPlayHandle.h b/include/PresetPreviewPlayHandle.h index a95b680abb1..fcdecf6b8bb 100644 --- a/include/PresetPreviewPlayHandle.h +++ b/include/PresetPreviewPlayHandle.h @@ -29,6 +29,7 @@ #include "NotePlayHandle.h" +class DataFile; class InstrumentTrack; class PreviewTrackContainer; diff --git a/include/ProjectVersion.h b/include/ProjectVersion.h index 439bdffbdff..00a639459dd 100644 --- a/include/ProjectVersion.h +++ b/include/ProjectVersion.h @@ -28,6 +28,9 @@ #define PROJECT_VERSION_H #include +#include + +#include #include "lmms_export.h" /*! \brief Version number parsing and comparison @@ -37,16 +40,17 @@ class LMMS_EXPORT ProjectVersion { public: - enum CompareType { Major, Minor, Release, Stage, Build }; + enum CompareType : int { None = 0, Major=1, Minor=2, Release=3, Stage=4, Build=5, All = std::numeric_limits::max() }; + - ProjectVersion(QString version, CompareType c = Build); - ProjectVersion(const char * version, CompareType c = Build); + ProjectVersion(QString version, CompareType c = All); + ProjectVersion(const char * version, CompareType c = All); + const QString& getVersion() const { return m_version; } int getMajor() const { return m_major; } int getMinor() const { return m_minor; } - int getRelease() const { return m_release; } - QString getStage() const { return m_stage; } - int getBuild() const { return m_build; } + int getPatch() const { return m_patch; } + const QStringList& getLabels() const { return m_labels; } CompareType getCompareType() const { return m_compareType; } ProjectVersion setCompareType(CompareType compareType) { m_compareType = compareType; return * this; } @@ -55,11 +59,10 @@ class LMMS_EXPORT ProjectVersion private: QString m_version; - int m_major; - int m_minor; - int m_release; - QString m_stage; - int m_build; + int m_major = 0; + int m_minor = 0; + int m_patch = 0; + QStringList m_labels; CompareType m_compareType; } ; diff --git a/include/SampleBuffer.h b/include/SampleBuffer.h index 4eae226fd77..6785e0a9092 100644 --- a/include/SampleBuffer.h +++ b/include/SampleBuffer.h @@ -62,7 +62,7 @@ class LMMS_EXPORT SampleBuffer : public QObject, public sharedObject { MM_OPERATORS public: - handleState( bool _varying_pitch = false, int interpolation_mode = SRC_LINEAR ); + handleState(bool varyingPitch = false, int interpolationMode = SRC_LINEAR); virtual ~handleState(); const f_cnt_t frameIndex() const @@ -70,9 +70,9 @@ class LMMS_EXPORT SampleBuffer : public QObject, public sharedObject return m_frameIndex; } - void setFrameIndex( f_cnt_t _index ) + void setFrameIndex(f_cnt_t index) { - m_frameIndex = _index; + m_frameIndex = index; } bool isBackwards() const @@ -80,11 +80,11 @@ class LMMS_EXPORT SampleBuffer : public QObject, public sharedObject return m_isBackwards; } - void setBackwards( bool _backwards ) + void setBackwards(bool backwards) { - m_isBackwards = _backwards; + m_isBackwards = backwards; } - + int interpolationMode() const { return m_interpolationMode; @@ -106,21 +106,35 @@ class LMMS_EXPORT SampleBuffer : public QObject, public sharedObject SampleBuffer(); // constructor which either loads sample _audio_file or decodes // base64-data out of string - SampleBuffer( const QString & _audio_file, bool _is_base64_data = false ); - SampleBuffer( const sampleFrame * _data, const f_cnt_t _frames ); - explicit SampleBuffer( const f_cnt_t _frames ); + SampleBuffer(const QString & audioFile, bool isBase64Data = false); + SampleBuffer(const sampleFrame * data, const f_cnt_t frames); + explicit SampleBuffer(const f_cnt_t frames); virtual ~SampleBuffer(); - bool play( sampleFrame * _ab, handleState * _state, - const fpp_t _frames, - const float _freq, - const LoopMode _loopmode = LoopOff ); - - void visualize( QPainter & _p, const QRect & _dr, const QRect & _clip, f_cnt_t _from_frame = 0, f_cnt_t _to_frame = 0 ); - inline void visualize( QPainter & _p, const QRect & _dr, f_cnt_t _from_frame = 0, f_cnt_t _to_frame = 0 ) + bool play( + sampleFrame * ab, + handleState * state, + const fpp_t frames, + const float freq, + const LoopMode loopMode = LoopOff + ); + + void visualize( + QPainter & p, + const QRect & dr, + const QRect & clip, + f_cnt_t fromFrame = 0, + f_cnt_t toFrame = 0 + ); + inline void visualize( + QPainter & p, + const QRect & dr, + f_cnt_t fromFrame = 0, + f_cnt_t toFrame = 0 + ) { - visualize( _p, _dr, _dr, _from_frame, _to_frame ); + visualize(p, dr, dr, fromFrame, toFrame); } inline const QString & audioFile() const @@ -148,22 +162,27 @@ class LMMS_EXPORT SampleBuffer : public QObject, public sharedObject return m_loopEndFrame; } - void setLoopStartFrame( f_cnt_t _start ) + void setLoopStartFrame(f_cnt_t start) { - m_loopStartFrame = _start; + m_loopStartFrame = start; } - void setLoopEndFrame( f_cnt_t _end ) + void setLoopEndFrame(f_cnt_t end) { - m_loopEndFrame = _end; + m_loopEndFrame = end; } - void setAllPointFrames( f_cnt_t _start, f_cnt_t _end, f_cnt_t _loopstart, f_cnt_t _loopend ) + void setAllPointFrames( + f_cnt_t start, + f_cnt_t end, + f_cnt_t loopStart, + f_cnt_t loopEnd + ) { - m_startFrame = _start; - m_endFrame = _end; - m_loopStartFrame = _loopstart; - m_loopEndFrame = _loopend; + m_startFrame = start; + m_endFrame = end; + m_loopStartFrame = loopStart; + m_loopEndFrame = loopEnd; } inline f_cnt_t frames() const @@ -193,17 +212,17 @@ class LMMS_EXPORT SampleBuffer : public QObject, public sharedObject int sampleLength() const { - return double( m_endFrame - m_startFrame ) / m_sampleRate * 1000; + return double(m_endFrame - m_startFrame) / m_sampleRate * 1000; } - inline void setFrequency( float _freq ) + inline void setFrequency(float freq) { - m_frequency = _freq; + m_frequency = freq; } - inline void setSampleRate( sample_rate_t _rate ) + inline void setSampleRate(sample_rate_t rate) { - m_sampleRate = _rate; + m_sampleRate = rate; } inline const sampleFrame * data() const @@ -215,30 +234,28 @@ class LMMS_EXPORT SampleBuffer : public QObject, public sharedObject QString openAndSetAudioFile(); QString openAndSetWaveformFile(); - QString & toBase64( QString & _dst ) const; + QString & toBase64(QString & dst) const; // protect calls from the GUI to this function with dataReadLock() and // dataUnlock() - SampleBuffer * resample( const sample_rate_t _src_sr, - const sample_rate_t _dst_sr ); + SampleBuffer * resample(const sample_rate_t srcSR, const sample_rate_t dstSR); - void normalizeSampleRate( const sample_rate_t _src_sr, - bool _keep_settings = false ); + void normalizeSampleRate(const sample_rate_t srcSR, bool keepSettings = false); // protect calls from the GUI to this function with dataReadLock() and // dataUnlock(), out of loops for efficiency - inline sample_t userWaveSample( const float _sample ) const + inline sample_t userWaveSample(const float sample) const { f_cnt_t frames = m_frames; sampleFrame * data = m_data; - const float frame = _sample * frames; - f_cnt_t f1 = static_cast( frame ) % frames; - if( f1 < 0 ) + const float frame = sample * frames; + f_cnt_t f1 = static_cast(frame) % frames; + if (f1 < 0) { f1 += frames; } - return linearInterpolate( data[f1][0], data[ (f1 + 1) % frames ][0], fraction( frame ) ); + return linearInterpolate(data[f1][0], data[(f1 + 1) % frames][0], fraction(frame)); } void dataReadLock() @@ -251,38 +268,44 @@ class LMMS_EXPORT SampleBuffer : public QObject, public sharedObject m_varLock.unlock(); } - static QString tryToMakeRelative( const QString & _file ); - static QString tryToMakeAbsolute(const QString & file); - public slots: - void setAudioFile( const QString & _audio_file ); - void loadFromBase64( const QString & _data ); - void setStartFrame( const f_cnt_t _s ); - void setEndFrame( const f_cnt_t _e ); - void setAmplification( float _a ); - void setReversed( bool _on ); + void setAudioFile(const QString & audioFile); + void loadFromBase64(const QString & data); + void setStartFrame(const f_cnt_t s); + void setEndFrame(const f_cnt_t e); + void setAmplification(float a); + void setReversed(bool on); void sampleRateChanged(); private: static sample_rate_t mixerSampleRate(); - void update( bool _keep_settings = false ); + void update(bool keepSettings = false); - void convertIntToFloat ( int_sample_t * & _ibuf, f_cnt_t _frames, int _channels); - void directFloatWrite ( sample_t * & _fbuf, f_cnt_t _frames, int _channels); + void convertIntToFloat(int_sample_t * & ibuf, f_cnt_t frames, int channels); + void directFloatWrite(sample_t * & fbuf, f_cnt_t frames, int channels); - f_cnt_t decodeSampleSF( QString _f, sample_t * & _buf, - ch_cnt_t & _channels, - sample_rate_t & _sample_rate ); + f_cnt_t decodeSampleSF( + QString fileName, + sample_t * & buf, + ch_cnt_t & channels, + sample_rate_t & samplerate + ); #ifdef LMMS_HAVE_OGGVORBIS - f_cnt_t decodeSampleOGGVorbis( QString _f, int_sample_t * & _buf, - ch_cnt_t & _channels, - sample_rate_t & _sample_rate ); + f_cnt_t decodeSampleOGGVorbis( + QString fileName, + int_sample_t * & buf, + ch_cnt_t & channels, + sample_rate_t & samplerate + ); #endif - f_cnt_t decodeSampleDS( QString _f, int_sample_t * & _buf, - ch_cnt_t & _channels, - sample_rate_t & _sample_rate ); + f_cnt_t decodeSampleDS( + QString fileName, + int_sample_t * & buf, + ch_cnt_t & channels, + sample_rate_t & samplerate + ); QString m_audioFile; sampleFrame * m_origData; @@ -299,13 +322,19 @@ public slots: float m_frequency; sample_rate_t m_sampleRate; - sampleFrame * getSampleFragment( f_cnt_t _index, f_cnt_t _frames, - LoopMode _loopmode, - sampleFrame * * _tmp, - bool * _backwards, f_cnt_t _loopstart, f_cnt_t _loopend, - f_cnt_t _end ) const; - f_cnt_t getLoopedIndex( f_cnt_t _index, f_cnt_t _startf, f_cnt_t _endf ) const; - f_cnt_t getPingPongIndex( f_cnt_t _index, f_cnt_t _startf, f_cnt_t _endf ) const; + sampleFrame * getSampleFragment( + f_cnt_t index, + f_cnt_t frames, + LoopMode loopMode, + sampleFrame * * tmp, + bool * backwards, + f_cnt_t loopStart, + f_cnt_t loopEnd, + f_cnt_t end + ) const; + + f_cnt_t getLoopedIndex(f_cnt_t index, f_cnt_t startf, f_cnt_t endf) const; + f_cnt_t getPingPongIndex(f_cnt_t index, f_cnt_t startf, f_cnt_t endf) const; signals: diff --git a/include/SampleRecordHandle.h b/include/SampleRecordHandle.h index fc40d062295..f2a6fd63be4 100644 --- a/include/SampleRecordHandle.h +++ b/include/SampleRecordHandle.h @@ -29,8 +29,8 @@ #include #include -#include "MidiTime.h" #include "PlayHandle.h" +#include "TimePos.h" class BBTrack; class SampleBuffer; @@ -60,7 +60,7 @@ class SampleRecordHandle : public PlayHandle typedef QList > bufferList; bufferList m_buffers; f_cnt_t m_framesRecorded; - MidiTime m_minLength; + TimePos m_minLength; Track * m_track; BBTrack * m_bbTrack; diff --git a/include/SampleTrack.h b/include/SampleTrack.h index 47cc0df3945..fab98e948d7 100644 --- a/include/SampleTrack.h +++ b/include/SampleTrack.h @@ -33,6 +33,8 @@ #include "FxMixer.h" #include "FxLineLcdSpinBox.h" #include "Track.h" +#include "TrackContentObjectView.h" +#include "TrackView.h" class EffectRackView; class Knob; @@ -50,7 +52,7 @@ class SampleTCO : public TrackContentObject SampleTCO( Track * _track ); virtual ~SampleTCO(); - void changeLength( const MidiTime & _length ) override; + void changeLength( const TimePos & _length ) override; const QString & sampleFile() const; void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; @@ -65,7 +67,7 @@ class SampleTCO : public TrackContentObject return m_sampleBuffer; } - MidiTime sampleLength() const; + TimePos sampleLength() const; void setSampleStartFrame( f_cnt_t startFrame ); void setSamplePlayLength( f_cnt_t length ); TrackContentObjectView * createView( TrackView * _tv ) override; @@ -94,6 +96,7 @@ public slots: signals: void sampleChanged(); + void wasReversed(); } ; @@ -109,6 +112,7 @@ class SampleTCOView : public TrackContentObjectView public slots: void updateSample(); + void reverseSample(); @@ -137,10 +141,10 @@ class SampleTrack : public Track SampleTrack( TrackContainer* tc ); virtual ~SampleTrack(); - virtual bool play( const MidiTime & _start, const fpp_t _frames, + virtual bool play( const TimePos & _start, const fpp_t _frames, const f_cnt_t _frame_base, int _tco_num = -1 ) override; TrackView * createView( TrackContainerView* tcv ) override; - TrackContentObject * createTCO( const MidiTime & _pos ) override; + TrackContentObject* createTCO(const TimePos & pos) override; virtual void saveTrackSpecificSettings( QDomDocument & _doc, @@ -251,7 +255,7 @@ private slots: TrackLabelButton * m_tlb; - FadeButton * getActivityIndicator() + FadeButton * getActivityIndicator() override { return m_activityIndicator; } diff --git a/include/SetupDialog.h b/include/SetupDialog.h index 80a22d69c35..931708b6a0b 100644 --- a/include/SetupDialog.h +++ b/include/SetupDialog.h @@ -75,6 +75,8 @@ private slots: void toggleCompactTrackButtons(bool enabled); void toggleOneInstrumentTrackWindow(bool enabled); void toggleSideBarOnRight(bool enabled); + void toggleLetPreviewsFinish(bool enabled); + void toggleSoloLegacyBehavior(bool enabled); void toggleMMPZ(bool enabled); void toggleDisableBackup(bool enabled); void toggleOpenLastProject(bool enabled); @@ -132,6 +134,8 @@ private slots: bool m_compactTrackButtons; bool m_oneInstrumentTrackWindow; bool m_sideBarOnRight; + bool m_letPreviewsFinish; + bool m_soloLegacyBehavior; bool m_MMPZ; bool m_disableBackup; bool m_openLastProject; @@ -175,6 +179,7 @@ private slots: QComboBox * m_midiInterfaces; MswMap m_midiIfaceSetupWidgets; trMap m_midiIfaceNames; + QComboBox * m_assignableMidiDevices; // Paths settings widgets. QString m_workingDir; diff --git a/include/Song.h b/include/Song.h index d398a168cdc..c15fed57cd2 100644 --- a/include/Song.h +++ b/include/Song.h @@ -29,6 +29,8 @@ #include #include +#include +#include #include "TrackContainer.h" #include "Controller.h" @@ -81,11 +83,11 @@ class LMMS_EXPORT Song : public TrackContainer bool hasErrors(); QString errorSummary(); - class PlayPos : public MidiTime + class PlayPos : public TimePos { public: PlayPos( const int abs = 0 ) : - MidiTime( abs ), + TimePos( abs ), m_timeLine( NULL ), m_currentFrame( 0.0f ) { @@ -131,27 +133,27 @@ class LMMS_EXPORT Song : public TrackContainer return m_elapsedMilliSeconds[playMode]; } - inline void setToTime(MidiTime const & midiTime) + inline void setToTime(TimePos const & pos) { - m_elapsedMilliSeconds[m_playMode] = midiTime.getTimeInMilliseconds(getTempo()); - m_playPos[m_playMode].setTicks(midiTime.getTicks()); + m_elapsedMilliSeconds[m_playMode] = pos.getTimeInMilliseconds(getTempo()); + m_playPos[m_playMode].setTicks(pos.getTicks()); } - inline void setToTime(MidiTime const & midiTime, PlayModes playMode) + inline void setToTime(TimePos const & pos, PlayModes playMode) { - m_elapsedMilliSeconds[playMode] = midiTime.getTimeInMilliseconds(getTempo()); - m_playPos[playMode].setTicks(midiTime.getTicks()); + m_elapsedMilliSeconds[playMode] = pos.getTimeInMilliseconds(getTempo()); + m_playPos[playMode].setTicks(pos.getTicks()); } inline void setToTimeByTicks(tick_t ticks) { - m_elapsedMilliSeconds[m_playMode] = MidiTime::ticksToMilliseconds(ticks, getTempo()); + m_elapsedMilliSeconds[m_playMode] = TimePos::ticksToMilliseconds(ticks, getTempo()); m_playPos[m_playMode].setTicks(ticks); } inline void setToTimeByTicks(tick_t ticks, PlayModes playMode) { - m_elapsedMilliSeconds[playMode] = MidiTime::ticksToMilliseconds(ticks, getTempo()); + m_elapsedMilliSeconds[playMode] = TimePos::ticksToMilliseconds(ticks, getTempo()); m_playPos[playMode].setTicks(ticks); } @@ -162,7 +164,7 @@ class LMMS_EXPORT Song : public TrackContainer inline int ticksPerBar() const { - return MidiTime::ticksPerBar(m_timeSigModel); + return TimePos::ticksPerBar(m_timeSigModel); } // Returns the beat position inside the bar, 0-based @@ -248,6 +250,10 @@ class LMMS_EXPORT Song : public TrackContainer { return m_playPos[pm]; } + inline PlayPos & getPlayPos() + { + return getPlayPos(m_playMode); + } inline const PlayPos & getPlayPos() const { return getPlayPos(m_playMode); @@ -269,7 +275,7 @@ class LMMS_EXPORT Song : public TrackContainer } //TODO: Add Q_DECL_OVERRIDE when Qt4 is dropped - AutomatedValueMap automatedValuesAt(MidiTime time, int tcoNum = -1) const override; + AutomatedValueMap automatedValuesAt(TimePos time, int tcoNum = -1) const override; // file management void createNewProject(); @@ -405,7 +411,7 @@ private slots: void removeAllControllers(); - void processAutomations(const TrackList& tracks, MidiTime timeStart, fpp_t frames); + void processAutomations(const TrackList& tracks, TimePos timeStart, fpp_t frames); void setModified(bool value); @@ -441,7 +447,7 @@ private slots: SaveOptions m_saveOptions; - QStringList m_errors; + QHash m_errors; PlayModes m_playMode; PlayPos m_playPos[Mode_Count]; @@ -458,11 +464,11 @@ private slots: int m_loopRenderCount; int m_loopRenderRemaining; - MidiTime m_exportSongBegin; - MidiTime m_exportLoopBegin; - MidiTime m_exportLoopEnd; - MidiTime m_exportSongEnd; - MidiTime m_exportEffectiveLength; + TimePos m_exportSongBegin; + TimePos m_exportLoopBegin; + TimePos m_exportLoopEnd; + TimePos m_exportSongEnd; + TimePos m_exportEffectiveLength; friend class LmmsCore; friend class SongEditor; diff --git a/include/SongEditor.h b/include/SongEditor.h index 9621bcc23d8..8d279c594a5 100644 --- a/include/SongEditor.h +++ b/include/SongEditor.h @@ -28,10 +28,12 @@ #define SONG_EDITOR_H #include +#include #include "ActionGroup.h" #include "Editor.h" #include "TrackContainerView.h" +#include "PositionLine.h" class QLabel; class QScrollBar; @@ -45,16 +47,6 @@ class Song; class TextFloat; class TimeLineWidget; -class positionLine : public QWidget -{ -public: - positionLine( QWidget * parent ); - -private: - void paintEvent( QPaintEvent * pe ) override; - -} ; - class SongEditor : public TrackContainerView { @@ -88,7 +80,7 @@ public slots: void setEditModeSelect(); void toggleProportionalSnap(); - void updatePosition( const MidiTime & t ); + void updatePosition( const TimePos & t ); void updatePositionLine(); void selectAllTcos( bool select ); @@ -140,7 +132,7 @@ private slots: TextFloat * m_mvsStatus; TextFloat * m_mpsStatus; - positionLine * m_positionLine; + PositionLine * m_positionLine; ComboBoxModel* m_zoomingModel; ComboBoxModel* m_snappingModel; @@ -158,12 +150,15 @@ private slots: QPoint m_scrollPos; QPoint m_mousePos; int m_rubberBandStartTrackview; - MidiTime m_rubberbandStartMidipos; + TimePos m_rubberbandStartTimePos; int m_currentZoomingValue; int m_trackHeadWidth; bool m_selectRegion; friend class SongEditorWindow; + +signals: + void zoomingValueChanged( double ); } ; @@ -215,6 +210,9 @@ protected slots: ComboBox * m_zoomingComboBox; ComboBox * m_snappingComboBox; QLabel* m_snapSizeLabel; + + QAction* m_insertBarAction; + QAction* m_removeBarAction; }; #endif diff --git a/include/StepRecorder.h b/include/StepRecorder.h index b9653b1bbea..13b3577a86c 100644 --- a/include/StepRecorder.h +++ b/include/StepRecorder.h @@ -21,7 +21,7 @@ #ifndef STEP_RECORDER_H #define STEP_RECORDER_H -#include +#include #include #include #include @@ -41,14 +41,14 @@ class StepRecorder : public QObject StepRecorder(PianoRoll& pianoRoll, StepRecorderWidget& stepRecorderWidget); void initialize(); - void start(const MidiTime& currentPosition,const MidiTime& stepLength); + void start(const TimePos& currentPosition,const TimePos& stepLength); void stop(); void notePressed(const Note & n); void noteReleased(const Note & n); bool keyPressEvent(QKeyEvent* ke); bool mousePressEvent(QMouseEvent* ke); void setCurrentPattern(Pattern* newPattern); - void setStepsLength(const MidiTime& newLength); + void setStepsLength(const TimePos& newLength); QVector getCurStepNotes(); @@ -73,7 +73,7 @@ class StepRecorder : public QObject void dismissStep(); void prepareNewStep(); - MidiTime getCurStepEndPos(); + TimePos getCurStepEndPos(); void updateCurStepNotes(); void updateWidget(); @@ -84,11 +84,11 @@ class StepRecorder : public QObject StepRecorderWidget& m_stepRecorderWidget; bool m_isRecording = false; - MidiTime m_curStepStartPos = 0; - MidiTime m_curStepEndPos = 0; + TimePos m_curStepStartPos = 0; + TimePos m_curStepEndPos = 0; - MidiTime m_stepsLength; - MidiTime m_curStepLength; // current step length refers to the step currently recorded. it may defer from m_stepsLength + TimePos m_stepsLength; + TimePos m_curStepLength; // current step length refers to the step currently recorded. it may defer from m_stepsLength // since the user can make current step larger QTimer m_updateReleasedTimer; @@ -130,7 +130,7 @@ class StepRecorder : public QObject private: bool m_pressed; - QTime releasedTimer; + QElapsedTimer releasedTimer; } ; QVector m_curStepNotes; // contains the current recorded step notes (i.e. while user still press the notes; before they are applied to the pattern) @@ -140,4 +140,4 @@ class StepRecorder : public QObject bool m_isStepInProgress = false; }; -#endif //STEP_RECORDER_H \ No newline at end of file +#endif //STEP_RECORDER_H diff --git a/include/StepRecorderWidget.h b/include/StepRecorderWidget.h index 14cfc2eedce..dfaeaed0aa6 100644 --- a/include/StepRecorderWidget.h +++ b/include/StepRecorderWidget.h @@ -44,13 +44,15 @@ class StepRecorderWidget : public QWidget //API used by PianoRoll void setPixelsPerBar(int ppb); - void setCurrentPosition(MidiTime currentPosition); + void setCurrentPosition(TimePos currentPosition); + void setMargins(const QMargins &qm); void setBottomMargin(const int marginBottom); + QMargins margins(); //API used by StepRecorder - void setStepsLength(MidiTime stepsLength); - void setStartPosition(MidiTime pos); - void setEndPosition(MidiTime pos); + void setStepsLength(TimePos stepsLength); + void setStartPosition(TimePos pos); + void setEndPosition(TimePos pos); void showHint(); @@ -60,16 +62,16 @@ class StepRecorderWidget : public QWidget int xCoordOfTick(int tick); void drawVerLine(QPainter* painter, int x, const QColor& color, int top, int bottom); - void drawVerLine(QPainter* painter, const MidiTime& pos, const QColor& color, int top, int bottom); + void drawVerLine(QPainter* painter, const TimePos& pos, const QColor& color, int top, int bottom); void updateBoundaries(); - MidiTime m_stepsLength; - MidiTime m_curStepStartPos; - MidiTime m_curStepEndPos; + TimePos m_stepsLength; + TimePos m_curStepStartPos; + TimePos m_curStepEndPos; int m_ppb; // pixels per bar - MidiTime m_currentPosition; // current position showed by on PianoRoll + TimePos m_currentPosition; // current position showed by on PianoRoll QColor m_colorLineStart; QColor m_colorLineEnd; @@ -86,7 +88,7 @@ class StepRecorderWidget : public QWidget const int m_marginRight; signals: - void positionChanged(const MidiTime & t); + void positionChanged(const TimePos & t); } ; #endif //STEP_RECOREDER_WIDGET_H diff --git a/include/StringPairDrag.h b/include/StringPairDrag.h index cebc3089a15..969a12eec4e 100644 --- a/include/StringPairDrag.h +++ b/include/StringPairDrag.h @@ -45,16 +45,8 @@ class LMMS_EXPORT StringPairDrag : public QDrag static bool processDragEnterEvent( QDragEnterEvent * _dee, const QString & _allowed_keys ); - static QString decodeMimeKey( const QMimeData * mimeData ); - static QString decodeMimeValue( const QMimeData * mimeData ); static QString decodeKey( QDropEvent * _de ); static QString decodeValue( QDropEvent * _de ); - - static const char * mimeType() - { - return( "application/x-lmms-stringpair" ); - } - } ; diff --git a/include/SubWindow.h b/include/SubWindow.h index 148cf2c9997..55d05425ab8 100644 --- a/include/SubWindow.h +++ b/include/SubWindow.h @@ -55,7 +55,7 @@ class LMMS_EXPORT SubWindow : public QMdiSubWindow Q_PROPERTY( QColor borderColor READ borderColor WRITE setBorderColor ) public: - SubWindow( QWidget *parent = NULL, Qt::WindowFlags windowFlags = 0 ); + SubWindow( QWidget *parent = NULL, Qt::WindowFlags windowFlags = QFlag(0) ); // same as QWidet::normalGeometry, but works properly under X11 (see https://bugreports.qt.io/browse/QTBUG-256) QRect getTrueNormalGeometry() const; QBrush activeColor() const; diff --git a/include/TimeLineWidget.h b/include/TimeLineWidget.h index bc0881f82ee..c7ac0124c9e 100644 --- a/include/TimeLineWidget.h +++ b/include/TimeLineWidget.h @@ -73,7 +73,7 @@ class TimeLineWidget : public QWidget, public JournallingObject TimeLineWidget(int xoff, int yoff, float ppb, Song::PlayPos & pos, - const MidiTime & begin, Song::PlayModes mode, QWidget * parent); + const TimePos & begin, Song::PlayModes mode, QWidget * parent); virtual ~TimeLineWidget(); inline QColor const & getBarLineColor() const { return m_barLineColor; } @@ -123,23 +123,23 @@ class TimeLineWidget : public QWidget, public JournallingObject return m_loopPoints == LoopPointsEnabled; } - inline const MidiTime & loopBegin() const + inline const TimePos & loopBegin() const { return ( m_loopPos[0] < m_loopPos[1] ) ? m_loopPos[0] : m_loopPos[1]; } - inline const MidiTime & loopEnd() const + inline const TimePos & loopEnd() const { return ( m_loopPos[0] > m_loopPos[1] ) ? m_loopPos[0] : m_loopPos[1]; } - inline void savePos( const MidiTime & pos ) + inline void savePos( const TimePos & pos ) { m_savedPos = pos; } - inline const MidiTime & savedPos() const + inline const TimePos & savedPos() const { return m_savedPos; } @@ -150,6 +150,8 @@ class TimeLineWidget : public QWidget, public JournallingObject update(); } + void setXOffset(const int x); + void addToolButtons(QToolBar* _tool_bar ); @@ -160,10 +162,10 @@ class TimeLineWidget : public QWidget, public JournallingObject return "timeline"; } - inline int markerX( const MidiTime & _t ) const + inline int markerX( const TimePos & _t ) const { return m_xOffset + static_cast( ( _t - m_begin ) * - m_ppb / MidiTime::ticksPerBar() ); + m_ppb / TimePos::ticksPerBar() ); } signals: @@ -173,10 +175,10 @@ class TimeLineWidget : public QWidget, public JournallingObject public slots: - void updatePosition( const MidiTime & ); + void updatePosition( const TimePos & ); void updatePosition() { - updatePosition( MidiTime() ); + updatePosition( TimePos() ); } void toggleAutoScroll( int _n ); void toggleLoopPoints( int _n ); @@ -216,11 +218,11 @@ public slots: int m_posMarkerX; float m_ppb; Song::PlayPos & m_pos; - const MidiTime & m_begin; + const TimePos & m_begin; const Song::PlayModes m_mode; - MidiTime m_loopPos[2]; + TimePos m_loopPos[2]; - MidiTime m_savedPos; + TimePos m_savedPos; TextFloat * m_hint; @@ -240,9 +242,10 @@ public slots: signals: - void positionChanged( const MidiTime & _t ); + void positionChanged( const TimePos & _t ); void loopPointStateLoaded( int _n ); void positionMarkerMoved(); + void loadBehaviourAtStop( int _n ); } ; diff --git a/include/MidiTime.h b/include/TimePos.h similarity index 74% rename from include/MidiTime.h rename to include/TimePos.h index 952b4b6d596..675416c4299 100644 --- a/include/MidiTime.h +++ b/include/TimePos.h @@ -1,6 +1,6 @@ /* - * MidiTime.h - declaration of class MidiTime which provides data type for - * position- and length-variables + * TimePos.h - declaration of class TimePos which provides data type for + * position- and length-variables * * Copyright (c) 2004-2014 Tobias Doerffel @@ -40,13 +40,15 @@ const int DefaultBeatsPerBar = DefaultTicksPerBar / DefaultStepsPerBar; class MeterModel; +/** + Represents a time signature, in which the numerator is the number of beats + in a bar, while the denominator is the type of note representing a beat. + + Example: 6/8 means 6 beats in a bar with each beat having a duration of one 8th-note. +*/ class LMMS_EXPORT TimeSig { public: - // in a time signature, - // the numerator represents the number of beats in a measure. - // the denominator indicates which type of note represents a beat. - // example: 6/8 means 6 beats in a measure, where each beat has duration equal to one 8th-note. TimeSig( int num, int denom ); TimeSig( const MeterModel &model ); int numerator() const; @@ -57,17 +59,20 @@ class LMMS_EXPORT TimeSig }; -class LMMS_EXPORT MidiTime +/** + Represents a position in time or length of a note or event, in ticks, beats, and bars +*/ +class LMMS_EXPORT TimePos { public: - MidiTime( const bar_t bar, const tick_t ticks ); - MidiTime( const tick_t ticks = 0 ); + TimePos( const bar_t bar, const tick_t ticks ); + TimePos( const tick_t ticks = 0 ); - MidiTime quantize(float) const; - MidiTime toAbsoluteBar() const; + TimePos quantize(float) const; + TimePos toAbsoluteBar() const; - MidiTime& operator+=( const MidiTime& time ); - MidiTime& operator-=( const MidiTime& time ); + TimePos& operator+=( const TimePos& time ); + TimePos& operator-=( const TimePos& time ); // return the bar, rounded down and 0-based bar_t getBar() const; @@ -92,12 +97,12 @@ class LMMS_EXPORT MidiTime double getTimeInMilliseconds( bpm_t beatsPerMinute ) const; - static MidiTime fromFrames( const f_cnt_t frames, const float framesPerTick ); + static TimePos fromFrames( const f_cnt_t frames, const float framesPerTick ); 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 TimePos stepPosition( int step ); static double ticksToMilliseconds( tick_t ticks, bpm_t beatsPerMinute ); static double ticksToMilliseconds( double ticks, bpm_t beatsPerMinute ); diff --git a/include/Track.h b/include/Track.h index 07cee8ffd6b..9ddd34f4fc6 100644 --- a/include/Track.h +++ b/include/Track.h @@ -1,6 +1,5 @@ /* - * Track.h - declaration of classes concerning tracks -> necessary for all - * track-like objects (beat/bassline, sample-track...) + * Track.h - declaration of Track class * * Copyright (c) 2004-2014 Tobias Doerffel * @@ -26,42 +25,22 @@ #ifndef TRACK_H #define TRACK_H + #include -#include -#include #include -#include -#include "lmms_basics.h" -#include "MidiTime.h" -#include "Rubberband.h" -#include "JournallingObject.h" #include "AutomatableModel.h" -#include "ModelView.h" -#include "DataFile.h" -#include "FadeButton.h" - +#include "JournallingObject.h" +#include "lmms_basics.h" -class QMenu; -class QPushButton; -class PixmapButton; -class TextFloat; -class Track; -class TrackContentObjectView; +class TimePos; class TrackContainer; class TrackContainerView; -class TrackContentWidget; +class TrackContentObject; class TrackView; -const int DEFAULT_SETTINGS_WIDGET_WIDTH = 224; -const int TRACK_OP_WIDTH = 78; -// This shaves 150-ish pixels off track buttons, -// ruled from config: ui.compacttrackbuttons -const int DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT = 96; -const int TRACK_OP_WIDTH_COMPACT = 62; - /*! The minimum track height in pixels * * Tracks can be resized by shift-dragging anywhere inside the track @@ -70,409 +49,10 @@ const int TRACK_OP_WIDTH_COMPACT = 62; const int MINIMAL_TRACK_HEIGHT = 32; const int DEFAULT_TRACK_HEIGHT = 32; -const int TCO_BORDER_WIDTH = 2; - char const *const FILENAME_FILTER = "[\\0000-\x1f\"*/:<>?\\\\|\x7f]"; -class LMMS_EXPORT TrackContentObject : public Model, public JournallingObject -{ - Q_OBJECT - MM_OPERATORS - mapPropertyFromModel(bool,isMuted,setMuted,m_mutedModel); - mapPropertyFromModel(bool,isSolo,setSolo,m_soloModel); -public: - TrackContentObject( Track * track ); - virtual ~TrackContentObject(); - - inline Track * getTrack() const - { - return m_track; - } - - inline const QString & name() const - { - return m_name; - } - - inline void setName( const QString & name ) - { - m_name = name; - emit dataChanged(); - } - - QString displayName() const override - { - return name(); - } - - - inline const MidiTime & startPosition() const - { - return m_startPosition; - } - - inline MidiTime endPosition() const - { - const int sp = m_startPosition; - return sp + m_length; - } - - inline const MidiTime & length() const - { - return m_length; - } - - inline void setAutoResize( const bool r ) - { - m_autoResize = r; - } - - inline const bool getAutoResize() const - { - return m_autoResize; - } - - virtual void movePosition( const MidiTime & pos ); - virtual void changeLength( const MidiTime & length ); - - virtual TrackContentObjectView * createView( TrackView * tv ) = 0; - - inline void selectViewOnCreate( bool select ) - { - m_selectViewOnCreate = select; - } - - inline bool getSelectViewOnCreate() - { - return m_selectViewOnCreate; - } - - /// Returns true if and only if a->startPosition() < b->startPosition() - static bool comparePosition(const TrackContentObject* a, const TrackContentObject* b); - - MidiTime startTimeOffset() const; - void setStartTimeOffset( const MidiTime &startTimeOffset ); - -public slots: - void copy(); - void paste(); - void toggleMute(); - - -signals: - void lengthChanged(); - void positionChanged(); - void destroyedTCO(); - - -private: - enum Actions - { - NoAction, - Move, - Resize - } ; - - Track * m_track; - QString m_name; - - MidiTime m_startPosition; - MidiTime m_length; - MidiTime m_startTimeOffset; - - BoolModel m_mutedModel; - BoolModel m_soloModel; - bool m_autoResize; - - bool m_selectViewOnCreate; - - friend class TrackContentObjectView; - -} ; - - - -class TrackContentObjectView : public selectableObject, public ModelView -{ - Q_OBJECT - -// theming qproperties - Q_PROPERTY( QColor mutedColor READ mutedColor WRITE setMutedColor ) - Q_PROPERTY( QColor mutedBackgroundColor READ mutedBackgroundColor WRITE setMutedBackgroundColor ) - Q_PROPERTY( QColor selectedColor READ selectedColor WRITE setSelectedColor ) - Q_PROPERTY( QColor textColor READ textColor WRITE setTextColor ) - Q_PROPERTY( QColor textBackgroundColor READ textBackgroundColor WRITE setTextBackgroundColor ) - Q_PROPERTY( QColor textShadowColor READ textShadowColor WRITE setTextShadowColor ) - Q_PROPERTY( QColor BBPatternBackground READ BBPatternBackground WRITE setBBPatternBackground ) - Q_PROPERTY( bool gradient READ gradient WRITE setGradient ) - -public: - TrackContentObjectView( TrackContentObject * tco, TrackView * tv ); - virtual ~TrackContentObjectView(); - - bool fixedTCOs(); - - inline TrackContentObject * getTrackContentObject() - { - return m_tco; - } - - inline TrackView * getTrackView() - { - return m_trackView; - } - - // qproperty access func - QColor mutedColor() const; - QColor mutedBackgroundColor() const; - QColor selectedColor() const; - QColor textColor() const; - QColor textBackgroundColor() const; - QColor textShadowColor() const; - QColor BBPatternBackground() const; - bool gradient() const; - void setMutedColor( const QColor & c ); - void setMutedBackgroundColor( const QColor & c ); - void setSelectedColor( const QColor & c ); - void setTextColor( const QColor & c ); - void setTextBackgroundColor( const QColor & c ); - void setTextShadowColor( const QColor & c ); - void setBBPatternBackground( const QColor & c ); - void setGradient( const bool & b ); - - // access needsUpdate member variable - bool needsUpdate(); - void setNeedsUpdate( bool b ); - -public slots: - virtual bool close(); - void cut(); - void remove(); - void update() override; - -protected: - virtual void constructContextMenu( QMenu * ) - { - } - - 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 pixelsPerBar(); - - - DataFile createTCODataFiles(const QVector & tcos) const; - - virtual void paintTextLabel(QString const & text, QPainter & painter); - - -protected slots: - void updateLength(); - void updatePosition(); - - -private: - enum Actions - { - NoAction, - Move, - MoveSelection, - Resize, - ResizeLeft, - CopySelection, - ToggleSelected - } ; - - static TextFloat * s_textFloat; - - TrackContentObject * m_tco; - TrackView * m_trackView; - Actions m_action; - QPoint m_initialMousePos; - QPoint m_initialMouseGlobalPos; - MidiTime m_initialTCOPos; - MidiTime m_initialTCOEnd; - QVector m_initialOffsets; - - TextFloat * m_hint; - -// qproperty fields - QColor m_mutedColor; - QColor m_mutedBackgroundColor; - QColor m_selectedColor; - QColor m_textColor; - QColor m_textBackgroundColor; - QColor m_textShadowColor; - QColor m_BBPatternBackground; - bool m_gradient; - - bool m_needsUpdate; - inline void setInitialPos( QPoint pos ) - { - m_initialMousePos = pos; - m_initialMouseGlobalPos = mapToGlobal( pos ); - m_initialTCOPos = m_tco->startPosition(); - m_initialTCOEnd = m_initialTCOPos + m_tco->length(); - } - void setInitialOffsets(); - - bool mouseMovedDistance( QMouseEvent * me, int distance ); - MidiTime draggedTCOPos( QMouseEvent * me ); -} ; - - - - - -class TrackContentWidget : public QWidget, public JournallingObject -{ - Q_OBJECT - - // qproperties for track background gradients - Q_PROPERTY( QBrush darkerColor READ darkerColor WRITE setDarkerColor ) - Q_PROPERTY( QBrush lighterColor READ lighterColor WRITE setLighterColor ) - Q_PROPERTY( QBrush gridColor READ gridColor WRITE setGridColor ) - Q_PROPERTY( QBrush embossColor READ embossColor WRITE setEmbossColor ) - -public: - TrackContentWidget( TrackView * parent ); - virtual ~TrackContentWidget(); - - /*! \brief Updates the background tile pixmap. */ - void updateBackground(); - - void addTCOView( TrackContentObjectView * tcov ); - void removeTCOView( TrackContentObjectView * tcov ); - void removeTCOView( int tcoNum ) - { - if( tcoNum >= 0 && tcoNum < m_tcoViews.size() ) - { - removeTCOView( m_tcoViews[tcoNum] ); - } - } - - bool canPasteSelection( MidiTime tcoPos, const QDropEvent *de ); - bool pasteSelection( MidiTime tcoPos, QDropEvent * de ); - - MidiTime endPosition( const MidiTime & posStart ); - - // qproperty access methods - - QBrush darkerColor() const; - QBrush lighterColor() const; - QBrush gridColor() const; - QBrush embossColor() const; - - void setDarkerColor( const QBrush & c ); - void setLighterColor( const QBrush & c ); - void setGridColor( const QBrush & c ); - void setEmbossColor( const QBrush & c); - -public slots: - void update(); - void changePosition( const MidiTime & newPos = MidiTime( -1 ) ); - -protected: - 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; - - QString nodeName() const override - { - return "trackcontentwidget"; - } - - void saveSettings( QDomDocument& doc, QDomElement& element ) override - { - Q_UNUSED(doc) - Q_UNUSED(element) - } - - void loadSettings( const QDomElement& element ) override - { - Q_UNUSED(element) - } - - -private: - Track * getTrack(); - MidiTime getPosition( int mouseX ); - - TrackView * m_trackView; - - typedef QVector tcoViewVector; - tcoViewVector m_tcoViews; - - QPixmap m_background; - - // qproperty fields - QBrush m_darkerColor; - QBrush m_lighterColor; - QBrush m_gridColor; - QBrush m_embossColor; -} ; - - - - - -class TrackOperationsWidget : public QWidget -{ - Q_OBJECT -public: - TrackOperationsWidget( TrackView * parent ); - ~TrackOperationsWidget(); - - -protected: - void mousePressEvent( QMouseEvent * me ) override; - void paintEvent( QPaintEvent * pe ) override; - - -private slots: - void cloneTrack(); - void removeTrack(); - void updateMenu(); - void toggleRecording(bool on); - void recordingOn(); - void recordingOff(); - void clearTrack(); - -private: - static QPixmap * s_grip; - - TrackView * m_trackView; - - QPushButton * m_trackOps; - PixmapButton * m_muteBtn; - PixmapButton * m_soloBtn; - - - friend class TrackView; - -signals: - void trackRemovalScheduled( TrackView * t ); - -} ; - - - - - -// base-class for all tracks +//! Base-class for all tracks class LMMS_EXPORT Track : public Model, public JournallingObject { Q_OBJECT @@ -509,12 +89,12 @@ class LMMS_EXPORT Track : public Model, public JournallingObject return m_type; } - virtual bool play( const MidiTime & start, const fpp_t frames, + virtual bool play( const TimePos & start, const fpp_t frames, const f_cnt_t frameBase, int tcoNum = -1 ) = 0; virtual TrackView * createView( TrackContainerView * view ) = 0; - virtual TrackContentObject * createTCO( const MidiTime & pos ) = 0; + virtual TrackContentObject * createTCO( const TimePos & pos ) = 0; virtual void saveTrackSpecificSettings( QDomDocument & doc, QDomElement & parent ) = 0; @@ -543,15 +123,15 @@ class LMMS_EXPORT Track : public Model, public JournallingObject { return m_trackContentObjects; } - void getTCOsInRange( tcoVector & tcoV, const MidiTime & start, - const MidiTime & end ); + void getTCOsInRange( tcoVector & tcoV, const TimePos & start, + const TimePos & end ); void swapPositionOfTCOs( int tcoNum1, int tcoNum2 ); void createTCOsForBB( int bb ); - void insertBar( const MidiTime & pos ); - void removeBar( const MidiTime & pos ); + void insertBar( const TimePos & pos ); + void removeBar( const TimePos & pos ); bar_t length() const; @@ -597,7 +177,16 @@ class LMMS_EXPORT Track : public Model, public JournallingObject { return m_processingLock.tryLock(); } - + + QColor color() + { + return m_color; + } + bool useColor() + { + return m_hasColor; + } + BoolModel* getMutedModel(); public slots: @@ -609,6 +198,8 @@ public slots: void toggleSolo(); + void trackColorChanged( QColor & c ); + void trackColorReset(); private: TrackContainer* m_trackContainer; @@ -627,6 +218,9 @@ public slots: tcoVector m_trackContentObjects; QMutex m_processingLock; + + QColor m_color; + bool m_hasColor; friend class TrackView; @@ -640,122 +234,4 @@ public slots: - -class TrackView : public QWidget, public ModelView, public JournallingObject -{ - Q_OBJECT -public: - TrackView( Track * _track, TrackContainerView* tcv ); - virtual ~TrackView(); - - inline const Track * getTrack() const - { - return m_track; - } - - inline Track * getTrack() - { - return m_track; - } - - inline TrackContainerView* trackContainerView() - { - return m_trackContainerView; - } - - inline TrackOperationsWidget * getTrackOperationsWidget() - { - return &m_trackOperationsWidget; - } - - inline QWidget * getTrackSettingsWidget() - { - return &m_trackSettingsWidget; - } - - inline TrackContentWidget * getTrackContentWidget() - { - return &m_trackContentWidget; - } - - bool isMovingTrack() const - { - return m_action == MoveTrack; - } - - virtual void update(); - - // Create a menu for assigning/creating channels for this track - // Currently instrument track and sample track supports it - virtual QMenu * createFxMenu(QString title, QString newFxLabel); - - -public slots: - virtual bool close(); - - -protected: - void modelChanged() override; - - void saveSettings( QDomDocument& doc, QDomElement& element ) override - { - Q_UNUSED(doc) - Q_UNUSED(element) - } - - void loadSettings( const QDomElement& element ) override - { - Q_UNUSED(element) - } - - QString nodeName() const override - { - return "trackview"; - } - - - 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: - enum Actions - { - NoAction, - MoveTrack, - ResizeTrack - } ; - - Track * m_track; - TrackContainerView * m_trackContainerView; - - TrackOperationsWidget m_trackOperationsWidget; - QWidget m_trackSettingsWidget; - TrackContentWidget m_trackContentWidget; - - Actions m_action; - - virtual FadeButton * getActivityIndicator() - { - return nullptr; - } - - void setIndicatorMute(FadeButton* indicator, bool muted); - - friend class TrackLabelButton; - - -private slots: - void createTCOView( TrackContentObject * tco ); - void muteChanged(); - -} ; - - - #endif diff --git a/include/TrackContainer.h b/include/TrackContainer.h index fd853a73c1e..00b391e102d 100644 --- a/include/TrackContainer.h +++ b/include/TrackContainer.h @@ -93,13 +93,13 @@ class LMMS_EXPORT TrackContainer : public Model, public JournallingObject return m_TrackContainerType; } - virtual AutomatedValueMap automatedValuesAt(MidiTime time, int tcoNum = -1) const; + virtual AutomatedValueMap automatedValuesAt(TimePos time, int tcoNum = -1) const; signals: void trackAdded( Track * _track ); protected: - static AutomatedValueMap automatedValuesFromTracks(const TrackList &tracks, MidiTime timeStart, int tcoNum = -1); + static AutomatedValueMap automatedValuesFromTracks(const TrackList &tracks, TimePos timeStart, int tcoNum = -1); mutable QReadWriteLock m_tracksMutex; @@ -115,30 +115,4 @@ class LMMS_EXPORT TrackContainer : public Model, public JournallingObject } ; -class DummyTrackContainer : public TrackContainer -{ -public: - DummyTrackContainer(); - - virtual ~DummyTrackContainer() - { - } - - QString nodeName() const override - { - return "DummyTrackContainer"; - } - - InstrumentTrack * dummyInstrumentTrack() - { - return m_dummyInstrumentTrack; - } - - -private: - InstrumentTrack * m_dummyInstrumentTrack; - -} ; - - #endif diff --git a/include/TrackContainerView.h b/include/TrackContainerView.h index 6e952189b01..0edd63865f6 100644 --- a/include/TrackContainerView.h +++ b/include/TrackContainerView.h @@ -31,12 +31,15 @@ #include #include -#include "Track.h" #include "JournallingObject.h" -#include "InstrumentTrack.h" +#include "ModelView.h" +#include "Rubberband.h" +#include "TrackView.h" class QVBoxLayout; + +class InstrumentTrack; class TrackContainer; @@ -57,7 +60,7 @@ class TrackContainerView : public QWidget, public ModelView, return m_scrollArea; } - inline const MidiTime & currentPosition() const + inline const TimePos & currentPosition() const { return m_currentPosition; } @@ -143,7 +146,7 @@ public slots: void resizeEvent( QResizeEvent * ) override; - MidiTime m_currentPosition; + TimePos m_currentPosition; private: @@ -182,7 +185,7 @@ public slots: signals: - void positionChanged( const MidiTime & _pos ); + void positionChanged( const TimePos & _pos ); } ; diff --git a/include/TrackContentObject.h b/include/TrackContentObject.h new file mode 100644 index 00000000000..dddd2b75c39 --- /dev/null +++ b/include/TrackContentObject.h @@ -0,0 +1,183 @@ +/* + * TrackConteintObject.h - declaration of TrackContentObject class + * + * Copyright (c) 2004-2014 Tobias Doerffel + * + * 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 TRACK_CONTENT_OBJECT_H +#define TRACK_CONTENT_OBJECT_H + +#include + +#include "AutomatableModel.h" +#include "lmms_basics.h" + + +class Track; +class TrackContentObjectView; +class TrackContainer; +class TrackView; + + +class LMMS_EXPORT TrackContentObject : public Model, public JournallingObject +{ + Q_OBJECT + MM_OPERATORS + mapPropertyFromModel(bool,isMuted,setMuted,m_mutedModel); + mapPropertyFromModel(bool,isSolo,setSolo,m_soloModel); +public: + TrackContentObject( Track * track ); + virtual ~TrackContentObject(); + + inline Track * getTrack() const + { + return m_track; + } + + inline const QString & name() const + { + return m_name; + } + + inline void setName( const QString & name ) + { + m_name = name; + emit dataChanged(); + } + + QString displayName() const override + { + return name(); + } + + + inline const TimePos & startPosition() const + { + return m_startPosition; + } + + inline TimePos endPosition() const + { + const int sp = m_startPosition; + return sp + m_length; + } + + inline const TimePos & length() const + { + return m_length; + } + + inline void setAutoResize( const bool r ) + { + m_autoResize = r; + } + + inline const bool getAutoResize() const + { + return m_autoResize; + } + + QColor color() const + { + return m_color; + } + + void setColor( const QColor & c ) + { + m_color = c; + } + + bool hasColor(); + + void useCustomClipColor( bool b ); + + bool usesCustomClipColor() + { + return m_useCustomClipColor; + } + + virtual void movePosition( const TimePos & pos ); + virtual void changeLength( const TimePos & length ); + + virtual TrackContentObjectView * createView( TrackView * tv ) = 0; + + inline void selectViewOnCreate( bool select ) + { + m_selectViewOnCreate = select; + } + + inline bool getSelectViewOnCreate() + { + return m_selectViewOnCreate; + } + + /// Returns true if and only if a->startPosition() < b->startPosition() + static bool comparePosition(const TrackContentObject* a, const TrackContentObject* b); + + TimePos startTimeOffset() const; + void setStartTimeOffset( const TimePos &startTimeOffset ); + + void updateColor(); + + // Will copy the state of a TCO to another TCO + static void copyStateTo( TrackContentObject *src, TrackContentObject *dst ); + +public slots: + void toggleMute(); + + +signals: + void lengthChanged(); + void positionChanged(); + void destroyedTCO(); + void trackColorChanged(); + + +private: + enum Actions + { + NoAction, + Move, + Resize + } ; + + Track * m_track; + QString m_name; + + TimePos m_startPosition; + TimePos m_length; + TimePos m_startTimeOffset; + + BoolModel m_mutedModel; + BoolModel m_soloModel; + bool m_autoResize; + + bool m_selectViewOnCreate; + + QColor m_color; + bool m_useCustomClipColor; + + friend class TrackContentObjectView; + +} ; + + +#endif diff --git a/include/TrackContentObjectView.h b/include/TrackContentObjectView.h new file mode 100644 index 00000000000..0f99af96479 --- /dev/null +++ b/include/TrackContentObjectView.h @@ -0,0 +1,218 @@ +/* + * TrackContentObjectView.h - declaration of TrackContentObjectView class + * + * Copyright (c) 2004-2014 Tobias Doerffel + * + * 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 TRACK_CONTENT_OBJECT_VIEW_H +#define TRACK_CONTENT_OBJECT_VIEW_H + + +#include + +#include "ModelView.h" +#include "Rubberband.h" +#include "TrackContentObject.h" + + +class QMenu; +class QContextMenuEvent; + +class DataFile; +class TextFloat; +class TrackContentObject; +class TrackView; + + +class TrackContentObjectView : public selectableObject, public ModelView +{ + Q_OBJECT + +// theming qproperties + Q_PROPERTY( QColor mutedColor READ mutedColor WRITE setMutedColor ) + Q_PROPERTY( QColor mutedBackgroundColor READ mutedBackgroundColor WRITE setMutedBackgroundColor ) + Q_PROPERTY( QColor selectedColor READ selectedColor WRITE setSelectedColor ) + Q_PROPERTY( QColor textColor READ textColor WRITE setTextColor ) + Q_PROPERTY( QColor textBackgroundColor READ textBackgroundColor WRITE setTextBackgroundColor ) + Q_PROPERTY( QColor textShadowColor READ textShadowColor WRITE setTextShadowColor ) + Q_PROPERTY( QColor BBPatternBackground READ BBPatternBackground WRITE setBBPatternBackground ) + Q_PROPERTY( bool gradient READ gradient WRITE setGradient ) + // We have to use a QSize here because using QPoint isn't supported. + // width -> x, height -> y + Q_PROPERTY( QSize mouseHotspotHand WRITE setMouseHotspotHand ) + +public: + TrackContentObjectView( TrackContentObject * tco, TrackView * tv ); + virtual ~TrackContentObjectView(); + + bool fixedTCOs(); + + inline TrackContentObject * getTrackContentObject() + { + return m_tco; + } + + inline TrackView * getTrackView() + { + return m_trackView; + } + + // qproperty access func + QColor mutedColor() const; + QColor mutedBackgroundColor() const; + QColor selectedColor() const; + QColor textColor() const; + QColor textBackgroundColor() const; + QColor textShadowColor() const; + QColor BBPatternBackground() const; + bool gradient() const; + void setMutedColor( const QColor & c ); + void setMutedBackgroundColor( const QColor & c ); + void setSelectedColor( const QColor & c ); + void setTextColor( const QColor & c ); + void setTextBackgroundColor( const QColor & c ); + void setTextShadowColor( const QColor & c ); + void setBBPatternBackground( const QColor & c ); + void setGradient( const bool & b ); + void setMouseHotspotHand(const QSize & s); + + // access needsUpdate member variable + bool needsUpdate(); + void setNeedsUpdate( bool b ); + + // Method to get a QVector of TCOs to be affected by a context menu action + QVector getClickedTCOs(); + + // Methods to remove, copy, cut, paste and mute a QVector of TCO views + void copy( QVector tcovs ); + void cut( QVector tcovs ); + void paste(); + // remove and toggleMute are static because they don't depend + // being called from a particular TCO view, but can be called anywhere as long + // as a valid TCO view list is given, while copy/cut require an instance for + // some metadata to be written to the clipboard. + static void remove( QVector tcovs ); + static void toggleMute( QVector tcovs ); + + QColor getColorForDisplay( QColor ); + +public slots: + virtual bool close(); + void remove(); + void update() override; + + void changeClipColor(); + void useTrackColor(); + +protected: + enum ContextMenuAction + { + Remove, + Cut, + Copy, + Paste, + Mute + }; + + virtual void constructContextMenu( QMenu * ) + { + } + + void contextMenuEvent( QContextMenuEvent * cme ) override; + void contextMenuAction( ContextMenuAction action ); + 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 pixelsPerBar(); + + + DataFile createTCODataFiles(const QVector & tcos) const; + + virtual void paintTextLabel(QString const & text, QPainter & painter); + + +protected slots: + void updateLength(); + void updatePosition(); + + +private: + enum Actions + { + NoAction, + Move, + MoveSelection, + Resize, + ResizeLeft, + CopySelection, + ToggleSelected + } ; + + static TextFloat * s_textFloat; + + TrackContentObject * m_tco; + TrackView * m_trackView; + Actions m_action; + QPoint m_initialMousePos; + QPoint m_initialMouseGlobalPos; + TimePos m_initialTCOPos; + TimePos m_initialTCOEnd; + QVector m_initialOffsets; + + TextFloat * m_hint; + +// qproperty fields + QColor m_mutedColor; + QColor m_mutedBackgroundColor; + QColor m_selectedColor; + QColor m_textColor; + QColor m_textBackgroundColor; + QColor m_textShadowColor; + QColor m_BBPatternBackground; + bool m_gradient; + QSize m_mouseHotspotHand; // QSize must be used because QPoint isn't supported by property system + bool m_cursorSetYet; + + bool m_needsUpdate; + inline void setInitialPos( QPoint pos ) + { + m_initialMousePos = pos; + m_initialMouseGlobalPos = mapToGlobal( pos ); + m_initialTCOPos = m_tco->startPosition(); + m_initialTCOEnd = m_initialTCOPos + m_tco->length(); + } + void setInitialOffsets(); + + bool mouseMovedDistance( QMouseEvent * me, int distance ); + TimePos draggedTCOPos( QMouseEvent * me ); +} ; + + +#endif diff --git a/include/TrackContentWidget.h b/include/TrackContentWidget.h new file mode 100644 index 00000000000..c2764bfc6b4 --- /dev/null +++ b/include/TrackContentWidget.h @@ -0,0 +1,142 @@ +/* + * TrackContentWidget.h - declaration of TrackContentWidget class + * + * Copyright (c) 2004-2014 Tobias Doerffel + * + * 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 TRACK_CONTENT_WIDGET_H +#define TRACK_CONTENT_WIDGET_H + +#include + +#include "JournallingObject.h" +#include "TimePos.h" + + +class QMimeData; + +class Track; +class TrackContentObjectView; +class TrackView; + + +class TrackContentWidget : public QWidget, public JournallingObject +{ + Q_OBJECT + + // qproperties for track background gradients + Q_PROPERTY( QBrush darkerColor READ darkerColor WRITE setDarkerColor ) + Q_PROPERTY( QBrush lighterColor READ lighterColor WRITE setLighterColor ) + Q_PROPERTY( QBrush gridColor READ gridColor WRITE setGridColor ) + Q_PROPERTY( QBrush embossColor READ embossColor WRITE setEmbossColor ) + +public: + TrackContentWidget( TrackView * parent ); + virtual ~TrackContentWidget(); + + /*! \brief Updates the background tile pixmap. */ + void updateBackground(); + + void addTCOView( TrackContentObjectView * tcov ); + void removeTCOView( TrackContentObjectView * tcov ); + void removeTCOView( int tcoNum ) + { + if( tcoNum >= 0 && tcoNum < m_tcoViews.size() ) + { + removeTCOView( m_tcoViews[tcoNum] ); + } + } + + bool canPasteSelection( TimePos tcoPos, const QDropEvent *de ); + bool canPasteSelection( TimePos tcoPos, const QMimeData *md, bool allowSameBar = false ); + bool pasteSelection( TimePos tcoPos, QDropEvent * de ); + bool pasteSelection( TimePos tcoPos, const QMimeData * md, bool skipSafetyCheck = false ); + + TimePos endPosition( const TimePos & posStart ); + + // qproperty access methods + + QBrush darkerColor() const; + QBrush lighterColor() const; + QBrush gridColor() const; + QBrush embossColor() const; + + void setDarkerColor( const QBrush & c ); + void setLighterColor( const QBrush & c ); + void setGridColor( const QBrush & c ); + void setEmbossColor( const QBrush & c); + +public slots: + void update(); + void changePosition( const TimePos & newPos = TimePos( -1 ) ); + +protected: + enum ContextMenuAction + { + Paste + }; + + void contextMenuEvent( QContextMenuEvent * cme ) override; + void contextMenuAction( QContextMenuEvent * cme, ContextMenuAction action ); + 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; + + QString nodeName() const override + { + return "trackcontentwidget"; + } + + void saveSettings( QDomDocument& doc, QDomElement& element ) override + { + Q_UNUSED(doc) + Q_UNUSED(element) + } + + void loadSettings( const QDomElement& element ) override + { + Q_UNUSED(element) + } + + +private: + Track * getTrack(); + TimePos getPosition( int mouseX ); + + TrackView * m_trackView; + + typedef QVector tcoViewVector; + tcoViewVector m_tcoViews; + + QPixmap m_background; + + // qproperty fields + QBrush m_darkerColor; + QBrush m_lighterColor; + QBrush m_gridColor; + QBrush m_embossColor; +} ; + + + +#endif diff --git a/include/TrackOperationsWidget.h b/include/TrackOperationsWidget.h new file mode 100644 index 00000000000..f78e0a2092a --- /dev/null +++ b/include/TrackOperationsWidget.h @@ -0,0 +1,79 @@ +/* + * TrackOperationsWidget.h - declaration of TrackOperationsWidget class + * + * Copyright (c) 2004-2014 Tobias Doerffel + * + * 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 TRACK_OPERATIONS_WIDGET_H +#define TRACK_OPERATIONS_WIDGET_H + +#include + +class QPushButton; + +class PixmapButton; +class TrackView; + +class TrackOperationsWidget : public QWidget +{ + Q_OBJECT +public: + TrackOperationsWidget( TrackView * parent ); + ~TrackOperationsWidget(); + + +protected: + void mousePressEvent( QMouseEvent * me ) override; + void paintEvent( QPaintEvent * pe ) override; + + +private slots: + void cloneTrack(); + void removeTrack(); + void updateMenu(); + void changeTrackColor(); + void randomTrackColor(); + void resetTrackColor(); + void useTrackColor(); + void toggleRecording(bool on); + void recordingOn(); + void recordingOff(); + void clearTrack(); + +private: + TrackView * m_trackView; + + QPushButton * m_trackOps; + PixmapButton * m_muteBtn; + PixmapButton * m_soloBtn; + + + friend class TrackView; + +signals: + void trackRemovalScheduled( TrackView * t ); + void colorChanged( QColor & c ); + void colorParented(); + void colorReset(); + +} ; + +#endif diff --git a/include/TrackView.h b/include/TrackView.h new file mode 100644 index 00000000000..1029e148c1d --- /dev/null +++ b/include/TrackView.h @@ -0,0 +1,173 @@ +/* + * TrackView.h - declaration of TrackView class + * + * Copyright (c) 2004-2014 Tobias Doerffel + * + * 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 TRACK_VIEW_H +#define TRACK_VIEW_H + +#include + +#include "JournallingObject.h" +#include "ModelView.h" +#include "TrackContentWidget.h" +#include "TrackOperationsWidget.h" + + +class QMenu; + +class FadeButton; +class Track; +class TrackContainerView; +class TrackContentObject; + + +const int DEFAULT_SETTINGS_WIDGET_WIDTH = 224; +const int TRACK_OP_WIDTH = 78; +// This shaves 150-ish pixels off track buttons, +// ruled from config: ui.compacttrackbuttons +const int DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT = 96; +const int TRACK_OP_WIDTH_COMPACT = 62; + +const int TCO_BORDER_WIDTH = 2; + + +class TrackView : public QWidget, public ModelView, public JournallingObject +{ + Q_OBJECT +public: + TrackView( Track * _track, TrackContainerView* tcv ); + virtual ~TrackView(); + + inline const Track * getTrack() const + { + return m_track; + } + + inline Track * getTrack() + { + return m_track; + } + + inline TrackContainerView* trackContainerView() + { + return m_trackContainerView; + } + + inline TrackOperationsWidget * getTrackOperationsWidget() + { + return &m_trackOperationsWidget; + } + + inline QWidget * getTrackSettingsWidget() + { + return &m_trackSettingsWidget; + } + + inline TrackContentWidget * getTrackContentWidget() + { + return &m_trackContentWidget; + } + + bool isMovingTrack() const + { + return m_action == MoveTrack; + } + + virtual void update(); + + // Create a menu for assigning/creating channels for this track + // Currently instrument track and sample track supports it + virtual QMenu * createFxMenu(QString title, QString newFxLabel); + + +public slots: + virtual bool close(); + + +protected: + void modelChanged() override; + + void saveSettings( QDomDocument& doc, QDomElement& element ) override + { + Q_UNUSED(doc) + Q_UNUSED(element) + } + + void loadSettings( const QDomElement& element ) override + { + Q_UNUSED(element) + } + + QString nodeName() const override + { + return "trackview"; + } + + + 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: + enum Actions + { + NoAction, + MoveTrack, + ResizeTrack + } ; + + Track * m_track; + TrackContainerView * m_trackContainerView; + + TrackOperationsWidget m_trackOperationsWidget; + QWidget m_trackSettingsWidget; + TrackContentWidget m_trackContentWidget; + + Actions m_action; + + virtual FadeButton * getActivityIndicator() + { + return nullptr; + } + + void setIndicatorMute(FadeButton* indicator, bool muted); + + friend class TrackLabelButton; + + +private slots: + void createTCOView( TrackContentObject * tco ); + void muteChanged(); + +} ; + + + +#endif diff --git a/include/aeffectx.h b/include/aeffectx.h index 133d925acd8..b7a78dfad2b 100644 --- a/include/aeffectx.h +++ b/include/aeffectx.h @@ -97,6 +97,8 @@ const int effClose = 1; // currently unused const int effSetProgram = 2; // currently unused const int effGetProgram = 3; // currently unused const int effGetProgramName = 5; // currently unused +const int effGetParamLabel = 6; +const int effGetParamDisplay = 7; const int effGetParamName = 8; // currently unused const int effSetSampleRate = 10; const int effSetBlockSize = 11; diff --git a/include/lmms_basics.h b/include/lmms_basics.h index 9618108563e..f114f362c15 100644 --- a/include/lmms_basics.h +++ b/include/lmms_basics.h @@ -32,6 +32,7 @@ #ifdef LMMS_HAVE_STDINT_H #include +#include #endif @@ -55,9 +56,6 @@ typedef uint16_t fx_ch_t; // FX-channel (0 to MAX_EFFECT_CHANNEL) typedef uint32_t jo_id_t; // (unique) ID of a journalling object -// use for improved branch prediction -#define likely(x) Q_LIKELY(x) -#define unlikely(x) Q_UNLIKELY(x) // windows headers define "min" and "max" macros, breaking the methods bwloe #undef min @@ -130,12 +128,9 @@ const ch_cnt_t SURROUND_CHANNELS = -typedef sample_t sampleFrame[DEFAULT_CHANNELS]; -typedef sample_t surroundSampleFrame[SURROUND_CHANNELS]; +using sampleFrame = std::array; +using surroundSampleFrame = std::array; #define ALIGN_SIZE 16 -#if __GNUC__ -typedef sample_t sampleFrameA[DEFAULT_CHANNELS] __attribute__((__aligned__(ALIGN_SIZE))); -#endif #define STRINGIFY(s) STR(s) diff --git a/include/lmms_math.h b/include/lmms_math.h index 7c68c6bfbf5..3fd76896e18 100644 --- a/include/lmms_math.h +++ b/include/lmms_math.h @@ -42,22 +42,41 @@ using namespace std; static inline float absFraction( const float _x ) { - return( _x - ( _x >= 0.0f ? floorf( _x ) : floorf( _x ) - 1 ) ); + return( _x - floorf( _x ) ); } static inline float fraction( const float _x ) { - return( _x - floorf( _x ) ); + return( _x - floorf( _x ) - ( _x >= 0.0f ? 0.0 : 1.0 ) ); } #else +/*! + * @brief Returns the wrapped fractional part of a float, a value between 0.0f and 1.0f. + * + * absFraction( 2.3) => 0.3 + * absFraction(-2.3) => 0.7 + * + * Note that this not the same as the absolute value of the fraction (as the function name suggests). + * If the result is interpreted as a phase of an oscillator, it makes that negative phases are + * converted to positive phases. + */ static inline float absFraction( const float _x ) { return( _x - ( _x >= 0.0f ? static_cast( _x ) : static_cast( _x ) - 1 ) ); } +/*! + * @brief Returns the fractional part of a float, a value between -1.0f and 1.0f. + * + * fraction( 2.3) => 0.3 + * fraction(-2.3) => -0.3 + * + * Note that if the return value is used as a phase of an oscillator, that the oscillator must support + * negative phases. + */ static inline float fraction( const float _x ) { return( _x - static_cast( _x ) ); diff --git a/include/stdshims.h b/include/stdshims.h index c12254e1506..dc89a1b0933 100644 --- a/include/stdshims.h +++ b/include/stdshims.h @@ -4,33 +4,9 @@ #ifndef STDSHIMS_H #define STDSHIMS_H -#include #include #include -#if (__cplusplus >= 201402L || _MSC_VER) -#ifndef _MSC_VER -#warning "This part of this file should now be removed! The functions it provides are part of the C++14 standard." -#endif -using std::make_unique; - -#else - -/// Shim for http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique -template -std::unique_ptr make_unique(Args&&... args) -{ - return std::unique_ptr(new T(std::forward(args)...)); -} - -//! Overload for the case a deleter should be specified -template -std::unique_ptr make_unique(Args&&... args) -{ - return std::unique_ptr(new T(std::forward(args)...)); -} -#endif - #if (__cplusplus >= 201703L || _MSC_VER >= 1914) #ifndef _MSC_VER #warning "This part of this file should now be removed! The functions it provides are part of the C++17 standard." diff --git a/plugins/Amplifier/Amplifier.cpp b/plugins/Amplifier/Amplifier.cpp index cc2a63304ff..e7250872f53 100644 --- a/plugins/Amplifier/Amplifier.cpp +++ b/plugins/Amplifier/Amplifier.cpp @@ -35,7 +35,7 @@ Plugin::Descriptor PLUGIN_EXPORT amplifier_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Amplifier", - QT_TRANSLATE_NOOP( "pluginBrowser", "A native amplifier plugin" ), + QT_TRANSLATE_NOOP( "PluginBrowser", "A native amplifier plugin" ), "Vesa Kivimäki ", 0x0100, Plugin::Effect, diff --git a/plugins/BassBooster/BassBooster.cpp b/plugins/BassBooster/BassBooster.cpp index 535834aae77..1ed1f246712 100644 --- a/plugins/BassBooster/BassBooster.cpp +++ b/plugins/BassBooster/BassBooster.cpp @@ -34,7 +34,7 @@ Plugin::Descriptor PLUGIN_EXPORT bassbooster_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "BassBooster", - QT_TRANSLATE_NOOP( "pluginBrowser", "Boost your bass the fast and simple way" ), + QT_TRANSLATE_NOOP( "PluginBrowser", "Boost your bass the fast and simple way" ), "Tobias Doerffel ", 0x0100, Plugin::Effect, diff --git a/plugins/Bitcrush/Bitcrush.cpp b/plugins/Bitcrush/Bitcrush.cpp index 0580d47cd5e..fa19b195fc4 100644 --- a/plugins/Bitcrush/Bitcrush.cpp +++ b/plugins/Bitcrush/Bitcrush.cpp @@ -41,7 +41,7 @@ Plugin::Descriptor PLUGIN_EXPORT bitcrush_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Bitcrush", - QT_TRANSLATE_NOOP( "pluginBrowser", "An oversampling bitcrusher" ), + QT_TRANSLATE_NOOP( "PluginBrowser", "An oversampling bitcrusher" ), "Vesa Kivimäki ", 0x0100, Plugin::Effect, diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index a4e56921fea..dde913d56ef 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -2,8 +2,8 @@ SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") SET(CMAKE_DEBUG_POSTFIX "") -# Enable C++11 -SET(CMAKE_CXX_STANDARD 11) +# Enable C++14 +SET(CMAKE_CXX_STANDARD 14) IF(LMMS_BUILD_APPLE) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") diff --git a/plugins/CrossoverEQ/CrossoverEQ.cpp b/plugins/CrossoverEQ/CrossoverEQ.cpp index e2090980a06..78029134ebc 100644 --- a/plugins/CrossoverEQ/CrossoverEQ.cpp +++ b/plugins/CrossoverEQ/CrossoverEQ.cpp @@ -36,7 +36,7 @@ Plugin::Descriptor PLUGIN_EXPORT crossovereq_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Crossover Equalizer", - QT_TRANSLATE_NOOP( "pluginBrowser", "A 4-band Crossover Equalizer" ), + QT_TRANSLATE_NOOP( "PluginBrowser", "A 4-band Crossover Equalizer" ), "Vesa Kivimäki ", 0x0100, Plugin::Effect, diff --git a/plugins/Delay/DelayEffect.cpp b/plugins/Delay/DelayEffect.cpp index 0daad0d9d8c..69ee924e8b0 100644 --- a/plugins/Delay/DelayEffect.cpp +++ b/plugins/Delay/DelayEffect.cpp @@ -35,7 +35,7 @@ Plugin::Descriptor PLUGIN_EXPORT delay_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Delay", - QT_TRANSLATE_NOOP( "pluginBrowser", "A native delay plugin" ), + QT_TRANSLATE_NOOP( "PluginBrowser", "A native delay plugin" ), "Dave French ", 0x0100, Plugin::Effect, diff --git a/plugins/Delay/StereoDelay.cpp b/plugins/Delay/StereoDelay.cpp index d25f6b52b18..f240b93547b 100644 --- a/plugins/Delay/StereoDelay.cpp +++ b/plugins/Delay/StereoDelay.cpp @@ -55,7 +55,7 @@ StereoDelay::~StereoDelay() -void StereoDelay::tick( sampleFrame frame ) +void StereoDelay::tick( sampleFrame& frame ) { m_writeIndex = ( m_writeIndex + 1 ) % ( int )m_maxLength; int readIndex = m_writeIndex - m_length; diff --git a/plugins/Delay/StereoDelay.h b/plugins/Delay/StereoDelay.h index a0dbdc22064..afea59b9af1 100644 --- a/plugins/Delay/StereoDelay.h +++ b/plugins/Delay/StereoDelay.h @@ -45,7 +45,7 @@ class StereoDelay m_feedback = feedback; } - void tick( sampleFrame frame ); + void tick( sampleFrame& frame ); void setSampleRate( int sampleRate ); private: diff --git a/plugins/DualFilter/DualFilter.cpp b/plugins/DualFilter/DualFilter.cpp index b4e11ccb396..d4e5d4b5ef0 100644 --- a/plugins/DualFilter/DualFilter.cpp +++ b/plugins/DualFilter/DualFilter.cpp @@ -36,7 +36,7 @@ Plugin::Descriptor PLUGIN_EXPORT dualfilter_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Dual Filter", - QT_TRANSLATE_NOOP( "pluginBrowser", "A Dual filter plugin" ), + QT_TRANSLATE_NOOP( "PluginBrowser", "A Dual filter plugin" ), "Vesa Kivimäki ", 0x0100, Plugin::Effect, diff --git a/plugins/DualFilter/DualFilterControlDialog.cpp b/plugins/DualFilter/DualFilterControlDialog.cpp index 73755bef38f..0c7732bc6c2 100755 --- a/plugins/DualFilter/DualFilterControlDialog.cpp +++ b/plugins/DualFilter/DualFilterControlDialog.cpp @@ -75,12 +75,12 @@ DualFilterControlDialog::DualFilterControlDialog( DualFilterControls* controls ) ToolTip::add( enabled2Toggle, tr( "Enable/disable filter 2" ) ); ComboBox * m_filter1ComboBox = new ComboBox( this ); - m_filter1ComboBox->setGeometry( 19, 70, 137, 22 ); + m_filter1ComboBox->setGeometry( 19, 70, 137, ComboBox::DEFAULT_HEIGHT ); m_filter1ComboBox->setFont( pointSize<8>( m_filter1ComboBox->font() ) ); m_filter1ComboBox->setModel( &controls->m_filter1Model ); ComboBox * m_filter2ComboBox = new ComboBox( this ); - m_filter2ComboBox->setGeometry( 217, 70, 137, 22 ); + m_filter2ComboBox->setGeometry( 217, 70, 137, ComboBox::DEFAULT_HEIGHT ); m_filter2ComboBox->setFont( pointSize<8>( m_filter2ComboBox->font() ) ); m_filter2ComboBox->setModel( &controls->m_filter2Model ); } diff --git a/plugins/DualFilter/DualFilterControls.cpp b/plugins/DualFilter/DualFilterControls.cpp index 0992d478cb1..35cbaab3a94 100644 --- a/plugins/DualFilter/DualFilterControls.cpp +++ b/plugins/DualFilter/DualFilterControls.cpp @@ -32,7 +32,6 @@ #include "embed.h" #include "Engine.h" #include "Song.h" -#include "stdshims.h" DualFilterControls::DualFilterControls( DualFilterEffect* effect ) : EffectControls( effect ), @@ -52,51 +51,51 @@ DualFilterControls::DualFilterControls( DualFilterEffect* effect ) : m_res2Model( 0.5, BasicFilters<>::minQ(), 10.0, 0.01, this, tr( "Q/Resonance 2" ) ), m_gain2Model( 100.0f, 0.0f, 200.0f, 0.1f, this, tr( "Gain 2" ) ) { - m_filter1Model.addItem( tr( "Low-pass" ), make_unique( "filter_lp" ) ); - m_filter1Model.addItem( tr( "Hi-pass" ), make_unique( "filter_hp" ) ); - m_filter1Model.addItem( tr( "Band-pass csg" ), make_unique( "filter_bp" ) ); - m_filter1Model.addItem( tr( "Band-pass czpg" ), make_unique( "filter_bp" ) ); - m_filter1Model.addItem( tr( "Notch" ), make_unique( "filter_notch" ) ); - m_filter1Model.addItem( tr( "All-pass" ), make_unique( "filter_ap" ) ); - m_filter1Model.addItem( tr( "Moog" ), make_unique( "filter_lp" ) ); - m_filter1Model.addItem( tr( "2x Low-pass" ), make_unique( "filter_2lp" ) ); - m_filter1Model.addItem( tr( "RC Low-pass 12 dB/oct" ), make_unique( "filter_lp" ) ); - m_filter1Model.addItem( tr( "RC Band-pass 12 dB/oct" ), make_unique( "filter_bp" ) ); - m_filter1Model.addItem( tr( "RC High-pass 12 dB/oct" ), make_unique( "filter_hp" ) ); - m_filter1Model.addItem( tr( "RC Low-pass 24 dB/oct" ), make_unique( "filter_lp" ) ); - m_filter1Model.addItem( tr( "RC Band-pass 24 dB/oct" ), make_unique( "filter_bp" ) ); - m_filter1Model.addItem( tr( "RC High-pass 24 dB/oct" ), make_unique( "filter_hp" ) ); - m_filter1Model.addItem( tr( "Vocal Formant" ), make_unique( "filter_hp" ) ); - m_filter1Model.addItem( tr( "2x Moog" ), make_unique( "filter_2lp" ) ); - m_filter1Model.addItem( tr( "SV Low-pass" ), make_unique( "filter_lp" ) ); - m_filter1Model.addItem( tr( "SV Band-pass" ), make_unique( "filter_bp" ) ); - m_filter1Model.addItem( tr( "SV High-pass" ), make_unique( "filter_hp" ) ); - m_filter1Model.addItem( tr( "SV Notch" ), make_unique( "filter_notch" ) ); - m_filter1Model.addItem( tr( "Fast Formant" ), make_unique( "filter_hp" ) ); - m_filter1Model.addItem( tr( "Tripole" ), make_unique( "filter_lp" ) ); - - m_filter2Model.addItem( tr( "Low-pass" ), make_unique( "filter_lp" ) ); - m_filter2Model.addItem( tr( "Hi-pass" ), make_unique( "filter_hp" ) ); - m_filter2Model.addItem( tr( "Band-pass csg" ), make_unique( "filter_bp" ) ); - m_filter2Model.addItem( tr( "Band-pass czpg" ), make_unique( "filter_bp" ) ); - m_filter2Model.addItem( tr( "Notch" ), make_unique( "filter_notch" ) ); - m_filter2Model.addItem( tr( "All-pass" ), make_unique( "filter_ap" ) ); - m_filter2Model.addItem( tr( "Moog" ), make_unique( "filter_lp" ) ); - m_filter2Model.addItem( tr( "2x Low-pass" ), make_unique( "filter_2lp" ) ); - m_filter2Model.addItem( tr( "RC Low-pass 12 dB/oct" ), make_unique( "filter_lp" ) ); - m_filter2Model.addItem( tr( "RC Band-pass 12 dB/oct" ), make_unique( "filter_bp" ) ); - m_filter2Model.addItem( tr( "RC High-pass 12 dB/oct" ), make_unique( "filter_hp" ) ); - m_filter2Model.addItem( tr( "RC Low-pass 24 dB/oct" ), make_unique( "filter_lp" ) ); - m_filter2Model.addItem( tr( "RC Band-pass 24 dB/oct" ), make_unique( "filter_bp" ) ); - m_filter2Model.addItem( tr( "RC High-pass 24 dB/oct" ), make_unique( "filter_hp" ) ); - m_filter2Model.addItem( tr( "Vocal Formant" ), make_unique( "filter_hp" ) ); - m_filter2Model.addItem( tr( "2x Moog" ), make_unique( "filter_2lp" ) ); - m_filter2Model.addItem( tr( "SV Low-pass" ), make_unique( "filter_lp" ) ); - m_filter2Model.addItem( tr( "SV Band-pass" ), make_unique( "filter_bp" ) ); - m_filter2Model.addItem( tr( "SV High-pass" ), make_unique( "filter_hp" ) ); - m_filter2Model.addItem( tr( "SV Notch" ), make_unique( "filter_notch" ) ); - m_filter2Model.addItem( tr( "Fast Formant" ), make_unique( "filter_hp" ) ); - m_filter2Model.addItem( tr( "Tripole" ), make_unique( "filter_lp" ) ); + m_filter1Model.addItem( tr( "Low-pass" ), std::make_unique( "filter_lp" ) ); + m_filter1Model.addItem( tr( "Hi-pass" ), std::make_unique( "filter_hp" ) ); + m_filter1Model.addItem( tr( "Band-pass csg" ), std::make_unique( "filter_bp" ) ); + m_filter1Model.addItem( tr( "Band-pass czpg" ), std::make_unique( "filter_bp" ) ); + m_filter1Model.addItem( tr( "Notch" ), std::make_unique( "filter_notch" ) ); + m_filter1Model.addItem( tr( "All-pass" ), std::make_unique( "filter_ap" ) ); + m_filter1Model.addItem( tr( "Moog" ), std::make_unique( "filter_lp" ) ); + m_filter1Model.addItem( tr( "2x Low-pass" ), std::make_unique( "filter_2lp" ) ); + m_filter1Model.addItem( tr( "RC Low-pass 12 dB/oct" ), std::make_unique( "filter_lp" ) ); + m_filter1Model.addItem( tr( "RC Band-pass 12 dB/oct" ), std::make_unique( "filter_bp" ) ); + m_filter1Model.addItem( tr( "RC High-pass 12 dB/oct" ), std::make_unique( "filter_hp" ) ); + m_filter1Model.addItem( tr( "RC Low-pass 24 dB/oct" ), std::make_unique( "filter_lp" ) ); + m_filter1Model.addItem( tr( "RC Band-pass 24 dB/oct" ), std::make_unique( "filter_bp" ) ); + m_filter1Model.addItem( tr( "RC High-pass 24 dB/oct" ), std::make_unique( "filter_hp" ) ); + m_filter1Model.addItem( tr( "Vocal Formant" ), std::make_unique( "filter_hp" ) ); + m_filter1Model.addItem( tr( "2x Moog" ), std::make_unique( "filter_2lp" ) ); + m_filter1Model.addItem( tr( "SV Low-pass" ), std::make_unique( "filter_lp" ) ); + m_filter1Model.addItem( tr( "SV Band-pass" ), std::make_unique( "filter_bp" ) ); + m_filter1Model.addItem( tr( "SV High-pass" ), std::make_unique( "filter_hp" ) ); + m_filter1Model.addItem( tr( "SV Notch" ), std::make_unique( "filter_notch" ) ); + m_filter1Model.addItem( tr( "Fast Formant" ), std::make_unique( "filter_hp" ) ); + m_filter1Model.addItem( tr( "Tripole" ), std::make_unique( "filter_lp" ) ); + + m_filter2Model.addItem( tr( "Low-pass" ), std::make_unique( "filter_lp" ) ); + m_filter2Model.addItem( tr( "Hi-pass" ), std::make_unique( "filter_hp" ) ); + m_filter2Model.addItem( tr( "Band-pass csg" ), std::make_unique( "filter_bp" ) ); + m_filter2Model.addItem( tr( "Band-pass czpg" ), std::make_unique( "filter_bp" ) ); + m_filter2Model.addItem( tr( "Notch" ), std::make_unique( "filter_notch" ) ); + m_filter2Model.addItem( tr( "All-pass" ), std::make_unique( "filter_ap" ) ); + m_filter2Model.addItem( tr( "Moog" ), std::make_unique( "filter_lp" ) ); + m_filter2Model.addItem( tr( "2x Low-pass" ), std::make_unique( "filter_2lp" ) ); + m_filter2Model.addItem( tr( "RC Low-pass 12 dB/oct" ), std::make_unique( "filter_lp" ) ); + m_filter2Model.addItem( tr( "RC Band-pass 12 dB/oct" ), std::make_unique( "filter_bp" ) ); + m_filter2Model.addItem( tr( "RC High-pass 12 dB/oct" ), std::make_unique( "filter_hp" ) ); + m_filter2Model.addItem( tr( "RC Low-pass 24 dB/oct" ), std::make_unique( "filter_lp" ) ); + m_filter2Model.addItem( tr( "RC Band-pass 24 dB/oct" ), std::make_unique( "filter_bp" ) ); + m_filter2Model.addItem( tr( "RC High-pass 24 dB/oct" ), std::make_unique( "filter_hp" ) ); + m_filter2Model.addItem( tr( "Vocal Formant" ), std::make_unique( "filter_hp" ) ); + m_filter2Model.addItem( tr( "2x Moog" ), std::make_unique( "filter_2lp" ) ); + m_filter2Model.addItem( tr( "SV Low-pass" ), std::make_unique( "filter_lp" ) ); + m_filter2Model.addItem( tr( "SV Band-pass" ), std::make_unique( "filter_bp" ) ); + m_filter2Model.addItem( tr( "SV High-pass" ), std::make_unique( "filter_hp" ) ); + m_filter2Model.addItem( tr( "SV Notch" ), std::make_unique( "filter_notch" ) ); + m_filter2Model.addItem( tr( "Fast Formant" ), std::make_unique( "filter_hp" ) ); + m_filter2Model.addItem( tr( "Tripole" ), std::make_unique( "filter_lp" ) ); connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateFilters() ) ); } diff --git a/plugins/Eq/EqEffect.cpp b/plugins/Eq/EqEffect.cpp index 6b7c61bcc49..a295374931c 100644 --- a/plugins/Eq/EqEffect.cpp +++ b/plugins/Eq/EqEffect.cpp @@ -39,7 +39,7 @@ Plugin::Descriptor PLUGIN_EXPORT eq_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Equalizer", - QT_TRANSLATE_NOOP( "pluginBrowser", "A native eq plugin" ), + QT_TRANSLATE_NOOP( "PluginBrowser", "A native eq plugin" ), "Dave French ", 0x0100, Plugin::Effect, diff --git a/plugins/Eq/EqSpectrumView.h b/plugins/Eq/EqSpectrumView.h index cd3f1775863..84feeff13e8 100644 --- a/plugins/Eq/EqSpectrumView.h +++ b/plugins/Eq/EqSpectrumView.h @@ -24,6 +24,7 @@ #define EQSPECTRUMVIEW_H #include +#include #include #include "fft_helpers.h" diff --git a/plugins/Flanger/FlangerEffect.cpp b/plugins/Flanger/FlangerEffect.cpp index 7e441cf62a3..65b58ce49ed 100644 --- a/plugins/Flanger/FlangerEffect.cpp +++ b/plugins/Flanger/FlangerEffect.cpp @@ -35,7 +35,7 @@ Plugin::Descriptor PLUGIN_EXPORT flanger_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Flanger", - QT_TRANSLATE_NOOP( "pluginBrowser", "A native flanger plugin" ), + QT_TRANSLATE_NOOP( "PluginBrowser", "A native flanger plugin" ), "Dave French ", 0x0100, Plugin::Effect, diff --git a/plugins/FreeBoy/FreeBoy.cpp b/plugins/FreeBoy/FreeBoy.cpp index 2f787044f25..95ba5a215b5 100644 --- a/plugins/FreeBoy/FreeBoy.cpp +++ b/plugins/FreeBoy/FreeBoy.cpp @@ -53,7 +53,7 @@ Plugin::Descriptor PLUGIN_EXPORT freeboy_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "FreeBoy", - QT_TRANSLATE_NOOP( "pluginBrowser", "Emulation of GameBoy (TM) APU" ), + QT_TRANSLATE_NOOP( "PluginBrowser", "Emulation of GameBoy (TM) APU" ), "Attila Herman " "Csaba Hruska ", diff --git a/plugins/GigPlayer/GigPlayer.cpp b/plugins/GigPlayer/GigPlayer.cpp index b358e24e93c..1e077f5d4e3 100644 --- a/plugins/GigPlayer/GigPlayer.cpp +++ b/plugins/GigPlayer/GigPlayer.cpp @@ -28,6 +28,7 @@ * */ +#include "GigPlayer.h" #include #include @@ -35,18 +36,18 @@ #include #include -#include "FileDialog.h" -#include "GigPlayer.h" +#include "ConfigManager.h" +#include "endian_handling.h" #include "Engine.h" +#include "FileDialog.h" #include "InstrumentTrack.h" #include "InstrumentPlayHandle.h" +#include "Knob.h" #include "Mixer.h" #include "NotePlayHandle.h" -#include "Knob.h" +#include "PathUtil.h" #include "SampleBuffer.h" #include "Song.h" -#include "ConfigManager.h" -#include "endian_handling.h" #include "PatchesDialog.h" #include "ToolTip.h" @@ -62,7 +63,7 @@ Plugin::Descriptor PLUGIN_EXPORT gigplayer_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "GIG Player", - QT_TRANSLATE_NOOP( "pluginBrowser", "Player for GIG files" ), + QT_TRANSLATE_NOOP( "PluginBrowser", "Player for GIG files" ), "Garrett Wilson ", 0x0100, Plugin::Instrument, @@ -211,8 +212,8 @@ void GigInstrument::openFile( const QString & _gigFile, bool updateTrackName ) try { - m_instance = new GigInstance( SampleBuffer::tryToMakeAbsolute( _gigFile ) ); - m_filename = SampleBuffer::tryToMakeRelative( _gigFile ); + m_instance = new GigInstance( PathUtil::toAbsolute( _gigFile ) ); + m_filename = PathUtil::toShortestRelative( _gigFile ); } catch( ... ) { @@ -225,7 +226,7 @@ void GigInstrument::openFile( const QString & _gigFile, bool updateTrackName ) if( updateTrackName == true ) { - instrumentTrack()->setName( QFileInfo( _gigFile ).baseName() ); + instrumentTrack()->setName(PathUtil::cleanName( _gigFile ) ); updatePatch(); } } @@ -1057,7 +1058,7 @@ void GigInstrumentView::showFileDialog() if( k->m_filename != "" ) { - QString f = SampleBuffer::tryToMakeAbsolute( k->m_filename ); + QString f = PathUtil::toAbsolute( k->m_filename ); ofd.setDirectory( QFileInfo( f ).absolutePath() ); ofd.selectFile( QFileInfo( f ).fileName() ); } diff --git a/plugins/GigPlayer/PatchesDialog.h b/plugins/GigPlayer/PatchesDialog.h index 0836631acad..ae00f660aaf 100644 --- a/plugins/GigPlayer/PatchesDialog.h +++ b/plugins/GigPlayer/PatchesDialog.h @@ -43,7 +43,7 @@ class PatchesDialog : public QDialog, private Ui::PatchesDialog public: // Constructor. - PatchesDialog( QWidget * pParent = 0, Qt::WindowFlags wflags = 0 ); + PatchesDialog(QWidget * pParent = 0, Qt::WindowFlags wflags = QFlag(0)); // Destructor. virtual ~PatchesDialog(); diff --git a/plugins/HydrogenImport/HydrogenImport.cpp b/plugins/HydrogenImport/HydrogenImport.cpp index 4ed0a89a3f1..c39c52416fc 100644 --- a/plugins/HydrogenImport/HydrogenImport.cpp +++ b/plugins/HydrogenImport/HydrogenImport.cpp @@ -29,7 +29,7 @@ Plugin::Descriptor PLUGIN_EXPORT hydrogenimport_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Hydrogen Import", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "Filter for importing Hydrogen files into LMMS" ), "frank mather", 0x0100, @@ -314,10 +314,8 @@ bool HydrogenImport::readSong() int i = pattern_id[patId]+song_num_tracks; Track *t = ( BBTrack * ) s->tracks().at( i ); - TrackContentObject *tco = t->createTCO( pos ); - tco->movePosition( pos ); + t->createTCO(pos); - if ( pattern_length[patId] > best_length ) { best_length = pattern_length[patId]; diff --git a/plugins/LadspaEffect/CMakeLists.txt b/plugins/LadspaEffect/CMakeLists.txt index 5bfbc3284c8..951615ad4d0 100644 --- a/plugins/LadspaEffect/CMakeLists.txt +++ b/plugins/LadspaEffect/CMakeLists.txt @@ -4,8 +4,6 @@ BUILD_PLUGIN(ladspaeffect LadspaEffect.cpp LadspaControls.cpp LadspaControlDialo SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/ladspa") -SET(CMAKE_CXX_STANDARD 11) - IF(WANT_CAPS) ADD_SUBDIRECTORY(caps) ENDIF(WANT_CAPS) diff --git a/plugins/LadspaEffect/LadspaControls.h b/plugins/LadspaEffect/LadspaControls.h index ccb96dd7484..013b914d45d 100644 --- a/plugins/LadspaEffect/LadspaControls.h +++ b/plugins/LadspaEffect/LadspaControls.h @@ -71,6 +71,7 @@ protected slots: ch_cnt_t m_controlCount; bool m_noLink; BoolModel m_stereoLinkModel; + //! control vector for each processor QVector m_controls; diff --git a/plugins/LadspaEffect/LadspaEffect.cpp b/plugins/LadspaEffect/LadspaEffect.cpp index 7199825214f..79a3c102736 100644 --- a/plugins/LadspaEffect/LadspaEffect.cpp +++ b/plugins/LadspaEffect/LadspaEffect.cpp @@ -53,7 +53,7 @@ Plugin::Descriptor PLUGIN_EXPORT ladspaeffect_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "LADSPA", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "plugin for using arbitrary LADSPA-effects " "inside LMMS." ), "Danny McRae ", diff --git a/plugins/LadspaEffect/calf/CMakeLists.txt b/plugins/LadspaEffect/calf/CMakeLists.txt index 3e213c92cc6..4b264ea1a1d 100644 --- a/plugins/LadspaEffect/calf/CMakeLists.txt +++ b/plugins/LadspaEffect/calf/CMakeLists.txt @@ -1,8 +1,6 @@ # Note: # The last version of Calf that was LADSPA-capable is version 0.0.18.2 -SET(CMAKE_CXX_STANDARD 11) - # Parse version info from autoconf FILE(READ veal/configure.ac VERSION_FILE) STRING(REPLACE "[" ";" VERSION_FILE ${VERSION_FILE} ) diff --git a/plugins/LadspaEffect/cmt/CMakeLists.txt b/plugins/LadspaEffect/cmt/CMakeLists.txt index f9fcd89cbb4..7aae5a68324 100644 --- a/plugins/LadspaEffect/cmt/CMakeLists.txt +++ b/plugins/LadspaEffect/cmt/CMakeLists.txt @@ -1,5 +1,5 @@ INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/include") -FILE(GLOB_RECURSE SOURCES src/*.cpp) +FILE(GLOB_RECURSE SOURCES cmt/src/*.cpp) LIST(SORT SOURCES) ADD_LIBRARY(cmt MODULE ${SOURCES}) INSTALL(TARGETS cmt LIBRARY DESTINATION "${PLUGIN_DIR}/ladspa") @@ -7,13 +7,13 @@ INSTALL(TARGETS cmt LIBRARY DESTINATION "${PLUGIN_DIR}/ladspa") SET_TARGET_PROPERTIES(cmt PROPERTIES PREFIX "") SET_TARGET_PROPERTIES(cmt PROPERTIES COMPILE_FLAGS "-Wall -O3 -fno-strict-aliasing") -IF(LMMS_BUILD_WIN32) - ADD_CUSTOM_COMMAND(TARGET cmt POST_BUILD COMMAND "${STRIP}" \"$\") -ELSE(LMMS_BUILD_WIN32) +IF(LMMS_BUILD_WIN32 AND NOT CMAKE_BUILD_TYPE MATCHES "Deb") + ADD_CUSTOM_COMMAND(TARGET cmt POST_BUILD COMMAND "${STRIP}" "$") +ELSE() SET_TARGET_PROPERTIES(cmt PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -fPIC") -ENDIF(LMMS_BUILD_WIN32) +ENDIF() IF(NOT LMMS_BUILD_APPLE AND NOT LMMS_BUILD_OPENBSD) SET_TARGET_PROPERTIES(cmt PROPERTIES LINK_FLAGS "${LINK_FLAGS} -shared -Wl,-no-undefined") -ENDIF(NOT LMMS_BUILD_APPLE AND NOT LMMS_BUILD_OPENBSD) +ENDIF() diff --git a/plugins/LadspaEffect/cmt/README b/plugins/LadspaEffect/cmt/README deleted file mode 100644 index 3653569fcbf..00000000000 --- a/plugins/LadspaEffect/cmt/README +++ /dev/null @@ -1,7 +0,0 @@ -Computer Music Toolkit (CMT) ----------------------------- - -This toolkit is a set of musical sound processing and synthesis tools -presented as a LADSPA plugin library. See the doc/ directory for -documentation and installation instructions. See http://www.ladspa.org -for LADSPA information. See http://www.ladspa.org/cmt for CMT updates. diff --git a/plugins/LadspaEffect/cmt/cmt b/plugins/LadspaEffect/cmt/cmt new file mode 160000 index 00000000000..f7c25ed4ef7 --- /dev/null +++ b/plugins/LadspaEffect/cmt/cmt @@ -0,0 +1 @@ +Subproject commit f7c25ed4ef7f4d7efb1bcd4229d25595d4f1ce55 diff --git a/plugins/LadspaEffect/cmt/doc/COPYING b/plugins/LadspaEffect/cmt/doc/COPYING deleted file mode 100644 index eeb586b392a..00000000000 --- a/plugins/LadspaEffect/cmt/doc/COPYING +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) 19yy - - 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; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) 19yy name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/plugins/LadspaEffect/cmt/doc/adding_plugins.html b/plugins/LadspaEffect/cmt/doc/adding_plugins.html deleted file mode 100644 index 785bdfdea8d..00000000000 --- a/plugins/LadspaEffect/cmt/doc/adding_plugins.html +++ /dev/null @@ -1,54 +0,0 @@ -

Adding Plugins to the CMT Library

- -

The CMT -LADSPA plugin collection is written in C++ and uses a little -additional sophistication to make plugin writing easier. This document -describes how to add a new plugin to the toolkit.

- -

At the moment CMT is not under public version control, so please -send changes to Richard -Furse.

- -

CMT plugins interpret LADSPA_Handle entities as -pointers to objects derived from the CMT_PluginInstance -class. Plugin instance structures are defined by subclassing this, so -writing a descendent of CMT_PluginInstance is the first -thing to do. The CMT library provides its own implementation of -connect_port(), cleanup() and a templated -form of instantiate() (see -CMT_Instantiate<>()). These calls assume that any -instantiation or cleanup mechanisms required will be written in the -constructor or destructor of the class.

- -

When writing a plugin module, an initialisation function should be -included. To ensure this is called, add a call to the -initialise_modules() function in -descriptor.cpp. The module should also be added to the -makefile.

- -

Your initialisation function should construct new -CMT_Desctiptor plugin descriptor structures and pass them -to registerNewPluginDescriptor(). The -CMT_Descriptor is directly descended from -LADSPA_Descriptor but provides constructor, destructor -and addPort() methods.

- -

All plugins need unique IDs. During development, use values between -1 and 1000. When the plugin is ready, please request an ID from ladspa@muse.demon.co.uk. Please -also add a brief description of your module to plugins.html.

- -

In practice, CMT plugin writing is probably best learned by -example. For a simple case, see the mixer.cpp -module. This defines a SimpleMixer class to handle -instance data, a runSimpleMixer() function for use with -it and a mixer_descriptor() function to provide a -description of the plugin to the CMT core. The -mixer_descriptor() function is declared and referenced in -the descriptor.cpp module. Additional information is -available in cmt.h and ladspa.h.

- -

CMT plugins are licenced under GPL -version 2. Please read and understand this license before submitting -plugins to the library.

diff --git a/plugins/LadspaEffect/cmt/doc/bugs.html b/plugins/LadspaEffect/cmt/doc/bugs.html deleted file mode 100644 index e1c89b44801..00000000000 --- a/plugins/LadspaEffect/cmt/doc/bugs.html +++ /dev/null @@ -1,20 +0,0 @@ -

CMT Bugs

- -

Please report bugs to -richard@muse.demon.co.uk.

- -
    - -
  • I'm not sure I've got attack & decay the right way around in the -expander plugins.
  • - -
  • Need to have a look at dynamic.cpp for handling of unusual -arithmetic situation such as isnan(), -isinf() etc.
  • - -
  • Memory management is a little haphazard at present. What happens -when new() fails? The host can use -set_new_handler(), but I suspect this needs further -thought anyway.
  • - -
diff --git a/plugins/LadspaEffect/cmt/doc/changes.html b/plugins/LadspaEffect/cmt/doc/changes.html deleted file mode 100644 index 38bd7071755..00000000000 --- a/plugins/LadspaEffect/cmt/doc/changes.html +++ /dev/null @@ -1,149 +0,0 @@ -

CMT Changes

- -

Version 1.01 - 4 May 2000

-
    - -
  • Initial Release.
  • - -
- -

Version 1.02 - 11 May 2000

-
    - -
  • Use _init() and _fini(). To handle -memory management automatically.
  • - -
  • Change from *_descriptor() approach simpler -initialise_*() approach. Use _init() and -_fini() to handle memory management. Supply -CMT_Descriptor::~CMT_Descriptor().
  • - -
  • Make comments compatible with Doxygen.
  • - -
  • Addition of Ambisonic encoder, decoder, converter and rotation -plugins.
  • - -
  • Addition of Sine Waveshaper and Granular Scatter Processor -plugin.
  • - -
- -

Version 1.03 - 14 May 2000

-
    - -
  • Updated to correspond to http://www.ladspa.org/.
  • - -
- -

Version 1.04 - 18 May 2000

-
    - -
  • Bugfixes: Ambisonic encoder inputs, white noise amplitude/DC, -Ambisonic rotation inplace support, sine oscillator frequency input -inplace support.
  • - -
- -

Version 1.05 - 18 May 2000

-
    - -
  • Bugfix: use explicit pointer type when deleting -ImplementationData in ~CMT_Descriptor.
  • - -
- -

Version 1.06 - 24 Sep 2000

-
    - -
  • Introduction of Identity plugins.
  • - -
- -

Version 1.07 - 30 Sep 2000

-
    - -
  • Use constructor/destructor rather than _fini() and _init(). Use -C++ for linkage.
  • - -
- -

Version 1.08 - 30 Sep 2000

-
    - -
  • Fix to Ambisonic decode equations.
  • - -
- -

Version 1.09 - 4 Nov 2000

-
    - -
  • Addition of a port of Freeverb (version 3) and a collection of -plugins by David Bartold (analogue, canyon_delay, organ, syndrum, -vcf303).
  • - -
- -

Version 1.10 - 17 Feb 2001

-
    - -
  • Small compile fixes to some modules. Apologies to David who sent -me a patch ages ago for the analogue module.
  • - -
- -

Version 1.11 - 8 May 2001

-
    - -
  • Addition of newline character to end of allpass.h.
  • - -
- -

Version 1.12 - 17 Sept 2001

-
    - -
  • Addition of new plugins by David: "Lo Fi" and "Phase Modulated -Voice."
  • - -
- -

Version 1.13 - 7 May 2002

-
    - -
  • Fix to B-Format rotation algorithm.
  • - -
- -

Version 1.14 - 7 Aug 2002

-
    - -
  • Fix to B-Format rotation algorithm.
  • - -
  • Update for LADSPA 1.1 (include default values).
  • - -
- -

Version 1.15 - 19 Dec 2002

-
    - -
  • Addition of a number of utility routines and namespaces by -Nathaniel Virgo.
  • - -
  • Addition of a number of plugins by Nathaniel Virgo.
  • - -
  • Small change to trigger mechanism in syndrum plugin.
  • - -
- -

Version 1.16 - 6 Nov 2007

-
    - -
  • Remove -Werror from compile options in makefile.
  • - -
  • Remove "local" part from install directories.
  • - -
  • Small additional changes to makefile for robustness.
  • - -
  • Replace strdup() with localStrdup() to avoid malloc/new -mismatch.
  • - -
diff --git a/plugins/LadspaEffect/cmt/doc/index.html b/plugins/LadspaEffect/cmt/doc/index.html deleted file mode 100644 index abab9a5a90b..00000000000 --- a/plugins/LadspaEffect/cmt/doc/index.html +++ /dev/null @@ -1,26 +0,0 @@ -

CMT Index

- - - -

Other Links

- - - -

Richard Furse can be emailed as richard@muse.demon.co.uk. - -

- diff --git a/plugins/LadspaEffect/cmt/doc/installation.html b/plugins/LadspaEffect/cmt/doc/installation.html deleted file mode 100644 index e66e29a03d1..00000000000 --- a/plugins/LadspaEffect/cmt/doc/installation.html +++ /dev/null @@ -1,19 +0,0 @@ -

CMT Installation

- -

To build the plugin library, enter the src/ directory -and run make. The makefile expects to find the -ladspa.h header file in your include path or -/usr/local/include/. If you do not have this file it can -be downloaded as part of the LADSPA SDK from -http://www.ladspa.org/download/.

- -

Running make will generate the CMT LADSPA plugin -library (cmt.so) in the plugins/ -directory. This can be moved to an appropriate location depending on -the application you are using. Running make install from -the src/ directory as root will install to -/usr/local/lib/ladspa/ which is on the search path -recommended for hosts looking for plugin libraries. Some applications -may not search this directory automatically.

- diff --git a/plugins/LadspaEffect/cmt/doc/license.html b/plugins/LadspaEffect/cmt/doc/license.html deleted file mode 100644 index a7e00db169d..00000000000 --- a/plugins/LadspaEffect/cmt/doc/license.html +++ /dev/null @@ -1,16 +0,0 @@ -

CMT License

- -

The CMT toolkit is licensed under GPL version -2.

- -

As I understand it (I'm not a lawyer) this means that, once built, -the CMT library may be used with non-GPL'd applications as -long as it is built and loaded using the standard LADSPA -dynamic-linking approach without modification. In my opinion this is a -good thing for the toolkit, if not for the GPL.

- -

The above may not be correct when built against the LGPL version of -the ladpsa.h header file, but it is certainly the way we would like -things to be. See the LADPSA -license for further details.

diff --git a/plugins/LadspaEffect/cmt/doc/overview.html b/plugins/LadspaEffect/cmt/doc/overview.html deleted file mode 100644 index e34b7a9b7b3..00000000000 --- a/plugins/LadspaEffect/cmt/doc/overview.html +++ /dev/null @@ -1,14 +0,0 @@ -

Computer Music Toolkit (CMT) v1.16 Overview

- -

The Computer Music Toolkit (CMT) is a collection of LADSPA plugins for use with software -synthesis and recording packages on Linux. See the license before use.

- -

The CMT was initially designed and developed by Richard W.E. Furse -(who was also the principal designer of the LADSPA standard) and -further plugins have been provided by by Jezar, David Bartold and -Nathaniel Virgo. If you are a programmer or can write documentation -and would like to help out, please feel free to contact Richard.

- diff --git a/plugins/LadspaEffect/cmt/doc/plugins.html b/plugins/LadspaEffect/cmt/doc/plugins.html deleted file mode 100644 index 9eddd04886d..00000000000 --- a/plugins/LadspaEffect/cmt/doc/plugins.html +++ /dev/null @@ -1,477 +0,0 @@ -

CMT Library Plugins

- -

The following plugins are provided in the CMT library:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Plugin IDPlugin LabelDescription
1051lpfLow Pass Filter (One Pole).
1052hpfHigh Pass Filter (One Pole).
1053delay_0.01sEcho Delay Line. The delay time may be varied up to 0.01 -seconds. No feedback is provided.
1054delay_0.1sEcho Delay Line. The delay time may be varied up to 0.1 -seconds. No feedback is provided.
1055delay_1sEcho Delay Line. The delay time may be varied up to 1 -second. No feedback is provided.
1056delay_5sEcho Delay Line. The delay time may be varied up to 5 -seconds. No feedback is provided.
1057delay_60sEcho Delay Line. The delay time may be varied up to 60 -seconds. No feedback is provided.
1058fbdelay_0.01sFeedback Delay Line. The delay time may be varied up to 0.01 -seconds.
1059fbdelay_0.1sFeedback Delay Line. The delay time may be varied up to 0.1 -seconds.
1060fbdelay_1sFeedback Delay Line. The delay time may be varied up to 1 -second.
1061fbdelay_5sFeedback Delay Line. The delay time may be varied up to 5 -seconds.
1062fbdelay_60sFeedback Delay Line. The delay time may be varied up to 60 -seconds.
1063sine_faaaSine Oscillator. Frequency input is audio, Amplitude input is -audio.
1064sine_faacSine Oscillator. Frequency input is audio, Amplitude input is -control.
1065sine_fcaaSine Oscillator. Frequency input is control, Amplitude input is -audio.
1066sine_fcacSine Oscillator. Frequency input is control, Amplitude input is -control.
1067amp_monoAmplifier (Mono).
1068amp_stereoAmplifier (Stereo).
1069noise_source_whiteNoise Source (White).
1070amAmplitude Modulator.
1071mixerMixer (Stereo to Mono).
1072compress_peakSimple Compressor (Peak Envelope Tracking).
1073compress_rmsSimple Compressor (RMS Envelope Tracking).
1074expand_peakSimple Expander (Peak Envelope Tracking).
1075expand_rmsSimple Expander (RMS Envelope Tracking).
1076limit_peakSimple Limiter (Peak Envelope Tracking).
1077limit_rmsSimple Limiter (RMS Envelope Tracking).
1078track_peakEnvelope Tracker (Peak).
1079track_rmsEnvelope Tracker (RMS).
1080track_max_peakEnvelope Tracker (Maximum Peak).
1081track_max_rmsEnvelope Tracker (Maximum RMS).
1082peakPeak Monitor.
1083null_ciNull Plugin (Control Input).
1084null_aiNull Plugin (Audio Input).
1085null_coNull Plugin (Control Output).
1086null_aoNull Plugin (Audio Output).
1087encode_bformatB-Format Encoder. This plugin encodes ambisonic B-Format audio -using the inverse square law but no filtering, reverb or delay.
1088encode_fmhFMH-Format Encoder. This plugin encodes ambisonic FMH-Format audio -using the inverse square law but no filtering, reverb or delay.
1089fmh2bfFMH-Format to B-Format. This plugin simply discards the R, S, T, U -and V channels but is included for clarity.
1090bf2stereoB-Format to Stereo Ambisonic Decoder. This plugin only actually -uses its W and Y input signals and does not use UHJ.
1091bf2quadB-Format to Quad Ambisonic Decoder. This plugin only actually uses -its W, Y and Z input signals.
1092bf2cubeB-Format to Cube Ambisonic Decoder.
1093bf2octFMH-Format to Octagon Ambisonic Decoder. This plugin only actually -uses its W, X, Y, U and V inputs.
1094bf_rotate_zB-Format Rotation (Horizontal). This plugin rotates an B-Format -encoded soundfield around the Z-axis.
1095fmh_rotate_zFMH-Format Rotation (Horizontal). This plugin rotates an -FMH-Format encoded soundfield around the Z-axis.
1096grain_scatterGranular Scattering Processor. This plugin generates an output -audio stream by scattering short `grains' of sound from an input -stream. It is possible to control the length and envelope of these -grains, how far away from their source time grains may be scattered -and the density (grains/sec) of the texture produced.
1097wsshape_sineWave Shaper (Sine-Based).
1098identity_audioIdentity (Audio).
1099identity_controlIdentity (Control).
1123freeverb3Freeverb (Version 3). This reverb unit is a direct port of the -free public domain source code available from Jezar at Dreampoint.
1221analogueAnalogue Synthesizer Voice. Contains two audio oscillators, one LFO, -and three ADSRs. There are five waveforms available for the DCOs: -Sine, Triangle, Square, Sawtooth, and Fullwave rectified sine. The DCOs -may be frequency modulated and/or pulse width modulated by the LFO.
1222organOrgan Voice with Configurable Harmonics. The user may control the -loudness of the harmonics. There are three additional tones that may -be enabled and combined: brass, flute, and reed. Two ADSRs control -the envelope for the upper and lower harmonics.
1223syndrumDrum Synthesizer.
1224vcf303VCF 303. A TB-303 resonant filter clone.
1225canyon_delayCanyon Delay. A deep stereo crossdelay with built-in low pass -filters.
1226phasemodPhase Modulated Synthesizer Voice. Contains six audio oscillators, each -oscillator phase modulates the next. If a modulation coefficient is zero, -then the former oscillator's output is summed with the module's output. -DCO1's phase modulation parameter specifies an offset not a coefficient. -Example modulation parameters {1.0, 0.5, 0.0, 0.5, 0.2, 0.0} for all -six oscillators results in the output function: DCO2 (phase = DCO1 (phase = -1.0) * 0.5) + DCO5 (phase = DCO4 (phase = DCO3 (phase = 0.0) * 0.5) * 0.2) + -DCO6 (phase = 0.0). Each oscillator's output is bounded by -1.0 and 1.0, -or -360o and 360o.
1227lofiLo Fi. Simulates old audio equipment. Adds distortion, -bandwidth limiting, compression, and crackling to audio.
1841pink_interpolated_audioInterpolated pink noise. Pink noise is a kind of random -one-dimensional fractal. This plugin approximates the effect of an -extreme low pass filter on a pink noise signal. It is useful as a -natural-sounding continuously varying control signal with long-term -trends as well as short-term variation. If you use it to control the -pitch of a sine wave it can sound a bit like wind blowing. Notice that -the average value tends to gradually drift over long periods of -time. This is in the nature of pink noise, and so can't be -helped.
1843pink_shSample and hold pink noise. Similar to pink, but with stepped -instead of interpolated output.
1844pink_full_frequencyPink noise simulation with a full frequency range. You can low -pass filter this to get a similar effect to the interpolated pink -noise generator.
1845hard_gateHard noise gate. If the absolute value of the signal falls below -"threshold", it is set to zero. There is no antialiasing.
1846disintegratorAmplifies random half-cycles of it's input by multiplier. Set -multiplier to 0 and vary probability for a weird fade effect, or set -multiplier to -1 and probability to 0.5 to turn pitched sounds into -noise.
1848sledgehammerA Dynamic Sledgehammer, which you can use to bash your signals -into shape. It's basically a very simple and heavy compressor with a -sidechain. Try it with a pad sound as the carrier and a drum loop as -the modulator. Also, you can get some nice "Satan Maximiser"-style -distortion by not connecting the modulator (set it's influence to 0) -and putting the rate up to around 0.1.
1849logisticLogistic Map chaotic stepped control generator. The logistic map -is a classic example from chaos theory. It can be summarised by the -formula
x := r*x*(1-x).
With r<3, x just converges to a -constant value. With r just greater than 3 it oscillates with period -2. at about 3.45 the period doubles again to 4. These period doublings -occur at smaller and smaller increments of r, until at about 3.5699 -there have been an infinite number and the signal never -repeates. Between this value and 4 the system exhibits chaotic -behaviour (although there are regions of periodicity). Papers are -still being published today on the subject of this system's -behaviour. This plugin iterates this map at a given frequency to -produce a stepped signal, which is scaled to lie in the range -(-1,1). When this signal is used as a frequency control it can -sometimes sound quite musical.
- -

"Ambisonics" is a registered trademark of Nimbus Communications -International.

diff --git a/plugins/LadspaEffect/cmt/doc/tasks.html b/plugins/LadspaEffect/cmt/doc/tasks.html deleted file mode 100644 index 72a9ff6d35d..00000000000 --- a/plugins/LadspaEffect/cmt/doc/tasks.html +++ /dev/null @@ -1,36 +0,0 @@ -

CMT Library Task List

- -

Basic Plugins Needed

- -
    - -
  • Noise Gate
  • -
  • Flanger
  • -
  • Phaser
  • -
  • Chorus
  • -
  • Unbounded Delay (echo & feedback)
  • -
  • Distortion
  • -
  • Overdrive
  • -
  • Exciter
  • -
  • Resonant Filter
  • -
  • Graphic EQ
  • -
  • Envelope Generator
  • - -
- -

Other Plugins Planned

- -
    - -
  • Vocoder
  • - -
- -

Other Tasks

- -
    - -
  • Think up a better name than CMT.
  • - -
- diff --git a/plugins/LadspaEffect/cmt/src/am.cpp b/plugins/LadspaEffect/cmt/src/am.cpp deleted file mode 100644 index 2e07ae5538d..00000000000 --- a/plugins/LadspaEffect/cmt/src/am.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* am.cpp - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include -#include - -/*****************************************************************************/ - -#include "cmt.h" - -/*****************************************************************************/ - -#define AM_INPUT1 0 -#define AM_INPUT2 1 -#define AM_OUTPUT 2 - -/** This plugin multiplies two signals together to produce a third. */ -class AmplitudeModulator : public CMT_PluginInstance { -public: - - AmplitudeModulator(const LADSPA_Descriptor *, - unsigned long) - : CMT_PluginInstance(3) { - } - - friend void runAmplitudeModulator(LADSPA_Handle Instance, - unsigned long SAmplitudeModulatorpleCount); - -}; - -/*****************************************************************************/ - -void -runAmplitudeModulator(LADSPA_Handle Instance, - unsigned long SAmplitudeModulatorpleCount) { - - AmplitudeModulator * poAmplitudeModulator = (AmplitudeModulator *)Instance; - - LADSPA_Data * pfInput1 = poAmplitudeModulator->m_ppfPorts[AM_INPUT1]; - LADSPA_Data * pfInput2 = poAmplitudeModulator->m_ppfPorts[AM_INPUT2]; - LADSPA_Data * pfOutput = poAmplitudeModulator->m_ppfPorts[AM_OUTPUT]; - - for (unsigned long lSAmplitudeModulatorpleIndex = 0; - lSAmplitudeModulatorpleIndex < SAmplitudeModulatorpleCount; - lSAmplitudeModulatorpleIndex++) - *(pfOutput++) = *(pfInput1++) * *(pfInput2++); -} - -/*****************************************************************************/ - -void -initialise_am() { - - CMT_Descriptor * psDescriptor = new CMT_Descriptor - (1070, - "am", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Amplitude Modulator", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runAmplitudeModulator, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input 1"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input 2"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - - registerNewPluginDescriptor(psDescriptor); -} - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/ambisonic.cpp b/plugins/LadspaEffect/cmt/src/ambisonic.cpp deleted file mode 100644 index 60e42809ca1..00000000000 --- a/plugins/LadspaEffect/cmt/src/ambisonic.cpp +++ /dev/null @@ -1,1135 +0,0 @@ -/* ambisonic.cpp - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -/* This module provides simple plugins handling B-Format and - FMH-Format audio. Ambisonics is a mathematical technique designed - to capture the sound field around point. See - http://www.muse.demon.co.uk/3daudio.html. "Ambisonics" is a - registered trademark of Nimbus Communications International - although. An exteremly `vanilla' approach is taken to encoding - distance, using inverse square, but no filtering or delay. */ - -/*****************************************************************************/ - -#include -#include -#include - -/*****************************************************************************/ - -#include "cmt.h" - -/*****************************************************************************/ - -#define ENC_INPUT 0 -#define ENC_IN_X 1 -#define ENC_IN_Y 2 -#define ENC_IN_Z 3 -#define ENC_OUT_W 4 -#define ENC_OUT_X 5 -#define ENC_OUT_Y 6 -#define ENC_OUT_Z 7 - -#define ENC_OUT_R 8 -#define ENC_OUT_S 9 -#define ENC_OUT_T 10 -#define ENC_OUT_U 11 -#define ENC_OUT_V 12 - -/*****************************************************************************/ - -/** This plugin encodes a signal to B-Format depending on where it is - located in a virtual space. */ -class BFormatEncoder : public CMT_PluginInstance { -public: - BFormatEncoder(const LADSPA_Descriptor *, - unsigned long lSampleRate) - : CMT_PluginInstance(8) { - } - friend void runBFormatEncoder(LADSPA_Handle Instance, - unsigned long SampleCount); -}; - -/** This plugin encodes a signal to FMH-Format depending on where it - is located in a virtual space. */ -class FMHFormatEncoder : public CMT_PluginInstance { -public: - FMHFormatEncoder(const LADSPA_Descriptor *, - unsigned long lSampleRate) - : CMT_PluginInstance(13) { - } - friend void runFMHFormatEncoder(LADSPA_Handle Instance, - unsigned long SampleCount); -}; - -/*****************************************************************************/ - -#define F2B_IN_W 0 -#define F2B_IN_X 1 -#define F2B_IN_Y 2 -#define F2B_IN_Z 3 -#define F2B_IN_R 4 -#define F2B_IN_S 5 -#define F2B_IN_T 6 -#define F2B_IN_U 7 -#define F2B_IN_V 8 -#define F2B_OUT_W 9 -#define F2B_OUT_X 10 -#define F2B_OUT_Y 11 -#define F2B_OUT_Z 12 - -/** This plugin coverts FMH-Format to B-Format. This is a trivial - operation that can also be achieved simply by discarding RSTUV - channels. */ -class FMHToB : public CMT_PluginInstance { -public: - FMHToB(const LADSPA_Descriptor *, - unsigned long lSampleRate) - : CMT_PluginInstance(13) { - } - friend void runFMHToB(LADSPA_Handle Instance, - unsigned long SampleCount); -}; - -/*****************************************************************************/ - -#define DECST_IN_W 0 -#define DECST_IN_X 1 -#define DECST_IN_Y 2 -#define DECST_IN_Z 3 -#define DECST_OUT_L 4 -#define DECST_OUT_R 5 - -/** This plugin decodes B-Format to produce a stereo speaker feed. */ -class BFormatToStereo : public CMT_PluginInstance { -public: - BFormatToStereo(const LADSPA_Descriptor *, - unsigned long lSampleRate) - : CMT_PluginInstance(6) { - } - friend void runBFormatToStereo(LADSPA_Handle Instance, - unsigned long SampleCount); -}; - -/*****************************************************************************/ - -#define DECQ_IN_W 0 -#define DECQ_IN_X 1 -#define DECQ_IN_Y 2 -#define DECQ_IN_Z 3 -#define DECQ_OUT_FL 4 -#define DECQ_OUT_FR 5 -#define DECQ_OUT_BL 6 -#define DECQ_OUT_BR 7 - -/** This plugin decodes B-Format to produce a quad (square) speaker feed. */ -class BFormatToQuad : public CMT_PluginInstance { -public: - BFormatToQuad(const LADSPA_Descriptor *, - unsigned long lSampleRate) - : CMT_PluginInstance(8) { - } - friend void runBFormatToQuad(LADSPA_Handle Instance, - unsigned long SampleCount); -}; - -/*****************************************************************************/ - -#define DECC_IN_W 0 -#define DECC_IN_X 1 -#define DECC_IN_Y 2 -#define DECC_IN_Z 3 -#define DECC_OUT_BFL 4 -#define DECC_OUT_BFR 5 -#define DECC_OUT_BBL 6 -#define DECC_OUT_BBR 7 -#define DECC_OUT_TFL 8 -#define DECC_OUT_TFR 9 -#define DECC_OUT_TBL 10 -#define DECC_OUT_TBR 11 - -/** This plugin decodes B-Format to produce a speaker feed for eight - speakers arranged at the corners of a cube. */ -class BFormatToCube : public CMT_PluginInstance { -public: - BFormatToCube(const LADSPA_Descriptor *, - unsigned long lSampleRate) - : CMT_PluginInstance(12) { - } - friend void runBFormatToCube(LADSPA_Handle Instance, - unsigned long SampleCount); -}; - -/*****************************************************************************/ - -#define DECO_IN_W 0 -#define DECO_IN_X 1 -#define DECO_IN_Y 2 -#define DECO_IN_Z 3 -#define DECO_IN_R 4 -#define DECO_IN_S 5 -#define DECO_IN_T 6 -#define DECO_IN_U 7 -#define DECO_IN_V 8 -#define DECO_OUT_FFL 9 -#define DECO_OUT_FFR 10 -#define DECO_OUT_FRR 11 -#define DECO_OUT_BRR 12 -#define DECO_OUT_BBR 13 -#define DECO_OUT_BBL 14 -#define DECO_OUT_BLL 15 -#define DECO_OUT_FLL 16 - -/** This plugin decodes FMH-Format to produce a speaker feed for eight - speakers arranged at the corners of an octagon. */ -class FMHFormatToOct : public CMT_PluginInstance { -public: - FMHFormatToOct(const LADSPA_Descriptor *, - unsigned long lSampleRate) - : CMT_PluginInstance(17) { - } - friend void runFMHFormatToOct(LADSPA_Handle Instance, - unsigned long SampleCount); -}; - -/*****************************************************************************/ - -#define BFROT_ANGLE 0 -#define BFROT_IN_W 1 -#define BFROT_IN_X 2 -#define BFROT_IN_Y 3 -#define BFROT_IN_Z 4 -#define BFROT_OUT_W 5 -#define BFROT_OUT_X 6 -#define BFROT_OUT_Y 7 -#define BFROT_OUT_Z 8 - -/** This plugin rotates an B-Format soundfield around the Z-axis. */ -class BFormatRotation : public CMT_PluginInstance { -public: - BFormatRotation(const LADSPA_Descriptor *, - unsigned long lSampleRate) - : CMT_PluginInstance(9) { - } - friend void runBFormatRotation(LADSPA_Handle Instance, - unsigned long SampleCount); -}; - -/*****************************************************************************/ - -#define FMHROT_ANGLE 0 - -#define FMHROT_IN_W 1 -#define FMHROT_IN_X 2 -#define FMHROT_IN_Y 3 -#define FMHROT_IN_Z 4 -#define FMHROT_IN_R 5 -#define FMHROT_IN_S 6 -#define FMHROT_IN_T 7 -#define FMHROT_IN_U 8 -#define FMHROT_IN_V 9 - -#define FMHROT_OUT_W 10 -#define FMHROT_OUT_X 11 -#define FMHROT_OUT_Y 12 -#define FMHROT_OUT_Z 13 -#define FMHROT_OUT_R 14 -#define FMHROT_OUT_S 15 -#define FMHROT_OUT_T 16 -#define FMHROT_OUT_U 17 -#define FMHROT_OUT_V 18 - -/** This plugin rotates an FMH-Format soundfield around the Z-axis. */ -class FMHFormatRotation : public CMT_PluginInstance { -public: - FMHFormatRotation(const LADSPA_Descriptor *, - unsigned long lSampleRate) - : CMT_PluginInstance(19) { - } - friend void runFMHFormatRotation(LADSPA_Handle Instance, - unsigned long SampleCount); -}; - -/*****************************************************************************/ - -void -runBFormatEncoder(LADSPA_Handle Instance, - unsigned long SampleCount) { - - BFormatEncoder * poProcessor = (BFormatEncoder *)Instance; - - LADSPA_Data * pfInput = poProcessor->m_ppfPorts[ENC_INPUT]; - LADSPA_Data * pfOutW = poProcessor->m_ppfPorts[ENC_OUT_W]; - LADSPA_Data * pfOutX = poProcessor->m_ppfPorts[ENC_OUT_X]; - LADSPA_Data * pfOutY = poProcessor->m_ppfPorts[ENC_OUT_Y]; - LADSPA_Data * pfOutZ = poProcessor->m_ppfPorts[ENC_OUT_Z]; - - LADSPA_Data fX = *(poProcessor->m_ppfPorts[ENC_IN_X]); - LADSPA_Data fY = *(poProcessor->m_ppfPorts[ENC_IN_Y]); - LADSPA_Data fZ = *(poProcessor->m_ppfPorts[ENC_IN_Z]); - LADSPA_Data fDistanceSquared = fX * fX + fY * fY + fZ * fZ; - const LADSPA_Data fWScalar = 0.707107; - LADSPA_Data fXScalar, fYScalar, fZScalar; - if (fDistanceSquared > 1e-10) { - LADSPA_Data fOneOverDistanceSquared = 1 / fDistanceSquared; - fXScalar = fX * fOneOverDistanceSquared; - fYScalar = fY * fOneOverDistanceSquared; - fZScalar = fZ * fOneOverDistanceSquared; - } - else { - /* Avoid division by zero issues. */ - fXScalar = fYScalar = fZScalar = 0; - } - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - LADSPA_Data fInput = *(pfInput++); - *(pfOutW++) = fWScalar * fInput; - *(pfOutX++) = fXScalar * fInput; - *(pfOutY++) = fYScalar * fInput; - *(pfOutZ++) = fZScalar * fInput; - } -} - -/*****************************************************************************/ - -void -runFMHFormatEncoder(LADSPA_Handle Instance, - unsigned long SampleCount) { - - FMHFormatEncoder * poProcessor = (FMHFormatEncoder *)Instance; - - LADSPA_Data * pfInput = poProcessor->m_ppfPorts[ENC_INPUT]; - LADSPA_Data * pfOutW = poProcessor->m_ppfPorts[ENC_OUT_W]; - LADSPA_Data * pfOutX = poProcessor->m_ppfPorts[ENC_OUT_X]; - LADSPA_Data * pfOutY = poProcessor->m_ppfPorts[ENC_OUT_Y]; - LADSPA_Data * pfOutZ = poProcessor->m_ppfPorts[ENC_OUT_Z]; - LADSPA_Data * pfOutR = poProcessor->m_ppfPorts[ENC_OUT_R]; - LADSPA_Data * pfOutS = poProcessor->m_ppfPorts[ENC_OUT_S]; - LADSPA_Data * pfOutT = poProcessor->m_ppfPorts[ENC_OUT_T]; - LADSPA_Data * pfOutU = poProcessor->m_ppfPorts[ENC_OUT_U]; - LADSPA_Data * pfOutV = poProcessor->m_ppfPorts[ENC_OUT_V]; - - LADSPA_Data fX = *(poProcessor->m_ppfPorts[ENC_IN_X]); - LADSPA_Data fY = *(poProcessor->m_ppfPorts[ENC_IN_Y]); - LADSPA_Data fZ = *(poProcessor->m_ppfPorts[ENC_IN_Z]); - LADSPA_Data fDistanceSquared = fX * fX + fY * fY + fZ * fZ; - const LADSPA_Data fWScalar = 0.707107; - LADSPA_Data fXScalar, fYScalar, fZScalar; - LADSPA_Data fRScalar, fSScalar, fTScalar; - LADSPA_Data fUScalar, fVScalar; - if (fDistanceSquared > 1e-10) { - LADSPA_Data fOneOverDistanceSquared - = 1 / fDistanceSquared; - LADSPA_Data fOneOverDistanceCubed - = LADSPA_Data(pow(fDistanceSquared, -1.5)); - fXScalar = fX * fOneOverDistanceSquared; - fYScalar = fY * fOneOverDistanceSquared; - fZScalar = fZ * fOneOverDistanceSquared; - fRScalar = ((fZ * fZ) * fOneOverDistanceSquared - 0.5) - * sqrt(fOneOverDistanceSquared); - fSScalar = 2 * (fZ * fX) * fOneOverDistanceCubed; - fTScalar = 2 * (fY * fX) * fOneOverDistanceCubed; - fUScalar = (fX * fX - fY * fY) * fOneOverDistanceCubed; - fVScalar = 2 * (fX * fY) * fOneOverDistanceCubed; - } - else { - /* Avoid division by zero issues. */ - fXScalar = fYScalar = fZScalar - = fRScalar = fSScalar = fTScalar - = fUScalar = fVScalar = 0; - } - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - LADSPA_Data fInput = *(pfInput++); - *(pfOutW++) = fWScalar * fInput; - *(pfOutX++) = fXScalar * fInput; - *(pfOutY++) = fYScalar * fInput; - *(pfOutZ++) = fZScalar * fInput; - *(pfOutR++) = fRScalar * fInput; - *(pfOutS++) = fSScalar * fInput; - *(pfOutT++) = fTScalar * fInput; - *(pfOutU++) = fUScalar * fInput; - *(pfOutV++) = fVScalar * fInput; - } -} - -/*****************************************************************************/ - -void -runFMHToB(LADSPA_Handle Instance, - unsigned long SampleCount) { - - FMHToB * poProcessor = (FMHToB *)Instance; - - LADSPA_Data * pfInW = poProcessor->m_ppfPorts[F2B_IN_W]; - LADSPA_Data * pfInX = poProcessor->m_ppfPorts[F2B_IN_X]; - LADSPA_Data * pfInY = poProcessor->m_ppfPorts[F2B_IN_Y]; - LADSPA_Data * pfInZ = poProcessor->m_ppfPorts[F2B_IN_Z]; - LADSPA_Data * pfOutW = poProcessor->m_ppfPorts[F2B_OUT_W]; - LADSPA_Data * pfOutX = poProcessor->m_ppfPorts[F2B_OUT_X]; - LADSPA_Data * pfOutY = poProcessor->m_ppfPorts[F2B_OUT_Y]; - LADSPA_Data * pfOutZ = poProcessor->m_ppfPorts[F2B_OUT_Z]; - - int iSize = sizeof(LADSPA_Data) * SampleCount; - memcpy(pfOutW, pfInW, iSize); - memcpy(pfOutX, pfInX, iSize); - memcpy(pfOutY, pfInY, iSize); - memcpy(pfOutZ, pfInZ, iSize); -} - -/*****************************************************************************/ - -void -runBFormatToStereo(LADSPA_Handle Instance, - unsigned long SampleCount) { - - BFormatToStereo * poProcessor = (BFormatToStereo *)Instance; - - LADSPA_Data * pfInW = poProcessor->m_ppfPorts[DECST_IN_W]; - LADSPA_Data * pfInY = poProcessor->m_ppfPorts[DECST_IN_Y]; - - LADSPA_Data * pfOutL = poProcessor->m_ppfPorts[DECST_OUT_L]; - LADSPA_Data * pfOutR = poProcessor->m_ppfPorts[DECST_OUT_R]; - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - LADSPA_Data fA = 0.707107 * *(pfInW++); - LADSPA_Data fB = 0.5 * *(pfInY++); - *(pfOutL++) = fA + fB; - *(pfOutR++) = fA - fB; - } - -} - -/*****************************************************************************/ - -void -runBFormatToQuad(LADSPA_Handle Instance, - unsigned long SampleCount) { - - BFormatToQuad * poProcessor = (BFormatToQuad *)Instance; - - LADSPA_Data * pfInW = poProcessor->m_ppfPorts[DECQ_IN_W]; - LADSPA_Data * pfInX = poProcessor->m_ppfPorts[DECQ_IN_X]; - LADSPA_Data * pfInY = poProcessor->m_ppfPorts[DECQ_IN_Y]; - - LADSPA_Data * pfOutFL = poProcessor->m_ppfPorts[DECQ_OUT_FL]; - LADSPA_Data * pfOutFR = poProcessor->m_ppfPorts[DECQ_OUT_FR]; - LADSPA_Data * pfOutBL = poProcessor->m_ppfPorts[DECQ_OUT_BL]; - LADSPA_Data * pfOutBR = poProcessor->m_ppfPorts[DECQ_OUT_BR]; - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - LADSPA_Data fW = 0.353553 * *(pfInW++); - LADSPA_Data fX = 0.243361 * *(pfInX++); - LADSPA_Data fY = 0.243361 * *(pfInY++); - LADSPA_Data fV = 0.096383 * *(pfInY++); - *(pfOutFL++) = fW + fX + fY + fV; - *(pfOutFR++) = fW + fX - fY - fV; - *(pfOutBL++) = fW - fX + fY + fV; - *(pfOutBR++) = fW - fX - fY - fV; - } - -} - -/*****************************************************************************/ - -void -runBFormatToCube(LADSPA_Handle Instance, - unsigned long SampleCount) { - - BFormatToCube * poProcessor = (BFormatToCube *)Instance; - - LADSPA_Data * pfInW = poProcessor->m_ppfPorts[DECC_IN_W]; - LADSPA_Data * pfInX = poProcessor->m_ppfPorts[DECC_IN_X]; - LADSPA_Data * pfInY = poProcessor->m_ppfPorts[DECC_IN_Y]; - LADSPA_Data * pfInZ = poProcessor->m_ppfPorts[DECC_IN_Z]; - - LADSPA_Data * pfOutBFL = poProcessor->m_ppfPorts[DECC_OUT_BFL]; - LADSPA_Data * pfOutBFR = poProcessor->m_ppfPorts[DECC_OUT_BFR]; - LADSPA_Data * pfOutBBL = poProcessor->m_ppfPorts[DECC_OUT_BBL]; - LADSPA_Data * pfOutBBR = poProcessor->m_ppfPorts[DECC_OUT_BBR]; - LADSPA_Data * pfOutTFL = poProcessor->m_ppfPorts[DECC_OUT_BFL]; - LADSPA_Data * pfOutTFR = poProcessor->m_ppfPorts[DECC_OUT_BFR]; - LADSPA_Data * pfOutTBL = poProcessor->m_ppfPorts[DECC_OUT_BBL]; - LADSPA_Data * pfOutTBR = poProcessor->m_ppfPorts[DECC_OUT_BBR]; - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - LADSPA_Data fW = 0.176777 * *(pfInW++); - LADSPA_Data fX = 0.113996 * *(pfInX++); - LADSPA_Data fY = 0.113996 * *(pfInY++); - LADSPA_Data fZ = 0.113996 * *(pfInZ++); - LADSPA_Data fS = 0.036859 * *(pfInX++); - LADSPA_Data fT = 0.036859 * *(pfInY++); - LADSPA_Data fV = 0.036859 * *(pfInZ++); - *(pfOutBFL++) = fW + fX + fY - fZ + fV - fT - fS; - *(pfOutBFR++) = fW + fX - fY - fZ - fV + fT - fS; - *(pfOutBBL++) = fW - fX + fY - fZ + fV + fT + fS; - *(pfOutBBR++) = fW - fX - fY - fZ - fV - fT + fS; - *(pfOutTFL++) = fW + fX + fY + fZ + fV + fT + fS; - *(pfOutTFR++) = fW + fX - fY + fZ - fV - fT + fS; - *(pfOutTBL++) = fW - fX + fY + fZ + fV - fT - fS; - *(pfOutTBR++) = fW - fX - fY + fZ - fV + fT - fS; - } - -} - -/*****************************************************************************/ - -void -runFMHFormatToOct(LADSPA_Handle Instance, - unsigned long SampleCount) { - - FMHFormatToOct * poProcessor = (FMHFormatToOct *)Instance; - - LADSPA_Data * pfInW = poProcessor->m_ppfPorts[DECO_IN_W]; - LADSPA_Data * pfInX = poProcessor->m_ppfPorts[DECO_IN_X]; - LADSPA_Data * pfInY = poProcessor->m_ppfPorts[DECO_IN_Y]; - LADSPA_Data * pfInU = poProcessor->m_ppfPorts[DECO_IN_U]; - LADSPA_Data * pfInV = poProcessor->m_ppfPorts[DECO_IN_V]; - - LADSPA_Data * pfOutFFL = poProcessor->m_ppfPorts[DECO_OUT_FFL]; - LADSPA_Data * pfOutFFR = poProcessor->m_ppfPorts[DECO_OUT_FFR]; - LADSPA_Data * pfOutFRR = poProcessor->m_ppfPorts[DECO_OUT_FRR]; - LADSPA_Data * pfOutBRR = poProcessor->m_ppfPorts[DECO_OUT_BRR]; - LADSPA_Data * pfOutBBR = poProcessor->m_ppfPorts[DECO_OUT_BBR]; - LADSPA_Data * pfOutBBL = poProcessor->m_ppfPorts[DECO_OUT_BBL]; - LADSPA_Data * pfOutBLL = poProcessor->m_ppfPorts[DECO_OUT_BLL]; - LADSPA_Data * pfOutFLL = poProcessor->m_ppfPorts[DECO_OUT_FLL]; - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - LADSPA_Data fW = 0.176777 * *(pfInW++); - LADSPA_Data fX1 = 0.065888 * *pfInX; - LADSPA_Data fX2 = 0.159068 * *(pfInX++); - LADSPA_Data fY1 = 0.065888 * *pfInY; - LADSPA_Data fY2 = 0.159068 * *(pfInY++); - LADSPA_Data fU = 0.034175 * *(pfInU++); - LADSPA_Data fV = 0.034175 * *(pfInV++); - *(pfOutFFL++) = fW + fX2 + fY1 + fU + fV; - *(pfOutFFR++) = fW + fX2 - fY1 + fU - fV; - *(pfOutFRR++) = fW + fX1 - fY2 - fU - fV; - *(pfOutBRR++) = fW - fX1 + fY2 - fU + fV; - *(pfOutBBR++) = fW - fX2 + fY1 + fU + fV; - *(pfOutBBL++) = fW - fX2 - fY1 + fU - fV; - *(pfOutBLL++) = fW - fX1 - fY2 - fU - fV; - *(pfOutFLL++) = fW + fX1 + fY2 - fU + fV; - } - -} - -/*****************************************************************************/ - -void -runBFormatRotation(LADSPA_Handle Instance, - unsigned long SampleCount) { - - BFormatRotation * poProcessor = (BFormatRotation *)Instance; - - /* Work in radians. */ - LADSPA_Data fAngle - = LADSPA_Data(M_PI / 180.0) * *(poProcessor->m_ppfPorts[FMHROT_ANGLE]); - LADSPA_Data fSin = sin(fAngle); - LADSPA_Data fCos = cos(fAngle); - - LADSPA_Data * pfInW = poProcessor->m_ppfPorts[BFROT_IN_W]; - LADSPA_Data * pfInX = poProcessor->m_ppfPorts[BFROT_IN_X]; - LADSPA_Data * pfInY = poProcessor->m_ppfPorts[BFROT_IN_Y]; - LADSPA_Data * pfInZ = poProcessor->m_ppfPorts[BFROT_IN_Z]; - - LADSPA_Data * pfOutW = poProcessor->m_ppfPorts[BFROT_OUT_W]; - LADSPA_Data * pfOutX = poProcessor->m_ppfPorts[BFROT_OUT_X]; - LADSPA_Data * pfOutY = poProcessor->m_ppfPorts[BFROT_OUT_Y]; - LADSPA_Data * pfOutZ = poProcessor->m_ppfPorts[BFROT_OUT_Z]; - - int iSize = sizeof(LADSPA_Data) * SampleCount; - memcpy(pfOutW, pfInW, iSize); - memcpy(pfOutZ, pfInZ, iSize); - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - float fInX = *(pfInX++); - float fInY = *(pfInY++); - *(pfOutX++) = fCos * fInX - fSin * fInY; - *(pfOutY++) = fSin * fInX + fCos * fInY; - } -} - -/*****************************************************************************/ - -void -runFMHFormatRotation(LADSPA_Handle Instance, - unsigned long SampleCount) { - - FMHFormatRotation * poProcessor = (FMHFormatRotation *)Instance; - - /* Work in radians. */ - LADSPA_Data fAngle - = LADSPA_Data(M_PI / 180.0) * *(poProcessor->m_ppfPorts[FMHROT_ANGLE]); - LADSPA_Data fSin = sin(fAngle); - LADSPA_Data fCos = cos(fAngle); - LADSPA_Data fSin2 = sin(fAngle * 2); - LADSPA_Data fCos2 = cos(fAngle * 2); - - LADSPA_Data * pfInW = poProcessor->m_ppfPorts[FMHROT_IN_W]; - LADSPA_Data * pfInX = poProcessor->m_ppfPorts[FMHROT_IN_X]; - LADSPA_Data * pfInY = poProcessor->m_ppfPorts[FMHROT_IN_Y]; - LADSPA_Data * pfInZ = poProcessor->m_ppfPorts[FMHROT_IN_Z]; - LADSPA_Data * pfInR = poProcessor->m_ppfPorts[FMHROT_IN_R]; - LADSPA_Data * pfInS = poProcessor->m_ppfPorts[FMHROT_IN_S]; - LADSPA_Data * pfInT = poProcessor->m_ppfPorts[FMHROT_IN_T]; - LADSPA_Data * pfInU = poProcessor->m_ppfPorts[FMHROT_IN_U]; - LADSPA_Data * pfInV = poProcessor->m_ppfPorts[FMHROT_IN_V]; - - LADSPA_Data * pfOutW = poProcessor->m_ppfPorts[FMHROT_OUT_W]; - LADSPA_Data * pfOutX = poProcessor->m_ppfPorts[FMHROT_OUT_X]; - LADSPA_Data * pfOutY = poProcessor->m_ppfPorts[FMHROT_OUT_Y]; - LADSPA_Data * pfOutZ = poProcessor->m_ppfPorts[FMHROT_OUT_Z]; - LADSPA_Data * pfOutR = poProcessor->m_ppfPorts[FMHROT_OUT_R]; - LADSPA_Data * pfOutS = poProcessor->m_ppfPorts[FMHROT_OUT_S]; - LADSPA_Data * pfOutT = poProcessor->m_ppfPorts[FMHROT_OUT_T]; - LADSPA_Data * pfOutU = poProcessor->m_ppfPorts[FMHROT_OUT_U]; - LADSPA_Data * pfOutV = poProcessor->m_ppfPorts[FMHROT_OUT_V]; - - int iSize = sizeof(LADSPA_Data) * SampleCount; - memcpy(pfOutW, pfInW, iSize); - memcpy(pfOutZ, pfInZ, iSize); - memcpy(pfOutR, pfInR, iSize); - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - - float fInX = *(pfInX++); - float fInY = *(pfInY++); - float fInS = *(pfInS++); - float fInT = *(pfInT++); - float fInU = *(pfInU++); - float fInV = *(pfInV++); - - *(pfOutX++) = fCos * fInX - fSin * fInY; - *(pfOutY++) = fSin * fInX + fCos * fInY; - *(pfOutS++) = fCos * fInS - fSin * fInT; - *(pfOutT++) = fSin * fInS + fCos * fInT; - *(pfOutU++) = fCos2 * fInU - fSin2 * fInV; - *(pfOutV++) = fSin2 * fInU + fCos2 * fInV; - } -} - -/*****************************************************************************/ - -void -initialise_ambisonic() { - - CMT_Descriptor * psDescriptor; - - psDescriptor = new CMT_Descriptor - (1087, - "encode_bformat", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Ambisonic Encoder (B-Format)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runBFormatEncoder, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Sound Source X Coordinate", - LADSPA_HINT_DEFAULT_1); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Sound Source Y Coordinate", - LADSPA_HINT_DEFAULT_0); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Sound Source Z Coordinate", - LADSPA_HINT_DEFAULT_0); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (W)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (X)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Y)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Z)"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1088, - "encode_fmh", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Ambisonic Encoder (FMH-Format)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runFMHFormatEncoder, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Sound Source X Coordinate", - LADSPA_HINT_DEFAULT_1); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Sound Source Y Coordinate", - LADSPA_HINT_DEFAULT_0); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Sound Source Z Coordinate", - LADSPA_HINT_DEFAULT_0); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (W)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (X)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Y)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Z)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (R)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (S)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (T)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (U)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (V)"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1089, - "fmh2bf", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "FMH-Format to B-Format (Discards RSTUV Channels)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runFMHToB, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (W)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (X)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (Y)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (Z)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (R)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (S)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (T)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (U)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (V)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (W)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (X)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Y)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Z)"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1090, - "bf2stereo", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Ambisonic Decoder (B-Format to Stereo)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runBFormatToStereo, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (W)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (X)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (Y)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (Z)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Left)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Right)"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1091, - "bf2quad", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Ambisonic Decoder (B-Format to Quad)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runBFormatToQuad, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (W)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (X)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (Y)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (Z)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Front Left)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Front Right)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Back Left)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Back Right)"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1092, - "bf2cube", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Ambisonic Decoder (B-Format to Cube)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runBFormatToCube, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (W)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (X)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (Y)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (Z)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Base Front Left)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Base Front Right)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Base Back Left)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Base Back Right)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Top Front Left)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Top Front Right)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Top Back Left)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Top Back Right)"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1093, - "fmh2oct", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Ambisonic Decoder (FMH-Format to Octagon)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runFMHFormatToOct, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (W)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (X)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (Y)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (Z)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (R)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (S)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (T)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (U)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (V)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Front Front Left)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Front Front Right)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Front Right Right)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Back Right Right)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Back Back Right)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Back Back Left)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Back Left Left)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Front Left Left)"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1094, - "bf_rotate_z", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Ambisonic Rotation (B-Format, Horizontal)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runBFormatRotation, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Angle of Rotation (Degrees Anticlockwise)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_HIGH), - -180, - 180); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (W)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (X)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (Y)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (Z)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (W)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (X)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Y)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Z)"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1095, - "fmh_rotate_z", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Ambisonic Rotation (FMH-Format, Horizontal)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runFMHFormatRotation, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Angle of Rotation (Degrees Anticlockwise)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_HIGH), - -180, - 180); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (W)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (X)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (Y)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (Z)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (R)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (S)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (T)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (U)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (V)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (W)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (X)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Y)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Z)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (R)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (S)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (T)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (U)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (V)"); - registerNewPluginDescriptor(psDescriptor); - -} - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/amp.cpp b/plugins/LadspaEffect/cmt/src/amp.cpp deleted file mode 100644 index 1d806f1b891..00000000000 --- a/plugins/LadspaEffect/cmt/src/amp.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/* amp.cpp - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include - -/*****************************************************************************/ - -#include "cmt.h" - -/*****************************************************************************/ - -#define AMP_CONTROL 0 -#define AMP_INPUT1 1 -#define AMP_OUTPUT1 2 - -/** This plugin applies a gain to a mono signal. */ -class MonoAmplifier : public CMT_PluginInstance { -public: - - MonoAmplifier(const LADSPA_Descriptor *, - unsigned long) - : CMT_PluginInstance(3) { - } - - friend void runMonoAmplifier(LADSPA_Handle Instance, - unsigned long SampleCount); - -}; - -/*****************************************************************************/ - -/* Ports as above, plus... */ -#define AMP_INPUT2 3 -#define AMP_OUTPUT2 4 - -/** This plugin applies a gain to a stereo signal. */ -class StereoAmplifier : public CMT_PluginInstance { -public: - - StereoAmplifier(const LADSPA_Descriptor *, - unsigned long) - : CMT_PluginInstance(5) { - } - - friend void runStereoAmplifier(LADSPA_Handle Instance, - unsigned long SampleCount); -}; - -/*****************************************************************************/ - -void -runMonoAmplifier(LADSPA_Handle Instance, - unsigned long SampleCount) { - - MonoAmplifier * poAmplifier = (MonoAmplifier *)Instance; - - LADSPA_Data * pfInput = poAmplifier->m_ppfPorts[AMP_INPUT1]; - LADSPA_Data * pfOutput = poAmplifier->m_ppfPorts[AMP_OUTPUT1]; - LADSPA_Data fGain = *(poAmplifier->m_ppfPorts[AMP_CONTROL]); - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) - *(pfOutput++) = *(pfInput++) * fGain; -} - -/*****************************************************************************/ - -void -runStereoAmplifier(LADSPA_Handle Instance, - unsigned long SampleCount) { - - unsigned long lSampleIndex; - - StereoAmplifier * poAmplifier = (StereoAmplifier *)Instance; - - LADSPA_Data fGain = *(poAmplifier->m_ppfPorts[AMP_CONTROL]); - - LADSPA_Data * pfInput = poAmplifier->m_ppfPorts[AMP_INPUT1]; - LADSPA_Data * pfOutput = poAmplifier->m_ppfPorts[AMP_OUTPUT1]; - for (lSampleIndex = 0; lSampleIndex < SampleCount; lSampleIndex++) - *(pfOutput++) = *(pfInput++) * fGain; - - pfInput = poAmplifier->m_ppfPorts[AMP_INPUT2]; - pfOutput = poAmplifier->m_ppfPorts[AMP_OUTPUT2]; - for (lSampleIndex = 0; lSampleIndex < SampleCount; lSampleIndex++) - *(pfOutput++) = *(pfInput++) * fGain; -} - -/*****************************************************************************/ - -void -initialise_amp() { - - CMT_Descriptor * psDescriptor; - - psDescriptor = new CMT_Descriptor - (1067, - "amp_mono", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Amplifier (Mono)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runMonoAmplifier, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Gain", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_LOGARITHMIC - | LADSPA_HINT_DEFAULT_1), - 0, - 0); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1068, - "amp_stereo", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Amplifier (Stereo)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runStereoAmplifier, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Gain", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_LOGARITHMIC - | LADSPA_HINT_DEFAULT_1), - 0, - 0); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (Left)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Left)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (Right)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Right)"); - registerNewPluginDescriptor(psDescriptor); -} - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/analogue.cpp b/plugins/LadspaEffect/cmt/src/analogue.cpp deleted file mode 100644 index 5a8dc265cdb..00000000000 --- a/plugins/LadspaEffect/cmt/src/analogue.cpp +++ /dev/null @@ -1,504 +0,0 @@ -/* analogue.cpp - - Analogue Voice - Analog synthesizer voice - Copyright (c) 2000 David A. Bartold - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include -#include -#include "cmt.h" - -#define PORT_OUT 0 -#define PORT_GATE 1 -#define PORT_VELOCITY 2 -#define PORT_FREQ 3 -#define PORT_DCO1_OCTAVE 4 -#define PORT_DCO1_WAVEFORM 5 -#define PORT_DCO1_FM 6 -#define PORT_DCO1_PWM 7 -#define PORT_DCO1_ATTACK 8 -#define PORT_DCO1_DECAY 9 -#define PORT_DCO1_SUSTAIN 10 -#define PORT_DCO1_RELEASE 11 -#define PORT_DCO2_OCTAVE 12 -#define PORT_DCO2_WAVEFORM 13 -#define PORT_DCO2_FM 14 -#define PORT_DCO2_PWM 15 -#define PORT_DCO2_ATTACK 16 -#define PORT_DCO2_DECAY 17 -#define PORT_DCO2_SUSTAIN 18 -#define PORT_DCO2_RELEASE 19 -#define PORT_LFO_FREQ 20 -#define PORT_LFO_FADEIN 21 -#define PORT_FILT_ENV_MOD 22 -#define PORT_FILT_LFO_MOD 23 -#define PORT_FILT_RES 24 -#define PORT_FILT_ATTACK 25 -#define PORT_FILT_DECAY 26 -#define PORT_FILT_SUSTAIN 27 -#define PORT_FILT_RELEASE 28 - -#define NUM_PORTS 29 - -#ifndef PI -#define PI 3.14159265358979F -#endif - -typedef struct Envelope -{ - int envelope_decay; - LADSPA_Data envelope; - - Envelope () : envelope_decay (0), envelope (0.0) {} -} Envelope; - -class Analogue : public CMT_PluginInstance -{ - LADSPA_Data sample_rate; - - int trigger; - Envelope dco1_env; - Envelope dco2_env; - Envelope filt_env; - LADSPA_Data d1; - LADSPA_Data d2; - - LADSPA_Data dco1_accum; - LADSPA_Data dco2_accum; - LADSPA_Data lfo_accum; - - LADSPA_Data lfo_vol; - -public: - Analogue(const LADSPA_Descriptor * Descriptor, - unsigned long SampleRate) - : CMT_PluginInstance(NUM_PORTS), - sample_rate (SampleRate), - trigger (0), - d1 (0.0), d2 (0.0), - dco1_accum (0.0), dco2_accum (0.0), lfo_accum (0.0) { - } - - ~Analogue () { - } - - /* Third-order approximation of a sine wave. */ - static inline LADSPA_Data - fast_sin(LADSPA_Data x) { - if (x > PI) - x = (x < PI * 1.5F) ? (PI - x) : (x - 2.0F * PI); - else if (x > PI * 0.5F) - x = PI - x; - - return x * (1.05F - x * x * 0.175F); - } - - static inline LADSPA_Data - tri(LADSPA_Data x) { - if (x > 0.75F) - x = x - 1.0F; - else if (x > 0.25F) - x = 0.5F - x; - - return x * 4.0F; - } - - static inline LADSPA_Data - envelope(Envelope *env, - int gate, - LADSPA_Data attack, - LADSPA_Data decay, - LADSPA_Data sustain, - LADSPA_Data release) - { - if (gate) - if (env->envelope_decay == 0) - { - env->envelope += (1.0F - env->envelope) * attack; - if (env->envelope >= 0.95F) - env->envelope_decay = 1; - } - else - env->envelope += (sustain - env->envelope) * decay; - else - env->envelope += -env->envelope * release; - - return env->envelope; - } - - static void - activate(LADSPA_Handle Instance) { - Analogue *analogue = (Analogue*) Instance; - - analogue->trigger = 0; - analogue->dco1_env.envelope_decay = 0; - analogue->dco1_env.envelope = 0.0; - analogue->dco2_env.envelope_decay = 0; - analogue->dco2_env.envelope = 0.0; - analogue->filt_env.envelope_decay = 0; - analogue->filt_env.envelope = 0.0; - analogue->d1 = 0.0F; - analogue->d2 = 0.0F; - - analogue->dco1_accum = 0.0F; - analogue->dco2_accum = 0.0F; - analogue->lfo_accum = 0.0F; - analogue->lfo_vol = 0.0F; - } - - static inline LADSPA_Data - osc(int waveform, - LADSPA_Data inc, - LADSPA_Data width, - LADSPA_Data *accum) { - *accum += inc; - while (*accum >= 1.0F) - *accum -= 1.0F; - - /* 0 = Sine wave */ - if (waveform == 0) - if (*accum < width) - return fast_sin (*accum / width * PI); - else - return fast_sin (PI + (*accum - width) / (1.0F - width) * PI); - - /* 1 = Triangle wave */ - else if (waveform == 1) - if (*accum < width) - return tri (*accum / width * 0.5); - else - return tri (0.5 + (*accum - width) * 0.5 / (1.0F - width)); - - /* 2 = Square wave */ - else if (waveform == 2) - return (*accum > width) ? 1.0F : -1.0F; - - /* 3 = Sawtooth wave */ - else if (waveform == 3) - if (*accum < width) - return *accum / width * 2.0F - 1.0F; - else - return (*accum - width) / (1.0F - width) * 2.0F - 1.0F; - - /* 4 = Fullwave Rectified Sine wave */ - else if (waveform == 4) - if (*accum < width) - return fast_sin (*accum / width * PI); - else - return fast_sin ((*accum - width) / (1.0F - width) * PI); - - /* 5 = Static */ - else - return (rand () & 1) ? -1.0F : 1.0F; - } - - static LADSPA_Data - inc(LADSPA_Data oct, - LADSPA_Data freq, - LADSPA_Data sample_rate) { - return pow (2.0, oct) * freq / sample_rate; - } - - static void - calc_a_b_c(Analogue *analogue, - LADSPA_Data freq, - LADSPA_Data *a, - LADSPA_Data *b, - LADSPA_Data *c) { - LADSPA_Data top_freq, k, res; - - top_freq = freq; - top_freq *= PI / analogue->sample_rate; - res = exp (-1.20 + 3.455 * *analogue->m_ppfPorts[PORT_FILT_RES]); - - k = exp (-top_freq / res); - - *a = 2.0 * cos (2.0 * top_freq) * k; - *b = -k * k; - *c = (1.0 - *a - *b) * 0.2; - } - - static inline LADSPA_Data - multiplier(Analogue *analogue, - LADSPA_Data value) { - return 1.0 - pow (0.05, 1.0 / (analogue->sample_rate * value)); - } - - static void - run(LADSPA_Handle Instance, - unsigned long SampleCount) { - Analogue *analogue = (Analogue*) Instance; - unsigned long i; - int waveform1, waveform2; - int gate; - LADSPA_Data lfo_inc, inc1, inc2; - LADSPA_Data attack1, decay1, release1; - LADSPA_Data attack2, decay2, release2; - LADSPA_Data filt_attack, filt_decay, filt_release; - LADSPA_Data lfo_fadein, a = 0, b = 0, c = 0; - LADSPA_Data dco1_pwm, dco2_pwm; - LADSPA_Data dco1_fm, dco2_fm; - LADSPA_Data filt_lfo_mod; - LADSPA_Data **ports; - - ports = analogue->m_ppfPorts; - gate = (*ports[PORT_GATE] > 0.0); - if (gate == 1 && analogue->trigger == 0) - { - analogue->lfo_vol = 0.0F; - analogue->dco1_env.envelope_decay = 0; - analogue->dco1_env.envelope = 0.0; - analogue->dco2_env.envelope_decay = 0; - analogue->dco2_env.envelope = 0.0; - analogue->filt_env.envelope_decay = 0; - analogue->filt_env.envelope = 0.0; - } - - analogue->trigger = gate; - - waveform1 = (int) *ports[PORT_DCO1_WAVEFORM]; - waveform2 = (int) *ports[PORT_DCO2_WAVEFORM]; - - inc1 = inc (*ports[PORT_DCO1_OCTAVE], - *ports[PORT_FREQ], - analogue->sample_rate); - inc2 = inc (*ports[PORT_DCO2_OCTAVE], - *ports[PORT_FREQ], - analogue->sample_rate); - lfo_inc = 2.0F * PI * *ports[PORT_LFO_FREQ] / analogue->sample_rate; - - attack1 = multiplier (analogue, *ports[PORT_DCO1_ATTACK]); - decay1 = multiplier (analogue, *ports[PORT_DCO1_DECAY]); - release1 = multiplier (analogue, *ports[PORT_DCO1_RELEASE]); - - attack2 = multiplier (analogue, *ports[PORT_DCO2_ATTACK]); - decay2 = multiplier (analogue, *ports[PORT_DCO2_DECAY]); - release2 = multiplier (analogue, *ports[PORT_DCO2_RELEASE]); - - filt_attack = multiplier (analogue, *ports[PORT_FILT_ATTACK]); - filt_decay = multiplier (analogue, *ports[PORT_FILT_DECAY]); - filt_release = multiplier (analogue, *ports[PORT_FILT_RELEASE]); - - lfo_fadein = 1.0 / (*ports[PORT_LFO_FADEIN] * analogue->sample_rate); - - dco1_pwm = *analogue->m_ppfPorts[PORT_DCO1_PWM] * 0.225F; - dco2_pwm = *analogue->m_ppfPorts[PORT_DCO2_PWM] * 0.225F; - dco1_fm = *analogue->m_ppfPorts[PORT_DCO1_FM] * inc1 * 0.45F; - dco2_fm = *analogue->m_ppfPorts[PORT_DCO2_FM] * inc2 * 0.45F; - filt_lfo_mod = *analogue->m_ppfPorts[PORT_FILT_LFO_MOD] * 0.45F; - - for (i = 0; i < SampleCount; i++) - { - LADSPA_Data lfo, sample; - - analogue->lfo_accum += lfo_inc; - while (analogue->lfo_accum >= 2.0F * PI) - analogue->lfo_accum -= 2.0F * PI; - - lfo = fast_sin (analogue->lfo_accum) * analogue->lfo_vol; - - analogue->lfo_vol += lfo_fadein; - if (analogue->lfo_vol >= 1.0F) - analogue->lfo_vol = 1.0F; - - envelope (&analogue->filt_env, - gate, filt_attack, filt_decay, - *ports[PORT_FILT_SUSTAIN], filt_release); - - if ((i & 0x000f) == 0) - calc_a_b_c (analogue, - *ports[PORT_FREQ] * 0.25F + (analogue->filt_env.envelope * - *ports[PORT_FILT_ENV_MOD] * *ports[PORT_VELOCITY] * - (1.5 + filt_lfo_mod * lfo)) * *ports[PORT_FREQ] * 10.0F, &a, &b, &c); - - sample = osc (waveform1, inc1 * (1.0 + lfo * dco1_fm), - 0.5F + lfo * dco1_pwm, - &analogue->dco1_accum) - * envelope (&analogue->dco1_env, - gate, attack1, decay1, - *ports[PORT_DCO1_SUSTAIN], release1) - + osc (waveform2, inc2 * (1.0 + lfo * dco2_fm), - 0.5F + lfo * dco2_pwm, - &analogue->dco2_accum) - * envelope (&analogue->dco2_env, - gate, attack2, decay2, - *ports[PORT_DCO2_SUSTAIN], release2); - - sample = a * analogue->d1 + - b * analogue->d2 + - c * *ports[PORT_VELOCITY] * sample; - - analogue->d2 = analogue->d1; - analogue->d1 = sample; - ports[PORT_OUT][i] = sample; - } - } -}; - -static LADSPA_PortDescriptor g_psPortDescriptors[] = -{ - LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT -}; - -static const char * const g_psPortNames[] = -{ - "Out", - "Gate", - "Velocity", - "Frequency (Hz)", - - "DCO1 Octave", - "DCO1 Waveform", - "DCO1 LFO Frequency Modulation", - "DCO1 LFO Pulse Width Modulation", - - "DCO1 Attack", - "DCO1 Decay", - "DCO1 Sustain", - "DCO1 Release", - - "DCO2 Octave", - "DCO2 Waveform", - "DCO2 LFO Frequency Modulation", - "DCO2 LFO Pulse Width Modulation", - - "DCO2 Attack", - "DCO2 Decay", - "DCO2 Sustain", - "DCO2 Release", - - "LFO Frequency (Hz)", - "LFO Fadein", - - "Filter Envelope Modulation", - "Filter LFO Modulation", - "Filter Resonance", - - "Filter Attack", - "Filter Decay", - "Filter Sustain", - "Filter Release" -}; - -static LADSPA_PortRangeHint g_psPortRangeHints[] = -{ - /* Hints, Lower bound, Upper bound */ - { 0, 0.0, 0.0 }, - { LADSPA_HINT_TOGGLED, 0.0, 0.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 20000.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.001, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 10.0 }, - - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, -2.0, 2.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | - LADSPA_HINT_INTEGER, -0.1, 5.1 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.00, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, -2.0, 2.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | - LADSPA_HINT_INTEGER, -0.1, 5.1 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.00, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 20.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.00, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 } -}; - -void -initialise_analogue() { - CMT_Descriptor * psDescriptor; - - psDescriptor = new CMT_Descriptor - (1221, - "analogue", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Analogue Voice", - CMT_MAKER("David A. Bartold"), - CMT_COPYRIGHT("2000", "David A. Bartold"), - NULL, - CMT_Instantiate, - Analogue::activate, - Analogue::run, - NULL, - NULL, - NULL); - - for (int i = 0; i < NUM_PORTS; i++) - psDescriptor->addPort( - g_psPortDescriptors[i], - g_psPortNames[i], - g_psPortRangeHints[i].HintDescriptor, - g_psPortRangeHints[i].LowerBound, - g_psPortRangeHints[i].UpperBound); - - registerNewPluginDescriptor(psDescriptor); -} diff --git a/plugins/LadspaEffect/cmt/src/canyondelay.cpp b/plugins/LadspaEffect/cmt/src/canyondelay.cpp deleted file mode 100644 index 23651bd50af..00000000000 --- a/plugins/LadspaEffect/cmt/src/canyondelay.cpp +++ /dev/null @@ -1,223 +0,0 @@ -/* canyondelay.cpp - - Canyon Delay - Deep Stereo Cross Delay - Copyright (c) 1999, 2000 David A. Bartold - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - - -#include -#include -#include "cmt.h" - -#define PORT_IN_LEFT 0 -#define PORT_IN_RIGHT 1 -#define PORT_OUT_LEFT 2 -#define PORT_OUT_RIGHT 3 -#define PORT_LTR_TIME 4 -#define PORT_LTR_FEEDBACK 5 -#define PORT_RTL_TIME 6 -#define PORT_RTL_FEEDBACK 7 -#define PORT_CUTOFF 8 - -#define NUM_PORTS 9 - -#ifndef PI -#define PI 3.14159265358979 -#endif - -class CanyonDelay : public CMT_PluginInstance { - LADSPA_Data sample_rate; - - long datasize; - LADSPA_Data *data_l; - LADSPA_Data *data_r; - LADSPA_Data accum_l; - LADSPA_Data accum_r; - - int pos; - -public: - CanyonDelay(const LADSPA_Descriptor *, - unsigned long s_rate) - : CMT_PluginInstance(NUM_PORTS), - sample_rate(s_rate), - datasize(s_rate), - data_l(new LADSPA_Data[datasize]), - data_r(new LADSPA_Data[datasize]), - accum_l(0.0), - accum_r(0.0), - pos(0) { - for (long i = 0; i < datasize; i++) - data_l[i] = data_r[i] = 0.0; - } - - ~CanyonDelay() { - delete[] data_l; - delete[] data_r; - } - - static void - activate(LADSPA_Handle Instance) { - CanyonDelay *delay = (CanyonDelay*) Instance; - - for (long i = 0; i < delay->datasize; i++) - delay->data_l[i] = delay->data_r[i] = 0.0; - - delay->accum_l = 0.0; - delay->accum_r = 0.0; - delay->pos = 0; - } - - static void - run(LADSPA_Handle Instance, - unsigned long SampleCount) { - CanyonDelay *delay = (CanyonDelay*) Instance; - LADSPA_Data **ports; - unsigned long i; - int l_to_r_offset, r_to_l_offset; - LADSPA_Data ltr_invmag, rtl_invmag; - LADSPA_Data filter_mag, filter_invmag; - - ports = delay->m_ppfPorts; - - l_to_r_offset = (int) (*ports[PORT_LTR_TIME] * delay->sample_rate); - r_to_l_offset = (int) (*ports[PORT_RTL_TIME] * delay->sample_rate); - - ltr_invmag = 1.0 - fabs (*ports[PORT_LTR_FEEDBACK]); - rtl_invmag = 1.0 - fabs (*ports[PORT_RTL_FEEDBACK]); - - filter_invmag = pow (0.5, (4.0 * PI * *ports[PORT_CUTOFF]) / delay->sample_rate); - filter_mag = 1.0 - filter_invmag; - - for (i = 0; i < SampleCount; i++) - { - LADSPA_Data accum_l, accum_r; - int pos1, pos2; - - accum_l = ports[PORT_IN_LEFT][i]; - accum_r = ports[PORT_IN_RIGHT][i]; - - pos1 = delay->pos - r_to_l_offset + delay->datasize; - while (pos1 >= delay->datasize) - pos1 -= delay->datasize; - - pos2 = delay->pos - l_to_r_offset + delay->datasize; - while (pos2 >= delay->datasize) - pos2 -= delay->datasize; - - /* Mix channels with past samples. */ - accum_l = accum_l * rtl_invmag + delay->data_r[pos1] * *ports[PORT_RTL_FEEDBACK]; - accum_r = accum_r * ltr_invmag + delay->data_l[pos2] * *ports[PORT_LTR_FEEDBACK]; - - /* Low-pass filter output. */ - accum_l = delay->accum_l * filter_invmag + accum_l * filter_mag; - accum_r = delay->accum_r * filter_invmag + accum_r * filter_mag; - - /* Store IIR samples. */ - delay->accum_l = accum_l; - delay->accum_r = accum_r; - - /* Store samples in arrays. */ - delay->data_l[delay->pos] = accum_l; - delay->data_r[delay->pos] = accum_r; - - ports[PORT_OUT_LEFT][i] = accum_l; - ports[PORT_OUT_RIGHT][i] = accum_r; - - delay->pos++; - if (delay->pos >= delay->datasize) - delay->pos -= delay->datasize; - } - } -}; - - -static LADSPA_PortDescriptor g_psPortDescriptors[] = -{ - LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT, - LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT, - LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT, - LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT -}; - -static const char * const g_psPortNames[] = -{ - "In (Left)", - "In (Right)", - "Out (Left)", - "Out (Right)", - "Left to Right Time (Seconds)", - "Left to Right Feedback (Percent)", - "Right to Left Time (Seconds)", - "Right to Left Feedback (Percent)", - "Low-Pass Cutoff (Hz)" -}; - -static LADSPA_PortRangeHint g_psPortRangeHints[] = -{ - /* Hints, Lower bound, Upper bound */ - { 0, 0.0, 0.0 }, - { 0, 0.0, 0.0 }, - { 0, 0.0, 0.0 }, - { 0, 0.0, 0.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 0.99 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, -1.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 0.99 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, -1.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 1.0, 5000.0 } -}; - -void -initialise_canyondelay() { - CMT_Descriptor * psDescriptor; - - psDescriptor = new CMT_Descriptor - (1225, - "canyon_delay", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Canyon Delay", - CMT_MAKER("David A. Bartold"), - CMT_COPYRIGHT("1999, 2000", "David A. Bartold"), - NULL, - CMT_Instantiate, - CanyonDelay::activate, - CanyonDelay::run, - NULL, - NULL, - NULL); - - for (int i = 0; i < NUM_PORTS; i++) - psDescriptor->addPort( - g_psPortDescriptors[i], - g_psPortNames[i], - g_psPortRangeHints[i].HintDescriptor, - g_psPortRangeHints[i].LowerBound, - g_psPortRangeHints[i].UpperBound); - - registerNewPluginDescriptor(psDescriptor); -} diff --git a/plugins/LadspaEffect/cmt/src/cmt.cpp b/plugins/LadspaEffect/cmt/src/cmt.cpp deleted file mode 100644 index d735c44b970..00000000000 --- a/plugins/LadspaEffect/cmt/src/cmt.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* cmt.cpp - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include - -/*****************************************************************************/ - -#include "cmt.h" - -/*****************************************************************************/ - -inline char * -localStrdup(const char * input) { - char * output = new char[strlen(input) + 1]; - strcpy(output, input); - return output; -} - -/*****************************************************************************/ - -CMT_Descriptor:: -~CMT_Descriptor() { - if (Label) - delete [] Label; - if (Name) - delete [] Name; - if (Maker) - delete [] Maker; - if (Copyright) - delete [] Copyright; - if (ImplementationData) - delete (CMT_ImplementationData *)ImplementationData; - if (PortDescriptors) - delete [] PortDescriptors; - if (PortNames) { - for (unsigned long lIndex = 0; lIndex < PortCount; lIndex++) - if (PortNames[lIndex]) - delete [] PortNames[lIndex]; - delete [] PortNames; - } - if (PortRangeHints) - delete [] PortRangeHints; -} - -/*****************************************************************************/ - -void -CMT_ConnectPort(LADSPA_Handle Instance, - unsigned long Port, - LADSPA_Data * DataLocation) { - CMT_PluginInstance * poInstance = (CMT_PluginInstance *)Instance; - poInstance->m_ppfPorts[Port] = DataLocation; -} - -/*****************************************************************************/ - -void -CMT_Cleanup(LADSPA_Handle Instance) { - CMT_PluginInstance * poInstance = (CMT_PluginInstance *)Instance; - delete poInstance; -} - -/*****************************************************************************/ - -CMT_Descriptor:: -CMT_Descriptor(unsigned long lUniqueID, - const char * pcLabel, - LADSPA_Properties iProperties, - const char * pcName, - const char * pcMaker, - const char * pcCopyright, - CMT_ImplementationData * poImplementationData, - LADSPA_Instantiate_Function fInstantiate, - LADSPA_Activate_Function fActivate, - LADSPA_Run_Function fRun, - LADSPA_Run_Adding_Function fRunAdding, - LADSPA_Set_Run_Adding_Gain_Function fSetRunAddingGain, - LADSPA_Deactivate_Function fDeactivate) { - - UniqueID = lUniqueID; - Label = localStrdup(pcLabel); - Properties = iProperties; - Name = localStrdup(pcName); - Maker = localStrdup(pcMaker); - Copyright = localStrdup(pcCopyright); - PortCount = 0; - ImplementationData = poImplementationData; - - instantiate = fInstantiate; - connect_port = CMT_ConnectPort; - activate = fActivate; - run = fRun; - run_adding = fRunAdding; - set_run_adding_gain = fSetRunAddingGain; - deactivate = fDeactivate; - cleanup = CMT_Cleanup; - -}; - -/*****************************************************************************/ - -typedef char * char_ptr; - -void CMT_Descriptor:: -addPort(LADSPA_PortDescriptor iPortDescriptor, - const char * pcPortName, - LADSPA_PortRangeHintDescriptor iHintDescriptor, - LADSPA_Data fLowerBound, - LADSPA_Data fUpperBound) { - - unsigned long lOldPortCount = PortCount; - unsigned long lNewPortCount = PortCount + 1; - - LADSPA_PortDescriptor * piOldPortDescriptors - = (LADSPA_PortDescriptor *)PortDescriptors; - char ** ppcOldPortNames - = (char **)PortNames; - LADSPA_PortRangeHint * psOldPortRangeHints - = (LADSPA_PortRangeHint *)PortRangeHints; - - LADSPA_PortDescriptor * piNewPortDescriptors - = new LADSPA_PortDescriptor[lNewPortCount]; - char ** ppcNewPortNames - = new char_ptr[lNewPortCount]; - LADSPA_PortRangeHint * psNewPortRangeHints - = new LADSPA_PortRangeHint[lNewPortCount]; - - if (piNewPortDescriptors == NULL - || ppcNewPortNames == NULL - || psNewPortRangeHints == NULL) { - /* Memory allocation failure that we cannot handle. Best option is - probably just to get out while the going is reasonably good. */ - return; - } - - for (unsigned long lPortIndex = 0; - lPortIndex < lOldPortCount; - lPortIndex++) { - piNewPortDescriptors[lPortIndex] = piOldPortDescriptors[lPortIndex]; - ppcNewPortNames[lPortIndex] = ppcOldPortNames[lPortIndex]; - psNewPortRangeHints[lPortIndex] = psOldPortRangeHints[lPortIndex]; - } - if (lOldPortCount > 0) { - delete [] piOldPortDescriptors; - delete [] ppcOldPortNames; - delete [] psOldPortRangeHints; - } - - piNewPortDescriptors[lOldPortCount] = iPortDescriptor; - ppcNewPortNames[lOldPortCount] = localStrdup(pcPortName); - psNewPortRangeHints[lOldPortCount].HintDescriptor = iHintDescriptor; - psNewPortRangeHints[lOldPortCount].LowerBound = fLowerBound; - psNewPortRangeHints[lOldPortCount].UpperBound = fUpperBound; - - PortDescriptors = piNewPortDescriptors; - PortNames = ppcNewPortNames; - PortRangeHints = psNewPortRangeHints; - - PortCount++; -} - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/cmt.h b/plugins/LadspaEffect/cmt/src/cmt.h deleted file mode 100644 index f151f34dfa2..00000000000 --- a/plugins/LadspaEffect/cmt/src/cmt.h +++ /dev/null @@ -1,180 +0,0 @@ -/* cmt.h - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -#ifndef CMT_BASE_INCLUDED -#define CMT_BASE_INCLUDED - -/*****************************************************************************/ - -#include "ladspa_types.h" - -/*****************************************************************************/ - -/** This class is the baseclass of all CMT plugin implementation - data. Baseclassed so virtual destructors can be used. */ -class CMT_ImplementationData { -public: - virtual ~CMT_ImplementationData() { - } -}; - -/*****************************************************************************/ - -/** This structure describes a CMT LADSPA Plugin. It is a direct - ancestor of the _LADSPA_Descriptor structure which allows direct - casting. A rich constructor function is provided make it easier to - write LADSPA_Descriptor objects. (Less code is required and the - compiler will tell you when you have missed an entry.) An - addPort() function makes configuration of ports more - straightforward than using the _LADSPA_Descriptor structure - directly. */ - -struct CMT_Descriptor : public _LADSPA_Descriptor { -private: - - CMT_Descriptor &operator=(const CMT_Descriptor &) { - return *this; - } - CMT_Descriptor(const CMT_Descriptor &) { - } - -public: - - ~CMT_Descriptor(); - - /** The basic constructor for a CMT_Descriptor object. If you do not - know what the parameters mean, please see the fields in the - LADSPA_Descriptor structure, described in ladspa.h. Note that - some parameters may be NULL. Note also that a template is - provided to generate instantiate functions automatically (see - CMT_Instantiate<>() below). Implementation data must be NULL if - not allocated. */ - CMT_Descriptor(unsigned long lUniqueID, - const char * pcLabel, - LADSPA_Properties iProperties, - const char * pcName, - const char * pcMaker, - const char * pcCopyright, - CMT_ImplementationData * poImplementationData, - LADSPA_Instantiate_Function fInstantiate, - LADSPA_Activate_Function fActivate, - LADSPA_Run_Function fRun, - LADSPA_Run_Adding_Function fRunAdding, - LADSPA_Set_Run_Adding_Gain_Function fSetRunAddingGain, - LADSPA_Deactivate_Function fDeactivate); - - /** This method adds a new port to the descriptor. If you do not - know what the parameters mean, please see the fields in the - LADSPA_Descriptor structure, described in ladspa.h. */ - void addPort(LADSPA_PortDescriptor iPortDescriptor, - const char * pcPortName, - LADSPA_PortRangeHintDescriptor iHintDescriptor = 0, - LADSPA_Data fLowerBound = 0, - LADSPA_Data fUpperBound = 0); - -}; - -typedef CMT_Descriptor * CMT_Descriptor_ptr; - -/*****************************************************************************/ - -/** Each plugin type must register itself with the descriptor - registry. This is done by calling the following function, passing - a newly allocated structure (that will be cleaned up on library - unload automatically). - - Each module needs to be initialised in order to have a chance to - register new plugins. This can be achieved by modifying the list - of initialiser functions in descriptor.cpp. */ -void registerNewPluginDescriptor(CMT_Descriptor * psDescriptor); - -/*****************************************************************************/ - -/** This class is the baseclass of all CMT plugins. It provides - functionality to handle LADSPA connect_port() and cleanup() - requirements (as long as plugins have correctly written - destructors!) A CMT_Instantiate<>() template is provided also, - which makes LADSPA instantiate() methods easier to write. - - Derived classes access port data through the m_ppfPorts[] - array. This contains one entry for each port, in the order in - which ports were added to the corresponding CMT_Descriptor - object. */ -class CMT_PluginInstance { -private: - - CMT_PluginInstance &operator=(const CMT_PluginInstance &) { - return *this; - } - CMT_PluginInstance(const CMT_PluginInstance &) { - } - -protected: - - LADSPA_Data ** m_ppfPorts; - - CMT_PluginInstance(const unsigned long lPortCount) - : m_ppfPorts(new LADSPA_Data_ptr[lPortCount]) { - } - virtual ~CMT_PluginInstance() { - delete [] m_ppfPorts; - } - - friend void CMT_ConnectPort(LADSPA_Handle Instance, - unsigned long Port, - LADSPA_Data * DataLocation); - friend void CMT_Cleanup(LADSPA_Handle Instance); - -}; - -/*****************************************************************************/ - -/** This template can be used to generate functions to instantiate CMT - plugins. To be used with this function, the plugin must accept two - parameters (a LADSPA_Descriptor pointer and a sample rate). See - the SimpleMixer class and mixer_descriptor() in mixer.cpp for a - simple example of this: the instantiate function for the mixer - class is generated within the mixer_descriptor() function as - "CMT_Instantiate". */ -template LADSPA_Handle -CMT_Instantiate(const LADSPA_Descriptor * Descriptor, - unsigned long SampleRate) { - return new T(Descriptor, SampleRate); -} - -/*****************************************************************************/ - -/** This macro should be used to fill in the `Maker' field in the - CMT_Descriptor. */ -#define CMT_MAKER(AUTHORS) \ - "CMT (http://www.ladspa.org/cmt, plugin by " AUTHORS ")" - -/** This macro should be used to fill in the `Copyright' field in the - CMT_Descriptor. */ -#define CMT_COPYRIGHT(YEARS, AUTHORS) \ - "(C)" YEARS ", " AUTHORS ". " \ - "GNU General Public Licence Version 2 applies." - -/*****************************************************************************/ - -#endif - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/delay.cpp b/plugins/LadspaEffect/cmt/src/delay.cpp deleted file mode 100644 index 12f6fedaa4c..00000000000 --- a/plugins/LadspaEffect/cmt/src/delay.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/* delay.cpp - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -/* This module provides delays and delays with feedback. A variety of - maximum delay times are available. (The plugins reserve different - amounts of memory space on this basis.) */ - -/*****************************************************************************/ - -#include -#include -#include - -/*****************************************************************************/ - -#include "cmt.h" - -/*****************************************************************************/ - -#define DELAY_TYPE_COUNT 2 - -#define DELAY_LENGTH_COUNT 5 - -/*****************************************************************************/ - -#define LIMIT_BETWEEN(x, a, b) \ -(((x) < a) ? a : (((x) > b) ? b : (x))) - -/*****************************************************************************/ - -#define DL_DELAY_LENGTH 0 -#define DL_DRY_WET 1 -#define DL_INPUT 2 -#define DL_OUTPUT 3 -/* Present only on feedback delays: */ -#define DL_FEEDBACK 4 - -/** This class is used to implement delay line plugins. Different - maximum delay times are supported as are both echo and feedback - delays. */ -class DelayLine : public CMT_PluginInstance { -private: - - LADSPA_Data m_fSampleRate; - - LADSPA_Data m_fMaximumDelay; - - LADSPA_Data * m_pfBuffer; - - /** Buffer size, a power of two. */ - unsigned long m_lBufferSize; - - /** Write pointer in buffer. */ - unsigned long m_lWritePointer; - - friend void activateDelayLine(LADSPA_Handle Instance); - friend void runSimpleDelayLine(LADSPA_Handle Instance, - unsigned long SampleCount); - friend void runFeedbackDelayLine(LADSPA_Handle Instance, - unsigned long SampleCount); - -public: - - DelayLine(const unsigned long lSampleRate, - const LADSPA_Data fMaximumDelay) - : CMT_PluginInstance(5), - m_fSampleRate(LADSPA_Data(lSampleRate)), - m_fMaximumDelay(fMaximumDelay) { - /* Buffer size is a power of two bigger than max delay time. */ - unsigned long lMinimumBufferSize - = (unsigned long)((LADSPA_Data)lSampleRate * m_fMaximumDelay); - m_lBufferSize = 1; - while (m_lBufferSize < lMinimumBufferSize) - m_lBufferSize <<= 1; - m_pfBuffer = new LADSPA_Data[m_lBufferSize]; - } - - ~DelayLine() { - delete [] m_pfBuffer; - } -}; - -/*****************************************************************************/ - -/* Initialise and activate a plugin instance. */ -void -activateDelayLine(LADSPA_Handle Instance) { - - DelayLine * poDelayLine = (DelayLine *)Instance; - - /* Need to reset the delay history in this function rather than - instantiate() in case deactivate() followed by activate() have - been called to reinitialise a delay line. */ - memset(poDelayLine->m_pfBuffer, - 0, - sizeof(LADSPA_Data) * poDelayLine->m_lBufferSize); - - poDelayLine->m_lWritePointer = 0; -} - -/*****************************************************************************/ - -/* Run a delay line instance for a block of SampleCount samples. */ -void -runSimpleDelayLine(LADSPA_Handle Instance, - unsigned long SampleCount) { - - DelayLine * poDelayLine = (DelayLine *)Instance; - - unsigned long lBufferSizeMinusOne = poDelayLine->m_lBufferSize - 1; - unsigned long lDelay = (unsigned long) - (LIMIT_BETWEEN(*(poDelayLine->m_ppfPorts[DL_DELAY_LENGTH]), - 0, - poDelayLine->m_fMaximumDelay) - * poDelayLine->m_fSampleRate); - - LADSPA_Data * pfInput - = poDelayLine->m_ppfPorts[DL_INPUT]; - LADSPA_Data * pfOutput - = poDelayLine->m_ppfPorts[DL_OUTPUT]; - LADSPA_Data * pfBuffer - = poDelayLine->m_pfBuffer; - - unsigned long lBufferWriteOffset - = poDelayLine->m_lWritePointer; - unsigned long lBufferReadOffset - = lBufferWriteOffset + poDelayLine->m_lBufferSize - lDelay; - LADSPA_Data fWet - = LIMIT_BETWEEN(*(poDelayLine->m_ppfPorts[DL_DRY_WET]), - 0, - 1); - LADSPA_Data fDry - = 1 - fWet; - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - LADSPA_Data fInputSample = *(pfInput++); - *(pfOutput++) = (fDry * fInputSample - + fWet * pfBuffer[((lSampleIndex + lBufferReadOffset) - & lBufferSizeMinusOne)]); - pfBuffer[((lSampleIndex + lBufferWriteOffset) - & lBufferSizeMinusOne)] = fInputSample; - } - - poDelayLine->m_lWritePointer - = ((poDelayLine->m_lWritePointer + SampleCount) - & lBufferSizeMinusOne); -} - -/*****************************************************************************/ - -/** Run a feedback delay line instance for a block of SampleCount samples. */ -void -runFeedbackDelayLine(LADSPA_Handle Instance, - unsigned long SampleCount) { - - DelayLine * poDelayLine = (DelayLine *)Instance; - - unsigned long lBufferSizeMinusOne = poDelayLine->m_lBufferSize - 1; - unsigned long lDelay = (unsigned long) - (LIMIT_BETWEEN(*(poDelayLine->m_ppfPorts[DL_DELAY_LENGTH]), - 0, - poDelayLine->m_fMaximumDelay) - * poDelayLine->m_fSampleRate); - - LADSPA_Data * pfInput - = poDelayLine->m_ppfPorts[DL_INPUT]; - LADSPA_Data * pfOutput - = poDelayLine->m_ppfPorts[DL_OUTPUT]; - LADSPA_Data * pfBuffer - = poDelayLine->m_pfBuffer; - - unsigned long lBufferWriteOffset - = poDelayLine->m_lWritePointer; - unsigned long lBufferReadOffset - = lBufferWriteOffset + poDelayLine->m_lBufferSize - lDelay; - LADSPA_Data fWet - = LIMIT_BETWEEN(*(poDelayLine->m_ppfPorts[DL_DRY_WET]), - 0, - 1); - LADSPA_Data fDry - = 1 - fWet; - LADSPA_Data fFeedback - = LIMIT_BETWEEN(*(poDelayLine->m_ppfPorts[DL_FEEDBACK]), - -1, - 1); - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - - LADSPA_Data fInputSample = *(pfInput++); - LADSPA_Data &fDelayedSample = pfBuffer[((lSampleIndex + lBufferReadOffset) - & lBufferSizeMinusOne)]; - - *(pfOutput++) = (fDry * fInputSample + fWet * fDelayedSample); - - pfBuffer[((lSampleIndex + lBufferWriteOffset) - & lBufferSizeMinusOne)] - = fInputSample + fDelayedSample * fFeedback; - } - - poDelayLine->m_lWritePointer - = ((poDelayLine->m_lWritePointer + SampleCount) - & lBufferSizeMinusOne); -} - -/*****************************************************************************/ - -template LADSPA_Handle -CMT_Delay_Instantiate(const LADSPA_Descriptor * Descriptor, - unsigned long SampleRate) { - return new DelayLine(SampleRate, - LADSPA_Data(lMaximumDelayMilliseconds - * 0.001)); -} - -/*****************************************************************************/ - -void -initialise_delay() { - - CMT_Descriptor * psDescriptor; - - const char * apcDelayTypeNames[DELAY_TYPE_COUNT] = { - "Echo", - "Feedback" - }; - const char * apcDelayTypeLabels[DELAY_TYPE_COUNT] = { - "delay", - "fbdelay" - }; - LADSPA_Run_Function afRunFunctions[DELAY_TYPE_COUNT] = { - runSimpleDelayLine, - runFeedbackDelayLine - }; - - LADSPA_Data afMaximumDelays[DELAY_LENGTH_COUNT] = { - 0.01, - 0.1, - 1, - 5, - 60 - }; - LADSPA_Instantiate_Function afInstantiateFunctions[DELAY_LENGTH_COUNT] = { - CMT_Delay_Instantiate<10>, - CMT_Delay_Instantiate<100>, - CMT_Delay_Instantiate<1000>, - CMT_Delay_Instantiate<5000>, - CMT_Delay_Instantiate<60000> - }; - - for (long lDelayTypeIndex = 0; - lDelayTypeIndex < DELAY_TYPE_COUNT; - lDelayTypeIndex++) { - - for (long lDelayLengthIndex = 0; - lDelayLengthIndex < DELAY_LENGTH_COUNT; - lDelayLengthIndex++) { - - long lPluginIndex - = lDelayTypeIndex * DELAY_LENGTH_COUNT + lDelayLengthIndex; - - char acLabel[100]; - sprintf(acLabel, - "%s_%gs", - apcDelayTypeLabels[lDelayTypeIndex], - afMaximumDelays[lDelayLengthIndex]); - char acName[100]; - sprintf(acName, - "%s Delay Line (Maximum Delay %gs)", - apcDelayTypeNames[lDelayTypeIndex], - afMaximumDelays[lDelayLengthIndex]); - - psDescriptor = new CMT_Descriptor - (1053 + lPluginIndex, - acLabel, - LADSPA_PROPERTY_HARD_RT_CAPABLE, - acName, - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - afInstantiateFunctions[lDelayLengthIndex], - activateDelayLine, - afRunFunctions[lDelayTypeIndex], - NULL, - NULL, - NULL); - - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Delay (Seconds)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_1), - 0, - afMaximumDelays[lDelayLengthIndex]); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Dry/Wet Balance", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_MIDDLE), - 0, - 1); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - - if (lDelayTypeIndex == 1) - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Feedback", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_HIGH), - -1, - 1); - - registerNewPluginDescriptor(psDescriptor); - } - } -} - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/descriptor.cpp b/plugins/LadspaEffect/cmt/src/descriptor.cpp deleted file mode 100644 index 0a20dc67a99..00000000000 --- a/plugins/LadspaEffect/cmt/src/descriptor.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* descriptor.cpp - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -/* This module contains code providing and supporting the - CMT_Descriptor() function that provides hosts with initial access - to LADSPA plugins. ALL PLUGINS MUST BE REGISTERED IN THIS FILE (see - below). */ - -/*****************************************************************************/ - -/* Module Initialisation: - ---------------------- */ - -void initialise_am(); -void initialise_ambisonic(); -void initialise_amp(); -void initialise_analogue(); -void initialise_canyondelay(); -void initialise_delay(); -void initialise_dynamic(); -void initialise_filter(); -void initialise_freeverb3(); -void initialise_grain(); -void initialise_lofi(); -void initialise_mixer(); -void initialise_noise(); -void initialise_null(); -void initialise_organ(); -void initialise_peak(); -void initialise_phasemod(); -void initialise_sine(); -void initialise_syndrum(); -void initialise_vcf303(); -void initialise_wshape_sine(); -namespace hardgate { void initialise(); } -namespace disintegrator { void initialise(); } -namespace pink { void initialise(); } -namespace pink_full { void initialise(); } -namespace pink_sh { void initialise(); } -namespace sledgehammer { void initialise(); } -namespace logistic { void initialise(); } - -/** This function should initialise all modules in the library. This - will lead to all plugin descriptors being registered. If you write - a new plugin you should initialise it here. If the module has - structures it wishes to remove also then these should be included - in finalise_modules(). */ -void -initialise_modules() { - initialise_am(); - initialise_ambisonic(); - initialise_amp(); - initialise_analogue(); - initialise_canyondelay(); - initialise_delay(); - initialise_dynamic(); - initialise_filter(); - initialise_freeverb3(); - initialise_grain(); - initialise_lofi(); - initialise_mixer(); - initialise_noise(); - initialise_null(); - initialise_organ(); - initialise_peak(); - initialise_phasemod(); - initialise_sine(); - initialise_syndrum(); - initialise_vcf303(); - initialise_wshape_sine(); - hardgate::initialise(); - disintegrator::initialise(); - pink::initialise(); - pink_full::initialise(); - pink_sh::initialise(); - sledgehammer::initialise(); - logistic::initialise(); -} - -/*****************************************************************************/ - -/* Module Finalisation: - -------------------- */ - -void finalise_sine(); - -/** Finalise any structures allocated by the modules. This does not - include descriptors passed to registerNewPluginDescriptor(). */ -void -finalise_modules() { - finalise_sine(); -} - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/disintegrator.cpp b/plugins/LadspaEffect/cmt/src/disintegrator.cpp deleted file mode 100644 index 39edefc5bd2..00000000000 --- a/plugins/LadspaEffect/cmt/src/disintegrator.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* disintegrator.cpp - - (c) 2002 Nathaniel Virgo - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include - -/*****************************************************************************/ - -#include "cmt.h" -#include "run_adding.h" - -/*****************************************************************************/ - -namespace disintegrator { - - enum { - port_probability = 0, - port_multiplier = 1, - port_input = 2, - port_output = 3, - n_ports = 4 - }; - -/** This plugin multiplies random half-waveforms by port_multiplier, - with probability port_probability */ - class Plugin : public CMT_PluginInstance { - LADSPA_Data run_adding_gain; - bool active; - LADSPA_Data last_input; - public: - Plugin(const LADSPA_Descriptor *, - unsigned long) - : CMT_PluginInstance(n_ports) { - active = false; last_input = 0.0f; - } - - template - friend void run(LADSPA_Handle instance, - unsigned long sample_count); - - friend void set_run_adding_gain(LADSPA_Handle instance, - LADSPA_Data new_gain); - }; - - template - void run(LADSPA_Handle instance, - unsigned long sample_count) { - - Plugin *pp = (Plugin *) instance; - Plugin &p = *pp; - - LADSPA_Data prob = *pp->m_ppfPorts[port_probability]; - LADSPA_Data mult = *pp->m_ppfPorts[port_multiplier]; - LADSPA_Data * in = pp->m_ppfPorts[port_input]; - LADSPA_Data * out = pp->m_ppfPorts[port_output]; - - mult *= get_gain(p.run_adding_gain); - - for ( unsigned long i = 0; i < sample_count ; ++i ) { - LADSPA_Data insig = *(in++); - if ( ( p.last_input>0 && insig<0 ) || ( p.last_input<0 && insig>0 ) ) - p.active = rand() < prob*RAND_MAX; - p.last_input = insig; - if (p.active) - write_output(out, insig*mult, 1.0f); - else - write_output(out, insig, p.run_adding_gain); - } - } - - void set_run_adding_gain(LADSPA_Handle instance, - LADSPA_Data new_gain) { - ((Plugin *) instance)->run_adding_gain = new_gain; - } - - void - initialise() { - - CMT_Descriptor * d = new CMT_Descriptor - (1846, - "disintegrator", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Disintegrator", - CMT_MAKER("Nathaniel Virgo"), - CMT_COPYRIGHT("2002", "Nathaniel Virgo"), - NULL, - CMT_Instantiate, - NULL, - run, - run, - set_run_adding_gain, - NULL); - - d->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Probability", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_0), - 0, - 1); - d->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Multiplier", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_0), - -1, - 1); - d->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - d->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - - registerNewPluginDescriptor(d); - - } - -} // end of namespace - -/*****************************************************************************/ - -/* EOF */ - - - - - diff --git a/plugins/LadspaEffect/cmt/src/dynamic.cpp b/plugins/LadspaEffect/cmt/src/dynamic.cpp deleted file mode 100644 index 6314cdfeb6f..00000000000 --- a/plugins/LadspaEffect/cmt/src/dynamic.cpp +++ /dev/null @@ -1,800 +0,0 @@ -/* dynamic.cpp - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -/* This module provides unsophisticated implementations of compressor, - expander and limiter plugins. Note that attack and decay times are - applied at the LEVEL DETECTION stage rather than at gain processing - (the reason no noise gate is provided). No delay is applied to the - main signal. These are useful (and efficient) tools and extended - compressors should probably allocate new IDs rather than break - compatibility in parameter set and sound for this set. */ - -// Having said this, I'm not sure the attack/decay parameters are the -// right way around. - -/*****************************************************************************/ - -#include -#include -#include - -/*****************************************************************************/ - -#include "cmt.h" -#include "utils.h" - -/*****************************************************************************/ - -class DynamicProcessor { -protected: - - /** This state variable is used to track the input envelope (peak or - rms). The state is stored here so that the run function can - perform low-pass filtering to produce a smoothed envelope. */ - LADSPA_Data m_fEnvelopeState; - - /** The sample rate in the world this instance exists in. */ - LADSPA_Data m_fSampleRate; - - DynamicProcessor(const LADSPA_Data fSampleRate) - : m_fSampleRate(fSampleRate) { - } - -}; - -/*****************************************************************************/ - -#define CE_THRESHOLD 0 -#define CE_RATIO 1 -#define CE_ATTACK 2 -#define CE_DECAY 3 -#define CE_INPUT 4 -#define CE_OUTPUT 5 - -/** This class is used to implement simple compressor and expander - plugins. Attack and decay times are applied at the level detection - stage rather than at gain processing. No delay is applied to the - main signal. Both peak and RMS support is included. */ -class CompressorExpander - : public CMT_PluginInstance, public DynamicProcessor { -public: - - CompressorExpander(const LADSPA_Descriptor *, - unsigned long lSampleRate) - : CMT_PluginInstance(6), - DynamicProcessor(lSampleRate) { - } - - friend void activateCompressorExpander(void * pvHandle); - friend void runCompressor_Peak(LADSPA_Handle Instance, - unsigned long SampleCount); - friend void runCompressor_RMS(LADSPA_Handle Instance, - unsigned long SampleCount); - friend void runExpander_Peak(LADSPA_Handle Instance, - unsigned long SampleCount); - friend void runExpander_RMS(LADSPA_Handle Instance, - unsigned long SampleCount); - -}; - -/*****************************************************************************/ - -#define LN_THRESHOLD 0 -#define LN_ATTACK 1 -#define LN_DECAY 2 -#define LN_INPUT 3 -#define LN_OUTPUT 4 - -/** This class is used to implement simple limiter plugins. Attack and - decay times are applied at the level detection stage rather than - at gain processing. No delay is applied to the main signal. Both - peak and RMS support is included. */ -class Limiter - : public CMT_PluginInstance, public DynamicProcessor { -public: - - Limiter(const LADSPA_Descriptor *, - unsigned long lSampleRate) - : CMT_PluginInstance(5), - DynamicProcessor(lSampleRate) { - } - - friend void activateLimiter(void * pvHandle); - friend void runLimiter_Peak(LADSPA_Handle Instance, - unsigned long SampleCount); - friend void runLimiter_RMS(LADSPA_Handle Instance, - unsigned long SampleCount); - -}; - -/*****************************************************************************/ - -void -activateCompressorExpander(void * pvHandle) { - CompressorExpander * poProcessor = (CompressorExpander *)pvHandle; - poProcessor->m_fEnvelopeState = 0; -} - -/*****************************************************************************/ - -void -activateLimiter(void * pvHandle) { - Limiter * poProcessor = (Limiter *)pvHandle; - poProcessor->m_fEnvelopeState = 0; -} - -/*****************************************************************************/ - -void -runCompressor_Peak(LADSPA_Handle Instance, - unsigned long SampleCount) { - - CompressorExpander * poProcessor = (CompressorExpander *)Instance; - - LADSPA_Data fThreshold - = BOUNDED_BELOW(*(poProcessor->m_ppfPorts[CE_THRESHOLD]), - 0); - LADSPA_Data fOneOverThreshold - = 1 / fThreshold; - LADSPA_Data fRatioMinusOne - = *(poProcessor->m_ppfPorts[CE_RATIO]) - 1; - LADSPA_Data * pfInput - = poProcessor->m_ppfPorts[CE_INPUT]; - LADSPA_Data * pfOutput - = poProcessor->m_ppfPorts[CE_OUTPUT]; - - LADSPA_Data fEnvelopeDrag_Attack - = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_ATTACK]), - poProcessor->m_fSampleRate); - LADSPA_Data fEnvelopeDrag_Decay - = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_DECAY]), - poProcessor->m_fSampleRate); - - LADSPA_Data &rfEnvelopeState - = poProcessor->m_fEnvelopeState; - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - - LADSPA_Data fInput = *(pfInput++); - LADSPA_Data fEnvelopeTarget = fabs(fInput); - if (fEnvelopeTarget > rfEnvelopeState) - rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Attack - + fEnvelopeTarget * (1 - fEnvelopeDrag_Attack)); - else - rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Decay - + fEnvelopeTarget * (1 - fEnvelopeDrag_Decay)); - - /* Perform the mapping. This questions this plugin's claim of - being `hard-realtime.' */ - LADSPA_Data fGain; - if (rfEnvelopeState < fThreshold) - fGain = 1; - else { - fGain = pow(rfEnvelopeState * fOneOverThreshold, fRatioMinusOne); - if (isnan(fGain)) - fGain = 0; - } - - /* Perform output. */ - *(pfOutput++) = fInput * fGain; - } -} - -/*****************************************************************************/ - -void -runCompressor_RMS(LADSPA_Handle Instance, - unsigned long SampleCount) { - - CompressorExpander * poProcessor = (CompressorExpander *)Instance; - - LADSPA_Data fThreshold - = BOUNDED_BELOW(*(poProcessor->m_ppfPorts[CE_THRESHOLD]), - 0); - LADSPA_Data fOneOverThreshold - = 1 / fThreshold; - LADSPA_Data fRatioMinusOne - = *(poProcessor->m_ppfPorts[CE_RATIO]) - 1; - LADSPA_Data * pfInput - = poProcessor->m_ppfPorts[CE_INPUT]; - LADSPA_Data * pfOutput - = poProcessor->m_ppfPorts[CE_OUTPUT]; - - LADSPA_Data fEnvelopeDrag_Attack - = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_ATTACK]), - poProcessor->m_fSampleRate); - LADSPA_Data fEnvelopeDrag_Decay - = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_DECAY]), - poProcessor->m_fSampleRate); - - LADSPA_Data &rfEnvelopeState - = poProcessor->m_fEnvelopeState; - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - - LADSPA_Data fInput = *(pfInput++); - LADSPA_Data fEnvelopeTarget = fInput * fInput; - if (fEnvelopeTarget > rfEnvelopeState) - rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Attack - + fEnvelopeTarget * (1 - fEnvelopeDrag_Attack)); - else - rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Decay - + fEnvelopeTarget * (1 - fEnvelopeDrag_Decay)); - - LADSPA_Data fEnvelopeAmplitude = sqrt(rfEnvelopeState); - - /* Perform the mapping. This questions this plugin's claim of - being `hard-realtime.' */ - LADSPA_Data fGain; - if (fEnvelopeAmplitude < fThreshold) - fGain = 1; - else { - fGain = pow(fEnvelopeAmplitude * fOneOverThreshold, fRatioMinusOne); - if (isnan(fGain)) - fGain = 0; - } - - /* Perform output. */ - *(pfOutput++) = fInput * fGain; - } -} - -/*****************************************************************************/ - -void -runExpander_Peak(LADSPA_Handle Instance, - unsigned long SampleCount) { - - CompressorExpander * poProcessor = (CompressorExpander *)Instance; - - LADSPA_Data fThreshold - = BOUNDED_BELOW(*(poProcessor->m_ppfPorts[CE_THRESHOLD]), - 0); - LADSPA_Data fOneOverThreshold - = 1 / fThreshold; - LADSPA_Data fOneMinusRatio - = 1 - *(poProcessor->m_ppfPorts[CE_RATIO]); - LADSPA_Data * pfInput - = poProcessor->m_ppfPorts[CE_INPUT]; - LADSPA_Data * pfOutput - = poProcessor->m_ppfPorts[CE_OUTPUT]; - - LADSPA_Data fEnvelopeDrag_Attack - = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_ATTACK]), - poProcessor->m_fSampleRate); - LADSPA_Data fEnvelopeDrag_Decay - = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_DECAY]), - poProcessor->m_fSampleRate); - - LADSPA_Data &rfEnvelopeState - = poProcessor->m_fEnvelopeState; - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - - LADSPA_Data fInput = *(pfInput++); - LADSPA_Data fEnvelopeTarget = fabs(fInput); - if (fEnvelopeTarget > rfEnvelopeState) - rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Attack - + fEnvelopeTarget * (1 - fEnvelopeDrag_Attack)); - else - rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Decay - + fEnvelopeTarget * (1 - fEnvelopeDrag_Decay)); - - /* Perform the mapping. This questions this plugin's claim of - being `hard-realtime.' */ - LADSPA_Data fGain; - if (rfEnvelopeState > fThreshold) - fGain = 1; - else { - fGain = pow(rfEnvelopeState * fOneOverThreshold, fOneMinusRatio); - if (isnan(fGain)) - fGain = 0; - } - - /* Perform output. */ - *(pfOutput++) = fInput * fGain; - } -} - -/*****************************************************************************/ - -void -runExpander_RMS(LADSPA_Handle Instance, - unsigned long SampleCount) { - - CompressorExpander * poProcessor = (CompressorExpander *)Instance; - - LADSPA_Data fThreshold - = BOUNDED_BELOW(*(poProcessor->m_ppfPorts[CE_THRESHOLD]), - 0); - LADSPA_Data fOneOverThreshold - = 1 / fThreshold; - LADSPA_Data fOneMinusRatio - = 1 - *(poProcessor->m_ppfPorts[CE_RATIO]); - LADSPA_Data * pfInput - = poProcessor->m_ppfPorts[CE_INPUT]; - LADSPA_Data * pfOutput - = poProcessor->m_ppfPorts[CE_OUTPUT]; - - LADSPA_Data fEnvelopeDrag_Attack - = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_ATTACK]), - poProcessor->m_fSampleRate); - LADSPA_Data fEnvelopeDrag_Decay - = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_DECAY]), - poProcessor->m_fSampleRate); - - LADSPA_Data &rfEnvelopeState - = poProcessor->m_fEnvelopeState; - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - - LADSPA_Data fInput = *(pfInput++); - LADSPA_Data fEnvelopeTarget = fInput * fInput; - if (fEnvelopeTarget > rfEnvelopeState) - rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Attack - + fEnvelopeTarget * (1 - fEnvelopeDrag_Attack)); - else - rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Decay - + fEnvelopeTarget * (1 - fEnvelopeDrag_Decay)); - - LADSPA_Data fEnvelopeAmplitude = sqrt(rfEnvelopeState); - - /* Perform the mapping. This questions this plugin's claim of - being `hard-realtime.' */ - LADSPA_Data fGain; - if (fEnvelopeAmplitude > fThreshold) - fGain = 1; - else { - fGain = pow(fEnvelopeAmplitude * fOneOverThreshold, fOneMinusRatio); - if (isnan(fGain)) - fGain = 0; - } - - /* Perform output. */ - *(pfOutput++) = fInput * fGain; - } -} - -/*****************************************************************************/ - -void -runLimiter_Peak(LADSPA_Handle Instance, - unsigned long SampleCount) { - - Limiter * poProcessor = (Limiter *)Instance; - - LADSPA_Data fThreshold - = BOUNDED_BELOW(*(poProcessor->m_ppfPorts[LN_THRESHOLD]), - 0); - LADSPA_Data * pfInput - = poProcessor->m_ppfPorts[LN_INPUT]; - LADSPA_Data * pfOutput - = poProcessor->m_ppfPorts[LN_OUTPUT]; - - LADSPA_Data fEnvelopeDrag_Attack - = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_ATTACK]), - poProcessor->m_fSampleRate); - LADSPA_Data fEnvelopeDrag_Decay - = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_DECAY]), - poProcessor->m_fSampleRate); - - LADSPA_Data &rfEnvelopeState - = poProcessor->m_fEnvelopeState; - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - - LADSPA_Data fInput = *(pfInput++); - LADSPA_Data fEnvelopeTarget = fabs(fInput); - if (fEnvelopeTarget > rfEnvelopeState) - rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Attack - + fEnvelopeTarget * (1 - fEnvelopeDrag_Attack)); - else - rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Decay - + fEnvelopeTarget * (1 - fEnvelopeDrag_Decay)); - - /* Perform the mapping. This questions this plugin's claim of - being `hard-realtime.' */ - LADSPA_Data fGain; - if (rfEnvelopeState < fThreshold) - fGain = 1; - else { - fGain = fThreshold / rfEnvelopeState; - if (isnan(fGain)) - fGain = 0; - } - - /* Perform output. */ - *(pfOutput++) = fInput * fGain; - } -} - -/*****************************************************************************/ - -void -runLimiter_RMS(LADSPA_Handle Instance, - unsigned long SampleCount) { - - Limiter * poProcessor = (Limiter *)Instance; - - LADSPA_Data fThreshold - = BOUNDED_BELOW(*(poProcessor->m_ppfPorts[LN_THRESHOLD]), - 0); - LADSPA_Data * pfInput - = poProcessor->m_ppfPorts[LN_INPUT]; - LADSPA_Data * pfOutput - = poProcessor->m_ppfPorts[LN_OUTPUT]; - - LADSPA_Data fEnvelopeDrag_Attack - = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_ATTACK]), - poProcessor->m_fSampleRate); - LADSPA_Data fEnvelopeDrag_Decay - = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_DECAY]), - poProcessor->m_fSampleRate); - - LADSPA_Data &rfEnvelopeState - = poProcessor->m_fEnvelopeState; - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - - LADSPA_Data fInput = *(pfInput++); - LADSPA_Data fEnvelopeTarget = fInput * fInput; - if (fEnvelopeTarget > rfEnvelopeState) - rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Attack - + fEnvelopeTarget * (1 - fEnvelopeDrag_Attack)); - else - rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Decay - + fEnvelopeTarget * (1 - fEnvelopeDrag_Decay)); - - LADSPA_Data fEnvelopeAmplitude = sqrt(rfEnvelopeState); - - /* Perform the mapping. This questions this plugin's claim of - being `hard-realtime.' */ - LADSPA_Data fGain; - if (fEnvelopeAmplitude < fThreshold) - fGain = 1; - else { - fGain = fThreshold / fEnvelopeAmplitude; - if (isnan(fGain)) - fGain = 0; - } - - /* Perform output. */ - *(pfOutput++) = fInput * fGain; - } -} - -/*****************************************************************************/ - -void -initialise_dynamic() { - - CMT_Descriptor * psDescriptor; - - psDescriptor = new CMT_Descriptor - (1072, - "compress_peak", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Simple Compressor (Peak Envelope Tracking)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - activateCompressorExpander, - runCompressor_Peak, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Threshold", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_LOGARITHMIC - | LADSPA_HINT_DEFAULT_1), - 0, - 0); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Compression Ratio", - (LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_MIDDLE), - 0, - 1); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Output Envelope Attack (s)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_DEFAULT_MAXIMUM), - 0, - 0.1f); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Output Envelope Decay (s)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_DEFAULT_MAXIMUM), - 0, - 0.1f); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1073, - "compress_rms", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Simple Compressor (RMS Envelope Tracking)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - activateCompressorExpander, - runCompressor_RMS, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Threshold", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_LOGARITHMIC - | LADSPA_HINT_DEFAULT_1), - 0, - 0); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Compression Ratio", - (LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_MIDDLE), - 0, - 1); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Output Envelope Attack (s)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_DEFAULT_MAXIMUM), - 0, - 0.1f); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Output Envelope Decay (s)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_DEFAULT_MAXIMUM), - 0, - 0.1f); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1074, - "expand_peak", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Simple Expander (Peak Envelope Tracking)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - activateCompressorExpander, - runExpander_Peak, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Threshold", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_LOGARITHMIC - | LADSPA_HINT_DEFAULT_1), - 0, - 0); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Expansion Ratio", - (LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_MIDDLE), - 0, - 1); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Output Envelope Attack (s)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_DEFAULT_MAXIMUM), - 0, - 0.1f); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Output Envelope Decay (s)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_DEFAULT_MAXIMUM), - 0, - 0.1f); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1075, - "expand_rms", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Simple Expander (RMS Envelope Tracking)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - activateCompressorExpander, - runExpander_RMS, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Threshold", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_LOGARITHMIC - | LADSPA_HINT_DEFAULT_1), - 0, - 0); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Expansion Ratio", - (LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_MIDDLE), - 0, - 1); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Output Envelope Attack (s)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_DEFAULT_MAXIMUM), - 0, - 0.1f); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Output Envelope Decay (s)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_DEFAULT_MAXIMUM), - 0, - 0.1f); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1076, - "limit_peak", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Simple Limiter (Peak Envelope Tracking)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - activateLimiter, - runLimiter_Peak, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Threshold", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_LOGARITHMIC - | LADSPA_HINT_DEFAULT_1), - 0, - 0); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Output Envelope Attack (s)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_DEFAULT_MAXIMUM), - 0, - 0.1f); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Output Envelope Decay (s)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_DEFAULT_MAXIMUM), - 0, - 0.1f); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1077, - "limit_rms", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Simple Limiter (RMS Envelope Tracking)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - activateLimiter, - runLimiter_RMS, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Threshold", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_LOGARITHMIC - | LADSPA_HINT_DEFAULT_1), - 0, - 0); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Output Envelope Attack (s)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_DEFAULT_MAXIMUM), - 0, - 0.1f); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Output Envelope Decay (s)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_DEFAULT_MAXIMUM), - 0, - 0.1f); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - registerNewPluginDescriptor(psDescriptor); -} - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/filter.cpp b/plugins/LadspaEffect/cmt/src/filter.cpp deleted file mode 100644 index a9006fbb7cf..00000000000 --- a/plugins/LadspaEffect/cmt/src/filter.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/* filter.cpp - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include -#include - -/*****************************************************************************/ - -#include "cmt.h" - -/*****************************************************************************/ - -#define SF_CUTOFF 0 -#define SF_INPUT 1 -#define SF_OUTPUT 2 - -/** Instance data for the OnePoll filter (one-poll, low or high - pass). We can get away with using this structure for both low- and - high-pass filters because the data stored is the same. Note that - the actual run() calls differ however. */ -class OnePollFilter : public CMT_PluginInstance { -private: - - LADSPA_Data m_fSampleRate; - LADSPA_Data m_fTwoPiOverSampleRate; - - LADSPA_Data m_fLastOutput; - LADSPA_Data m_fLastCutoff; - LADSPA_Data m_fAmountOfCurrent; - LADSPA_Data m_fAmountOfLast; - -public: - - OnePollFilter(const LADSPA_Descriptor *, - unsigned long lSampleRate) - : CMT_PluginInstance(3), - m_fSampleRate(LADSPA_Data(lSampleRate)), - m_fTwoPiOverSampleRate(LADSPA_Data((2 * M_PI) / lSampleRate)), - m_fLastCutoff(0), - m_fAmountOfCurrent(0), - m_fAmountOfLast(0) { - } - - friend void activateOnePollFilter(LADSPA_Handle Instance); - friend void runOnePollLowPassFilter(LADSPA_Handle Instance, - unsigned long SampleCount); - friend void runOnePollHighPassFilter(LADSPA_Handle Instance, - unsigned long SampleCount); - -}; - -/*****************************************************************************/ - -void -activateOnePollFilter(LADSPA_Handle Instance) { - ((OnePollFilter *)Instance)->m_fLastOutput = 0; -} - -/*****************************************************************************/ - -/** Run the LPF algorithm for a block of SampleCount samples. */ -void -runOnePollLowPassFilter(LADSPA_Handle Instance, - unsigned long SampleCount) { - - OnePollFilter * poFilter = (OnePollFilter *)Instance; - - LADSPA_Data * pfInput = poFilter->m_ppfPorts[SF_INPUT]; - LADSPA_Data * pfOutput = poFilter->m_ppfPorts[SF_OUTPUT]; - - if (poFilter->m_fLastCutoff != *(poFilter->m_ppfPorts[SF_CUTOFF])) { - poFilter->m_fLastCutoff = *(poFilter->m_ppfPorts[SF_CUTOFF]); - if (poFilter->m_fLastCutoff <= 0) { - /* Reject everything. */ - poFilter->m_fAmountOfCurrent = poFilter->m_fAmountOfLast = 0; - } - else if (poFilter->m_fLastCutoff > poFilter->m_fSampleRate * 0.5) { - /* Above Nyquist frequency. Let everything through. */ - poFilter->m_fAmountOfCurrent = 1; - poFilter->m_fAmountOfLast = 0; - } - else { - poFilter->m_fAmountOfLast = 0; - LADSPA_Data fComp = 2 - cos(poFilter->m_fTwoPiOverSampleRate - * poFilter->m_fLastCutoff); - poFilter->m_fAmountOfLast = fComp - (LADSPA_Data)sqrt(fComp * fComp - 1); - poFilter->m_fAmountOfCurrent = 1 - poFilter->m_fAmountOfLast; - } - } - - LADSPA_Data fAmountOfCurrent = poFilter->m_fAmountOfCurrent; - LADSPA_Data fAmountOfLast = poFilter->m_fAmountOfLast; - LADSPA_Data fLastOutput = poFilter->m_fLastOutput; - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - *(pfOutput++) - = fLastOutput - = (fAmountOfCurrent * *(pfInput++) - + fAmountOfLast * fLastOutput); - } - - poFilter->m_fLastOutput = fLastOutput; -} - -/*****************************************************************************/ - -/** Run the HPF algorithm for a block of SampleCount samples. */ -void -runOnePollHighPassFilter(LADSPA_Handle Instance, - unsigned long SampleCount) { - - OnePollFilter * poFilter = (OnePollFilter *)Instance; - - LADSPA_Data * pfInput = poFilter->m_ppfPorts[SF_INPUT]; - LADSPA_Data * pfOutput = poFilter->m_ppfPorts[SF_OUTPUT]; - - if (poFilter->m_fLastCutoff != *(poFilter->m_ppfPorts[SF_CUTOFF])) { - poFilter->m_fLastCutoff = *(poFilter->m_ppfPorts[SF_CUTOFF]); - if (poFilter->m_fLastCutoff <= 0) { - /* Let everything through. */ - poFilter->m_fAmountOfCurrent = 1; - poFilter->m_fAmountOfLast = 0; - } - else if (poFilter->m_fLastCutoff > poFilter->m_fSampleRate * 0.5) { - /* Above Nyquist frequency. Reject everything. */ - poFilter->m_fAmountOfCurrent = poFilter->m_fAmountOfLast = 0; - } - else { - poFilter->m_fAmountOfLast = 0; - LADSPA_Data fComp = 2 - cos(poFilter->m_fTwoPiOverSampleRate - * poFilter->m_fLastCutoff); - poFilter->m_fAmountOfLast = fComp - (LADSPA_Data)sqrt(fComp * fComp - 1); - poFilter->m_fAmountOfCurrent = 1 - poFilter->m_fAmountOfLast; - } - - } - - LADSPA_Data fAmountOfCurrent = poFilter->m_fAmountOfCurrent; - LADSPA_Data fAmountOfLast = poFilter->m_fAmountOfLast; - LADSPA_Data fLastOutput = poFilter->m_fLastOutput; - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - fLastOutput - = (fAmountOfCurrent * *pfInput - + fAmountOfLast * fLastOutput); - *(pfOutput++) = *(pfInput++) - fLastOutput; - } - - poFilter->m_fLastOutput = fLastOutput; -} - -/*****************************************************************************/ - -void -initialise_filter() { - - CMT_Descriptor * psDescriptor; - - psDescriptor = new CMT_Descriptor - (1051, - "lpf", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Low Pass Filter (One Pole)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - activateOnePollFilter, - runOnePollLowPassFilter, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Cutoff Frequency (Hz)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_SAMPLE_RATE - | LADSPA_HINT_LOGARITHMIC - | LADSPA_HINT_DEFAULT_440), - 0, - 0.5f); /* Nyquist frequency (half the sample rate) */ - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1052, - "hpf", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "High Pass Filter (One Pole)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - activateOnePollFilter, - runOnePollHighPassFilter, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Cutoff Frequency (Hz)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_SAMPLE_RATE - | LADSPA_HINT_LOGARITHMIC - | LADSPA_HINT_DEFAULT_440), - 0, - 0.5f); /* Nyquist frequency (half the sample rate) */ - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - registerNewPluginDescriptor(psDescriptor); -} - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/freeverb/Components/allpass.cpp b/plugins/LadspaEffect/cmt/src/freeverb/Components/allpass.cpp deleted file mode 100644 index 850337e3a33..00000000000 --- a/plugins/LadspaEffect/cmt/src/freeverb/Components/allpass.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Allpass filter implementation -// -// Written by Jezar at Dreampoint, June 2000 -// http://www.dreampoint.co.uk -// This code is public domain - -#include "allpass.h" - -allpass::allpass() -{ - bufidx = 0; -} - -void allpass::setbuffer(float *buf, int size) -{ - buffer = buf; - bufsize = size; -} - -void allpass::mute() -{ - for (int i=0; i=bufsize) bufidx = 0; - - return output; -} - -#endif//_allpass - -//ends diff --git a/plugins/LadspaEffect/cmt/src/freeverb/Components/comb.cpp b/plugins/LadspaEffect/cmt/src/freeverb/Components/comb.cpp deleted file mode 100644 index 62be706d705..00000000000 --- a/plugins/LadspaEffect/cmt/src/freeverb/Components/comb.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// Comb filter implementation -// -// Written by Jezar at Dreampoint, June 2000 -// http://www.dreampoint.co.uk -// This code is public domain - -#include "comb.h" - -comb::comb() -{ - filterstore = 0; - bufidx = 0; -} - -void comb::setbuffer(float *buf, int size) -{ - buffer = buf; - bufsize = size; -} - -void comb::mute() -{ - for (int i=0; i=bufsize) bufidx = 0; - - return output; -} - -#endif //_comb_ - -//ends diff --git a/plugins/LadspaEffect/cmt/src/freeverb/Components/denormals.h b/plugins/LadspaEffect/cmt/src/freeverb/Components/denormals.h deleted file mode 100644 index 01990916a53..00000000000 --- a/plugins/LadspaEffect/cmt/src/freeverb/Components/denormals.h +++ /dev/null @@ -1,20 +0,0 @@ -// Macro for killing denormalled numbers -// -// Written by Jezar at Dreampoint, June 2000 -// http://www.dreampoint.co.uk -// Based on IS_DENORMAL macro by Jon Watte -// This code is public domain - -#ifndef _denormals_ -#define _denormals_ - -/*#define undenormalise(sample) if(((*(unsigned int*)&sample)&0x7f800000)==0) sample=0.0f*/ -static void inline undenormalise(float *sample) -{ - if (((*(unsigned int*)sample) & 0x7f800000) == 0) - *sample = 0.0f; -} - -#endif//_denormals_ - -//ends diff --git a/plugins/LadspaEffect/cmt/src/freeverb/Components/revmodel.cpp b/plugins/LadspaEffect/cmt/src/freeverb/Components/revmodel.cpp deleted file mode 100644 index 4f7fcd4d1e7..00000000000 --- a/plugins/LadspaEffect/cmt/src/freeverb/Components/revmodel.cpp +++ /dev/null @@ -1,257 +0,0 @@ -// Reverb model implementation -// -// Written by Jezar at Dreampoint, June 2000 -// http://www.dreampoint.co.uk -// This code is public domain - -#include "revmodel.h" - -revmodel::revmodel( float sampleRatio ) : - m_sampleRatio( sampleRatio ) -{ - // Tie the components to their buffers - combL[0].setbuffer(bufcombL1,static_cast( combtuningL1 * m_sampleRatio )); - combR[0].setbuffer(bufcombR1,static_cast( combtuningR1 * m_sampleRatio )); - combL[1].setbuffer(bufcombL2,static_cast( combtuningL2 * m_sampleRatio )); - combR[1].setbuffer(bufcombR2,static_cast( combtuningR2 * m_sampleRatio )); - combL[2].setbuffer(bufcombL3,static_cast( combtuningL3 * m_sampleRatio )); - combR[2].setbuffer(bufcombR3,static_cast( combtuningR3 * m_sampleRatio )); - combL[3].setbuffer(bufcombL4,static_cast( combtuningL4 * m_sampleRatio )); - combR[3].setbuffer(bufcombR4,static_cast( combtuningR4 * m_sampleRatio )); - combL[4].setbuffer(bufcombL5,static_cast( combtuningL5 * m_sampleRatio )); - combR[4].setbuffer(bufcombR5,static_cast( combtuningR5 * m_sampleRatio )); - combL[5].setbuffer(bufcombL6,static_cast( combtuningL6 * m_sampleRatio )); - combR[5].setbuffer(bufcombR6,static_cast( combtuningR6 * m_sampleRatio )); - combL[6].setbuffer(bufcombL7,static_cast( combtuningL7 * m_sampleRatio )); - combR[6].setbuffer(bufcombR7,static_cast( combtuningR7 * m_sampleRatio )); - combL[7].setbuffer(bufcombL8,static_cast( combtuningL8 * m_sampleRatio )); - combR[7].setbuffer(bufcombR8,static_cast( combtuningR8 * m_sampleRatio )); - allpassL[0].setbuffer(bufallpassL1,static_cast( allpasstuningL1 * m_sampleRatio )); - allpassR[0].setbuffer(bufallpassR1,static_cast( allpasstuningR1 * m_sampleRatio )); - allpassL[1].setbuffer(bufallpassL2,static_cast( allpasstuningL2 * m_sampleRatio )); - allpassR[1].setbuffer(bufallpassR2,static_cast( allpasstuningR2 * m_sampleRatio )); - allpassL[2].setbuffer(bufallpassL3,static_cast( allpasstuningL3 * m_sampleRatio )); - allpassR[2].setbuffer(bufallpassR3,static_cast( allpasstuningR3 * m_sampleRatio )); - allpassL[3].setbuffer(bufallpassL4,static_cast( allpasstuningL4 * m_sampleRatio )); - allpassR[3].setbuffer(bufallpassR4,static_cast( allpasstuningR4 * m_sampleRatio )); - - // Set default values - allpassL[0].setfeedback(0.5f); - allpassR[0].setfeedback(0.5f); - allpassL[1].setfeedback(0.5f); - allpassR[1].setfeedback(0.5f); - allpassL[2].setfeedback(0.5f); - allpassR[2].setfeedback(0.5f); - allpassL[3].setfeedback(0.5f); - allpassR[3].setfeedback(0.5f); - setwet(initialwet); - setroomsize(initialroom); - setdry(initialdry); - setdamp(initialdamp); - setwidth(initialwidth); - setmode(initialmode); - - // Buffer will be full of rubbish - so we MUST mute them - mute(); -} - -void revmodel::mute() -{ - int i; - - if (getmode() >= freezemode) - return; - - for (i=0;i 0) - { - outL = outR = 0; - input = (*inputL + *inputR) * gain; - - // Accumulate comb filters in parallel - for(i=0; i 0) - { - outL = outR = 0; - input = (*inputL + *inputR) * gain; - - // Accumulate comb filters in parallel - for(i=0; i= freezemode) - { - roomsize1 = 1; - damp1 = 0; - gain = muted; - } - else - { - roomsize1 = roomsize; - damp1 = damp; - gain = fixedgain; - } - - for(i=0; i= freezemode) - return 1; - else - return 0; -} - -//ends diff --git a/plugins/LadspaEffect/cmt/src/freeverb/Components/revmodel.h b/plugins/LadspaEffect/cmt/src/freeverb/Components/revmodel.h deleted file mode 100644 index 9846eb40de3..00000000000 --- a/plugins/LadspaEffect/cmt/src/freeverb/Components/revmodel.h +++ /dev/null @@ -1,91 +0,0 @@ -// Reverb model declaration -// -// Written by Jezar at Dreampoint, June 2000 -// http://www.dreampoint.co.uk -// This code is public domain - -#ifndef _revmodel_ -#define _revmodel_ - -#include "comb.h" -#include "allpass.h" -#include "tuning.h" - -const int maxSampleRatio = 18; // enough for largest possible samplerate, 8 * 96000 - -class revmodel -{ -public: - revmodel( float sampleRatio ); - void mute(); - void processmix(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip); - void processreplace(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip); - void setroomsize(float value); - float getroomsize(); - void setdamp(float value); - float getdamp(); - void setwet(float value); - float getwet(); - void setdry(float value); - float getdry(); - void setwidth(float value); - float getwidth(); - void setmode(float value); - float getmode(); -private: - void update(); -private: - float gain; - float roomsize,roomsize1; - float damp,damp1; - float wet,wet1,wet2; - float dry; - float width; - float mode; - - float m_sampleRatio; - - // The following are all declared inline - // to remove the need for dynamic allocation - // with its subsequent error-checking messiness - - // Comb filters - comb combL[numcombs]; - comb combR[numcombs]; - - // Allpass filters - allpass allpassL[numallpasses]; - allpass allpassR[numallpasses]; - - // Buffers for the combs - float bufcombL1[combtuningL1 * maxSampleRatio]; - float bufcombR1[combtuningR1 * maxSampleRatio]; - float bufcombL2[combtuningL2 * maxSampleRatio]; - float bufcombR2[combtuningR2 * maxSampleRatio]; - float bufcombL3[combtuningL3 * maxSampleRatio]; - float bufcombR3[combtuningR3 * maxSampleRatio]; - float bufcombL4[combtuningL4 * maxSampleRatio]; - float bufcombR4[ combtuningR4 * maxSampleRatio ]; - float bufcombL5[ combtuningL5 * maxSampleRatio ]; - float bufcombR5[ combtuningR5 * maxSampleRatio ]; - float bufcombL6[ combtuningL6 * maxSampleRatio ]; - float bufcombR6[ combtuningR6 * maxSampleRatio ]; - float bufcombL7[ combtuningL7 * maxSampleRatio ]; - float bufcombR7[ combtuningR7 * maxSampleRatio ]; - float bufcombL8[ combtuningL8 * maxSampleRatio ]; - float bufcombR8[ combtuningR8 * maxSampleRatio ]; - - // Buffers for the allpasses - float bufallpassL1[ allpasstuningL1 * maxSampleRatio ]; - float bufallpassR1[ allpasstuningR1 * maxSampleRatio ]; - float bufallpassL2[ allpasstuningL2 * maxSampleRatio ]; - float bufallpassR2[ allpasstuningR2 * maxSampleRatio ]; - float bufallpassL3[ allpasstuningL3 * maxSampleRatio ]; - float bufallpassR3[ allpasstuningR3 * maxSampleRatio ]; - float bufallpassL4[ allpasstuningL4 * maxSampleRatio ]; - float bufallpassR4[ allpasstuningR4 * maxSampleRatio ]; -}; - -#endif//_revmodel_ - -//ends diff --git a/plugins/LadspaEffect/cmt/src/freeverb/Components/tuning.h b/plugins/LadspaEffect/cmt/src/freeverb/Components/tuning.h deleted file mode 100644 index ced89252813..00000000000 --- a/plugins/LadspaEffect/cmt/src/freeverb/Components/tuning.h +++ /dev/null @@ -1,60 +0,0 @@ -// Reverb model tuning values -// -// Written by Jezar at Dreampoint, June 2000 -// http://www.dreampoint.co.uk -// This code is public domain - -#ifndef _tuning_ -#define _tuning_ - -const int numcombs = 8; -const int numallpasses = 4; -const float muted = 0; -const float fixedgain = 0.015f; -const float scalewet = 3; -const float scaledry = 2; -const float scaledamp = 0.4f; -const float scaleroom = 0.28f; -const float offsetroom = 0.7f; -const float initialroom = 0.5f; -const float initialdamp = 0.5f; -const float initialwet = 1/scalewet; -const float initialdry = 0; -const float initialwidth = 1; -const float initialmode = 0; -const float freezemode = 0.5f; -const int stereospread = 23; - -// These values assume 44.1KHz sample rate -// they will probably be OK for 48KHz sample rate -// but would need scaling for 96KHz (or other) sample rates. -// The values were obtained by listening tests. -const int combtuningL1 = 1116; -const int combtuningR1 = 1116+stereospread; -const int combtuningL2 = 1188; -const int combtuningR2 = 1188+stereospread; -const int combtuningL3 = 1277; -const int combtuningR3 = 1277+stereospread; -const int combtuningL4 = 1356; -const int combtuningR4 = 1356+stereospread; -const int combtuningL5 = 1422; -const int combtuningR5 = 1422+stereospread; -const int combtuningL6 = 1491; -const int combtuningR6 = 1491+stereospread; -const int combtuningL7 = 1557; -const int combtuningR7 = 1557+stereospread; -const int combtuningL8 = 1617; -const int combtuningR8 = 1617+stereospread; -const int allpasstuningL1 = 556; -const int allpasstuningR1 = 556+stereospread; -const int allpasstuningL2 = 441; -const int allpasstuningR2 = 441+stereospread; -const int allpasstuningL3 = 341; -const int allpasstuningR3 = 341+stereospread; -const int allpasstuningL4 = 225; -const int allpasstuningR4 = 225+stereospread; - -#endif//_tuning_ - -//ends - diff --git a/plugins/LadspaEffect/cmt/src/freeverb/freeverb.cpp b/plugins/LadspaEffect/cmt/src/freeverb/freeverb.cpp deleted file mode 100644 index 418e4d91c47..00000000000 --- a/plugins/LadspaEffect/cmt/src/freeverb/freeverb.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/* freeverb.cpp - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. Freeverb is also Copyright (C) 2000 - Jezar. Richard may be contacted at richard@muse.demon.co.uk. [V1 - Ported to LADSPA 15/7/2000 Richard W.E. Furse, V3 ported to CMT - 4/11/2000.] - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include - -/*****************************************************************************/ - -#include "../cmt.h" -#include "Components/revmodel.h" - -/*****************************************************************************/ - -enum { - - FV_Input1 = 0, - FV_Input2, - FV_Output1, - FV_Output2, - FV_Mode, - FV_RoomSize, - FV_Damping, - FV_Wet, - FV_Dry, - FV_Width, - - FV_NumPorts - -}; - -/*****************************************************************************/ - -/** This plugin wraps Jezar's Freeverb free reverberation module - (version 3). */ -class Freeverb3 : public CMT_PluginInstance, public revmodel { -public: - - Freeverb3(const LADSPA_Descriptor *, unsigned long lSampleRate) - : CMT_PluginInstance(FV_NumPorts), - revmodel( (float) lSampleRate / 44100.0f ) - {} - - friend void activateFreeverb3(LADSPA_Handle Instance); - friend void runFreeverb3(LADSPA_Handle Instance, - unsigned long SampleCount); -}; - -/*****************************************************************************/ - -void -activateFreeverb3(LADSPA_Handle Instance) { - Freeverb3 * poFreeverb = (Freeverb3 *)Instance; - poFreeverb->mute(); -} - -/*****************************************************************************/ - -void -runFreeverb3(LADSPA_Handle Instance, - const unsigned long SampleCount) { - - Freeverb3 * poFreeverb = ((Freeverb3 *)Instance); - - /* Handle control ports. Note that this isn't especially efficient - because of the way the update() code works in revmodel.cpp, but - at least this approach allows Freeverb to work with almost no - code changes. */ - - if (*(poFreeverb->m_ppfPorts[FV_Mode]) > 0) - poFreeverb->setmode(1); - else - poFreeverb->setmode(0); - poFreeverb->setdamp(*(poFreeverb->m_ppfPorts[FV_Damping])); - poFreeverb->setwet(*(poFreeverb->m_ppfPorts[FV_Wet])); - poFreeverb->setdry(*(poFreeverb->m_ppfPorts[FV_Dry])); - poFreeverb->setroomsize(*(poFreeverb->m_ppfPorts[FV_RoomSize])); - poFreeverb->setwidth(*(poFreeverb->m_ppfPorts[FV_Width])); - - /* Connect to audio ports and run. */ - - poFreeverb->processreplace(poFreeverb->m_ppfPorts[FV_Input1], - poFreeverb->m_ppfPorts[FV_Input2], - poFreeverb->m_ppfPorts[FV_Output1], - poFreeverb->m_ppfPorts[FV_Output2], - SampleCount, - 1); -} - -/*****************************************************************************/ - -void -initialise_freeverb3() { - - CMT_Descriptor * psDescriptor; - - psDescriptor = new CMT_Descriptor - (1123, - "freeverb3", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Freeverb (Version 3)", - CMT_MAKER("Jezar at Dreampoint, ported by Richard W.E. Furse"), - CMT_COPYRIGHT("2000", "Jezar at Dreampoint"), - NULL, - CMT_Instantiate, - activateFreeverb3, - runFreeverb3, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (Left)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input (Right)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Left)"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output (Right)"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Freeze Mode", - (LADSPA_HINT_TOGGLED - | LADSPA_HINT_DEFAULT_0), - 0, - 0); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Room Size", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_MIDDLE), - 0, - 1); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Damping", - (LADSPA_HINT_LOGARITHMIC - | LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_MIDDLE), - 0, - 1); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Wet Level", - (LADSPA_HINT_LOGARITHMIC - | LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_MIDDLE), - 0, - 1); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Dry Level", - (LADSPA_HINT_LOGARITHMIC - | LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_MAXIMUM), - 0, - 1); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Width", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_MIDDLE), - 0, - 1); - - registerNewPluginDescriptor(psDescriptor); -} - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/freeverb/readme.txt b/plugins/LadspaEffect/cmt/src/freeverb/readme.txt deleted file mode 100644 index 1cc5e8b0097..00000000000 --- a/plugins/LadspaEffect/cmt/src/freeverb/readme.txt +++ /dev/null @@ -1,67 +0,0 @@ -Freeverb - Free, studio-quality reverb SOURCE CODE in the public domain ------------------------------------------------------------------------ - -Written by Jezar at Dreampoint - http://www.dreampoint.co.uk - - -Introduction ------------- - -Hello. - -I'll try to keep this "readme" reasonably small. There are few things in the world that I hate more than long "readme" files. Except "coding conventions" - but more on that later... - -In this zip file you will find two folders of C++ source code: - -"Components" - Contains files that should clean-compile ON ANY TYPE OF COMPUTER OR SYSTEM WHATSOEVER. It should not be necessary to make ANY changes to these files to get them to compile, except to make up for inadequacies of certain compilers. These files create three classes - a comb filter, an allpass filter, and a reverb model made up of a number of instances of the filters, with some features to control the filters at a macro level. You will need to link these classes into another program that interfaces with them. The files in the components drawer are completely independant, and can be built without dependancies on anything else. Because of the simple interface, it should be possible to interface these files to any system - VST, DirectX, anything - without changing them AT ALL. - -"FreeverbVST" - Contains a Steinberg VST implementation of this version of Freeverb, using the components in (surprise) the components folder. It was built on a PC but may compile properly for the Macintosh with no problems. I don't know - I don't have a Macintosh. If you've figured out how to compile the examples in the Steinberg VST Development Kit, then you should easilly figure out how to bring the files into a project and get it working in a few minutes. It should be very simple. - -Note that this version of Freeverb doesn't contain predelay, or any EQ. I thought that might make it difficult to understand the "reverb" part of the code. Once you figure out how Freeverb works, you should find it trivial to add such features with little CPU overhead. - -Also, the code in this version of Freeverb has been optimised. This has changed the sound *slightly*, but not significantly compared to how much processing power it saves. - -Finally, note that there is also a built copy of this version of Freeverb called "Freeverb3.dll" - this is a VST plugin for the PC. If you want a version for the Mac or anything else, then you'll need to build it yourself from the code. - - -Technical Explanation ---------------------- - -Freeverb is a simple implementation of the standard Schroeder/Moorer reverb model. I guess the only reason why it sounds better than other reverbs, is simply because I spent a long while doing listening tests in order to create the values found in "tuning.h". It uses 8 comb filters on both the left and right channels), and you might possibly be able to get away with less if CPU power is a serious constraint for you. It then feeds the result of the reverb through 4 allpass filters on both the left and right channels. These "smooth" the sound. Adding more than four allpasses doesn't seem to add anything significant to the sound, and if you use less, the sound gets a bit "grainy". The filters on the right channel are slightly detuned compared to the left channel in order to create a stereo effect. - -Hopefully, you should find the code in the components drawer a model of brevity and clarity. Notice that I don't use any "coding conventions". Personally, I think that coding conventions suck. They are meant to make the code "clearer", but they inevitably do the complete opposite, making the code completely unfathomable. Anyone whose done Windows programming with its - frankly stupid - "Hungarian notation" will know exactly what I mean. Coding conventions typically promote issues that are irrelevant up to the status of appearing supremely important. It may have helped back people in the days when compilers where somewhat feeble in their type-safety, but not in the new millenium with advanced C++ compilers. - -Imagine if we rewrote the English language to conform to coding conventions. After all, The arguments should be just as valid for the English language as they are for a computer language. For example, we could put a lower-case "n" in front of every noun, a lower-case "p" in front of a persons name, a lower-case "v" in front of every verb, and a lower-case "a" in front of every adjective. Can you imagine what the English language would look like? All in the name of "clarity". It's just as stupid to do this for computer code as it would be to do it for the English language. I hope that the code for Freeverb in the components drawer demonstrates this, and helps start a movement back towards sanity in coding practices. - - -Background ----------- - -Why is the Freeverb code now public domain? Simple. I only intended to create Freeverb to provide me and my friends with studio-quality reverb for free. I never intended to make any money out of it. However, I simply do not have the time to develop it any further. I'm working on a "concept album" at the moment, and I'll never finish it if I spend any more time programming. - -In any case, I make more far money as a contract programmer - making Mobile Internet products - than I ever could writing plugins, so it simply doesn't make financial sense for me to spend any more time on it. - -Rather than give Freeverb to any particular individual or organisation to profit from it, I've decided to give it away to the internet community at large, so that quality, FREE (or at the very least, low-cost) reverbs can be developed for all platforms. - -Feel free to use the source code for Freeverb in any of your own products, whether they are also available for free, or even if they are commercial - I really don't mind. You may do with the code whatever you wish. If you use it in a product (whether commercial or not), it would be very nice of you, if you were to send me a copy of your product - although I appreciate that this isn't always possible in all circumstances. - -HOWEVER, please don't bug me with questions about how to use this code. I gave away Freeverb because I don't have time to maintain it. That means I *certainly* don't have time to answer questions about the source code, so please don't email questions to me. I *will* ignore them. If you can't figure the code for Freeverb out - then find somebody who can. I hope that either way, you enjoy experimenting with it. - - -Disclaimer ----------- - -This software and source code is given away for free, without any warranties of any kind. It has been given away to the internet community as a free gift, so please treat it in the same spirit. - - -I hope this code is useful and interesting to you all! -I hope you have lots of fun experimenting with it and make good products! - -Very best regards, -Jezar. -Technology Consultant -Dreampoint Design and Engineering -http://www.dreampoint.co.uk - - -//ends diff --git a/plugins/LadspaEffect/cmt/src/grain.cpp b/plugins/LadspaEffect/cmt/src/grain.cpp deleted file mode 100644 index 3ec25436e8d..00000000000 --- a/plugins/LadspaEffect/cmt/src/grain.cpp +++ /dev/null @@ -1,401 +0,0 @@ -/* grain.cpp - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include -#include - -/*****************************************************************************/ - -#include "cmt.h" -#include "utils.h" - -/*****************************************************************************/ - -/** Period (in seconds) from which grains are selected. */ -#define GRAIN_MAXIMUM_HISTORY 6 -#define GRAIN_MAXIMUM_BLOCK 1 /* (seconds) */ - -#define GRAIN_MAXIMUM_SCATTER (GRAIN_MAXIMUM_HISTORY - GRAIN_MAXIMUM_BLOCK) -#define GRAIN_MAXIMUM_LENGTH (GRAIN_MAXIMUM_HISTORY - GRAIN_MAXIMUM_BLOCK) - -/** What quality should we require when sampling the normal - distribution to generate grain counts? */ -#define GRAIN_NORMAL_RV_QUALITY 16 - -/*****************************************************************************/ - -/** Pointers to this can be used as linked list of grains. */ -class Grain { -private: - - long m_lReadPointer; - long m_lGrainLength; - long m_lAttackTime; - - long m_lRunTime; - - bool m_bFinished; - - LADSPA_Data m_fAttackSlope; - LADSPA_Data m_fDecaySlope; - -public: - - Grain(const long lReadPointer, - const long lGrainLength, - const long lAttackTime) - : m_lReadPointer(lReadPointer), - m_lGrainLength(lGrainLength), - m_lAttackTime(lAttackTime), - m_lRunTime(0), - m_bFinished(false) { - if (lAttackTime <= 0) { - m_fAttackSlope = 0; - m_fDecaySlope = LADSPA_Data(1.0 / lGrainLength); - } - else { - m_fAttackSlope = LADSPA_Data(1.0 / lAttackTime); - if (lAttackTime >= lGrainLength) - m_fDecaySlope = 0; - else - m_fDecaySlope = LADSPA_Data(1.0 / (lGrainLength - lAttackTime)); - } - } - - bool isFinished() const { - return m_bFinished; - } - - /** NULL if end of grain list. */ - Grain * m_poNextGrain; - - void run(const unsigned long lSampleCount, - float * pfOutput, - const float * pfHistoryBuffer, - const unsigned long lHistoryBufferSize) { - - LADSPA_Data fAmp; - if (m_lRunTime < m_lAttackTime) - fAmp = m_fAttackSlope * m_lRunTime; - else - fAmp = m_fDecaySlope * (m_lGrainLength - m_lRunTime); - - for (unsigned long lSampleIndex = 0; - lSampleIndex < lSampleCount; - lSampleIndex++) { - - if (fAmp < 0) { - m_bFinished = true; - break; - } - - *(pfOutput++) += fAmp * pfHistoryBuffer[m_lReadPointer]; - - m_lReadPointer = (m_lReadPointer + 1) & (lHistoryBufferSize - 1); - - if (m_lRunTime < m_lAttackTime) - fAmp += m_fAttackSlope; - else - fAmp -= m_fDecaySlope; - - m_lRunTime++; - } - } -}; - -/*****************************************************************************/ - -#define GRN_INPUT 0 -#define GRN_OUTPUT 1 -#define GRN_DENSITY 2 -#define GRN_SCATTER 3 -#define GRN_GRAIN_LENGTH 4 -#define GRN_GRAIN_ATTACK 5 - -/** This plugin cuts an audio stream up and uses it to generate a - granular texture. */ -class GrainScatter : public CMT_PluginInstance { -private: - - Grain * m_poCurrentGrains; - - long m_lSampleRate; - - LADSPA_Data * m_pfBuffer; - - /** Buffer size, a power of two. */ - unsigned long m_lBufferSize; - - /** Write pointer in buffer. */ - unsigned long m_lWritePointer; - -public: - - GrainScatter(const LADSPA_Descriptor *, - unsigned long lSampleRate) - : CMT_PluginInstance(6), - m_poCurrentGrains(NULL), - m_lSampleRate(lSampleRate) { - /* Buffer size is a power of two bigger than max delay time. */ - unsigned long lMinimumBufferSize - = (unsigned long)((LADSPA_Data)lSampleRate * GRAIN_MAXIMUM_HISTORY); - m_lBufferSize = 1; - while (m_lBufferSize < lMinimumBufferSize) - m_lBufferSize <<= 1; - m_pfBuffer = new LADSPA_Data[m_lBufferSize]; - } - - ~GrainScatter() { - delete [] m_pfBuffer; - } - - friend void activateGrainScatter(LADSPA_Handle Instance); - friend void runGrainScatter(LADSPA_Handle Instance, - unsigned long SampleCount); - -}; - -/*****************************************************************************/ - -/** Initialise and activate a plugin instance. */ -void -activateGrainScatter(LADSPA_Handle Instance) { - - GrainScatter * poGrainScatter = (GrainScatter *)Instance; - - /* Need to reset the delay history in this function rather than - instantiate() in case deactivate() followed by activate() have - been called to reinitialise a delay line. */ - memset(poGrainScatter->m_pfBuffer, - 0, - sizeof(LADSPA_Data) * poGrainScatter->m_lBufferSize); - - poGrainScatter->m_lWritePointer = 0; -} - -/*****************************************************************************/ - -void -runGrainScatter(LADSPA_Handle Instance, - unsigned long SampleCount) { - - GrainScatter * poGrainScatter = (GrainScatter *)Instance; - - LADSPA_Data * pfInput = poGrainScatter->m_ppfPorts[GRN_INPUT]; - LADSPA_Data * pfOutput = poGrainScatter->m_ppfPorts[GRN_OUTPUT]; - - unsigned long lMaximumSampleCount - = (unsigned long)(poGrainScatter->m_lSampleRate - * GRAIN_MAXIMUM_BLOCK); - - if (SampleCount > lMaximumSampleCount) { - - /* We're beyond our capabilities. We're going to run out of delay - line for a large grain. Divide and conquer. */ - - runGrainScatter(Instance, lMaximumSampleCount); - - poGrainScatter->m_ppfPorts[GRN_INPUT] += lMaximumSampleCount; - poGrainScatter->m_ppfPorts[GRN_OUTPUT] += lMaximumSampleCount; - runGrainScatter(Instance, SampleCount - lMaximumSampleCount); - poGrainScatter->m_ppfPorts[GRN_INPUT] = pfInput; - poGrainScatter->m_ppfPorts[GRN_OUTPUT] = pfOutput; - - } - else { - - /* Move the delay line along. */ - if (poGrainScatter->m_lWritePointer - + SampleCount - > poGrainScatter->m_lBufferSize) { - memcpy(poGrainScatter->m_pfBuffer + poGrainScatter->m_lWritePointer, - pfInput, - sizeof(LADSPA_Data) * (poGrainScatter->m_lBufferSize - - poGrainScatter->m_lWritePointer)); - memcpy(poGrainScatter->m_pfBuffer, - pfInput + (poGrainScatter->m_lBufferSize - - poGrainScatter->m_lWritePointer), - sizeof(LADSPA_Data) * (SampleCount - - (poGrainScatter->m_lBufferSize - - poGrainScatter->m_lWritePointer))); - } - else { - memcpy(poGrainScatter->m_pfBuffer + poGrainScatter->m_lWritePointer, - pfInput, - sizeof(LADSPA_Data) * SampleCount); - } - poGrainScatter->m_lWritePointer - = ((poGrainScatter->m_lWritePointer + SampleCount) - & (poGrainScatter->m_lBufferSize - 1)); - - /* Empty the output buffer. */ - memset(pfOutput, 0, SampleCount * sizeof(LADSPA_Data)); - - /* Process current grains. */ - Grain ** ppoGrainReference = &(poGrainScatter->m_poCurrentGrains); - while (*ppoGrainReference != NULL) { - (*ppoGrainReference)->run(SampleCount, - pfOutput, - poGrainScatter->m_pfBuffer, - poGrainScatter->m_lBufferSize); - if ((*ppoGrainReference)->isFinished()) { - Grain *poNextGrain = (*ppoGrainReference)->m_poNextGrain; - delete *ppoGrainReference; - *ppoGrainReference = poNextGrain; - } - else { - ppoGrainReference = &((*ppoGrainReference)->m_poNextGrain); - } - } - - LADSPA_Data fSampleRate = LADSPA_Data(poGrainScatter->m_lSampleRate); - LADSPA_Data fDensity - = BOUNDED_BELOW(*(poGrainScatter->m_ppfPorts[GRN_DENSITY]), - 0); - - /* We want to average fDensity new grains per second. We need to - use a RNG to generate a new grain count from the fraction of a - second we are dealing with. Use a normal distribution and - choose standard deviation also to be fDensity. This could be - separately parameterised but any guarantees could be confusing - given that individual grains are uniformly distributed within - the block. Note that fDensity isn't quite grains/sec as we - discard negative samples from the RV. */ - double dGrainCountRV_Mean = fDensity * SampleCount / fSampleRate; - double dGrainCountRV_SD = dGrainCountRV_Mean; - double dGrainCountRV = sampleNormalDistribution(dGrainCountRV_Mean, - dGrainCountRV_SD, - GRAIN_NORMAL_RV_QUALITY); - unsigned long lNewGrainCount = 0; - if (dGrainCountRV > 0) - lNewGrainCount = (unsigned long)(0.5 + dGrainCountRV); - if (lNewGrainCount > 0) { - - LADSPA_Data fScatter - = BOUNDED(*(poGrainScatter->m_ppfPorts[GRN_SCATTER]), - 0, - GRAIN_MAXIMUM_SCATTER); - LADSPA_Data fGrainLength - = BOUNDED_BELOW(*(poGrainScatter->m_ppfPorts[GRN_GRAIN_LENGTH]), - 0); - LADSPA_Data fAttack - = BOUNDED_BELOW(*(poGrainScatter->m_ppfPorts[GRN_GRAIN_ATTACK]), - 0); - - long lScatterSampleWidth - = long(fSampleRate * fScatter) + 1; - long lGrainLength - = long(fSampleRate * fGrainLength); - long lAttackTime - = long(fSampleRate * fAttack); - - for (unsigned long lIndex = 0; lIndex < lNewGrainCount; lIndex++) { - - long lOffset = rand() % SampleCount; - - long lGrainReadPointer - = (poGrainScatter->m_lWritePointer - - SampleCount - + lOffset - - (rand() % lScatterSampleWidth)); - while (lGrainReadPointer < 0) - lGrainReadPointer += poGrainScatter->m_lBufferSize; - lGrainReadPointer &= (poGrainScatter->m_lBufferSize - 1); - - Grain * poNewGrain = new Grain(lGrainReadPointer, - lGrainLength, - lAttackTime); - - poNewGrain->m_poNextGrain = poGrainScatter->m_poCurrentGrains; - poGrainScatter->m_poCurrentGrains = poNewGrain; - - poNewGrain->run(SampleCount - lOffset, - pfOutput + lOffset, - poGrainScatter->m_pfBuffer, - poGrainScatter->m_lBufferSize); - } - } - } -} - -/*****************************************************************************/ - -void -initialise_grain() { - - CMT_Descriptor * psDescriptor = new CMT_Descriptor - (1096, - "grain_scatter", - 0, - "Granular Scatter Processor", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - activateGrainScatter, - runGrainScatter, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Density (Grains/s)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_DEFAULT_MAXIMUM), - 0, - 10); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Scatter (s)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_MIDDLE), - 0, - GRAIN_MAXIMUM_SCATTER); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Grain Length (s)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_DEFAULT_MAXIMUM), - 0, - 0.2); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Grain Attack (s)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_DEFAULT_MAXIMUM), - 0, - 0.05); - - registerNewPluginDescriptor(psDescriptor); -} - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/hardgate.cpp b/plugins/LadspaEffect/cmt/src/hardgate.cpp deleted file mode 100644 index a2f04b10e96..00000000000 --- a/plugins/LadspaEffect/cmt/src/hardgate.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* hardgate.cpp - - (c) 2002 Nathaniel Virgo - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include - -/*****************************************************************************/ - -#include "cmt.h" - -/*****************************************************************************/ - -namespace hardgate { - - enum { - port_threshold = 0, - port_input = 1, - port_output = 2, - n_ports = 3 - }; - -/** This plugin sets its input signal to 0 if it falls below a threshold. */ - class Plugin : public CMT_PluginInstance { - public: - - Plugin(const LADSPA_Descriptor *, - unsigned long) - : CMT_PluginInstance(n_ports) { - } - - friend void run(LADSPA_Handle instance, - unsigned long sample_count); - - }; - - void run(LADSPA_Handle instance, - unsigned long sample_count) { - - Plugin *pp = (Plugin *) instance; - - LADSPA_Data threshold = *pp->m_ppfPorts[port_threshold]; - LADSPA_Data * in = pp->m_ppfPorts[port_input]; - LADSPA_Data * out = pp->m_ppfPorts[port_output]; - - for ( unsigned long i = 0; i < sample_count ; ++i ) - { - LADSPA_Data insig = *(in++); - if ( insig < threshold && insig > -threshold ) - *(out++) = 0.0f; - else - *(out++) = insig; - } - } - - void - initialise() { - - CMT_Descriptor * d = new CMT_Descriptor - (1845, - "hard_gate", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Hard Gate", - CMT_MAKER("Nathaniel Virgo"), - CMT_COPYRIGHT("2002", "Nathaniel Virgo"), - NULL, - CMT_Instantiate, - NULL, - run, - NULL, - NULL, - NULL); - - d->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Threshold", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_0), - 0, - 1); - d->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - d->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - - registerNewPluginDescriptor(d); - - } - -} // end of namespace - -/*****************************************************************************/ - -/* EOF */ - - - - - diff --git a/plugins/LadspaEffect/cmt/src/init.cpp b/plugins/LadspaEffect/cmt/src/init.cpp deleted file mode 100644 index f232840fa9c..00000000000 --- a/plugins/LadspaEffect/cmt/src/init.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* init.cpp - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include -#include -#include - -/*****************************************************************************/ - -#include "cmt.h" - -/*****************************************************************************/ - -void initialise_modules(); -void finalise_modules(); - -/*****************************************************************************/ - -int -pluginNameComparator(const void * pvDescriptor1, const void * pvDescriptor2) { - - const CMT_Descriptor * psDescriptor1 - = *(const CMT_Descriptor **)pvDescriptor1; - const CMT_Descriptor * psDescriptor2 - = *(const CMT_Descriptor **)pvDescriptor2; - - int iResult = strcmp(psDescriptor1->Name, psDescriptor2->Name); - if (iResult < 0) - return -1; - else if (iResult > 0) - return 1; - else - return 0; -} - -/*****************************************************************************/ - -CMT_Descriptor ** g_ppsRegisteredDescriptors = NULL; -unsigned long g_lPluginCapacity = 0; -unsigned long g_lPluginCount = 0; - -/*****************************************************************************/ - -#define CAPACITY_STEP 20 - -void -registerNewPluginDescriptor(CMT_Descriptor * psDescriptor) { - if (g_lPluginCapacity == g_lPluginCount) { - /* Full. Enlarge capacity. */ - CMT_Descriptor ** ppsOldDescriptors - = g_ppsRegisteredDescriptors; - g_ppsRegisteredDescriptors - = new CMT_Descriptor_ptr[g_lPluginCapacity + CAPACITY_STEP]; - if (g_lPluginCapacity > 0) { - memcpy(g_ppsRegisteredDescriptors, - ppsOldDescriptors, - g_lPluginCapacity * sizeof(CMT_Descriptor_ptr)); - delete [] ppsOldDescriptors; - } - g_lPluginCapacity += CAPACITY_STEP; - } - g_ppsRegisteredDescriptors[g_lPluginCount++] = psDescriptor; -} - -/*****************************************************************************/ - -/** A global object of this class is used to perform initialisation - and shutdown services for the entire library. The constructor is - run when the library is loaded and the destructor when it is - unloaded. */ -class StartupShutdownHandler { -public: - - StartupShutdownHandler() { - initialise_modules(); - qsort(g_ppsRegisteredDescriptors, - g_lPluginCount, - sizeof(CMT_Descriptor_ptr), - pluginNameComparator); - } - - ~StartupShutdownHandler() { - if (g_ppsRegisteredDescriptors != NULL) { - for (unsigned long lIndex = 0; lIndex < g_lPluginCount; lIndex++) - delete g_ppsRegisteredDescriptors[lIndex]; - delete [] g_ppsRegisteredDescriptors; - } - finalise_modules(); - } - -} ; - -/*****************************************************************************/ - -extern "C" -{ - -const LADSPA_Descriptor * -ladspa_descriptor(unsigned long Index) { - - static StartupShutdownHandler handler; - - if (Index < g_lPluginCount) - return g_ppsRegisteredDescriptors[Index]; - else - return NULL; -} - -}; - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/ladspa_types.h b/plugins/LadspaEffect/cmt/src/ladspa_types.h deleted file mode 100644 index 31197b31bb2..00000000000 --- a/plugins/LadspaEffect/cmt/src/ladspa_types.h +++ /dev/null @@ -1,80 +0,0 @@ -/* ladspa_types.h - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -#ifndef CMT_LADSPA_TYPES_INCLUDED -#define CMT_LADSPA_TYPES_INCLUDED - -/*****************************************************************************/ - -#include - -/* Compatibility hack for version 1.0. */ -#ifndef LADSPA_VERSION_MAJOR -#define LADSPA_HINT_DEFAULT_MINIMUM 0x40 -#define LADSPA_HINT_DEFAULT_LOW 0x80 -#define LADSPA_HINT_DEFAULT_MIDDLE 0xC0 -#define LADSPA_HINT_DEFAULT_HIGH 0x100 -#define LADSPA_HINT_DEFAULT_MAXIMUM 0x140 -#define LADSPA_HINT_DEFAULT_0 0x200 -#define LADSPA_HINT_DEFAULT_1 0x240 -#define LADSPA_HINT_DEFAULT_100 0x280 -#define LADSPA_HINT_DEFAULT_440 0x2C0 -#endif - -/*****************************************************************************/ - -typedef LADSPA_Handle (*LADSPA_Instantiate_Function) - (const struct _LADSPA_Descriptor * Descriptor, - unsigned long SampleRate); - -typedef void (*LADSPA_Connect_Port_Function) - (LADSPA_Handle Instance, - unsigned long Port, - LADSPA_Data * DataLocation); - -typedef void (*LADSPA_Activate_Function) - (LADSPA_Handle Instance); - -typedef void (*LADSPA_Run_Function) - (LADSPA_Handle Instance, - unsigned long SampleCount); - -typedef void (*LADSPA_Run_Adding_Function) - (LADSPA_Handle Instance, - unsigned long SampleCount); - -typedef void (*LADSPA_Set_Run_Adding_Gain_Function) - (LADSPA_Handle Instance, - LADSPA_Data Gain); - -typedef void (*LADSPA_Deactivate_Function) - (LADSPA_Handle Instance); - -typedef void (*LADSPA_Cleanup_Function) - (LADSPA_Handle Instance); - -typedef LADSPA_Data * LADSPA_Data_ptr; - -/*****************************************************************************/ - -#endif - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/lofi.cpp b/plugins/LadspaEffect/cmt/src/lofi.cpp deleted file mode 100644 index 67be8008d08..00000000000 --- a/plugins/LadspaEffect/cmt/src/lofi.cpp +++ /dev/null @@ -1,415 +0,0 @@ -/* lofi.cpp - - Lo Fi - Simulate low quality audio equipment - Copyright (c) 2001 David A. Bartold - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include -#include -#include "cmt.h" - -#define PORT_IN_LEFT 0 -#define PORT_IN_RIGHT 1 -#define PORT_OUT_LEFT 2 -#define PORT_OUT_RIGHT 3 -#define PORT_CRACKLING 4 -#define PORT_OVERLOADING 5 -#define PORT_BANDWIDTH 6 - -#define NUM_PORTS 7 - -#ifndef PI -#define PI 3.14159265358979 -#endif - -#ifndef MIN -#define MIN(x,y) ((x)<(y)?(x):(y)) -#endif - -#ifndef MAX -#define MAX(x,y) ((x)>(y)?(x):(y)) -#endif - -class Pop -{ -public: - float x; - float dx; - float amp; - float pwr; - Pop *next; - - Pop (float dx, float amp, float pwr, Pop *next); - ~Pop (); -}; - -Pop::Pop (float _dx, - float _amp, - float _pwr, - Pop *_next) - : x (0.0), dx (_dx), amp (_amp), pwr (_pwr), next (_next) -{ -} - -Pop::~Pop () -{ - delete next; -} - - -class Record -{ -public: - int rate; - int amount; /* 0 -> 100% */ - Pop *pops; - - LADSPA_Data process (LADSPA_Data sample); - void setAmount (int _amount); - - Record (int sample_rate); - ~Record (); -}; - -Record::Record (int sample_rate) - : rate (sample_rate), - amount (0), - pops (NULL) -{ -} - -Record::~Record () -{ - delete pops; -} - -static Pop * -record_pop_new (Record *record, - Pop *next) -{ - return new Pop ((rand () % 1500 + 500.0) / record->rate, - (rand () % 50) / 10000.0, - 1.0, - next); -} - -static Pop * -record_pop_loud_new (Record *record, - Pop *next) -{ - return new Pop ((rand () % 500 + 2500.0) / record->rate, - (rand () % 100) / 400.0 + 0.5, - (rand () % 50) / 20.0, - next); -} - -LADSPA_Data -Record::process (LADSPA_Data sample) -{ - Pop *pop; - Pop **pop_prev; - - /* Add some crackle */ - if (rand () % rate < rate * amount / 4000) - pops = record_pop_new (this, pops); - - /* Add some loud pops */ - if (rand () % (rate * 10) < rate * amount / 400000) - pops = record_pop_loud_new (this, pops); - - /* Compute pops */ - pop_prev = &pops; - pop = *pop_prev; - while (pop != NULL) - { - if (pop->x >= 0.5) - sample += (pow ((1.0 - pop->x) * 2.0, pop->pwr) - 0.5) * pop->amp; - else - sample += (pow (pop->x * 2.0, pop->pwr) - 0.5) * pop->amp; - - pop->x += pop->dx; - if (pop->x > 1.0) - { - *pop_prev = pop->next; - pop->next = NULL; - delete pop; - } - else - pop_prev = &pop->next; - - pop = *pop_prev; - } - - return sample; -} - -void -Record::setAmount (int _amount) -{ - amount = _amount; -} - - -class Compressor -{ -public: - int rate; - double amp; - double up; - double down; - float vol; - float clamp_hi; - float clamp_lo; - - LADSPA_Data process (LADSPA_Data sample); - void setClamp (float clamp); - - Compressor (int sample_rate, float clamp); -}; - -Compressor::Compressor (int sample_rate, float clamp) - : rate (sample_rate), amp (0.5), - up (1.0 / pow (0.5, 20.0 / sample_rate)), - down (pow (0.5, 50.0 / sample_rate)), - vol (0.5), clamp_hi (clamp), clamp_lo (1.0 / clamp) -{ -} - -LADSPA_Data -Compressor::process (LADSPA_Data sample) -{ - sample *= amp; - - if (fabs (sample) > vol) - { - amp *= down; - if (amp < clamp_lo) - amp = clamp_lo; - } - else - { - amp *= up; - if (amp > clamp_hi) - amp = clamp_hi; - } - - return sample; -} - -void -Compressor::setClamp (float clamp) -{ - clamp_hi = clamp; - clamp_lo = 1.0 / clamp; -} - - -static inline LADSPA_Data -distort (LADSPA_Data in) -{ - if (in > 0.0F) - return (in * 1.0F) / (in + 1.0F) * 2.0F; - else - return -(-in * 1.0F) / (-in + 1.0F) * 2.0F; -} - - -class BandwidthLimit -{ -public: - int rate; - float x; - float dx; - - void setFreq (float freq); - - LADSPA_Data process (LADSPA_Data sample); - BandwidthLimit (int _rate, float _freq); -}; - -BandwidthLimit::BandwidthLimit (int _rate, float _freq) - : rate (_rate), x (0.0), dx (_freq / _rate) -{ -} - -LADSPA_Data -BandwidthLimit::process (LADSPA_Data sample) -{ - if (sample >= x) - sample = MIN (x + dx, sample); - else - sample = MAX (x - dx, sample); - x = sample; - - return sample; -} - -void -BandwidthLimit::setFreq (float freq) -{ - dx = freq / rate; -} - - -class LoFi : public CMT_PluginInstance { - Record *record; - Compressor *compressor; - BandwidthLimit *bandwidth_l; - BandwidthLimit *bandwidth_r; - -public: - LoFi(const LADSPA_Descriptor *, - unsigned long s_rate) - : CMT_PluginInstance (NUM_PORTS), - record (new Record (s_rate * 2)), - compressor (new Compressor (s_rate * 2, 1.6)), - bandwidth_l (new BandwidthLimit (s_rate, 8000.0)), - bandwidth_r (new BandwidthLimit (s_rate, 8000.0)) { - } - - ~LoFi() { - delete bandwidth_l; - delete bandwidth_r; - delete compressor; - delete record; - } - - static void - activate (LADSPA_Handle Instance) { - LoFi *lofi = (LoFi*) Instance; - - lofi->bandwidth_l->setFreq (8000); - lofi->bandwidth_r->setFreq (8000); - lofi->compressor->setClamp (1.6); - lofi->record->setAmount (0); - } - - static void - run(LADSPA_Handle Instance, - unsigned long SampleCount) { - LoFi *lofi = (LoFi*) Instance; - unsigned long i; - LADSPA_Data **ports = lofi->m_ppfPorts; - LADSPA_Data clamp; - - lofi->bandwidth_l->setFreq (ports[PORT_BANDWIDTH][0]); - lofi->bandwidth_r->setFreq (ports[PORT_BANDWIDTH][0]); - - if (ports[PORT_OVERLOADING][0] > 99.0) - clamp = 100.0; - else - clamp = 100.0 / (100.0 - ports[PORT_OVERLOADING][0]); - - lofi->compressor->setClamp (clamp); - - lofi->record->setAmount ((int) ports[PORT_CRACKLING][0]); - - for (i = 0; i < SampleCount; i++) - { - LADSPA_Data sample_l, sample_r; - - sample_l = ports[PORT_IN_LEFT][i]; - sample_r = ports[PORT_IN_RIGHT][i]; - - sample_l = lofi->compressor->process (sample_l); - sample_r = lofi->compressor->process (sample_r); - sample_l = lofi->bandwidth_l->process (sample_l); - sample_r = lofi->bandwidth_r->process (sample_r); - sample_l = distort (sample_l); - sample_r = distort (sample_r); - sample_l = lofi->record->process (sample_l); - sample_r = lofi->record->process (sample_r); - - ports[PORT_OUT_LEFT][i] = sample_l; - ports[PORT_OUT_RIGHT][i] = sample_r; - } - } -}; - - -static LADSPA_PortDescriptor g_psPortDescriptors[] = -{ - LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT, - LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT, - LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT, - LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT -}; - -static const char * const g_psPortNames[] = -{ - "In (Left)", - "In (Right)", - - "Out (Left)", - "Out (Right)", - - "Crackling (%)", - "Powersupply Overloading (%)", - "Opamp Bandwidth Limiting (Hz)" -}; - -static LADSPA_PortRangeHint g_psPortRangeHints[] = -{ - /* Hints, Lower bound, Upper bound */ - { 0, 0.0, 0.0 }, - { 0, 0.0, 0.0 }, - { 0, 0.0, 0.0 }, - { 0, 0.0, 0.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | - LADSPA_HINT_INTEGER, -0.1, 100.1 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 100.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 1.0, 10000.0 } -}; - -void -initialise_lofi() { - CMT_Descriptor * psDescriptor; - - psDescriptor = new CMT_Descriptor - (1227, - "lofi", - 0 /* Sorry, this module is not RT capable, run() calls malloc() */, - "Lo Fi", - CMT_MAKER("David A. Bartold"), - CMT_COPYRIGHT("2001", "David A. Bartold"), - NULL, - CMT_Instantiate, - LoFi::activate, - LoFi::run, - NULL, - NULL, - NULL); - - for (int i = 0; i < NUM_PORTS; i++) - psDescriptor->addPort( - g_psPortDescriptors[i], - g_psPortNames[i], - g_psPortRangeHints[i].HintDescriptor, - g_psPortRangeHints[i].LowerBound, - g_psPortRangeHints[i].UpperBound); - - registerNewPluginDescriptor(psDescriptor); -} diff --git a/plugins/LadspaEffect/cmt/src/logistic.cpp b/plugins/LadspaEffect/cmt/src/logistic.cpp deleted file mode 100644 index b2dfcb7fbf5..00000000000 --- a/plugins/LadspaEffect/cmt/src/logistic.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/* logistic.cpp - - A sample-and-hold logistic map control generator - - (c) 2002 Nathaniel Virgo - - Part of the Computer Music Toolkit - a library of LADSPA plugins. - The Computer Music Toolkit is Copyright (C) 2000-2002 - Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include - -/*****************************************************************************/ - -#include "cmt.h" - -#include "pinknoise.h" -#include "utils.h" - -/*****************************************************************************/ - -namespace logistic { - - enum { - port_r = 0, - port_frequency = 1, - port_output = 2, - n_ports = 3 - }; - - /** This plugin uses the logistic map to generate periodic or - chaotic control signals. */ - class Plugin : public CMT_PluginInstance { - private: - LADSPA_Data sample_rate; - LADSPA_Data x; - unsigned counter; - public: - - Plugin(const LADSPA_Descriptor *, - unsigned long s_rate) : - CMT_PluginInstance(n_ports), - sample_rate(s_rate) { - } - - ~Plugin() { - } - - friend void activate(LADSPA_Handle instance); - - friend void run(LADSPA_Handle instance, - unsigned long sample_count); - }; - - void activate(LADSPA_Handle instance) { - Plugin *pp = (Plugin *) instance; - Plugin &p = *pp; - - p.x = 0.3; // arbitrary non-zero value. - } - - void run(LADSPA_Handle instance, - unsigned long sample_count) { - - Plugin *pp = (Plugin *) instance; - Plugin &p = *pp; - - LADSPA_Data r = *pp->m_ppfPorts[port_r]; - LADSPA_Data frequency = *pp->m_ppfPorts[port_frequency]; - LADSPA_Data * out = pp->m_ppfPorts[port_output]; - - frequency = BOUNDED_ABOVE(frequency,p.sample_rate); - r = BOUNDED_ABOVE(r,4); - unsigned remain = sample_count; - - if (frequency > 0) { - while (remain) { - unsigned jump_samples = (remain, - activate, - run, - NULL, - NULL, - NULL); - d->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "\"r\" parameter", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_MAXIMUM), - 2.9, 3.9999); - d->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Step frequency", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_SAMPLE_RATE - | LADSPA_HINT_DEFAULT_MIDDLE), - 0, 0.001); - d->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - registerNewPluginDescriptor(d); - } - -} // end of namespace - -/*****************************************************************************/ - -/* EOF */ - diff --git a/plugins/LadspaEffect/cmt/src/mixer.cpp b/plugins/LadspaEffect/cmt/src/mixer.cpp deleted file mode 100644 index 32d3ec4a74b..00000000000 --- a/plugins/LadspaEffect/cmt/src/mixer.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* mixer.cpp - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include -#include - -/*****************************************************************************/ - -#include "cmt.h" - -/*****************************************************************************/ - -/* The port numbers for the plugin: */ - -#define MIXER_INPUT1 0 -#define MIXER_INPUT2 1 -#define MIXER_OUTPUT 2 - -/** This plugin adds two signals together to produce a third. */ -class SimpleMixer : public CMT_PluginInstance { -public: - - SimpleMixer(const LADSPA_Descriptor *, - unsigned long) - : CMT_PluginInstance(3) { - } - - friend void runSimpleMixer(LADSPA_Handle Instance, - unsigned long SampleCount); - -}; - -/*****************************************************************************/ - -void -runSimpleMixer(LADSPA_Handle Instance, - unsigned long SampleCount) { - - SimpleMixer * poMixer = (SimpleMixer *)Instance; - - LADSPA_Data * pfInput1 = poMixer->m_ppfPorts[MIXER_INPUT1]; - LADSPA_Data * pfInput2 = poMixer->m_ppfPorts[MIXER_INPUT2]; - LADSPA_Data * pfOutput = poMixer->m_ppfPorts[MIXER_OUTPUT]; - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) - *(pfOutput++) = *(pfInput1++) + *(pfInput2++); -} - -/*****************************************************************************/ - -void -initialise_mixer() { - - CMT_Descriptor * psDescriptor; - - psDescriptor = new CMT_Descriptor - (1071, - "mixer", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Mixer (Stereo to Mono)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runSimpleMixer, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input 1"); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input 2"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - registerNewPluginDescriptor(psDescriptor); -} - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/noise.cpp b/plugins/LadspaEffect/cmt/src/noise.cpp deleted file mode 100644 index bf6c5a89fc4..00000000000 --- a/plugins/LadspaEffect/cmt/src/noise.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* noise.cpp - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include - -/*****************************************************************************/ - -#include "cmt.h" - -/*****************************************************************************/ - -/* The port numbers for the plugin: */ - -#define NOISE_AMPLITUDE 0 -#define NOISE_OUTPUT 1 - -/** Plugin that provides white noise output. This is provided by - calling rand() repeatedly. */ -class WhiteNoise : public CMT_PluginInstance { -private: - - LADSPA_Data m_fRunAddingGain; - -public: - - WhiteNoise(const LADSPA_Descriptor *, - unsigned long) - : CMT_PluginInstance(2) { - } - - friend void runWhiteNoise(LADSPA_Handle Instance, - unsigned long SampleCount); - friend void runWhiteNoiseAdding(LADSPA_Handle Instance, - unsigned long SampleCount); - friend void setWhiteNoiseRunAddingGain(LADSPA_Handle Instance, - LADSPA_Data Gain); - -}; - -/*****************************************************************************/ - -void -runWhiteNoise(LADSPA_Handle Instance, - unsigned long SampleCount) { - - WhiteNoise * poNoise = (WhiteNoise *)Instance; - - LADSPA_Data fAmplitude = *(poNoise->m_ppfPorts[NOISE_AMPLITUDE]); - LADSPA_Data fScalar = fAmplitude * LADSPA_Data(2.0 / RAND_MAX); - - LADSPA_Data * pfOutput = poNoise->m_ppfPorts[NOISE_OUTPUT]; - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) - *(pfOutput++) = rand() * fScalar - fAmplitude; -} - -void -runWhiteNoiseAdding(LADSPA_Handle Instance, - unsigned long SampleCount) { - - WhiteNoise * poNoise = (WhiteNoise *)Instance; - - LADSPA_Data fAmplitude - = *(poNoise->m_ppfPorts[NOISE_AMPLITUDE]); - LADSPA_Data fScalar - = poNoise->m_fRunAddingGain * fAmplitude * LADSPA_Data(2.0 / RAND_MAX); - - LADSPA_Data * pfOutput = poNoise->m_ppfPorts[NOISE_OUTPUT]; - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) - *(pfOutput++) += rand() * fScalar - fAmplitude; - -} - -void -setWhiteNoiseRunAddingGain(LADSPA_Handle Instance, - LADSPA_Data Gain) { -} - -/*****************************************************************************/ - -void -initialise_noise() { - - CMT_Descriptor * psDescriptor; - - psDescriptor = new CMT_Descriptor - (1069, - "noise_source_white", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Noise Source (White)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runWhiteNoise, - runWhiteNoiseAdding, - setWhiteNoiseRunAddingGain, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Amplitude", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_LOGARITHMIC - | LADSPA_HINT_DEFAULT_1), - 0, - 0); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - registerNewPluginDescriptor(psDescriptor); -} - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/null.cpp b/plugins/LadspaEffect/cmt/src/null.cpp deleted file mode 100644 index afae4f48c67..00000000000 --- a/plugins/LadspaEffect/cmt/src/null.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/* null.cpp - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include -#include - -/*****************************************************************************/ - -#include "cmt.h" - -/*****************************************************************************/ - -/* The port numbers for the plugin: */ - -#define NULL_PORT 0 - -/** This plugin can be used to take care of unwanted connections in a - host's plugin network by generating zero data and audio or - accepting (but ignoring) data and audio. */ -class NullPlugin : public CMT_PluginInstance { -public: - - NullPlugin(const LADSPA_Descriptor *, - unsigned long) - : CMT_PluginInstance(1) { - } - - friend void runNull_Nop(LADSPA_Handle Instance, - unsigned long SampleCount); - friend void runNull_OutputAudio(LADSPA_Handle Instance, - unsigned long SampleCount); - friend void runNull_OutputControl(LADSPA_Handle Instance, - unsigned long SampleCount); - -}; - -/*****************************************************************************/ - -#define IDENTITY_INPUT 0 -#define IDENTITY_OUTPUT 1 - -/* This plugin passes its input to its output. There are audio and - control varieties. */ -class IdentityPlugin : public CMT_PluginInstance { -public: - - IdentityPlugin(const LADSPA_Descriptor *, - unsigned long) - : CMT_PluginInstance(2) { - } - - friend void runIdentity_Audio(LADSPA_Handle Instance, - unsigned long SampleCount); - friend void runIdentity_Control(LADSPA_Handle Instance, - unsigned long SampleCount); - -}; - -/*****************************************************************************/ - -void -runNull_Nop(LADSPA_Handle Instance, - unsigned long SampleCount) { - /* Nothing to do. */ -} - -/*****************************************************************************/ - -void -runNull_OutputAudio(LADSPA_Handle Instance, - unsigned long SampleCount) { - NullPlugin * poPlugin = (NullPlugin *)Instance; - memset(poPlugin->m_ppfPorts[NULL_PORT], - 0, - sizeof(LADSPA_Data) * SampleCount); -} - -/*****************************************************************************/ - -void -runNull_OutputControl(LADSPA_Handle Instance, - unsigned long) { - NullPlugin * poPlugin = (NullPlugin *)Instance; - *(poPlugin->m_ppfPorts[NULL_PORT]) = 0; -} - -/*****************************************************************************/ - -void -runIdentity_Audio(LADSPA_Handle Instance, - unsigned long SampleCount) { - IdentityPlugin * poPlugin = (IdentityPlugin *)Instance; - if (poPlugin->m_ppfPorts[IDENTITY_OUTPUT] - != poPlugin->m_ppfPorts[IDENTITY_INPUT]) - memcpy(poPlugin->m_ppfPorts[IDENTITY_OUTPUT], - poPlugin->m_ppfPorts[IDENTITY_INPUT], - sizeof(LADSPA_Data) * SampleCount); -} - -/*****************************************************************************/ - -void -runIdentity_Control(LADSPA_Handle Instance, - unsigned long) { - IdentityPlugin * poPlugin = (IdentityPlugin *)Instance; - *(poPlugin->m_ppfPorts[IDENTITY_OUTPUT]) - = *(poPlugin->m_ppfPorts[IDENTITY_INPUT]); -} - -/*****************************************************************************/ - -void -initialise_null() { - - CMT_Descriptor * psDescriptor; - - psDescriptor = new CMT_Descriptor - (1083, - "null_ci", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Null (Control Input)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runNull_Nop, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Input"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1084, - "null_ai", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Null (Audio Input)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runNull_Nop, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1085, - "null_co", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Null (Control Output)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runNull_OutputControl, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, - "Output"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1086, - "null_ao", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Null (Audio Output)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runNull_OutputAudio, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1098, - "identity_audio", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Identity (Audio)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runIdentity_Audio, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1099, - "identity_control", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Identity (Control)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runIdentity_Control, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, - "Output"); - registerNewPluginDescriptor(psDescriptor); -} - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/organ.cpp b/plugins/LadspaEffect/cmt/src/organ.cpp deleted file mode 100644 index f05d6b02ffb..00000000000 --- a/plugins/LadspaEffect/cmt/src/organ.cpp +++ /dev/null @@ -1,375 +0,0 @@ -/* organ.cpp - - Organ - Additive Organ Synthesizer Voice - Copyright (c) 1999, 2000 David A. Bartold - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include -#include -#include "cmt.h" - -#define PORT_OUT 0 -#define PORT_GATE 1 -#define PORT_VELOCITY 2 -#define PORT_FREQ 3 -#define PORT_BRASS 4 -#define PORT_FLUTE 5 -#define PORT_REED 6 -#define PORT_HARM0 7 -#define PORT_HARM1 8 -#define PORT_HARM2 9 -#define PORT_HARM3 10 -#define PORT_HARM4 11 -#define PORT_HARM5 12 -#define PORT_ATTACK_LO 13 -#define PORT_DECAY_LO 14 -#define PORT_SUSTAIN_LO 15 -#define PORT_RELEASE_LO 16 -#define PORT_ATTACK_HI 17 -#define PORT_DECAY_HI 18 -#define PORT_SUSTAIN_HI 19 -#define PORT_RELEASE_HI 20 - -#define NUM_PORTS 21 - -#define RESOLUTION 16384 - -#ifndef PI -#define PI 3.14159265358979 -#endif - -typedef struct Envelope -{ - int envelope_decay; - double envelope; - - Envelope () : envelope_decay (0), envelope (0.0) {} -} Envelope; - -static LADSPA_Data *g_sine_table; -static LADSPA_Data *g_triangle_table; -static LADSPA_Data *g_pulse_table; -static int ref_count; - -class Organ : CMT_PluginInstance -{ - LADSPA_Data sample_rate; - - Envelope env0; - Envelope env1; - - unsigned long harm0_accum; - unsigned long harm1_accum; - unsigned long harm2_accum; - unsigned long harm3_accum; - unsigned long harm4_accum; - unsigned long harm5_accum; - - public: - - Organ(const LADSPA_Descriptor * Descriptor, - unsigned long SampleRate) - : CMT_PluginInstance(NUM_PORTS), - sample_rate(SampleRate), - harm0_accum(0), harm1_accum(0), - harm2_accum(0), harm3_accum(0), - harm4_accum(0), harm5_accum(0) { - if (ref_count++ == 0) - { - int size = RESOLUTION; - int half = size / 2; - int slope = size / 10; - int i; - - /* Initialize sine table. */ - g_sine_table = new LADSPA_Data[size]; - for (i = 0; i < size; i++) - g_sine_table[i] = sin ((i * 2.0 * PI) / size) / 6.0; - - /* Initialize triangle table. */ - g_triangle_table = new LADSPA_Data[size]; - for (i = 0; i < half; i++) - g_triangle_table[i] = (4.0 / size * i - 1.0) / 6.0; - for (; i < size; i++) - g_triangle_table[i] = (4.0 / size * (size - i) - 1.0) / 6.0; - - /* Initialize pulse table. */ - g_pulse_table = new LADSPA_Data[size]; - for (i = 0; i < slope; i++) - g_pulse_table[i] = ((double) -i) / slope / 6.0; - for (; i < half - slope; i++) - g_pulse_table[i] = -1.0 / 6.0; - for (; i < half + slope; i++) - g_pulse_table[i] = ((double) i - half) / slope / 6.0; - for (; i < size - slope; i++) - g_pulse_table[i] = 1.0 / 6.0; - for (; i < size; i++) - g_pulse_table[i] = ((double) size - i) / slope / 6.0; - } - } - - ~Organ () { - if (--ref_count == 0) - { - delete[] g_pulse_table; - delete[] g_triangle_table; - delete[] g_sine_table; - } - } - - static inline LADSPA_Data - table_pos (LADSPA_Data *table, - unsigned long freq_256, - unsigned long *accum) { - *accum += freq_256; - while (*accum >= RESOLUTION * 256) - *accum -= RESOLUTION * 256; - - return table[*accum >> 8]; - } - - static inline LADSPA_Data - envelope(Envelope *env, - int gate, - LADSPA_Data attack, - LADSPA_Data decay, - LADSPA_Data sustain, - LADSPA_Data release) - { - if (gate) - if (env->envelope_decay == 0) - { - env->envelope += (1.0F - env->envelope) * attack; - if (env->envelope >= 0.95F) - env->envelope_decay = 1; - } - else - env->envelope += (sustain - env->envelope) * decay; - else - env->envelope += -env->envelope * release; - - return env->envelope; - } - - static inline LADSPA_Data - multiplier(Organ *organ, - LADSPA_Data value) { - return 1.0 - pow (0.05, 1.0 / (organ->sample_rate * value)); - } - - static void - activate(LADSPA_Handle Instance) { - Organ *organ = (Organ*) Instance; - - organ->env0.envelope_decay = 0; - organ->env0.envelope = 0.0; - organ->env1.envelope_decay = 0; - organ->env1.envelope = 0.0; - organ->harm0_accum = 0; - organ->harm1_accum = 0; - organ->harm2_accum = 0; - organ->harm3_accum = 0; - organ->harm4_accum = 0; - organ->harm5_accum = 0; - } - - static void - run(LADSPA_Handle Instance, - unsigned long SampleCount) { - Organ *organ = (Organ*) Instance; - unsigned long i; - LADSPA_Data **ports; - LADSPA_Data *sine_table; - LADSPA_Data *reed_table; - LADSPA_Data *flute_table; - unsigned long freq_256; - unsigned long freq_256_harm0, freq_256_harm1; - unsigned long freq_256_harm2, freq_256_harm3; - unsigned long freq_256_harm4, freq_256_harm5; - double attack0, decay0, release0; - double attack1, decay1, release1; - int gate; - - ports = organ->m_ppfPorts; - - gate = (*ports[PORT_GATE] > 0.0); - if (gate == 0) - { - organ->env0.envelope_decay = 0; - organ->env1.envelope_decay = 0; - } - - sine_table = g_sine_table; - reed_table = (*ports[PORT_REED] > 0.0) ? g_pulse_table : sine_table; - flute_table = (*ports[PORT_FLUTE] > 0.0) ? g_triangle_table : sine_table; - freq_256 = (int) (*ports[PORT_FREQ] * - ((double) RESOLUTION) / - organ->sample_rate * 256.0); - - freq_256_harm0 = freq_256 / 2; - freq_256_harm1 = freq_256; - - attack0 = multiplier (organ, *ports[PORT_ATTACK_LO]); - decay0 = multiplier (organ, *ports[PORT_DECAY_LO]); - release0 = multiplier (organ, *ports[PORT_RELEASE_LO]); - - attack1 = multiplier (organ, *ports[PORT_ATTACK_HI]); - decay1 = multiplier (organ, *ports[PORT_DECAY_HI]); - release1 = multiplier (organ, *ports[PORT_RELEASE_HI]); - - if (*ports[PORT_BRASS] > 0.0) - { - freq_256_harm2 = freq_256 * 2; - freq_256_harm3 = freq_256_harm2 * 2; - freq_256_harm4 = freq_256_harm3 * 2; - freq_256_harm5 = freq_256_harm4 * 2; - - for (i = 0; i < SampleCount; i++) - ports[PORT_OUT][i] = - ((table_pos (sine_table, freq_256_harm0, &organ->harm0_accum) * *ports[PORT_HARM0] - + table_pos (sine_table, freq_256_harm1, &organ->harm1_accum) * *ports[PORT_HARM1] - + table_pos (reed_table, freq_256_harm2, &organ->harm2_accum) * *ports[PORT_HARM2]) - * envelope (&organ->env0, gate, attack0, decay0, *ports[PORT_SUSTAIN_LO], release0) - + (table_pos (sine_table, freq_256_harm3, &organ->harm3_accum) * *ports[PORT_HARM3] - + table_pos (flute_table, freq_256_harm4, &organ->harm4_accum) * *ports[PORT_HARM4] - + table_pos (flute_table, freq_256_harm5, &organ->harm5_accum) * *ports[PORT_HARM5]) - * envelope (&organ->env1, gate, attack1, decay1, *ports[PORT_SUSTAIN_HI], release1)) * *ports[PORT_VELOCITY]; - } - else - { - freq_256_harm2 = freq_256 * 3 / 2; - freq_256_harm3 = freq_256 * 2; - freq_256_harm4 = freq_256 * 3; - freq_256_harm5 = freq_256_harm3 * 2; - - for (i = 0; i < SampleCount; i++) - ports[PORT_OUT][i] = - ((table_pos (sine_table, freq_256_harm0, &organ->harm0_accum) * *ports[PORT_HARM0] - + table_pos (sine_table, freq_256_harm1, &organ->harm1_accum) * *ports[PORT_HARM1] - + table_pos (sine_table, freq_256_harm2, &organ->harm2_accum) * *ports[PORT_HARM2]) - * envelope (&organ->env0, gate, attack0, decay0, *ports[PORT_SUSTAIN_LO], release0) - - + (table_pos (reed_table, freq_256_harm3, &organ->harm3_accum) * *ports[PORT_HARM3] - + table_pos (sine_table, freq_256_harm4, &organ->harm4_accum) * *ports[PORT_HARM4] - + table_pos (flute_table, freq_256_harm5, &organ->harm5_accum) * *ports[PORT_HARM5]) - * envelope (&organ->env1, gate, attack1, decay1, *ports[PORT_SUSTAIN_HI], release1)) * *ports[PORT_VELOCITY]; - } -} - - -}; - -static LADSPA_PortDescriptor g_psPortDescriptors[] = -{ - LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT -}; - -static const char * const g_psPortNames[] = -{ - "Out", - "Gate", - "Velocity", - "Frequency (Hz)", - "Brass", "Reed", "Flute", - "16th Harmonic", "8th Harmonic", - "5 1/3rd Harmonic", "4th Harmonic", - "2 2/3rd Harmonic", "2nd Harmonic", - "Attack Lo (Secs)", "Decay Lo (Secs)", "Sustain Lo (Level)", "Release Lo (Secs)", - "Attack Hi (Secs)", "Decay Hi (Secs)", "Sustain Hi (Level)", "Release Hi (Secs)", -}; - -static LADSPA_PortRangeHint g_psPortRangeHints[] = -{ - /* Hints, Lower bound, Upper bound */ - { 0, 0.0, 0.0 }, - { LADSPA_HINT_TOGGLED, 0.0, 0.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 20000.0 }, - { LADSPA_HINT_TOGGLED, 0.0, 0.0 }, - { LADSPA_HINT_TOGGLED, 0.0, 0.0 }, - { LADSPA_HINT_TOGGLED, 0.0, 0.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.00, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.00, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 1.0 } -}; - -void -initialise_organ() { - CMT_Descriptor * psDescriptor; - - psDescriptor = new CMT_Descriptor - (1222, - "organ", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Organ", - CMT_MAKER("David A. Bartold"), - CMT_COPYRIGHT("1999, 2000", "David A. Bartold"), - NULL, - CMT_Instantiate, - Organ::activate, - Organ::run, - NULL, - NULL, - NULL); - - for (int i = 0; i < NUM_PORTS; i++) - psDescriptor->addPort( - g_psPortDescriptors[i], - g_psPortNames[i], - g_psPortRangeHints[i].HintDescriptor, - g_psPortRangeHints[i].LowerBound, - g_psPortRangeHints[i].UpperBound); - - registerNewPluginDescriptor(psDescriptor); -} diff --git a/plugins/LadspaEffect/cmt/src/peak.cpp b/plugins/LadspaEffect/cmt/src/peak.cpp deleted file mode 100644 index d17fc2c7eb0..00000000000 --- a/plugins/LadspaEffect/cmt/src/peak.cpp +++ /dev/null @@ -1,371 +0,0 @@ -/* peak.cpp - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include -#include -#include - -/*****************************************************************************/ - -#include "cmt.h" -#include "utils.h" - -/*****************************************************************************/ - -#define ET_INPUT 0 -#define ET_OUTPUT 1 - -#define ET_FILTER 2 - -/** This class is used to provide plugins that perform envelope - tracking. Peak and RMS are supported and smoothed or smoothed - maximum approaches are available. */ -class Tracker : public CMT_PluginInstance { -private: - - LADSPA_Data m_fState; - LADSPA_Data m_fSampleRate; - -public: - - Tracker(const LADSPA_Descriptor *, - unsigned long lSampleRate) - : CMT_PluginInstance(3), - m_fSampleRate(LADSPA_Data(lSampleRate)) { - } - - friend void activateTracker(void * pvHandle); - friend void runEnvelopeTracker_Peak(LADSPA_Handle Instance, - unsigned long SampleCount); - friend void runEnvelopeTracker_RMS(LADSPA_Handle Instance, - unsigned long SampleCount); - friend void runEnvelopeTracker_MaxPeak(LADSPA_Handle Instance, - unsigned long SampleCount); - friend void runEnvelopeTracker_MaxRMS(LADSPA_Handle Instance, - unsigned long SampleCount); - -}; - -/** This class provides a simple peak monitor that records the highest - signal peak present ever. It can be useful to identify clipping - cases. */ -class PeakMonitor : public CMT_PluginInstance { -private: - - LADSPA_Data m_fState; - -public: - - PeakMonitor(const LADSPA_Descriptor *, - unsigned long lSampleRate) - : CMT_PluginInstance(2) { - } - - friend void activatePeakMonitor(void * pvHandle); - friend void runPeakMonitor(LADSPA_Handle Instance, - unsigned long SampleCount); - -}; - -/*****************************************************************************/ - -void -activateTracker(void * pvHandle) { - ((Tracker *)pvHandle)->m_fState = 0; -} - -/*****************************************************************************/ - -void -activatePeakMonitor(void * pvHandle) { - ((PeakMonitor *)pvHandle)->m_fState = 0; -} - -/*****************************************************************************/ - -void -runEnvelopeTracker_Peak(LADSPA_Handle Instance, - unsigned long SampleCount) { - Tracker * poProcessor = (Tracker *)Instance; - LADSPA_Data * pfInput = poProcessor->m_ppfPorts[ET_INPUT]; - LADSPA_Data fDrag = *(poProcessor->m_ppfPorts[ET_FILTER]); - LADSPA_Data fOneMinusDrag = 1 - fDrag; - LADSPA_Data &rfState = poProcessor->m_fState; - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - LADSPA_Data fInput = *(pfInput++); - LADSPA_Data fEnvelopeTarget = fabs(fInput); - rfState = rfState * fDrag + fEnvelopeTarget * fOneMinusDrag; - } - *(poProcessor->m_ppfPorts[ET_OUTPUT]) = rfState; -} - -/*****************************************************************************/ - -void -runEnvelopeTracker_RMS(LADSPA_Handle Instance, - unsigned long SampleCount) { - Tracker * poProcessor = (Tracker *)Instance; - LADSPA_Data * pfInput = poProcessor->m_ppfPorts[ET_INPUT]; - LADSPA_Data fDrag = *(poProcessor->m_ppfPorts[ET_FILTER]); - LADSPA_Data fOneMinusDrag = 1 - fDrag; - LADSPA_Data &rfState = poProcessor->m_fState; - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - LADSPA_Data fInput = *(pfInput++); - LADSPA_Data fEnvelopeTarget = fInput * fInput; - rfState = rfState * fDrag + fEnvelopeTarget * fOneMinusDrag; - } - *(poProcessor->m_ppfPorts[ET_OUTPUT]) = sqrt(rfState); -} - -/*****************************************************************************/ - -void -runEnvelopeTracker_MaxPeak(LADSPA_Handle Instance, - unsigned long SampleCount) { - Tracker * poProcessor = (Tracker *)Instance; - LADSPA_Data * pfInput = poProcessor->m_ppfPorts[ET_INPUT]; - LADSPA_Data fDrag = calculate60dBDrag(*(poProcessor->m_ppfPorts[ET_FILTER]), - poProcessor->m_fSampleRate); - LADSPA_Data &rfState = poProcessor->m_fState; - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - LADSPA_Data fInput = *(pfInput++); - LADSPA_Data fEnvelopeTarget = fabs(fInput); - if (fEnvelopeTarget > rfState) - rfState = fEnvelopeTarget; - else { - rfState *= fDrag; - if (fEnvelopeTarget > rfState) - rfState = fEnvelopeTarget; - } - } - *(poProcessor->m_ppfPorts[ET_OUTPUT]) = rfState; -} - -/*****************************************************************************/ - -void -runEnvelopeTracker_MaxRMS(LADSPA_Handle Instance, - unsigned long SampleCount) { - Tracker * poProcessor = (Tracker *)Instance; - LADSPA_Data * pfInput = poProcessor->m_ppfPorts[ET_INPUT]; - LADSPA_Data fDrag = calculate60dBDrag(*(poProcessor->m_ppfPorts[ET_FILTER]), - poProcessor->m_fSampleRate); - LADSPA_Data &rfState = poProcessor->m_fState; - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - LADSPA_Data fInput = *(pfInput++); - LADSPA_Data fEnvelopeTarget = fInput * fInput; - if (fEnvelopeTarget > rfState) - rfState = fEnvelopeTarget; - else { - rfState *= fDrag; - if (fEnvelopeTarget > rfState) - rfState = fEnvelopeTarget; - } - } - *(poProcessor->m_ppfPorts[ET_OUTPUT]) = sqrt(rfState); -} - -/*****************************************************************************/ - -void -runPeakMonitor(LADSPA_Handle Instance, - unsigned long SampleCount) { - PeakMonitor * poProcessor = (PeakMonitor *)Instance; - LADSPA_Data * pfInput = poProcessor->m_ppfPorts[ET_INPUT]; - LADSPA_Data &rfState = poProcessor->m_fState; - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) { - LADSPA_Data fInput = *(pfInput++); - LADSPA_Data fEnvelopeTarget = fabs(fInput); - if (rfState < fEnvelopeTarget) - rfState = fEnvelopeTarget; - } - *(poProcessor->m_ppfPorts[ET_OUTPUT]) = rfState; -} - -/*****************************************************************************/ - -void -initialise_peak() { - - CMT_Descriptor * psDescriptor; - - psDescriptor = new CMT_Descriptor - (1078, - "track_peak", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Envelope Tracker (Peak)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - activateTracker, - runEnvelopeTracker_Peak, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, - "Output", - LADSPA_HINT_BOUNDED_BELOW, - 0); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Smoothing Factor", - LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, - 0, - 1); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1079, - "track_rms", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Envelope Tracker (RMS)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - activateTracker, - runEnvelopeTracker_RMS, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, - "Output", - LADSPA_HINT_BOUNDED_BELOW, - 0); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Smoothing Factor", - LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, - 0, - 1); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1080, - "track_max_peak", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Envelope Tracker (Maximum Peak)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - activateTracker, - runEnvelopeTracker_MaxPeak, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, - "Output", - LADSPA_HINT_BOUNDED_BELOW, - 0); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Envelope Forgetting Factor (s/60dB)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_DEFAULT_MAXIMUM), - 0, - 10); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1081, - "track_max_rms", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Envelope Tracker (Maximum RMS)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - activateTracker, - runEnvelopeTracker_MaxRMS, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, - "Output", - LADSPA_HINT_BOUNDED_BELOW, - 0); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Envelope Forgetting Factor (s/60dB)", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_DEFAULT_MAXIMUM), - 0, - 10); - registerNewPluginDescriptor(psDescriptor); - - psDescriptor = new CMT_Descriptor - (1082, - "peak", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Peak Monitor", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - activatePeakMonitor, - runPeakMonitor, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, - "Peak", - LADSPA_HINT_BOUNDED_BELOW, - 0); - registerNewPluginDescriptor(psDescriptor); -} - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/phasemod.cpp b/plugins/LadspaEffect/cmt/src/phasemod.cpp deleted file mode 100644 index 0a8c8e27c4e..00000000000 --- a/plugins/LadspaEffect/cmt/src/phasemod.cpp +++ /dev/null @@ -1,465 +0,0 @@ -/* phasemod.cpp - - Phase Modulated Voice - Phase Modulation synthesizer voice - Copyright (c) 2001 David A. Bartold - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include -#include -#include "cmt.h" - -#define PORT_OUT 0 -#define PORT_GATE 1 -#define PORT_VELOCITY 2 -#define PORT_FREQ 3 -#define PORT_DCO_MODULATION 4 -#define PORT_DCO_OCTAVE 5 -#define PORT_DCO_WAVEFORM 6 -#define PORT_DCO_ATTACK 7 -#define PORT_DCO_DECAY 8 -#define PORT_DCO_SUSTAIN 9 -#define PORT_DCO_RELEASE 10 - -#define DCO_MULTIPLIER 7 - -#define NUM_PORTS 46 - -#ifndef PI -#define PI 3.14159265358979F -#endif - -typedef struct Envelope -{ - int envelope_decay; - LADSPA_Data envelope; - - Envelope () : envelope_decay (0), envelope (0.0) {} -} Envelope; - -class PhaseMod : public CMT_PluginInstance -{ - LADSPA_Data sample_rate; - - int trigger; - - Envelope dco_env[6]; - LADSPA_Data dco_accum[6]; - -public: - PhaseMod(const LADSPA_Descriptor * Descriptor, - unsigned long SampleRate) - : CMT_PluginInstance(NUM_PORTS), - sample_rate (SampleRate), - trigger (0) { - int i; - - for (i = 0; i < 6; i++) - dco_accum[i] = 0.0; - } - - ~PhaseMod () { - } - - static inline LADSPA_Data - tri(LADSPA_Data x) { - if (x > 0.75F) - x = x - 1.0F; - else if (x > 0.25F) - x = 0.5F - x; - - return x * 4.0F; - } - - static inline LADSPA_Data - envelope(Envelope *env, - int gate, - LADSPA_Data attack, - LADSPA_Data decay, - LADSPA_Data sustain, - LADSPA_Data release) - { - if (gate) - if (env->envelope_decay == 0) - { - env->envelope += (1.0F - env->envelope) * attack; - if (env->envelope >= 0.95F) - env->envelope_decay = 1; - } - else - env->envelope += (sustain - env->envelope) * decay; - else - env->envelope += -env->envelope * release; - - return env->envelope; - } - - static void - activate(LADSPA_Handle Instance) { - PhaseMod *phasemod = (PhaseMod*) Instance; - int i; - - phasemod->trigger = 0; - - for (i = 0; i < 6; i++) - { - phasemod->dco_env[i].envelope_decay = 0; - phasemod->dco_env[i].envelope = 0.0; - phasemod->dco_accum[i] = 0.0; - } - } - - static inline LADSPA_Data - osc(int waveform, - LADSPA_Data inc, - LADSPA_Data phasemod, - LADSPA_Data *accum) { - LADSPA_Data pos; - - *accum += inc; - while (*accum >= 1.0F) - *accum -= 1.0F; - - pos = *accum + phasemod; - while (pos < 0.0F) pos += 1.0F; - while (pos > 1.0F) pos -= 1.0F; - - /* 0 = Sine wave */ - if (waveform == 0) - return sin (pos * 2.0 * PI); - - /* 1 = Triangle wave */ - else if (waveform == 1) - return tri (pos); - - /* 2 = Square wave */ - else if (waveform == 2) - return (pos > 0.5) ? 1.0F : -1.0F; - - /* 3 = Sawtooth wave */ - else if (waveform == 3) - return pos * 2.0F - 1.0F; - - /* 4 = Fullwave Rectified Sine wave */ - else if (waveform == 4) - return fabs (pos * PI); - - /* 5 = Static */ - else - return (rand () & 1) ? -1.0F : 1.0F; - } - - static LADSPA_Data - calc_inc(LADSPA_Data oct, - LADSPA_Data freq, - LADSPA_Data sample_rate) { - return pow (2.0, oct) * freq / sample_rate; - } - - static inline LADSPA_Data - multiplier(PhaseMod *phasemod, - LADSPA_Data value) { - return 1.0 - pow (0.05, 1.0 / (phasemod->sample_rate * value)); - } - - static void - run(LADSPA_Handle Instance, - unsigned long SampleCount) { - PhaseMod *phasemod = (PhaseMod*) Instance; - - unsigned long i, j; - int gate; - int waveform[6]; - int store[6]; - LADSPA_Data inc[6]; - LADSPA_Data attack[6]; - LADSPA_Data decay[6]; - LADSPA_Data release[6]; - LADSPA_Data **ports; - LADSPA_Data vol; - - ports = phasemod->m_ppfPorts; - gate = (*ports[PORT_GATE] > 0.0); - - if (gate == 1 && phasemod->trigger == 0) - for (i = 0; i < 6; i++) - phasemod->dco_env[i].envelope_decay = 0; - - phasemod->trigger = gate; - - for (i = 0; i < 6; i++) - { - int offset = DCO_MULTIPLIER * i; - - waveform[i] = (int) *ports[PORT_DCO_WAVEFORM + offset]; - inc[i] = calc_inc (*ports[PORT_DCO_OCTAVE + offset], - *ports[PORT_FREQ], - phasemod->sample_rate); - attack[i] = multiplier (phasemod, *ports[PORT_DCO_ATTACK + offset]); - decay[i] = multiplier (phasemod, *ports[PORT_DCO_DECAY + offset]); - release[i] = multiplier (phasemod, *ports[PORT_DCO_RELEASE + offset]); - } - - j = 1; - for (i = 0; i < 5; i++) - if (*ports[PORT_DCO_MODULATION + (i + 1) * DCO_MULTIPLIER] < 0.0001) - store[i] = 1, j++; - else - store[i] = 0; - store[5] = 1; - vol = 1.0 / j; - - for (i = 0; i < SampleCount; i++) - { - LADSPA_Data sample; - LADSPA_Data prev; - - sample = 0.0; - prev = 1.0; - for (j = 0; j < 6; j++) - { - int offset = DCO_MULTIPLIER * j; - - prev = - envelope (&phasemod->dco_env[j], - gate, attack[j], decay[j], - *ports[PORT_DCO_SUSTAIN + offset], release[j]) * - osc (waveform[j], inc[j], - prev * *ports[PORT_DCO_MODULATION + offset], - &phasemod->dco_accum[j]) * - *ports[PORT_VELOCITY]; - - if (store[j]) - sample += prev; - } - ports[PORT_OUT][i] = sample * vol; - } - } -}; - -static LADSPA_PortDescriptor g_psPortDescriptors[] = -{ - LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT, - - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT -}; - -static const char * const g_psPortNames[] = -{ - "Out", - - "Gate", - "Velocity", - "Frequency (Hz)", - - "DCO1 Modulation", - "DCO1 Octave", - "DCO1 Waveform", - "DCO1 Attack", - "DCO1 Decay", - "DCO1 Sustain", - "DCO1 Release", - - "DCO2 Modulation", - "DCO2 Octave", - "DCO2 Waveform", - "DCO2 Attack", - "DCO2 Decay", - "DCO2 Sustain", - "DCO2 Release", - - "DCO3 Modulation", - "DCO3 Octave", - "DCO3 Waveform", - "DCO3 Attack", - "DCO3 Decay", - "DCO3 Sustain", - "DCO3 Release", - - "DCO4 Modulation", - "DCO4 Octave", - "DCO4 Waveform", - "DCO4 Attack", - "DCO4 Decay", - "DCO4 Sustain", - "DCO4 Release", - - "DCO5 Modulation", - "DCO5 Octave", - "DCO5 Waveform", - "DCO5 Attack", - "DCO5 Decay", - "DCO5 Sustain", - "DCO5 Release", - - "DCO6 Modulation", - "DCO6 Octave", - "DCO6 Waveform", - "DCO6 Attack", - "DCO6 Decay", - "DCO6 Sustain", - "DCO6 Release" -}; - -static LADSPA_PortRangeHint g_psPortRangeHints[] = -{ - /* Hints, Lower bound, Upper bound */ - { 0, 0.0, 0.0 }, - - { LADSPA_HINT_TOGGLED, 0.0, 0.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 20000.0 }, - - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, -2.0, 2.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | - LADSPA_HINT_INTEGER, -0.1, 5.1 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, -2.0, 2.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | - LADSPA_HINT_INTEGER, -0.1, 5.1 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, -2.0, 2.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | - LADSPA_HINT_INTEGER, -0.1, 5.1 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, -2.0, 2.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | - LADSPA_HINT_INTEGER, -0.1, 5.1 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, -2.0, 2.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | - LADSPA_HINT_INTEGER, -0.1, 5.1 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, -2.0, 2.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | - LADSPA_HINT_INTEGER, -0.1, 5.1 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 } -}; - -void -initialise_phasemod() { - CMT_Descriptor * psDescriptor; - - psDescriptor = new CMT_Descriptor - (1226, - "phasemod", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Phase Modulated Voice", - CMT_MAKER("David A. Bartold"), - CMT_COPYRIGHT("2001", "David A. Bartold"), - NULL, - CMT_Instantiate, - PhaseMod::activate, - PhaseMod::run, - NULL, - NULL, - NULL); - - for (int i = 0; i < NUM_PORTS; i++) - psDescriptor->addPort( - g_psPortDescriptors[i], - g_psPortNames[i], - g_psPortRangeHints[i].HintDescriptor, - g_psPortRangeHints[i].LowerBound, - g_psPortRangeHints[i].UpperBound); - - registerNewPluginDescriptor(psDescriptor); -} diff --git a/plugins/LadspaEffect/cmt/src/pink.cpp b/plugins/LadspaEffect/cmt/src/pink.cpp deleted file mode 100644 index bf3e1bb48e1..00000000000 --- a/plugins/LadspaEffect/cmt/src/pink.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/* pink.cpp - - Interpolated pink noise plugins for use as control signals. - - (c) 2002 Nathaniel Virgo - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include - -/*****************************************************************************/ - -#include "cmt.h" - -#include "pinknoise.h" -#include "utils.h" - -/*****************************************************************************/ - -namespace pink { - - enum { - port_frequency = 0, - port_output = 1, - n_ports = 2 - }; - - /** This plugin generates a signal which approximates the effect of low-pass - filtered pink noise, which makes for an interesting randomly changing - control parameter. It should probably use sinc interpolation, but in fact - it uses third-order splines, which sound more-or-less okay to me. */ - class Plugin : public CMT_PluginInstance { - private: - - LADSPA_Data sample_rate; - - PinkNoise noise_source; - LADSPA_Data *data_points; - int first_point; - unsigned long counter; - float multiplier; // 1/(max counter value) - - public: - - Plugin(const LADSPA_Descriptor *, - unsigned long s_rate) : - CMT_PluginInstance(n_ports), - sample_rate(s_rate) { - data_points = new LADSPA_Data[4]; - } - - ~Plugin() { - delete [] data_points; - } - - friend void activate(LADSPA_Handle instance); - - friend void run_interpolated_audio(LADSPA_Handle instance, - unsigned long sample_count); - - friend void run_interpolated_control(LADSPA_Handle instance, - unsigned long sample_count); - - }; - - void activate(LADSPA_Handle instance) { - Plugin *pp = (Plugin *) instance; - Plugin &p = *pp; - - p.noise_source.reset(); - for (int i=0; i<4; ++i) - p.data_points[i] = p.noise_source.getValue(); - p.first_point = 0; - p.counter = 0; - p.multiplier = 1; - } - - inline float thirdInterp(const float &x, - const float &L1,const float &L0, - const float &H0,const float &H1) { - return - L0 + - .5f* - x*(H0-L1 + - x*(H0 + L0*(-2) + L1 + - x*( (H0 - L0)*9 + (L1 - H1)*3 + - x*((L0 - H0)*15 + (H1 - L1)*5 + - x*((H0 - L0)*6 + (L1 - H1)*2 ))))); - } - - void run_interpolated_audio(LADSPA_Handle instance, - unsigned long sample_count) { - - Plugin *pp = (Plugin *) instance; - Plugin &p = *pp; - - LADSPA_Data frequency = *pp->m_ppfPorts[port_frequency]; - LADSPA_Data * out = pp->m_ppfPorts[port_output]; - - if (frequency<=0) { - LADSPA_Data value = thirdInterp( 1 - p.counter*p.multiplier, - p.data_points[ p.first_point ], - p.data_points[ (p.first_point+1) % 4 ], - p.data_points[ (p.first_point+2) % 4 ], - p.data_points[ (p.first_point+3) % 4 ] ); - for (unsigned long i=0; im_ppfPorts[port_frequency]; - LADSPA_Data * out = pp->m_ppfPorts[port_output]; - - float value = thirdInterp( 1 - p.counter*p.multiplier, - p.data_points[ p.first_point ], - p.data_points[ (p.first_point+1) % 4 ], - p.data_points[ (p.first_point+2) % 4 ], - p.data_points[ (p.first_point+3) % 4 ] ); - if (frequency>0) { - frequency = BOUNDED_ABOVE(frequency, p.sample_rate/sample_count); - while (p.counter <= sample_count) { - p.data_points[ p.first_point ] = p.noise_source.getValue(); - p.first_point = (p.first_point + 1) % 4; - p.multiplier = frequency/p.sample_rate; - p.counter += (unsigned long)(p.sample_rate/frequency); - } - p.counter -= (p.counter < sample_count) ? p.counter : sample_count; - } - *(out)=value; - } - - void initialise() { - CMT_Descriptor * d = new CMT_Descriptor - (1841, - "pink_interpolated_audio", - 0, - "Pink Noise (Interpolated)", - CMT_MAKER("Nathaniel Virgo"), - CMT_COPYRIGHT("2002", "Nathaniel Virgo"), - NULL, - CMT_Instantiate, - activate, - run_interpolated_audio, - NULL, - NULL, - NULL); - d->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Highest frequency", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_SAMPLE_RATE - | LADSPA_HINT_DEFAULT_1), - 0, - 1); - d->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - registerNewPluginDescriptor(d); - - // the following has been commented out because I'm pretty sure that - // control-rate outputs don't make sense for the vast majority of hosts. - // (SSM being the notable exception) - /* - d = new CMT_Descriptor - (1842, - "pink_interpolated_control", - 0, - "Pink Noise (Interpolated, control rate)", - CMT_MAKER("Nathaniel Virgo"), - CMT_COPYRIGHT("2002", "Nathaniel Virgo"), - NULL, - CMT_Instantiate, - activate, - run_interpolated_control, - NULL, - NULL, - NULL); - d->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Highest frequency", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_SAMPLE_RATE - | LADSPA_HINT_DEFAULT_1), - 0, - 0.002); // arbitrary low value (sensible for sample_count around 500) - d->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, - "Output"); - registerNewPluginDescriptor(d); - */ - } - -} // end of namespace - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/pink_full.cpp b/plugins/LadspaEffect/cmt/src/pink_full.cpp deleted file mode 100644 index 59c92906eca..00000000000 --- a/plugins/LadspaEffect/cmt/src/pink_full.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* pink_full.cpp - - A full-frequency pink noise generator. - - (c) 2002 Nathaniel Virgo - - Part of the Computer Music Toolkit - a library of LADSPA plugins. - The Computer Music Toolkit is Copyright (C) 2000-2002 - Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include - -/*****************************************************************************/ - -#include "cmt.h" - -#include "pinknoise.h" -#include "utils.h" - -/*****************************************************************************/ - -namespace pink_full { - - enum { - port_output = 0, - - n_ports = 1 - }; - - /** This plugin generates a signal which approximates pink noise, using the - Voss-McCartney algorithm described at www.firstpr.com.au/dsp/pink-noise/ */ - class Plugin : public CMT_PluginInstance { - private: - PinkNoise noise_source; - public: - - Plugin(const LADSPA_Descriptor *, - unsigned long s_rate) : - CMT_PluginInstance(n_ports) - { - } - - ~Plugin() { - } - - friend void activate(LADSPA_Handle instance); - - friend void run(LADSPA_Handle instance, - unsigned long sample_count); - }; - - void activate(LADSPA_Handle instance) { - Plugin *pp = (Plugin *) instance; - Plugin &p = *pp; - - p.noise_source.reset(); - } - - void run(LADSPA_Handle instance, - unsigned long sample_count) { - - Plugin *pp = (Plugin *) instance; - Plugin &p = *pp; - - LADSPA_Data * out = pp->m_ppfPorts[port_output]; - - for (unsigned long i=0; i, - activate, - run, - NULL, - NULL, - NULL); - d->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - registerNewPluginDescriptor(d); - } - -} // end of namespace - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/pink_sh.cpp b/plugins/LadspaEffect/cmt/src/pink_sh.cpp deleted file mode 100644 index 13f2a69d5e5..00000000000 --- a/plugins/LadspaEffect/cmt/src/pink_sh.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* pink_sh.cpp - - A sample-and-hold pink noise generator. - - (c) 2002 Nathaniel Virgo - - Part of the Computer Music Toolkit - a library of LADSPA plugins. - The Computer Music Toolkit is Copyright (C) 2000-2002 - Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include - -/*****************************************************************************/ - -#include "cmt.h" - -#include "pinknoise.h" -#include "utils.h" - -/*****************************************************************************/ - -namespace pink_sh { - - enum { - port_frequency = 0, - port_output = 1, - n_ports = 2 - }; - - /** This plugin generates a signal which approximates stepped - (sample-and-hold like) pink noise, using the - Voss-McCartney algorithm described at www.firstpr.com.au/dsp/pink-noise/ */ - class Plugin : public CMT_PluginInstance { - private: - LADSPA_Data sample_rate; - PinkNoise noise_source; - unsigned counter; - public: - - Plugin(const LADSPA_Descriptor *, - unsigned long s_rate) : - CMT_PluginInstance(n_ports), - sample_rate(s_rate) { - } - - ~Plugin() { - } - - friend void activate(LADSPA_Handle instance); - - friend void run(LADSPA_Handle instance, - unsigned long sample_count); - }; - - void activate(LADSPA_Handle instance) { - Plugin *pp = (Plugin *) instance; - Plugin &p = *pp; - - p.noise_source.reset(); - p.counter = 0; - } - - void run(LADSPA_Handle instance, - unsigned long sample_count) { - - Plugin *pp = (Plugin *) instance; - Plugin &p = *pp; - - LADSPA_Data frequency = *pp->m_ppfPorts[port_frequency]; - LADSPA_Data * out = pp->m_ppfPorts[port_output]; - - frequency = BOUNDED_ABOVE(frequency,p.sample_rate); - unsigned remain = sample_count; - - if (frequency > 0) { - while (remain) { - unsigned jump_samples = (remain, - activate, - run, - NULL, - NULL, - NULL); - d->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Sample and hold frequency", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_SAMPLE_RATE - | LADSPA_HINT_DEFAULT_1), - 0, 0.02); - d->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - registerNewPluginDescriptor(d); - } - -} // end of namespace - -/*****************************************************************************/ - -/* EOF */ - diff --git a/plugins/LadspaEffect/cmt/src/pinknoise.h b/plugins/LadspaEffect/cmt/src/pinknoise.h deleted file mode 100644 index c6b350ff8f6..00000000000 --- a/plugins/LadspaEffect/cmt/src/pinknoise.h +++ /dev/null @@ -1,111 +0,0 @@ -/* pinknoise.h - - pink noise generating class using the Voss-McCartney algorithm, as - described at www.firstpr.com.au/dsp/pink-noise/ - - (c) 2002 Nathaniel Virgo - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -#ifndef _PINKNOISE_H -#define _PINKNOISE_H - -#include - -typedef unsigned int CounterType; -typedef float DataValue; - -const int n_generators = 8*sizeof(CounterType); - -class PinkNoise { - private: - - CounterType counter; - DataValue * generators; - DataValue last_value; - - public: - - PinkNoise() { - generators = new DataValue[n_generators]; - reset(); - } - - ~PinkNoise() {delete [] generators;}; - - void reset() { - counter = 0; - last_value = 0; - for (int i=0; i>= 1; - index++; - // this loop means that the plugins cannot be labelled as - // capable of hard real-time performance. - } - - last_value -= generators[index]; - generators[index] = 2*(rand()/DataValue(RAND_MAX))-1; - last_value += generators[index]; - } - - counter++; - - return last_value; - } - - inline DataValue getValue() { - return getUnscaledValue()/n_generators; - } - - inline DataValue getLastValue() { - return last_value/n_generators; - } - - inline DataValue getValue2() { - // adding some white noise gets rid of some nulls in the frequency spectrum - // but makes the signal spikier, so possibly not so good for control signals. - return (getUnscaledValue() + rand()/DataValue(RAND_MAX*0.5)-1)/(n_generators+1); - } - -}; - -#endif - - - - - - - - - diff --git a/plugins/LadspaEffect/cmt/src/run_adding.h b/plugins/LadspaEffect/cmt/src/run_adding.h deleted file mode 100644 index 2ab1892af91..00000000000 --- a/plugins/LadspaEffect/cmt/src/run_adding.h +++ /dev/null @@ -1,159 +0,0 @@ -/* run_adding.h - - (c) 2002 Nathaniel Virgo - - a few simple inline functions that can be used with templates - to get run_adding for free. - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -/* - How to use this - --------------- - - Templates can be used to automatically generate code for both the run and - run_adding LADSPA functions. Simply define the plugin's run function as - - template - void run_foo(LADSPA_Handle Instance, unsigned long SampleCount); - - and in the body of the function use - - write_output(pfOutput, fValue, poFoo->m_fRunAddingGain); - - instead of - - *(pfOutput++) = fValue. - - and be sure to include a set_run_adding_gain function. - then set the LADSPA run function as - - run_foo; - - and the run_adding function as - - run_foo; - - With -O1 or greater g++ will inline the write_output function, and - although the code ends up slightly bigger there is no overhead compared to - having two seperate functions. - - Sometimes the run_adding_gain function can be made more efficient than this - - for instance, if the output is multiplied by a gain already then you are - doing one more multiplication than necessary on every sample. It's a lot - less code to maintain, though, and it should still save some work for the - host compared to not having a run_adding function. -*/ - -/*****************************************************************************/ - -#include - -/*****************************************************************************/ - -typedef void OutputFunction(LADSPA_Data *&, const LADSPA_Data &, - const LADSPA_Data &); - -inline void write_output_normal(LADSPA_Data *&out, const LADSPA_Data &value, - const LADSPA_Data &run_adding_gain) -{ - *(out++) = value; -} - -inline void write_output_adding(LADSPA_Data *&out, const LADSPA_Data &value, - const LADSPA_Data &run_adding_gain) -{ - *(out++) += value*run_adding_gain; -} - -/*****************************************************************************/ - -/* - If the plugin has a control-rate ouput then you don't want the write_output - function to try to increment the pointer. To achieve this, use - - write_control(pfOutput, fValue, poFoo->m_fRunAddingGain); - - instead of just - - write_output(...); - - I realise this feels a bit hacky, but it works. -*/ - -template -inline void write_control(LADSPA_Data *const, - const LADSPA_Data &, const LADSPA_Data &); - -template <> -inline void write_control(LADSPA_Data *const out, - const LADSPA_Data &value, - const LADSPA_Data &run_adding_gain) -{ - *out = value; -} - -template <> -inline void write_control(LADSPA_Data *const out, - const LADSPA_Data &value, - const LADSPA_Data &run_adding_gain) -{ - *out += value*run_adding_gain; -} - - -/*****************************************************************************/ - -/* - This next bit is an attempt to facilitate the writing of slightly - more efficent run_adding functions without writing two seperate pieces of - code. You can say something like - - LADSPA_Data fOutputGain = ... ; - ... - fOutputGain *= get_gain(poFoo->m_fRunAddingGain); - ... - write_output(pfOutput, fValue*fOutputGain, 1.0f); - - in run_foo. With -O1 or greater g++ should inline the functions and - optimise away the multiplies by 1.0f, so in run_foo - fOutputGain will be multiplied by m_fRunAddingGain and in - run_foo it will be left alone. - - This does not make for very clear code, sorry about that. See disintegrator.cpp - for an example. -*/ - -template -inline float get_gain(const LADSPA_Data &); - -template <> -inline float get_gain(const LADSPA_Data &) -{ - return 1.0f; -} - -template <> -inline float get_gain(const LADSPA_Data &run_adding_gain) -{ - return run_adding_gain; -} diff --git a/plugins/LadspaEffect/cmt/src/sine.cpp b/plugins/LadspaEffect/cmt/src/sine.cpp deleted file mode 100644 index 7b27ff4cf2c..00000000000 --- a/plugins/LadspaEffect/cmt/src/sine.cpp +++ /dev/null @@ -1,296 +0,0 @@ -/* sine.cpp - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include -#include - -/*****************************************************************************/ - -#include "cmt.h" - -/*****************************************************************************/ - -/* Sine table size is given by (1 << SINE_TABLE_BITS). */ -#define SINE_TABLE_BITS 14 -#define SINE_TABLE_SHIFT (8 * sizeof(unsigned long) - SINE_TABLE_BITS) - -/*****************************************************************************/ - -LADSPA_Data * g_pfSineTable = NULL; -LADSPA_Data g_fPhaseStepBase = 0; - -/*****************************************************************************/ - -void -initialise_sine_wavetable() { - if (g_pfSineTable == NULL) { - long lTableSize = (1 << SINE_TABLE_BITS); - double dShift = (double(M_PI) * 2) / lTableSize; - g_pfSineTable = new float[lTableSize]; - if (g_pfSineTable != NULL) - for (long lIndex = 0; lIndex < lTableSize; lIndex++) - g_pfSineTable[lIndex] = LADSPA_Data(sin(dShift * lIndex)); - } - if (g_fPhaseStepBase == 0) { - g_fPhaseStepBase = (LADSPA_Data)pow(2, sizeof(unsigned long) * 8); - } -} - -/*****************************************************************************/ - -#define OSC_FREQUENCY 0 -#define OSC_AMPLITUDE 1 -#define OSC_OUTPUT 2 - -/* This class provides sine wavetable oscillator - plugins. Band-limiting to avoid aliasing is trivial because of the - waveform in use. Four versions of the oscillator are provided, - allowing the amplitude and frequency inputs of the oscillator to be - audio signals rather than controls (for use in AM and FM - synthesis). */ -class SineOscillator : public CMT_PluginInstance{ -private: - - /* Oscillator state: */ - - unsigned long m_lPhase; - unsigned long m_lPhaseStep; - LADSPA_Data m_fCachedFrequency; - const LADSPA_Data m_fLimitFrequency; - const LADSPA_Data m_fPhaseStepScalar; - - void setPhaseStepFromFrequency(const LADSPA_Data fFrequency) { - if (fFrequency != m_fCachedFrequency) { - if (fFrequency >= 0 && fFrequency < m_fLimitFrequency) - m_lPhaseStep = (unsigned long)(m_fPhaseStepScalar * fFrequency); - else - m_lPhaseStep = 0; - m_fCachedFrequency = fFrequency; - } - } - -public: - - SineOscillator(const LADSPA_Descriptor *, - unsigned long lSampleRate) - : CMT_PluginInstance(3), - m_lPhaseStep(0), - m_fCachedFrequency(0), - m_fLimitFrequency(LADSPA_Data(lSampleRate * 0.5)), - m_fPhaseStepScalar(LADSPA_Data(g_fPhaseStepBase / lSampleRate)) { - } - - friend void activateSineOscillator(void * pvHandle); - friend void runSineOscillator_FreqAudio_AmpAudio(LADSPA_Handle Instance, - unsigned long SampleCount); - friend void runSineOscillator_FreqAudio_AmpCtrl(LADSPA_Handle Instance, - unsigned long SampleCount); - friend void runSineOscillator_FreqCtrl_AmpAudio(LADSPA_Handle Instance, - unsigned long SampleCount); - friend void runSineOscillator_FreqCtrl_AmpCtrl(LADSPA_Handle Instance, - unsigned long SampleCount); - -}; - -/*****************************************************************************/ - -void -activateSineOscillator(void * pvHandle) { - ((SineOscillator *)pvHandle)->m_lPhase = 0; -} - -/*****************************************************************************/ - -void -runSineOscillator_FreqAudio_AmpAudio(LADSPA_Handle Instance, - unsigned long SampleCount) { - SineOscillator * poSineOscillator = (SineOscillator *)Instance; - LADSPA_Data * pfFrequency = poSineOscillator->m_ppfPorts[OSC_FREQUENCY]; - LADSPA_Data * pfAmplitude = poSineOscillator->m_ppfPorts[OSC_AMPLITUDE]; - LADSPA_Data * pfOutput = poSineOscillator->m_ppfPorts[OSC_OUTPUT]; - for (unsigned long lIndex = 0; lIndex < SampleCount; lIndex++) { - /* Extract frequency at this point to guarantee inplace - support. */ - LADSPA_Data fFrequency = *(pfFrequency++); - *(pfOutput++) - = (g_pfSineTable[poSineOscillator->m_lPhase >> SINE_TABLE_SHIFT] - * *(pfAmplitude++)); - poSineOscillator->setPhaseStepFromFrequency(fFrequency); - poSineOscillator->m_lPhase - += poSineOscillator->m_lPhaseStep; - } -} - -/*****************************************************************************/ - -void -runSineOscillator_FreqAudio_AmpCtrl(LADSPA_Handle Instance, - unsigned long SampleCount) { - SineOscillator * poSineOscillator = (SineOscillator *)Instance; - LADSPA_Data fAmplitude = *(poSineOscillator->m_ppfPorts[OSC_AMPLITUDE]); - LADSPA_Data * pfFrequency = poSineOscillator->m_ppfPorts[OSC_FREQUENCY]; - LADSPA_Data * pfOutput = poSineOscillator->m_ppfPorts[OSC_OUTPUT]; - for (unsigned long lIndex = 0; lIndex < SampleCount; lIndex++) { - /* Extract frequency at this point to guarantee inplace - support. */ - LADSPA_Data fFrequency = *(pfFrequency++); - *(pfOutput++) - = (g_pfSineTable[poSineOscillator->m_lPhase >> SINE_TABLE_SHIFT] - * fAmplitude); - poSineOscillator->setPhaseStepFromFrequency(fFrequency); - poSineOscillator->m_lPhase - += poSineOscillator->m_lPhaseStep; - } -} - -/*****************************************************************************/ - -void -runSineOscillator_FreqCtrl_AmpAudio(LADSPA_Handle Instance, - unsigned long SampleCount) { - SineOscillator * poSineOscillator = (SineOscillator *)Instance; - poSineOscillator->setPhaseStepFromFrequency - (*(poSineOscillator->m_ppfPorts[OSC_FREQUENCY])); - LADSPA_Data * pfAmplitude = poSineOscillator->m_ppfPorts[OSC_AMPLITUDE]; - LADSPA_Data * pfOutput = poSineOscillator->m_ppfPorts[OSC_OUTPUT]; - for (unsigned long lIndex = 0; lIndex < SampleCount; lIndex++) { - *(pfOutput++) - = (g_pfSineTable[poSineOscillator->m_lPhase >> SINE_TABLE_SHIFT] - * *(pfAmplitude++)); - poSineOscillator->m_lPhase - += poSineOscillator->m_lPhaseStep; - } -} - -/*****************************************************************************/ - -void -runSineOscillator_FreqCtrl_AmpCtrl(LADSPA_Handle Instance, - unsigned long SampleCount) { - SineOscillator * poSineOscillator = (SineOscillator *)Instance; - LADSPA_Data fAmplitude = *(poSineOscillator->m_ppfPorts[OSC_AMPLITUDE]); - poSineOscillator->setPhaseStepFromFrequency - (*(poSineOscillator->m_ppfPorts[OSC_FREQUENCY])); - LADSPA_Data * pfOutput = poSineOscillator->m_ppfPorts[OSC_OUTPUT]; - for (unsigned long lIndex = 0; lIndex < SampleCount; lIndex++) { - *(pfOutput++) - = (g_pfSineTable[poSineOscillator->m_lPhase >> SINE_TABLE_SHIFT] - * fAmplitude); - poSineOscillator->m_lPhase - += poSineOscillator->m_lPhaseStep; - } -} - -/*****************************************************************************/ - -void -initialise_sine() { - - initialise_sine_wavetable(); - - const char * apcLabels[] = { - "sine_faaa", - "sine_faac", - "sine_fcaa", - "sine_fcac" - }; - const char * apcNames[] = { - "Sine Oscillator (Freq:audio, Amp:audio)", - "Sine Oscillator (Freq:audio, Amp:control)", - "Sine Oscillator (Freq:control, Amp:audio)", - "Sine Oscillator (Freq:control, Amp:control)" - }; - LADSPA_Run_Function afRunFunction[] = { - runSineOscillator_FreqAudio_AmpAudio, - runSineOscillator_FreqAudio_AmpCtrl, - runSineOscillator_FreqCtrl_AmpAudio, - runSineOscillator_FreqCtrl_AmpCtrl - }; - LADSPA_PortDescriptor piFrequencyPortProperties[] = { - LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL - }; - LADSPA_PortDescriptor piAmplitudePortProperties[] = { - LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL - }; - - for (long lPluginIndex = 0; lPluginIndex < 4; lPluginIndex++) { - - CMT_Descriptor * psDescriptor; - - psDescriptor = new CMT_Descriptor - (1063 + lPluginIndex, - apcLabels[lPluginIndex], - LADSPA_PROPERTY_HARD_RT_CAPABLE, - apcNames[lPluginIndex], - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - activateSineOscillator, - afRunFunction[lPluginIndex], - NULL, - NULL, - NULL); - - psDescriptor->addPort - (piFrequencyPortProperties[lPluginIndex], - "Frequency", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_SAMPLE_RATE - | LADSPA_HINT_LOGARITHMIC - | LADSPA_HINT_DEFAULT_440), - 0, - 0.5); - psDescriptor->addPort - (piAmplitudePortProperties[lPluginIndex], - "Amplitude", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_LOGARITHMIC - | LADSPA_HINT_DEFAULT_1), - 0, - 0); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - - registerNewPluginDescriptor(psDescriptor); - } -} - -/*****************************************************************************/ - -void -finalise_sine() { - delete [] g_pfSineTable; -} - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/sledgehammer.cpp b/plugins/LadspaEffect/cmt/src/sledgehammer.cpp deleted file mode 100644 index 60eb79f70cf..00000000000 --- a/plugins/LadspaEffect/cmt/src/sledgehammer.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/* sledgehammer.cpp - - "Dynamic Sledgehammer" - a thing to brutally mangle the dynamics of - a sound. - - (c) 2002 Nathaniel Virgo - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include -#include - -/*****************************************************************************/ - -#include "cmt.h" -#include "run_adding.h" - -/*****************************************************************************/ - -namespace sledgehammer { - - enum { - port_rate = 0, - port_mod_infl = 1, // modulator influence - port_car_infl = 2, // carrier influence (0 to 1 for compression) - port_modulator = 3, - port_carrier = 4, - port_output = 5, - n_ports = 6 - }; - -/** This plugin imposes the dynamics of one sound onto another. - It can be seen as a brutal compressor with a sidechain, or - as a kind of one-band vocoder. */ - class Plugin : public CMT_PluginInstance { - LADSPA_Data run_adding_gain; - LADSPA_Data running_ms_mod; - LADSPA_Data running_ms_car; // current mean square average - public: - Plugin(const LADSPA_Descriptor *, - unsigned long) - : CMT_PluginInstance(n_ports) {} - - friend void activate(LADSPA_Handle instance); - - template - friend void run(LADSPA_Handle instance, - unsigned long sample_count); - - friend void set_run_adding_gain(LADSPA_Handle instance, - LADSPA_Data new_gain); - }; - - void activate(LADSPA_Handle instance) { - Plugin *pp = (Plugin *) instance; - Plugin &p = *pp; - - p.running_ms_mod = 0; - p.running_ms_car = 0; - } - - template - void run(LADSPA_Handle instance, - unsigned long sample_count) { - - Plugin *pp = (Plugin *) instance; - Plugin &p = *pp; - - LADSPA_Data rate = *pp->m_ppfPorts[port_rate]; - LADSPA_Data mod_infl = *pp->m_ppfPorts[port_mod_infl]; - LADSPA_Data car_infl = *pp->m_ppfPorts[port_car_infl]; - LADSPA_Data * modptr = pp->m_ppfPorts[port_modulator]; - LADSPA_Data * carptr = pp->m_ppfPorts[port_carrier]; - LADSPA_Data * out = pp->m_ppfPorts[port_output]; - - for ( unsigned long i = 0; i < sample_count ; ++i ) { - LADSPA_Data mod = *(modptr++); - LADSPA_Data car = *(carptr++); - - p.running_ms_mod = p.running_ms_mod*(1-rate) + (mod*mod)*rate; - p.running_ms_car = p.running_ms_car*(1-rate) + (car*car)*rate; - - LADSPA_Data rms_mod = sqrt(p.running_ms_mod); - LADSPA_Data rms_car = sqrt(p.running_ms_car); - - LADSPA_Data outsig = car; - - if (rms_car>0) - outsig *= ((rms_car-0.5)*car_infl+0.5)/rms_car; - - outsig *= ((rms_mod-0.5)*mod_infl+0.5); - - write_output(out, outsig ,p.run_adding_gain); - } - } - - void set_run_adding_gain(LADSPA_Handle instance, - LADSPA_Data new_gain) { - ((Plugin *) instance)->run_adding_gain = new_gain; - } - - void - initialise() { - - CMT_Descriptor * d = new CMT_Descriptor - (1848, - "sledgehammer", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Dynamic Sledgehammer", - CMT_MAKER("Nathaniel Virgo"), - CMT_COPYRIGHT("2002", "Nathaniel Virgo"), - NULL, - CMT_Instantiate, - activate, - run, - run, - set_run_adding_gain, - NULL); - - d->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Rate", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_MIDDLE), - 0.00001, - 0.001); - d->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Modulator influence", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_0), - -1, - 1); - d->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Carrier influence", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_BOUNDED_ABOVE - | LADSPA_HINT_DEFAULT_1), - -1, - 1); - d->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Modulator"); - d->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Carrier"); - d->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - - registerNewPluginDescriptor(d); - - } - -} // end of namespace - -/*****************************************************************************/ - -/* EOF */ - - - - - diff --git a/plugins/LadspaEffect/cmt/src/syndrum.cpp b/plugins/LadspaEffect/cmt/src/syndrum.cpp deleted file mode 100644 index 0ff2e9b3941..00000000000 --- a/plugins/LadspaEffect/cmt/src/syndrum.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* syndrum.cpp - - SynDrum - Drum Synthesizer - Copyright (c) 1999, 2000 David A. Bartold - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include -#include -#include "cmt.h" - -#define PORT_OUT 0 -#define PORT_TRIGGER 1 -#define PORT_VELOCITY 2 -#define PORT_FREQ 3 -#define PORT_RESONANCE 4 -#define PORT_RATIO 5 - -#define NUM_PORTS 6 - -#ifndef PI -#define PI 3.14159265358979 -#endif - -class SynDrum : public CMT_PluginInstance { - LADSPA_Data sample_rate; - - LADSPA_Data spring_vel; - LADSPA_Data spring_pos; - LADSPA_Data env; - - int last_trigger; - -public: - SynDrum(const LADSPA_Descriptor *, - unsigned long s_rate) - : CMT_PluginInstance(NUM_PORTS), - sample_rate(s_rate), - spring_vel(0.0F), - spring_pos(0.0F), - env(0.0F) { - } - - ~SynDrum() { - } - - static void - activate(LADSPA_Handle Instance) { - SynDrum *syndrum = (SynDrum*) Instance; - syndrum->spring_vel = 0.0F; - syndrum->spring_pos = 0.0F; - syndrum->env = 0.0F; - syndrum->last_trigger = 0; - } - - static void - run(LADSPA_Handle Instance, - unsigned long SampleCount) { - SynDrum *syndrum = (SynDrum*) Instance; - unsigned long i; - int trigger; - LADSPA_Data freq_shift; - LADSPA_Data factor; - LADSPA_Data res; - - trigger = *syndrum->m_ppfPorts[PORT_TRIGGER] > 0.0; - if (trigger == 1 && syndrum->last_trigger == 0) - { - syndrum->spring_vel = *syndrum->m_ppfPorts[PORT_VELOCITY]; - syndrum->env = *syndrum->m_ppfPorts[PORT_VELOCITY]; - } - syndrum->last_trigger = trigger; - - factor = 2.0 * PI / syndrum->sample_rate; - freq_shift = *syndrum->m_ppfPorts[PORT_FREQ] * - *syndrum->m_ppfPorts[PORT_RATIO]; - res = pow (0.05, 1.0 / (syndrum->sample_rate * *syndrum->m_ppfPorts[PORT_RESONANCE])); - - for (i = 0; i < SampleCount; i++) - { - LADSPA_Data cur_freq; - - cur_freq = *syndrum->m_ppfPorts[PORT_FREQ] + - (syndrum->env * freq_shift); - cur_freq *= factor; - syndrum->spring_vel -= syndrum->spring_pos * cur_freq; - syndrum->spring_pos += syndrum->spring_vel * cur_freq; - syndrum->spring_vel *= res; - syndrum->env *= res; - - syndrum->m_ppfPorts[PORT_OUT][i] = syndrum->spring_pos; - } - } -}; - - -static LADSPA_PortDescriptor g_psPortDescriptors[] = -{ - LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT -}; - -static const char * const g_psPortNames[] = -{ - "Out", - "Trigger", - "Velocity", - "Frequency (Hz)", - "Resonance", - "Frequency Ratio" -}; - -static LADSPA_PortRangeHint g_psPortRangeHints[] = -{ - /* Hints, Lower bound, Upper bound */ - { 0, 0.0, 0.0 }, - { LADSPA_HINT_TOGGLED, 0.0, 0.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 10.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 20000.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.001, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 10.0 } -}; - -void -initialise_syndrum() { - CMT_Descriptor * psDescriptor; - - psDescriptor = new CMT_Descriptor - (1223, - "syndrum", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Syn Drum", - CMT_MAKER("David A. Bartold"), - CMT_COPYRIGHT("1999, 2000", "David A. Bartold"), - NULL, - CMT_Instantiate, - SynDrum::activate, - SynDrum::run, - NULL, - NULL, - NULL); - - for (int i = 0; i < NUM_PORTS; i++) - psDescriptor->addPort( - g_psPortDescriptors[i], - g_psPortNames[i], - g_psPortRangeHints[i].HintDescriptor, - g_psPortRangeHints[i].LowerBound, - g_psPortRangeHints[i].UpperBound); - - registerNewPluginDescriptor(psDescriptor); -} diff --git a/plugins/LadspaEffect/cmt/src/utils.h b/plugins/LadspaEffect/cmt/src/utils.h deleted file mode 100644 index 120567546e1..00000000000 --- a/plugins/LadspaEffect/cmt/src/utils.h +++ /dev/null @@ -1,103 +0,0 @@ -/* utils.h - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -#ifndef CMT_UTILS_INCLUDED -#define CMT_UTILS_INCLUDED - -/*****************************************************************************/ - -#include -#include - -/*****************************************************************************/ - -#include "ladspa_types.h" - -/*****************************************************************************/ - -/** The drag setting is arranged so that the gain drops by a factor of - 1e3 (60dB) in the time specified. This is a bit of an arbitrary - value but ties in with what the user will probably expect from - his/her experience with reverb units. */ -inline LADSPA_Data -calculate60dBDrag(const LADSPA_Data fTime, - const LADSPA_Data fSampleRate) { - if (fTime <= 0) - return 0; - else - return pow(1e3, -1 / (fTime * fSampleRate)); -} - -/*****************************************************************************/ - -inline LADSPA_Data -BOUNDED_BELOW(const LADSPA_Data fData, - const LADSPA_Data fLowerBound) { - if (fData <= fLowerBound) - return fLowerBound; - else - return fData; -} - -inline LADSPA_Data BOUNDED_ABOVE(const LADSPA_Data fData, - const LADSPA_Data fUpperBound) { - if (fData >= fUpperBound) - return fUpperBound; - else - return fData; -} - -inline LADSPA_Data -BOUNDED(const LADSPA_Data fData, - const LADSPA_Data fLowerBound, - const LADSPA_Data fUpperBound) { - if (fData <= fLowerBound) - return fLowerBound; - else if (fData >= fUpperBound) - return fUpperBound; - else - return fData; -} - -/*****************************************************************************/ - -/* Take a reading from a normal RV. The algorithm works by repeated - sampling of the uniform distribution, the lQuality variable giving - the number of samples. */ -inline double -sampleNormalDistribution(const double dMean, - const double dStandardDeviation, - const long lQuality = 12) { - - double dValue = 0; - for (long lIter = 0; lIter < lQuality; lIter++) - dValue += rand(); - - double dSampleFromNormal01 = (dValue / RAND_MAX) - (lQuality * 0.5); - - return dMean + dStandardDeviation * dSampleFromNormal01; -} - -/*****************************************************************************/ - -#endif - -/* EOF */ diff --git a/plugins/LadspaEffect/cmt/src/vcf303.cpp b/plugins/LadspaEffect/cmt/src/vcf303.cpp deleted file mode 100644 index 734850ec691..00000000000 --- a/plugins/LadspaEffect/cmt/src/vcf303.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* vcf303.cpp - - VCF 303 - TB-303 Resonant Filter - Copyright (c) 1998 Andy Sloane - Copyright (c) 1999, 2000 David A. Bartold - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - - -#include -#include -#include "cmt.h" - -#define PORT_IN 0 -#define PORT_OUT 1 -#define PORT_TRIGGER 2 -#define PORT_CUTOFF 3 -#define PORT_RESONANCE 4 -#define PORT_ENV_MOD 5 -#define PORT_DECAY 6 - -#define NUM_PORTS 7 - -#ifndef PI -#define PI 3.14159265358979 -#endif - -class Vcf303 : public CMT_PluginInstance { - LADSPA_Data sample_rate; - - LADSPA_Data d1, d2, c0; - int last_trigger; - int envpos; - -public: - Vcf303(const LADSPA_Descriptor *, - unsigned long s_rate) - : CMT_PluginInstance(NUM_PORTS), - sample_rate(s_rate), - d1(0.0), d2(0.0), c0(0.0), - last_trigger(0), - envpos(0) { - } - - ~Vcf303() { - } - - static void - activate(LADSPA_Handle Instance) { - Vcf303 *vcf303 = (Vcf303*) Instance; - - vcf303->d1 = 0.0; - vcf303->d2 = 0.0; - vcf303->c0 = 0.0; - vcf303->last_trigger = 0; - vcf303->envpos = 0; - } - - static inline void - recalc_a_b_c (Vcf303 *filter, - LADSPA_Data e0, - LADSPA_Data c0, - LADSPA_Data resonance, - LADSPA_Data *a, - LADSPA_Data *b, - LADSPA_Data *c) { - LADSPA_Data whopping, k; - - whopping = e0 + c0; - k = exp (-whopping / resonance); - - *a = 2.0 * cos (2.0 * whopping) * k; - *b = -k * k; - *c = (1.0 - *a - *b) * 0.2; - } - - static void - run(LADSPA_Handle Instance, - unsigned long SampleCount) { - Vcf303 *vcf303 = (Vcf303*) Instance; - unsigned long i; - LADSPA_Data e0, d, a, b, c; - LADSPA_Data decay, resonance; - LADSPA_Data **ports; - int trigger; - - /* Update vars given envmod, cutoff, and reso. */ - ports = vcf303->m_ppfPorts; - e0 = exp (5.613 - 0.8 * *ports[PORT_ENV_MOD] + 2.1553 * - *ports[PORT_CUTOFF] - 0.7696 * (1.0 - *ports[PORT_RESONANCE])); - e0 *= PI / vcf303->sample_rate; - - trigger = (*ports[PORT_TRIGGER] > 0.0); - if (trigger == 1 && vcf303->last_trigger == 0) - { - LADSPA_Data e1; - - e1 = exp (6.109 + 1.5876 * *ports[PORT_ENV_MOD] + 2.1553 * - *ports[PORT_CUTOFF] - 1.2 * (1.0 - *ports[PORT_RESONANCE])); - e1 *= PI / vcf303->sample_rate; - vcf303->c0 = e1 - e0; - } - vcf303->last_trigger = trigger; - - /* Update decay given envdecay. */ - d = 0.2 + (2.3 * *ports[PORT_DECAY]); - d *= vcf303->sample_rate; - d = pow (0.1, 1.0 / d); - decay = pow (d, 64); - - /* Update resonance. */ - resonance = exp (-1.20 + 3.455 * *ports[PORT_RESONANCE]); - - recalc_a_b_c (vcf303, e0, vcf303->c0, resonance, &a, &b, &c); - - for (i = 0; i < SampleCount; i++) - { - LADSPA_Data sample; - - sample = a * vcf303->d1 + b * vcf303->d2 + c * ports[PORT_IN][i]; - ports[PORT_OUT][i] = sample; - - vcf303->d2 = vcf303->d1; - vcf303->d1 = sample; - - vcf303->envpos++; - if (vcf303->envpos >= 64) - { - vcf303->envpos = 0; - vcf303->c0 *= decay; - recalc_a_b_c (vcf303, e0, vcf303->c0, resonance, &a, &b, &c); - } - } - } -}; - - -static LADSPA_PortDescriptor g_psPortDescriptors[] = -{ - LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT, - LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, - LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT -}; - -static const char * const g_psPortNames[] = -{ - "In", - "Out", - "Trigger", - "Cutoff", - "Resonance", - "Envelope Modulation", - "Decay" -}; - -static LADSPA_PortRangeHint g_psPortRangeHints[] = -{ - /* Hints, Lower bound, Upper bound */ - { 0, 0.0, 0.0 }, - { 0, 0.0, 0.0 }, - { LADSPA_HINT_TOGGLED, 0.0, 0.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, - { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 } -}; - -void -initialise_vcf303() { - CMT_Descriptor * psDescriptor; - - psDescriptor = new CMT_Descriptor - (1224, - "vcf303", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "VCF 303", - CMT_MAKER("David A. Bartold"), - CMT_COPYRIGHT("1998-2000", "Andy Sloane, David A. Bartold"), - NULL, - CMT_Instantiate, - Vcf303::activate, - Vcf303::run, - NULL, - NULL, - NULL); - - for (int i = 0; i < NUM_PORTS; i++) - psDescriptor->addPort( - g_psPortDescriptors[i], - g_psPortNames[i], - g_psPortRangeHints[i].HintDescriptor, - g_psPortRangeHints[i].LowerBound, - g_psPortRangeHints[i].UpperBound); - - registerNewPluginDescriptor(psDescriptor); -} diff --git a/plugins/LadspaEffect/cmt/src/wshape_sine.cpp b/plugins/LadspaEffect/cmt/src/wshape_sine.cpp deleted file mode 100644 index 07eab074f88..00000000000 --- a/plugins/LadspaEffect/cmt/src/wshape_sine.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* wshape_sine.cpp - - Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) - 2000-2002 Richard W.E. Furse. The author may be contacted at - richard@muse.demon.co.uk. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public Licence as - published by the Free Software Foundation; either version 2 of the - Licence, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA. */ - -/*****************************************************************************/ - -#include -#include - -/*****************************************************************************/ - -#include "cmt.h" - -/*****************************************************************************/ - -#define WSS_CONTROL 0 -#define WSS_INPUT 1 -#define WSS_OUTPUT 2 - -/** This plugin applies a gain to a mono signal. */ -class SineWaveshaper : public CMT_PluginInstance { -public: - - SineWaveshaper(const LADSPA_Descriptor *, - unsigned long) - : CMT_PluginInstance(3) { - } - - friend void runSineWaveshaper(LADSPA_Handle Instance, - unsigned long SampleCount); - -}; - -/*****************************************************************************/ - -void -runSineWaveshaper(LADSPA_Handle Instance, - unsigned long SampleCount) { - - SineWaveshaper * poProcessor = (SineWaveshaper *)Instance; - - LADSPA_Data * pfInput = poProcessor->m_ppfPorts[WSS_INPUT]; - LADSPA_Data * pfOutput = poProcessor->m_ppfPorts[WSS_OUTPUT]; - LADSPA_Data fLimit = *(poProcessor->m_ppfPorts[WSS_CONTROL]); - LADSPA_Data fOneOverLimit = 1 / fLimit; - - for (unsigned long lSampleIndex = 0; - lSampleIndex < SampleCount; - lSampleIndex++) - *(pfOutput++) = fLimit * sin(*(pfInput++) * fOneOverLimit); -} - -/*****************************************************************************/ - -void -initialise_wshape_sine() { - - CMT_Descriptor * psDescriptor; - - psDescriptor = new CMT_Descriptor - (1097, - "wshape_sine", - LADSPA_PROPERTY_HARD_RT_CAPABLE, - "Wave Shaper (Sine-Based)", - CMT_MAKER("Richard W.E. Furse"), - CMT_COPYRIGHT("2000-2002", "Richard W.E. Furse"), - NULL, - CMT_Instantiate, - NULL, - runSineWaveshaper, - NULL, - NULL, - NULL); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - "Limiting Amplitude", - (LADSPA_HINT_BOUNDED_BELOW - | LADSPA_HINT_LOGARITHMIC - | LADSPA_HINT_DEFAULT_1), - 0, - 0); - psDescriptor->addPort - (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - "Input"); - psDescriptor->addPort - (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - "Output"); - registerNewPluginDescriptor(psDescriptor); -} - -/*****************************************************************************/ - -/* EOF */ diff --git a/plugins/Lv2Effect/CMakeLists.txt b/plugins/Lv2Effect/CMakeLists.txt new file mode 100644 index 00000000000..915751797d1 --- /dev/null +++ b/plugins/Lv2Effect/CMakeLists.txt @@ -0,0 +1,9 @@ +IF(LMMS_HAVE_LV2) + INCLUDE_DIRECTORIES(${LV2_INCLUDE_DIRS}) + INCLUDE_DIRECTORIES(${LILV_INCLUDE_DIRS}) + INCLUDE_DIRECTORIES(${SUIL_INCLUDE_DIRS}) + INCLUDE(BuildPlugin) + BUILD_PLUGIN(lv2effect Lv2Effect.cpp Lv2FxControls.cpp Lv2FxControlDialog.cpp Lv2Effect.h Lv2FxControls.h Lv2FxControlDialog.h + MOCFILES Lv2Effect.h Lv2FxControls.h Lv2FxControlDialog.h + EMBEDDED_RESOURCES logo.png) +ENDIF(LMMS_HAVE_LV2) diff --git a/plugins/Lv2Effect/Lv2Effect.cpp b/plugins/Lv2Effect/Lv2Effect.cpp new file mode 100644 index 00000000000..dd0c4c44ff9 --- /dev/null +++ b/plugins/Lv2Effect/Lv2Effect.cpp @@ -0,0 +1,117 @@ +/* + * Lv2Effect.cpp - implementation of LV2 effect + * + * Copyright (c) 2018-2020 Johannes Lorenz + * + * 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. + * + */ + +#include "Lv2Effect.h" + +#include +#include + +#include "Lv2SubPluginFeatures.h" + +#include "embed.h" +#include "plugin_export.h" + + + + +extern "C" +{ + +Plugin::Descriptor PLUGIN_EXPORT lv2effect_plugin_descriptor = +{ + STRINGIFY(PLUGIN_NAME), + "LV2", + QT_TRANSLATE_NOOP("PluginBrowser", + "plugin for using arbitrary LV2-effects inside LMMS."), + "Johannes Lorenz ", + 0x0100, + Plugin::Effect, + new PluginPixmapLoader("logo"), + nullptr, + new Lv2SubPluginFeatures(Plugin::Effect) +}; + +} + + + + +Lv2Effect::Lv2Effect(Model* parent, const Descriptor::SubPluginFeatures::Key *key) : + Effect(&lv2effect_plugin_descriptor, parent, key), + m_controls(this, key->attributes["uri"]), + m_tmpOutputSmps(Engine::mixer()->framesPerPeriod()) +{ +} + + + + +bool Lv2Effect::processAudioBuffer(sampleFrame *buf, const fpp_t frames) +{ + if (!isEnabled() || !isRunning()) { return false; } + Q_ASSERT(frames <= static_cast(m_tmpOutputSmps.size())); + + m_controls.copyBuffersFromLmms(buf, frames); + m_controls.copyModelsFromLmms(); + +// m_pluginMutex.lock(); + m_controls.run(frames); +// m_pluginMutex.unlock(); + + m_controls.copyModelsToLmms(); + m_controls.copyBuffersToLmms(m_tmpOutputSmps.data(), frames); + + double outSum = .0; + bool corrupt = wetLevel() < 0; // #3261 - if w < 0, bash w := 0, d := 1 + const float d = corrupt ? 1 : dryLevel(); + const float w = corrupt ? 0 : wetLevel(); + for(fpp_t f = 0; f < frames; ++f) + { + buf[f][0] = d * buf[f][0] + w * m_tmpOutputSmps[f][0]; + buf[f][1] = d * buf[f][1] + w * m_tmpOutputSmps[f][1]; + double l = static_cast(buf[f][0]); + double r = static_cast(buf[f][1]); + outSum += l*l + r*r; + } + checkGate(outSum / frames); + + return isRunning(); +} + + + + +extern "C" +{ + +// necessary for getting instance out of shared lib +PLUGIN_EXPORT Plugin *lmms_plugin_main(Model *_parent, void *_data) +{ + using KeyType = Plugin::Descriptor::SubPluginFeatures::Key; + Lv2Effect* eff = new Lv2Effect(_parent, static_cast(_data)); + if (!eff->isValid()) { delete eff; eff = nullptr; } + return eff; +} + +} diff --git a/plugins/Lv2Effect/Lv2Effect.h b/plugins/Lv2Effect/Lv2Effect.h new file mode 100644 index 00000000000..77792d428a1 --- /dev/null +++ b/plugins/Lv2Effect/Lv2Effect.h @@ -0,0 +1,54 @@ +/* + * Lv2Effect.h - implementation of LV2 effect + * + * Copyright (c) 2018-2020 Johannes Lorenz + * + * 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 LV2_EFFECT_H +#define LV2_EFFECT_H + +#include "Effect.h" +#include "Lv2FxControls.h" + +class Lv2Effect : public Effect +{ + Q_OBJECT + +public: + /* + initialization + */ + Lv2Effect(Model* parent, const Descriptor::SubPluginFeatures::Key* _key); + //! Must be checked after ctor or reload + bool isValid() const { return m_controls.isValid(); } + + bool processAudioBuffer( sampleFrame* buf, const fpp_t frames ) override; + EffectControls* controls() override { return &m_controls; } + + Lv2FxControls* lv2Controls() { return &m_controls; } + const Lv2FxControls* lv2Controls() const { return &m_controls; } + +private: + Lv2FxControls m_controls; + std::vector m_tmpOutputSmps; +}; + +#endif // LMMS_HAVE_LV2 diff --git a/plugins/Lv2Effect/Lv2FxControlDialog.cpp b/plugins/Lv2Effect/Lv2FxControlDialog.cpp new file mode 100644 index 00000000000..9a77171d6df --- /dev/null +++ b/plugins/Lv2Effect/Lv2FxControlDialog.cpp @@ -0,0 +1,72 @@ +/* + * Lv2FxControlDialog.cpp - Lv2FxControlDialog implementation + * + * Copyright (c) 2018-2020 Johannes Lorenz + * + * 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. + * + */ + +#include "Lv2FxControlDialog.h" + +#include +#include +#include + +#include "Lv2Effect.h" +#include "Lv2FxControls.h" + + +Lv2FxControlDialog::Lv2FxControlDialog(Lv2FxControls *controls) : + EffectControlDialog(controls), + Lv2ViewBase(this, controls) +{ + if (m_reloadPluginButton) { + connect(m_reloadPluginButton, &QPushButton::clicked, + this, [this](){ lv2Controls()->reloadPlugin(); }); + } + if (m_toggleUIButton) { + connect(m_toggleUIButton, &QPushButton::toggled, + this, [this](){ toggleUI(); }); + } + if (m_helpButton) { + connect(m_helpButton, &QPushButton::toggled, + this, [this](bool visible){ toggleHelp(visible); }); + } + // for Effects, modelChanged only goes to the top EffectView + // we need to call it manually + modelChanged(); +} + + + + +Lv2FxControls *Lv2FxControlDialog::lv2Controls() +{ + return static_cast(m_effectControls); +} + + + + +void Lv2FxControlDialog::modelChanged() +{ + Lv2ViewBase::modelChanged(lv2Controls()); +} + + diff --git a/plugins/Lv2Effect/Lv2FxControlDialog.h b/plugins/Lv2Effect/Lv2FxControlDialog.h new file mode 100644 index 00000000000..3abdb300d4d --- /dev/null +++ b/plugins/Lv2Effect/Lv2FxControlDialog.h @@ -0,0 +1,47 @@ +/* + * Lv2FxControlDialog.h - Lv2FxControlDialog implementation + * + * Copyright (c) 2018-2020 Johannes Lorenz + * + * 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 LV2_FX_CONTROL_DIALOG_H +#define LV2_FX_CONTROL_DIALOG_H + +#include "EffectControlDialog.h" +#include "Lv2ViewBase.h" + +class Lv2FxControls; + + +class Lv2FxControlDialog : public EffectControlDialog, public Lv2ViewBase +{ + Q_OBJECT + +public: + Lv2FxControlDialog(Lv2FxControls *controls); + +private: + Lv2FxControls *lv2Controls(); + void modelChanged() override; +}; + + +#endif diff --git a/plugins/Lv2Effect/Lv2FxControls.cpp b/plugins/Lv2Effect/Lv2FxControls.cpp new file mode 100644 index 00000000000..a5733fec670 --- /dev/null +++ b/plugins/Lv2Effect/Lv2FxControls.cpp @@ -0,0 +1,104 @@ +/* + * Lv2FxControls.cpp - Lv2FxControls implementation + * + * Copyright (c) 2018-2020 Johannes Lorenz + * + * 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. + * + */ + +#include "Lv2FxControls.h" + +#include + +#include "Engine.h" +#include "Lv2Effect.h" +#include "Lv2FxControlDialog.h" +#include "Lv2Proc.h" + + + + +Lv2FxControls::Lv2FxControls(class Lv2Effect *effect, const QString& uri) : + EffectControls(effect), + Lv2ControlBase(this, uri) +{ + if (isValid()) + { + connect(Engine::mixer(), &Mixer::sampleRateChanged, + this, [this](){Lv2ControlBase::reloadPlugin();}); + } +} + + + + +void Lv2FxControls::saveSettings(QDomDocument &doc, QDomElement &that) +{ + Lv2ControlBase::saveSettings(doc, that); +} + + + + +void Lv2FxControls::loadSettings(const QDomElement &that) +{ + Lv2ControlBase::loadSettings(that); +} + + + + +int Lv2FxControls::controlCount() +{ + return static_cast(Lv2ControlBase::controlCount()); +} + + + + +EffectControlDialog *Lv2FxControls::createView() +{ + return new Lv2FxControlDialog(this); +} + + + + +void Lv2FxControls::changeControl() // TODO: what is that? +{ + // engine::getSong()->setModified(); +} + + + + +DataFile::Types Lv2FxControls::settingsType() +{ + return DataFile::EffectSettings; +} + + + + +void Lv2FxControls::setNameFromFile(const QString &name) +{ + effect()->setDisplayName(name); +} + + diff --git a/plugins/Lv2Effect/Lv2FxControls.h b/plugins/Lv2Effect/Lv2FxControls.h new file mode 100644 index 00000000000..e5449a4f7fe --- /dev/null +++ b/plugins/Lv2Effect/Lv2FxControls.h @@ -0,0 +1,61 @@ +/* + * Lv2FxControls.h - Lv2FxControls implementation + * + * Copyright (c) 2018-2020 Johannes Lorenz + * + * 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 LV2_FX_CONTROLS_H +#define LV2_FX_CONTROLS_H + +#include "EffectControls.h" +#include "Lv2ControlBase.h" + +class Lv2Effect; + + +class Lv2FxControls : public EffectControls, public Lv2ControlBase +{ + Q_OBJECT +public: + Lv2FxControls(Lv2Effect *effect, const QString &uri); + + void saveSettings(QDomDocument &_doc, QDomElement &_parent) override; + void loadSettings(const QDomElement &that) override; + inline QString nodeName() const override + { + return Lv2ControlBase::nodeName(); + } + + int controlCount() override; + EffectControlDialog *createView() override; + +private slots: + void changeControl(); + +private: + DataFile::Types settingsType() override; + void setNameFromFile(const QString &name) override; + + friend class Lv2FxControlDialog; + friend class Lv2Effect; +}; + +#endif diff --git a/plugins/Lv2Effect/logo.png b/plugins/Lv2Effect/logo.png new file mode 100644 index 00000000000..c423ccea458 Binary files /dev/null and b/plugins/Lv2Effect/logo.png differ diff --git a/plugins/Lv2Instrument/CMakeLists.txt b/plugins/Lv2Instrument/CMakeLists.txt new file mode 100644 index 00000000000..290bd84e82e --- /dev/null +++ b/plugins/Lv2Instrument/CMakeLists.txt @@ -0,0 +1,7 @@ +IF(LMMS_HAVE_LV2) + INCLUDE_DIRECTORIES(${LV2_INCLUDE_DIRS}) + INCLUDE_DIRECTORIES(${LILV_INCLUDE_DIRS}) + INCLUDE_DIRECTORIES(${SUIL_INCLUDE_DIRS}) + INCLUDE(BuildPlugin) + BUILD_PLUGIN(lv2instrument Lv2Instrument.cpp Lv2Instrument.h MOCFILES Lv2Instrument.h EMBEDDED_RESOURCES logo.png) +ENDIF(LMMS_HAVE_LV2) diff --git a/plugins/Lv2Instrument/Lv2Instrument.cpp b/plugins/Lv2Instrument/Lv2Instrument.cpp new file mode 100644 index 00000000000..3eba7cdcc00 --- /dev/null +++ b/plugins/Lv2Instrument/Lv2Instrument.cpp @@ -0,0 +1,304 @@ +/* + * Lv2Instrument.cpp - implementation of LV2 instrument + * + * Copyright (c) 2018-2020 Johannes Lorenz + * + * 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. + * + */ + +#include "Lv2Instrument.h" + +#include +#include + +#include "Engine.h" +#include "InstrumentPlayHandle.h" +#include "InstrumentTrack.h" +#include "Lv2SubPluginFeatures.h" +#include "Mixer.h" +#include "StringPairDrag.h" +#include "Clipboard.h" + +#include "embed.h" +#include "plugin_export.h" + + + + +extern "C" +{ + +Plugin::Descriptor PLUGIN_EXPORT lv2instrument_plugin_descriptor = +{ + STRINGIFY(PLUGIN_NAME), + "LV2", + QT_TRANSLATE_NOOP("PluginBrowser", + "plugin for using arbitrary LV2 instruments inside LMMS."), + "Johannes Lorenz ", + 0x0100, + Plugin::Instrument, + new PluginPixmapLoader("logo"), + nullptr, + new Lv2SubPluginFeatures(Plugin::Instrument) +}; + +} + + + + +/* + Lv2Instrument +*/ + + +Lv2Instrument::Lv2Instrument(InstrumentTrack *instrumentTrackArg, + Descriptor::SubPluginFeatures::Key *key) : + Instrument(instrumentTrackArg, &lv2instrument_plugin_descriptor, key), + Lv2ControlBase(this, key->attributes["uri"]) +{ + if (Lv2ControlBase::isValid()) + { +#ifdef LV2_INSTRUMENT_USE_MIDI + for (int i = 0; i < NumKeys; ++i) { m_runningNotes[i] = 0; } +#endif + connect(instrumentTrack()->pitchRangeModel(), SIGNAL(dataChanged()), + this, SLOT(updatePitchRange()), Qt::DirectConnection); + connect(Engine::mixer(), &Mixer::sampleRateChanged, + this, [this](){Lv2ControlBase::reloadPlugin();}); + + // now we need a play-handle which cares for calling play() + InstrumentPlayHandle *iph = + new InstrumentPlayHandle(this, instrumentTrackArg); + Engine::mixer()->addPlayHandle(iph); + } +} + + + + +Lv2Instrument::~Lv2Instrument() +{ + Engine::mixer()->removePlayHandlesOfTypes(instrumentTrack(), + PlayHandle::TypeNotePlayHandle | + PlayHandle::TypeInstrumentPlayHandle); +} + + + + +bool Lv2Instrument::isValid() const { return Lv2ControlBase::isValid(); } + + + + +void Lv2Instrument::saveSettings(QDomDocument &doc, QDomElement &that) +{ + Lv2ControlBase::saveSettings(doc, that); +} + + + + +void Lv2Instrument::loadSettings(const QDomElement &that) +{ + Lv2ControlBase::loadSettings(that); +} + + + + +void Lv2Instrument::loadFile(const QString &file) +{ + Lv2ControlBase::loadFile(file); +} + + + + +#ifdef LV2_INSTRUMENT_USE_MIDI +bool Lv2Instrument::handleMidiEvent( + const MidiEvent &event, const TimePos &time, f_cnt_t offset) +{ + // this function can be called from GUI threads while the plugin is running + // handleMidiInputEvent will use a thread-safe ringbuffer + handleMidiInputEvent(event, time, offset); + return true; +} +#endif + + + + +// not yet working +#ifndef LV2_INSTRUMENT_USE_MIDI +void Lv2Instrument::playNote(NotePlayHandle *nph, sampleFrame *) +{ +} +#endif + + + + +void Lv2Instrument::play(sampleFrame *buf) +{ + copyModelsFromLmms(); + + fpp_t fpp = Engine::mixer()->framesPerPeriod(); + + run(fpp); + + copyModelsToLmms(); + copyBuffersToLmms(buf, fpp); + + instrumentTrack()->processAudioBuffer(buf, fpp, nullptr); +} + + + + +PluginView *Lv2Instrument::instantiateView(QWidget *parent) +{ + return new Lv2InsView(this, parent); +} + + + + +void Lv2Instrument::updatePitchRange() +{ + qDebug() << "Lmms: Cannot update pitch range for lv2 plugin:" + "not implemented yet"; +} + + + + +QString Lv2Instrument::nodeName() const +{ + return Lv2ControlBase::nodeName(); +} + + + + +DataFile::Types Lv2Instrument::settingsType() +{ + return DataFile::InstrumentTrackSettings; +} + + + + +void Lv2Instrument::setNameFromFile(const QString &name) +{ + instrumentTrack()->setName(name); +} + + + + +/* + Lv2InsView +*/ + + +Lv2InsView::Lv2InsView(Lv2Instrument *_instrument, QWidget *_parent) : + InstrumentView(_instrument, _parent), + Lv2ViewBase(this, _instrument) +{ + setAutoFillBackground(true); + if (m_reloadPluginButton) { + connect(m_reloadPluginButton, &QPushButton::clicked, + this, [this](){ this->castModel()->reloadPlugin();} ); + } + if (m_toggleUIButton) { + connect(m_toggleUIButton, &QPushButton::toggled, + this, [this](){ toggleUI(); }); + } + if (m_helpButton) { + connect(m_helpButton, &QPushButton::toggled, + this, [this](bool visible){ toggleHelp(visible); }); + } +} + + + + +void Lv2InsView::dragEnterEvent(QDragEnterEvent *_dee) +{ + // For mimeType() and MimeType enum class + using namespace Clipboard; + + void (QDragEnterEvent::*reaction)(void) = &QDragEnterEvent::ignore; + + if (_dee->mimeData()->hasFormat( mimeType( MimeType::StringPair ))) + { + const QString txt = + _dee->mimeData()->data( mimeType( MimeType::StringPair ) ); + if (txt.section(':', 0, 0) == "pluginpresetfile") { + reaction = &QDragEnterEvent::acceptProposedAction; + } + } + + (_dee->*reaction)(); +} + + + + +void Lv2InsView::dropEvent(QDropEvent *_de) +{ + const QString type = StringPairDrag::decodeKey(_de); + const QString value = StringPairDrag::decodeValue(_de); + if (type == "pluginpresetfile") + { + castModel()->loadFile(value); + _de->accept(); + return; + } + _de->ignore(); +} + + + + +void Lv2InsView::modelChanged() +{ + Lv2ViewBase::modelChanged(castModel()); +} + + + + +extern "C" +{ + +// necessary for getting instance out of shared lib +PLUGIN_EXPORT Plugin *lmms_plugin_main(Model *_parent, void *_data) +{ + using KeyType = Plugin::Descriptor::SubPluginFeatures::Key; + Lv2Instrument* ins = new Lv2Instrument( + static_cast(_parent), + static_cast(_data )); + if (!ins->isValid()) { delete ins; ins = nullptr; } + return ins; +} + +} diff --git a/plugins/Lv2Instrument/Lv2Instrument.h b/plugins/Lv2Instrument/Lv2Instrument.h new file mode 100644 index 00000000000..60575d42689 --- /dev/null +++ b/plugins/Lv2Instrument/Lv2Instrument.h @@ -0,0 +1,119 @@ +/* + * Lv2Instrument.h - implementation of LV2 instrument + * + * Copyright (c) 2018-2020 Johannes Lorenz + * + * 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 LV2_INSTRUMENT_H +#define LV2_INSTRUMENT_H + +#include + +#include "Instrument.h" +#include "InstrumentView.h" +#include "Note.h" +#include "Lv2ControlBase.h" +#include "Lv2ViewBase.h" + +// whether to use MIDI vs playHandle +// currently only MIDI works +#define LV2_INSTRUMENT_USE_MIDI + +class QPushButton; + + +class Lv2Instrument : public Instrument, public Lv2ControlBase +{ + Q_OBJECT +public: + /* + initialization + */ + Lv2Instrument(InstrumentTrack *instrumentTrackArg, + Descriptor::SubPluginFeatures::Key* key); + ~Lv2Instrument() override; + //! Must be checked after ctor or reload + bool isValid() const; + + /* + load/save + */ + void saveSettings(QDomDocument &doc, QDomElement &that) override; + void loadSettings(const QDomElement &that) override; + void loadFile(const QString &file) override; + + /* + realtime funcs + */ + bool hasNoteInput() const override { return Lv2ControlBase::hasNoteInput(); } +#ifdef LV2_INSTRUMENT_USE_MIDI + bool handleMidiEvent(const MidiEvent &event, + const TimePos &time = TimePos(), f_cnt_t offset = 0) override; +#else + void playNote(NotePlayHandle *nph, sampleFrame *) override; +#endif + void play(sampleFrame *buf) override; + + /* + misc + */ + Flags flags() const override + { +#ifdef LV2_INSTRUMENT_USE_MIDI + return IsSingleStreamed | IsMidiBased; +#else + return IsSingleStreamed; +#endif + } + PluginView *instantiateView(QWidget *parent) override; + +private slots: + void updatePitchRange(); + +private: + QString nodeName() const override; + DataFile::Types settingsType() override; + void setNameFromFile(const QString &name) override; + +#ifdef LV2_INSTRUMENT_USE_MIDI + int m_runningNotes[NumKeys]; +#endif + + friend class Lv2InsView; +}; + + +class Lv2InsView : public InstrumentView, public Lv2ViewBase +{ + Q_OBJECT +public: + Lv2InsView(Lv2Instrument *_instrument, QWidget *_parent); + +protected: + void dragEnterEvent(QDragEnterEvent *_dee) override; + void dropEvent(QDropEvent *_de) override; + +private: + void modelChanged() override; +}; + + +#endif // LV2_INSTRUMENT_H diff --git a/plugins/Lv2Instrument/logo.png b/plugins/Lv2Instrument/logo.png new file mode 100644 index 00000000000..c423ccea458 Binary files /dev/null and b/plugins/Lv2Instrument/logo.png differ diff --git a/plugins/MidiExport/MidiExport.cpp b/plugins/MidiExport/MidiExport.cpp index 1860527c10e..929f7d38cf5 100644 --- a/plugins/MidiExport/MidiExport.cpp +++ b/plugins/MidiExport/MidiExport.cpp @@ -35,6 +35,7 @@ #include "lmms_math.h" #include "TrackContainer.h" #include "BBTrack.h" +#include "DataFile.h" #include "InstrumentTrack.h" #include "LocaleHelper.h" @@ -47,7 +48,7 @@ Plugin::Descriptor PLUGIN_EXPORT midiexport_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "MIDI Export", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "Filter for exporting MIDI-files from LMMS" ), "Mohamed Abdel Maksoud and " "Hyunjin Song ", diff --git a/plugins/MidiImport/MidiImport.cpp b/plugins/MidiImport/MidiImport.cpp index 3646975a29a..97c81460424 100644 --- a/plugins/MidiImport/MidiImport.cpp +++ b/plugins/MidiImport/MidiImport.cpp @@ -31,6 +31,7 @@ #include #include +#include #include "MidiImport.h" #include "TrackContainer.h" @@ -42,7 +43,7 @@ #include "Instrument.h" #include "GuiApplication.h" #include "MainWindow.h" -#include "MidiTime.h" +#include "TimePos.h" #include "debug.h" #include "Song.h" @@ -64,7 +65,7 @@ Plugin::Descriptor PLUGIN_EXPORT midiimport_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "MIDI Import", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "Filter for importing MIDI-files into LMMS" ), "Tobias Doerffel ", 0x0100, @@ -159,7 +160,7 @@ class smfMidiCC AutomationTrack * at; AutomationPattern * ap; - MidiTime lastPos; + TimePos lastPos; smfMidiCC & create( TrackContainer* tc, QString tn ) { @@ -186,21 +187,20 @@ class smfMidiCC } - smfMidiCC & putValue( MidiTime time, AutomatableModel * objModel, float value ) + smfMidiCC & putValue( TimePos time, AutomatableModel * objModel, float value ) { if( !ap || time > lastPos + DefaultTicksPerBar ) { - MidiTime pPos = MidiTime( time.getBar(), 0 ); + TimePos pPos = TimePos( time.getBar(), 0 ); ap = dynamic_cast( - at->createTCO(0) ); - ap->movePosition( pPos ); + at->createTCO(pPos)); ap->addObject( objModel ); } lastPos = time; time = time - ap->startPosition(); ap->putValue( time, value, false ); - ap->changeLength( MidiTime( time.getBar() + 1, 0 ) ); + ap->changeLength( TimePos( time.getBar() + 1, 0 ) ); return *this; } @@ -278,16 +278,15 @@ class smfMidiChannel void splitPatterns() { Pattern * newPattern = nullptr; - MidiTime lastEnd(0); + TimePos lastEnd(0); p->rearrangeAllNotes(); for (auto n : p->notes()) { if (!newPattern || n->pos() > lastEnd + DefaultTicksPerBar) { - MidiTime pPos = MidiTime(n->pos().getBar(), 0); - newPattern = dynamic_cast(it->createTCO(0)); - newPattern->movePosition(pPos); + TimePos pPos = TimePos(n->pos().getBar(), 0); + newPattern = dynamic_cast(it->createTCO(pPos)); } lastEnd = n->pos() + n->length(); @@ -305,7 +304,7 @@ class smfMidiChannel bool MidiImport::readSMF( TrackContainer* tc ) { - + const int MIDI_CC_COUNT = 128 + 1; // 0-127 (128) + pitch bend const int preTrackSteps = 2; QProgressDialog pd( TrackContainer::tr( "Importing MIDI-file..." ), TrackContainer::tr( "Cancel" ), 0, preTrackSteps, gui->mainWindow() ); @@ -315,10 +314,7 @@ bool MidiImport::readSMF( TrackContainer* tc ) pd.setValue( 0 ); - std::stringstream stream; - QByteArray arr = readAllData(); - stream.str(std::string(arr.constData(), arr.size())); - + std::istringstream stream(readAllData().toStdString()); Alg_seq_ptr seq = new Alg_seq(stream, true); seq->convert_to_beats(); @@ -326,8 +322,12 @@ bool MidiImport::readSMF( TrackContainer* tc ) pd.setValue( 1 ); // 128 CC + Pitch Bend - smfMidiCC ccs[129]; - smfMidiChannel chs[256]; + smfMidiCC ccs[MIDI_CC_COUNT]; + + // channels can be set out of 256 range + // using unordered_map should fix most invalid loads and crashes while loading + std::unordered_map chs; + // NOTE: unordered_map::operator[] creates a new element if none exists MeterModel & timeSigMM = Engine::getSong()->getTimeSigModel(); AutomationTrack * nt = dynamic_cast( @@ -407,7 +407,7 @@ bool MidiImport::readSMF( TrackContainer* tc ) Alg_track_ptr trk = seq->track( t ); pd.setValue( t + preTrackSteps ); - for( int c = 0; c < 129; c++ ) + for( int c = 0; c < MIDI_CC_COUNT; c++ ) { ccs[c].clear(); } @@ -423,7 +423,10 @@ bool MidiImport::readSMF( TrackContainer* tc ) if( evt->is_update() ) { QString attr = evt->get_attribute(); - if( attr == "tracknames" && evt->get_update_type() == 's' ) { + // seqnames is a track0 identifier (see allegro code) + if (attr == (t == 0 ? "seqnames" : "tracknames") + && evt->get_update_type() == 's') + { trackName = evt->get_string_value(); handled = true; } @@ -444,7 +447,7 @@ bool MidiImport::readSMF( TrackContainer* tc ) printf( "\n" ); } } - else if( evt->is_note() && evt->chan < 256 ) + else if (evt->is_note()) { smfMidiChannel * ch = chs[evt->chan].create( tc, trackName ); Alg_note_ptr noteEvt = dynamic_cast( evt ); @@ -558,28 +561,26 @@ bool MidiImport::readSMF( TrackContainer* tc ) delete seq; - for( int c=0; c < 256; ++c ) + for( auto& c: chs ) { - if (chs[c].hasNotes) + if (c.second.hasNotes) { - chs[c].splitPatterns(); + c.second.splitPatterns(); } - else if (chs[c].it) + else if (c.second.it) { printf(" Should remove empty track\n"); // must delete trackView first - but where is it? //tc->removeTrack( chs[c].it ); //it->deleteLater(); } - } - - // Set channel 10 to drums as per General MIDI's orders - if( chs[9].hasNotes && chs[9].it_inst && chs[9].isSF2 ) - { - // AFAIK, 128 should be the standard bank for drums in SF2. - // If not, this has to be made configurable. - chs[9].it_inst->childModel( "bank" )->setValue( 128 ); - chs[9].it_inst->childModel( "patch" )->setValue( 0 ); + // Set channel 10 to drums as per General MIDI's orders + if (c.first % 16l == 9 /* channel 10 */ + && c.second.hasNotes && c.second.it_inst && c.second.isSF2) + { + c.second.it_inst->childModel("bank")->setValue(128); + c.second.it_inst->childModel("patch")->setValue(0); + } } return true; diff --git a/plugins/MidiImport/portsmf/algrd_internal.h b/plugins/MidiImport/portsmf/algrd_internal.h index 3b77adc4cd2..7e3ac88522b 100644 --- a/plugins/MidiImport/portsmf/algrd_internal.h +++ b/plugins/MidiImport/portsmf/algrd_internal.h @@ -1,4 +1,5 @@ -/* algread_internal.h -- interface between allegro.cpp and allegrord.cpp */ - -Alg_error alg_read(std::istream &file, Alg_seq_ptr new_seq); - +/* algread_internal.h -- interface between allegro.cpp and allegrord.cpp */ + +Alg_error alg_read(std::istream &file, Alg_seq_ptr new_seq, + double *offset_ptr = NULL); + diff --git a/plugins/MidiImport/portsmf/allegro.cpp b/plugins/MidiImport/portsmf/allegro.cpp index 3f7b84073a5..5664e910eca 100644 --- a/plugins/MidiImport/portsmf/allegro.cpp +++ b/plugins/MidiImport/portsmf/allegro.cpp @@ -9,7 +9,7 @@ 04 apr 03 -- fixed bug in add_track that caused infinite loop */ -#include "debug.h" +#include "assert.h" #include "stdlib.h" #include "stdio.h" #include "string.h" @@ -25,13 +25,15 @@ using namespace std; #define STREQL(x, y) (strcmp(x, y) == 0) #define MAX(x, y) ((x) > (y) ? (x) : (y)) +#define ROUND(x) ((int) ((x) + 0.5)) // 4311 is type cast ponter to long warning // 4996 is warning against strcpy // 4267 is size_t to long warning //#pragma warning(disable: 4311 4996 4267) Alg_atoms symbol_table; -Serial_buffer Alg_track::ser_buf; // declare the static variable +Serial_read_buffer Alg_track::ser_read_buf; // declare the static variables +Serial_write_buffer Alg_track::ser_write_buf; bool within(double d1, double d2, double epsilon) { @@ -52,12 +54,10 @@ void Alg_atoms::expand() { maxlen = (maxlen + 5); // extra growth for small sizes maxlen += (maxlen >> 2); // add 25% - char **new_atoms = new Alg_attribute[maxlen]; + Alg_attribute *new_atoms = new Alg_attribute[maxlen]; // now do copy - if (atoms) { - memcpy(new_atoms, atoms, len * sizeof(Alg_attribute)); - delete[] atoms; - } + memcpy(new_atoms, atoms, len * sizeof(Alg_attribute)); + if (atoms) delete[] atoms; atoms = new_atoms; } @@ -81,6 +81,7 @@ Alg_attribute Alg_atoms::insert_new(const char *name, char attr_type) Alg_attribute Alg_atoms::insert_attribute(Alg_attribute attr) { + // should use hash algorithm for (int i = 0; i < len; i++) { if (STREQL(attr, atoms[i])) { return atoms[i]; @@ -123,7 +124,7 @@ void Alg_parameter::show() printf("%s:%s", attr_name(), s); break; case 'i': - printf("%s:%d", attr_name(), (int) i); + printf("%s:%ld", attr_name(), i); break; case 'l': printf("%s:%s", attr_name(), (l ? "t" : "f")); @@ -143,7 +144,8 @@ Alg_parameter::~Alg_parameter() } -void Alg_parameters::insert_real(Alg_parameters **list, char *name, double r) +void Alg_parameters::insert_real(Alg_parameters **list, const char *name, + double r) { Alg_parameters_ptr a = new Alg_parameters(*list); *list = a; @@ -153,7 +155,8 @@ void Alg_parameters::insert_real(Alg_parameters **list, char *name, double r) } -void Alg_parameters::insert_string(Alg_parameters **list, char *name, char *s) +void Alg_parameters::insert_string(Alg_parameters **list, const char *name, + const char *s) { Alg_parameters_ptr a = new Alg_parameters(*list); *list = a; @@ -164,7 +167,8 @@ void Alg_parameters::insert_string(Alg_parameters **list, char *name, char *s) } -void Alg_parameters::insert_integer(Alg_parameters **list, char *name, long i) +void Alg_parameters::insert_integer(Alg_parameters **list, const char *name, + long i) { Alg_parameters_ptr a = new Alg_parameters(*list); *list = a; @@ -174,7 +178,8 @@ void Alg_parameters::insert_integer(Alg_parameters **list, char *name, long i) } -void Alg_parameters::insert_logical(Alg_parameters **list, char *name, bool l) +void Alg_parameters::insert_logical(Alg_parameters **list, const char *name, + bool l) { Alg_parameters_ptr a = new Alg_parameters(*list); *list = a; @@ -184,7 +189,8 @@ void Alg_parameters::insert_logical(Alg_parameters **list, char *name, bool l) } -void Alg_parameters::insert_atom(Alg_parameters **list, char *name, char *s) +void Alg_parameters::insert_atom(Alg_parameters **list, const char *name, + const char *s) { Alg_parameters_ptr a = new Alg_parameters(*list); *list = a; @@ -194,7 +200,8 @@ void Alg_parameters::insert_atom(Alg_parameters **list, char *name, char *s) } -Alg_parameters *Alg_parameters::remove_key(Alg_parameters **list, const char *name) +Alg_parameters *Alg_parameters::remove_key(Alg_parameters **list, + const char *name) { while (*list) { if (STREQL((*list)->parm.attr_name(), name)) { @@ -209,12 +216,12 @@ Alg_parameters *Alg_parameters::remove_key(Alg_parameters **list, const char *na } -Alg_parameter_ptr Alg_parameters::find(Alg_attribute *attr) +Alg_parameter_ptr Alg_parameters::find(Alg_attribute attr) { assert(attr); Alg_parameters_ptr temp = this; while (temp) { - if (temp->parm.attr == *attr) { + if (temp->parm.attr == attr) { return &(temp->parm); } } @@ -226,9 +233,9 @@ int Alg_event::get_type_code() { if (!is_note()) { const char* attr = get_attribute(); - if (STREQL(attr, "gate")) // volume change + if (STREQL(attr, "gater")) // volume change return ALG_GATE; - if (STREQL(attr, "bend")) // pitch bend + if (STREQL(attr, "bendr")) // pitch bend return ALG_BEND; if (strncmp(attr, "control", 7) == 0) // control change // note that midi control changes have attributes of the form @@ -237,15 +244,15 @@ int Alg_event::get_type_code() // We don't check for decimal numbers in the range 0-127, so any // attribute that begins with "control" is an ALG_CONTROL: return ALG_CONTROL; - if (STREQL(attr, "program")) // program change + if (STREQL(attr, "programi")) // program change return ALG_PROGRAM; - if (STREQL(attr, "pressure")) // pressure change + if (STREQL(attr, "pressurer")) // pressure change return ALG_PRESSURE; - if (STREQL(attr, "keysig")) // key signature + if (STREQL(attr, "keysigi")) // key signature return ALG_KEYSIG; - if (STREQL(attr, "timesig_num")) // time signature numerator + if (STREQL(attr, "timesig_numi")) // time signature numerator return ALG_TIMESIG_NUM; - if (STREQL(attr, "timesig_den")) // time signature denominator + if (STREQL(attr, "timesig_deni")) // time signature denominator return ALG_TIMESIG_DEN; return ALG_OTHER; } @@ -258,7 +265,7 @@ void Alg_event::set_parameter(Alg_parameter_ptr new_parameter) Alg_parameter_ptr parm; if (is_note()) { Alg_note_ptr note = (Alg_note_ptr) this; - parm = note->parameters->find(&(new_parameter->attr)); + parm = note->parameters->find(new_parameter->attr); if (!parm) { note->parameters = new Alg_parameters(note->parameters); parm = &(note->parameters->parm); @@ -271,7 +278,7 @@ void Alg_event::set_parameter(Alg_parameter_ptr new_parameter) } -void Alg_event::set_string_value(char *a, char *value) +void Alg_event::set_string_value(const char *a, const char *value) { assert(a); // must be non-null Alg_attribute attr = symbol_table.insert_string(a); @@ -284,7 +291,7 @@ void Alg_event::set_string_value(char *a, char *value) } -void Alg_event::set_real_value(char *a, double value) +void Alg_event::set_real_value(const char *a, double value) { assert(a); // must be non-null // attr is like a, but it has the type code prefixed for @@ -300,7 +307,7 @@ void Alg_event::set_real_value(char *a, double value) } -void Alg_event::set_logical_value(char *a, bool value) +void Alg_event::set_logical_value(const char *a, bool value) { assert(a); // must be non-null Alg_attribute attr = symbol_table.insert_string(a); @@ -313,7 +320,7 @@ void Alg_event::set_logical_value(char *a, bool value) } -void Alg_event::set_integer_value(char *a, long value) +void Alg_event::set_integer_value(const char *a, long value) { assert(a); // must be non-null Alg_attribute attr = symbol_table.insert_string(a); @@ -326,7 +333,7 @@ void Alg_event::set_integer_value(char *a, long value) } -void Alg_event::set_atom_value(char *a, char *value) +void Alg_event::set_atom_value(const char *a, const char *value) { assert(a); // must be non-null Alg_attribute attr = symbol_table.insert_string(a); @@ -402,18 +409,18 @@ void Alg_event::set_duration(double d) } -bool Alg_event::has_attribute(char *a) +bool Alg_event::has_attribute(const char *a) { assert(is_note()); assert(a); // must be non-null Alg_note* note = (Alg_note *) this; Alg_attribute attr = symbol_table.insert_string(a); - Alg_parameter_ptr parm = note->parameters->find(&attr); + Alg_parameter_ptr parm = note->parameters->find(attr); return parm != NULL; } -char Alg_event::get_attribute_type(char *a) +char Alg_event::get_attribute_type(const char *a) { assert(is_note()); assert(a); @@ -421,66 +428,66 @@ char Alg_event::get_attribute_type(char *a) } -char *Alg_event::get_string_value(char *a, char *value) +const char *Alg_event::get_string_value(const char *a, const char *value) { assert(is_note()); assert(a); // must be non-null Alg_note* note = (Alg_note *) this; Alg_attribute attr = symbol_table.insert_string(a); assert(a[0] == 's'); // must be of type string - Alg_parameter_ptr parm = note->parameters->find(&attr); + Alg_parameter_ptr parm = note->parameters->find(attr); if (parm) return parm->s; return value; } -double Alg_event::get_real_value(char *a, double value) +double Alg_event::get_real_value(const char *a, double value) { assert(is_note()); assert(a); Alg_note* note = (Alg_note *) this; Alg_attribute attr = symbol_table.insert_string(a); assert(a[0] == 'r'); // must be of type real - Alg_parameter_ptr parm = note->parameters->find(&attr); + Alg_parameter_ptr parm = note->parameters->find(attr); if (parm) return parm->r; return value; } -bool Alg_event::get_logical_value(char *a, bool value) +bool Alg_event::get_logical_value(const char *a, bool value) { assert(is_note()); assert(a); Alg_note* note = (Alg_note *) this; Alg_attribute attr = symbol_table.insert_string(a); assert(a[0] == 'l'); // must be of type logical - Alg_parameter_ptr parm = note->parameters->find(&attr); + Alg_parameter_ptr parm = note->parameters->find(attr); if (parm) return parm->l; return value; } -long Alg_event::get_integer_value(char *a, long value) +long Alg_event::get_integer_value(const char *a, long value) { assert(is_note()); assert(a); Alg_note* note = (Alg_note *) this; Alg_attribute attr = symbol_table.insert_string(a); assert(a[0] == 'i'); // must be of type integer - Alg_parameter_ptr parm = note->parameters->find(&attr); + Alg_parameter_ptr parm = note->parameters->find(attr); if (parm) return parm->i; return value; } -char *Alg_event::get_atom_value(char *a, char *value) +const char *Alg_event::get_atom_value(const char *a, const char *value) { assert(is_note()); assert(a); Alg_note* note = (Alg_note *) this; Alg_attribute attr = symbol_table.insert_string(a); assert(a[0] == 'a'); // must be of type atom - Alg_parameter_ptr parm = note->parameters->find(&attr); + Alg_parameter_ptr parm = note->parameters->find(attr); if (parm) return parm->a; // if default is a string, convert to an atom (unique // string in symbol table) and return it @@ -489,7 +496,7 @@ char *Alg_event::get_atom_value(char *a, char *value) } -void Alg_event::delete_attribute(char *a) +void Alg_event::delete_attribute(const char *a) { assert(is_note()); Alg_note* note = (Alg_note *) this; @@ -514,12 +521,12 @@ char Alg_event::get_update_type() } -char *Alg_event::get_string_value() +const char *Alg_event::get_string_value() { assert(is_update()); Alg_update* update = (Alg_update *) this; assert(get_update_type() == 's'); - return update->parameter.a; + return update->parameter.s; } @@ -550,7 +557,7 @@ long Alg_event::get_integer_value() } -char *Alg_event::get_atom_value() +const char *Alg_event::get_atom_value() { assert(is_update()); Alg_update* update = (Alg_update *) this; @@ -566,7 +573,7 @@ bool Alg_event::overlap(double t, double len, bool all) return true; if (all && is_note()) { double dur = ((Alg_note_ptr) this)->dur; - // note ends within region + // note overlaps with region if (time < t && time + dur - ALG_EPS > t) return true; } @@ -601,9 +608,9 @@ Alg_note::~Alg_note() void Alg_note::show() { - printf("Alg_note: time %g, chan %d, dur %g, key %d, " + printf("Alg_note: time %g, chan %ld, dur %g, key %ld, " "pitch %g, loud %g, attributes ", - time, (int) chan, dur, (int) key, pitch, loud); + time, chan, dur, key, pitch, loud); Alg_parameters_ptr parms = parameters; while (parms) { parms->parm.show(); @@ -670,6 +677,8 @@ Alg_event_ptr Alg_events::uninsert(long index) { assert(0 <= index && index < len); Alg_event_ptr event = events[index]; + //printf("memmove: %x from %x (%d)\n", events + index, events + index + 1, + // sizeof(Alg_event_ptr) * (len - index - 1)); memmove(events + index, events + index + 1, sizeof(Alg_event_ptr) * (len - index - 1)); len--; @@ -695,6 +704,7 @@ void Alg_events::append(Alg_event_ptr event) Alg_events::~Alg_events() { + assert(!in_use); // individual events are not deleted, only the array if (events) { delete[] events; @@ -710,7 +720,7 @@ Alg_event_list::Alg_event_list(Alg_track *owner) } -Alg_event_ptr &Alg_event_list::operator [](int i) +Alg_event_ptr const &Alg_event_list::operator [](int i) { assert(i >= 0 && i < len); return events[i]; @@ -729,8 +739,8 @@ void Alg_event_list::set_start_time(Alg_event *event, double t) // For Alg_track, change the time and move the event to the right place // For Alg_seq, find the track and do the update there - long index = 0, i; - Alg_track_ptr track_ptr = Alg_track_ptr(); + long index = 0, i; + Alg_track_ptr track_ptr = nullptr; if (type == 'e') { // this is an Alg_event_list // make sure the owner has not changed its event set assert(events_owner && @@ -847,7 +857,12 @@ double Alg_time_map::beat_to_time(double beat) return beat; } int i = locate_beat(beat); - if (i == beats.len) { + // case 1: beat is between two time/beat pairs + if (0 < i && i < beats.len) { + mbi = &beats[i - 1]; + mbi1 = &beats[i]; + // case 2: beat is beyond last time/beat pair + } else if (i == beats.len) { if (last_tempo_flag) { return beats[i - 1].time + (beat - beats[i - 1].beat) / last_tempo; @@ -858,11 +873,11 @@ double Alg_time_map::beat_to_time(double beat) mbi = &beats[i - 2]; mbi1 = &beats[i - 1]; } - } else { - mbi = &beats[i - 1]; - mbi1 = &beats[i]; + // case 3: beat is at time 0 + } else /* if (i == 0) */ { + return beats[0].time; } - // whether w extrapolate or interpolate, the math is the same + // whether we extrapolate or interpolate, the math is the same double time_dif = mbi1->time - mbi->time; double beat_dif = mbi1->beat - mbi->beat; return mbi->time + (beat - mbi->beat) * time_dif / beat_dif; @@ -945,6 +960,7 @@ bool Alg_time_map::insert_tempo(double tempo, double beat) // compute difference too diff = diff - old_diff; // apply new_diff to score and beats + i++; while (i < beats.len) { beats[i].time = beats[i].time + diff; i++; @@ -954,6 +970,38 @@ bool Alg_time_map::insert_tempo(double tempo, double beat) } +double Alg_time_map::get_tempo(double beat) +{ + Alg_beat_ptr mbi; + Alg_beat_ptr mbi1; + // if beat < 0, there is probably an error; return something nice anyway + if (beat < 0) return ALG_DEFAULT_BPM / 60.0; + long i = locate_beat(beat); + // this code is similar to beat_to_time() so far, but we want to get + // beyond beat if possible because we want the tempo FOLLOWING beat + // (Consider the case beat == 0.0) + if (i < beats.len && beat >= beats[i].beat) i++; + // case 1: beat is between two time/beat pairs + if (i < beats.len) { + mbi = &beats[i - 1]; + mbi1 = &beats[i]; + // case 2: beat is beyond last time/beat pair + } else /* if (i == beats.len) */ { + if (last_tempo_flag) { + return last_tempo; + } else if (i == 1) { + return ALG_DEFAULT_BPM / 60.0; + } else { + mbi = &beats[i - 2]; + mbi1 = &beats[i - 1]; + } + } + double time_dif = mbi1->time - mbi->time; + double beat_dif = mbi1->beat - mbi->beat; + return beat_dif / time_dif; +} + + bool Alg_time_map::set_tempo(double tempo, double start_beat, double end_beat) { if (start_beat >= end_beat) return false; @@ -975,6 +1023,34 @@ bool Alg_time_map::set_tempo(double tempo, double start_beat, double end_beat) } +bool Alg_time_map::stretch_region(double b0, double b1, double dur) +{ + // find current duration + double t0 = beat_to_time(b0); + double t1 = beat_to_time(b1); + double old_dur = t1 - t0; + if (old_dur <= 0 || dur <= 0) return false; + double scale = dur / old_dur; // larger scale => slower + // insert a beat if necessary at b0 and b1 + insert_beat(t0, b0); + insert_beat(t1, b1); + long start_x = locate_beat(b0); + long stop_x = locate_beat(b1); + double orig_time = beats[start_x].time; + double prev_time = orig_time; + for (int i = start_x + 1; i < beats.len; i++) { + double delta = beats[i].time - orig_time; + if (i <= stop_x) { // change tempo to next Alg_beat + delta *= scale; + } + orig_time = beats[i].time; + prev_time += delta; + beats[i].time = prev_time; + } + return true; +} + + void Alg_time_map::trim(double start, double end, bool units_are_seconds) { // extract the time map from start to end and shift to time zero @@ -1277,22 +1353,22 @@ void Alg_track::serialize(void **buffer, long *bytes) // // The format for a track is given within the Seq format above assert(get_type() == 't'); - ser_buf.init_for_write(); + ser_write_buf.init_for_write(); serialize_track(); - *buffer = ser_buf.to_heap(bytes); + *buffer = ser_write_buf.to_heap(bytes); } void Alg_seq::serialize(void **buffer, long *bytes) { assert(get_type() == 's'); - ser_buf.init_for_write(); + ser_write_buf.init_for_write(); serialize_seq(); - *buffer = ser_buf.to_heap(bytes); + *buffer = ser_write_buf.to_heap(bytes); } -void Serial_buffer::check_buffer(long needed) +void Serial_write_buffer::check_buffer(long needed) { if (len < (ptr - buffer) + needed) { // do we need more space? long new_len = len * 2; // exponential growth is important @@ -1301,9 +1377,11 @@ void Serial_buffer::check_buffer(long needed) // make sure new_len is as big as needed if (needed > new_len) new_len = needed; char *new_buffer = new char[new_len]; // allocate space - memcpy(new_buffer, buffer, len); // copy from old buffer ptr = new_buffer + (ptr - buffer); // relocate ptr to new buffer - delete buffer; // free old buffer + if (len > 0) { // we had a buffer already + memcpy(new_buffer, buffer, len); // copy from old buffer + delete buffer; // free old buffer + } buffer = new_buffer; // update buffer information len = new_len; } @@ -1315,37 +1393,39 @@ void Alg_seq::serialize_seq() int i; // loop counters // we can easily compute how much buffer space we need until we // get to tracks, so expand at least that much - long needed = 48 + 16 * time_map->beats.len + 24 * time_sig.length(); - ser_buf.check_buffer(needed); - ser_buf.set_char('A'); - ser_buf.set_char('L'); - ser_buf.set_char('G'); - ser_buf.set_char('S'); - long length_offset = ser_buf.get_posn(); - ser_buf.set_int32(0); // leave room to come back and write length - ser_buf.set_int32(channel_offset_per_track); - ser_buf.set_int32(units_are_seconds); - ser_buf.set_double(time_map->last_tempo); - ser_buf.set_int32(time_map->last_tempo_flag); - ser_buf.set_int32(time_map->beats.len); + long needed = 64 + 16 * time_map->beats.len + 24 * time_sig.length(); + ser_write_buf.check_buffer(needed); + ser_write_buf.set_char('A'); + ser_write_buf.set_char('L'); + ser_write_buf.set_char('G'); + ser_write_buf.set_char('S'); + long length_offset = ser_write_buf.get_posn(); + ser_write_buf.set_int32(0); // leave room to come back and write length + ser_write_buf.set_int32(channel_offset_per_track); + ser_write_buf.set_int32(units_are_seconds); + ser_write_buf.set_double(beat_dur); + ser_write_buf.set_double(real_dur); + ser_write_buf.set_double(time_map->last_tempo); + ser_write_buf.set_int32(time_map->last_tempo_flag); + ser_write_buf.set_int32(time_map->beats.len); for (i = 0; i < time_map->beats.len; i++) { - ser_buf.set_double(time_map->beats[i].time); - ser_buf.set_double(time_map->beats[i].beat); + ser_write_buf.set_double(time_map->beats[i].time); + ser_write_buf.set_double(time_map->beats[i].beat); } - ser_buf.set_int32(time_sig.length()); - ser_buf.pad(); + ser_write_buf.set_int32(time_sig.length()); + ser_write_buf.pad(); for (i = 0; i < time_sig.length(); i++) { - ser_buf.set_double(time_sig[i].beat); - ser_buf.set_double(time_sig[i].num); - ser_buf.set_double(time_sig[i].den); + ser_write_buf.set_double(time_sig[i].beat); + ser_write_buf.set_double(time_sig[i].num); + ser_write_buf.set_double(time_sig[i].den); } - ser_buf.set_int32(tracks()); - ser_buf.pad(); + ser_write_buf.set_int32(tracks()); + ser_write_buf.pad(); for (i = 0; i < tracks(); i++) { track(i)->serialize_track(); } // do not include ALGS, include padding at end - ser_buf.store_long(length_offset, ser_buf.get_posn() - length_offset); + ser_write_buf.store_long(length_offset, ser_write_buf.get_posn() - length_offset); } @@ -1353,51 +1433,51 @@ void Alg_track::serialize_track() { // to simplify the code, copy from parameter addresses to locals int j; - ser_buf.check_buffer(32); - ser_buf.set_char('A'); - ser_buf.set_char('L'); - ser_buf.set_char('G'); - ser_buf.set_char('T'); - long length_offset = ser_buf.get_posn(); // save location for track length - ser_buf.set_int32(0); // room to write track length - ser_buf.set_int32(units_are_seconds); - ser_buf.set_double(beat_dur); - ser_buf.set_double(real_dur); - ser_buf.set_int32(len); + ser_write_buf.check_buffer(32); + ser_write_buf.set_char('A'); + ser_write_buf.set_char('L'); + ser_write_buf.set_char('G'); + ser_write_buf.set_char('T'); + long length_offset = ser_write_buf.get_posn(); // save location for track length + ser_write_buf.set_int32(0); // room to write track length + ser_write_buf.set_int32(units_are_seconds); + ser_write_buf.set_double(beat_dur); + ser_write_buf.set_double(real_dur); + ser_write_buf.set_int32(len); for (j = 0; j < len; j++) { - ser_buf.check_buffer(24); + ser_write_buf.check_buffer(24); Alg_event *event = (*this)[j]; - ser_buf.set_int32(event->get_selected()); - ser_buf.set_int32(event->get_type()); - ser_buf.set_int32(event->get_identifier()); - ser_buf.set_int32(event->chan); - ser_buf.set_double(event->time); + ser_write_buf.set_int32(event->get_selected()); + ser_write_buf.set_int32(event->get_type()); + ser_write_buf.set_int32(event->get_identifier()); + ser_write_buf.set_int32(event->chan); + ser_write_buf.set_double(event->time); if (event->is_note()) { - ser_buf.check_buffer(20); + ser_write_buf.check_buffer(20); Alg_note *note = (Alg_note *) event; - ser_buf.set_float(note->pitch); - ser_buf.set_float(note->loud); - ser_buf.set_double(note->dur); - long parm_num_offset = ser_buf.get_posn(); + ser_write_buf.set_float(note->pitch); + ser_write_buf.set_float(note->loud); + ser_write_buf.set_double(note->dur); + long parm_num_offset = ser_write_buf.get_posn(); long parm_num = 0; - ser_buf.set_int32(0); // placeholder for no. parameters + ser_write_buf.set_int32(0); // placeholder for no. parameters Alg_parameters_ptr parms = note->parameters; while (parms) { serialize_parameter(&(parms->parm)); parms = parms->next; parm_num++; } - ser_buf.store_long(parm_num_offset, parm_num); + ser_write_buf.store_long(parm_num_offset, parm_num); } else { assert(event->is_update()); Alg_update *update = (Alg_update *) event; serialize_parameter(&(update->parameter)); } - ser_buf.check_buffer(7); // maximum padding possible - ser_buf.pad(); + ser_write_buf.check_buffer(7); // maximum padding possible + ser_write_buf.pad(); } // write length, not including ALGT, including padding at end - ser_buf.store_long(length_offset, ser_buf.get_posn() - length_offset); + ser_write_buf.store_long(length_offset, ser_write_buf.get_posn() - length_offset); } @@ -1406,29 +1486,29 @@ void Alg_track::serialize_parameter(Alg_parameter *parm) // add eight to account for name + zero end-of-string and the // possibility of adding 7 padding bytes long len = strlen(parm->attr_name()) + 8; - ser_buf.check_buffer(len); - ser_buf.set_string(parm->attr_name()); - ser_buf.pad(); + ser_write_buf.check_buffer(len); + ser_write_buf.set_string(parm->attr_name()); + ser_write_buf.pad(); switch (parm->attr_type()) { case 'r': - ser_buf.check_buffer(8); - ser_buf.set_double(parm->r); + ser_write_buf.check_buffer(8); + ser_write_buf.set_double(parm->r); break; case 's': - ser_buf.check_buffer(strlen(parm->s) + 1); - ser_buf.set_string(parm->s); + ser_write_buf.check_buffer(strlen(parm->s) + 1); + ser_write_buf.set_string(parm->s); break; case 'i': - ser_buf.check_buffer(4); - ser_buf.set_int32(parm->i); + ser_write_buf.check_buffer(4); + ser_write_buf.set_int32(parm->i); break; case 'l': - ser_buf.check_buffer(4); - ser_buf.set_int32(parm->l); + ser_write_buf.check_buffer(4); + ser_write_buf.set_int32(parm->l); break; case 'a': - ser_buf.check_buffer(strlen(parm->a) + 1); - ser_buf.set_string(parm->a); + ser_write_buf.check_buffer(strlen(parm->a) + 1); + ser_write_buf.set_string(parm->a); break; } } @@ -1438,55 +1518,69 @@ void Alg_track::serialize_parameter(Alg_parameter *parm) Alg_track *Alg_track::unserialize(void *buffer, long len) { assert(len > 8); - ser_buf.init_for_read(buffer, len); - bool alg = ser_buf.get_char() == 'A' && - ser_buf.get_char() == 'L' && - ser_buf.get_char() == 'G'; - assert(alg); - char c = ser_buf.get_char(); + ser_read_buf.init_for_read(buffer, len); + bool alg = ser_read_buf.get_char() == 'A' && + ser_read_buf.get_char() == 'L' && + ser_read_buf.get_char() == 'G'; + assert(alg); (void)alg; // unused variable + char c = ser_read_buf.get_char(); if (c == 'S') { Alg_seq *seq = new Alg_seq; + ser_read_buf.unget_chars(4); // undo get_char() of A,L,G,S seq->unserialize_seq(); return seq; } else { assert(c == 'T'); Alg_track *track = new Alg_track; + ser_read_buf.unget_chars(4); // undo get_char() of A,L,G,T track->unserialize_track(); return track; } } +//#pragma warning(disable: 4800) // long to bool performance warning + +/* Note: this Alg_seq must have a default initialized Alg_time_map. + * It will be filled in with data from the ser_read_buf buffer. + */ void Alg_seq::unserialize_seq() { - ser_buf.check_input_buffer(28); - long len = ser_buf.get_int32(); - assert(ser_buf.get_len() >= len); - channel_offset_per_track = ser_buf.get_int32(); - units_are_seconds = (bool) ser_buf.get_int32(); - time_map = new Alg_time_map(); - time_map->last_tempo = ser_buf.get_double(); - time_map->last_tempo_flag = (bool) ser_buf.get_int32(); - long beats = ser_buf.get_int32(); - ser_buf.check_input_buffer(beats * 16 + 4); + ser_read_buf.check_input_buffer(48); + bool algs = (ser_read_buf.get_char() == 'A') && + (ser_read_buf.get_char() == 'L') && + (ser_read_buf.get_char() == 'G') && + (ser_read_buf.get_char() == 'S'); + assert(algs); (void)algs; // unused variable + long len = ser_read_buf.get_int32(); + assert(ser_read_buf.get_len() >= len); (void)len; // unused variable + channel_offset_per_track = ser_read_buf.get_int32(); + units_are_seconds = ser_read_buf.get_int32() != 0; + beat_dur = ser_read_buf.get_double(); + real_dur = ser_read_buf.get_double(); + // no need to allocate an Alg_time_map since it's done during initialization + time_map->last_tempo = ser_read_buf.get_double(); + time_map->last_tempo_flag = ser_read_buf.get_int32() != 0; + long beats = ser_read_buf.get_int32(); + ser_read_buf.check_input_buffer(beats * 16 + 4); int i; for (i = 0; i < beats; i++) { - double time = ser_buf.get_double(); - double beat = ser_buf.get_double(); + double time = ser_read_buf.get_double(); + double beat = ser_read_buf.get_double(); time_map->insert_beat(time, beat); // printf("time_map: %g, %g\n", time, beat); } - long time_sig_len = ser_buf.get_int32(); - ser_buf.get_pad(); - ser_buf.check_input_buffer(time_sig_len * 24 + 8); + long time_sig_len = ser_read_buf.get_int32(); + ser_read_buf.get_pad(); + ser_read_buf.check_input_buffer(time_sig_len * 24 + 8); for (i = 0; i < time_sig_len; i++) { - double beat = ser_buf.get_double(); - double num = ser_buf.get_double(); - double den = ser_buf.get_double(); + double beat = ser_read_buf.get_double(); + double num = ser_read_buf.get_double(); + double den = ser_read_buf.get_double(); time_sig.insert(beat, num, den); } - long tracks_num = ser_buf.get_int32(); - ser_buf.get_pad(); + long tracks_num = ser_read_buf.get_int32(); + ser_read_buf.get_pad(); add_track(tracks_num - 1); // create tracks_num tracks for (i = 0; i < tracks_num; i++) { track(i)->unserialize_track(); @@ -1494,40 +1588,41 @@ void Alg_seq::unserialize_seq() // assume seq started at beginning of buffer. len measures // bytes after 'ALGS' header, so add 4 bytes and compare to // current buffer position -- they should agree - assert(ser_buf.get_posn() == len + 4); + assert(ser_read_buf.get_posn() == len + 4); } void Alg_track::unserialize_track() { - ser_buf.check_input_buffer(32); - assert(ser_buf.get_char() == 'A'); - assert(ser_buf.get_char() == 'L'); - assert(ser_buf.get_char() == 'G'); - assert(ser_buf.get_char() == 'T'); - long offset = ser_buf.get_posn(); // stored length does not include 'ALGT' - long bytes = ser_buf.get_int32(); - assert(bytes <= ser_buf.get_len() - offset); - units_are_seconds = (bool) ser_buf.get_int32(); - beat_dur = ser_buf.get_double(); - real_dur = ser_buf.get_double(); - int event_count = ser_buf.get_int32(); + ser_read_buf.check_input_buffer(32); + bool algt = (ser_read_buf.get_char() == 'A') && + (ser_read_buf.get_char() == 'L') && + (ser_read_buf.get_char() == 'G') && + (ser_read_buf.get_char() == 'T'); + assert(algt); (void)algt; // unused variable + long offset = ser_read_buf.get_posn(); // stored length does not include 'ALGT' + long bytes = ser_read_buf.get_int32(); + assert(bytes <= ser_read_buf.get_len() - offset); (void)offset; (void)bytes; // unused variable + units_are_seconds = (bool) ser_read_buf.get_int32(); + beat_dur = ser_read_buf.get_double(); + real_dur = ser_read_buf.get_double(); + int event_count = ser_read_buf.get_int32(); for (int i = 0; i < event_count; i++) { - ser_buf.check_input_buffer(24); - long selected = ser_buf.get_int32(); - char type = (char) ser_buf.get_int32(); - long key = ser_buf.get_int32(); - long channel = ser_buf.get_int32(); - double time = ser_buf.get_double(); + ser_read_buf.check_input_buffer(24); + long selected = ser_read_buf.get_int32(); + char type = (char) ser_read_buf.get_int32(); + long key = ser_read_buf.get_int32(); + long channel = ser_read_buf.get_int32(); + double time = ser_read_buf.get_double(); if (type == 'n') { - ser_buf.check_input_buffer(20); - float pitch = ser_buf.get_float(); - float loud = ser_buf.get_float(); - double dur = ser_buf.get_double(); + ser_read_buf.check_input_buffer(20); + float pitch = ser_read_buf.get_float(); + float loud = ser_read_buf.get_float(); + double dur = ser_read_buf.get_double(); Alg_note *note = create_note(time, channel, key, pitch, loud, dur); - note->set_selected(selected); - long param_num = ser_buf.get_int32(); + note->set_selected(selected != 0); + long param_num = ser_read_buf.get_int32(); int j; // this builds a list of parameters in the correct order // (although order shouldn't matter) @@ -1541,42 +1636,43 @@ void Alg_track::unserialize_track() } else { assert(type == 'u'); Alg_update *update = create_update(time, channel, key); - update->set_selected(selected); + update->set_selected(selected != 0); unserialize_parameter(&(update->parameter)); append(update); } - ser_buf.get_pad(); + ser_read_buf.get_pad(); } - assert(offset + bytes == ser_buf.get_posn()); + assert(offset + bytes == ser_read_buf.get_posn()); } void Alg_track::unserialize_parameter(Alg_parameter_ptr parm_ptr) { - char *attr = ser_buf.get_string(); + Alg_attribute attr = ser_read_buf.get_string(); parm_ptr->attr = symbol_table.insert_string(attr); switch (parm_ptr->attr_type()) { case 'r': - ser_buf.check_input_buffer(8); - parm_ptr->r = ser_buf.get_double(); + ser_read_buf.check_input_buffer(8); + parm_ptr->r = ser_read_buf.get_double(); break; case 's': - parm_ptr->s = heapify(ser_buf.get_string()); + parm_ptr->s = heapify(ser_read_buf.get_string()); break; case 'i': - ser_buf.check_input_buffer(4); - parm_ptr->i = ser_buf.get_int32(); + ser_read_buf.check_input_buffer(4); + parm_ptr->i = ser_read_buf.get_int32(); break; case 'l': - ser_buf.check_input_buffer(4); - parm_ptr->l = (bool) ser_buf.get_int32(); + ser_read_buf.check_input_buffer(4); + parm_ptr->l = ser_read_buf.get_int32() != 0; break; case 'a': - parm_ptr->a = symbol_table.insert_attribute(ser_buf.get_string()); + parm_ptr->a = symbol_table.insert_attribute(ser_read_buf.get_string()); break; } } +//#pragma warning(default: 4800) void Alg_track::set_time_map(Alg_time_map *map) { @@ -1741,9 +1837,10 @@ void Alg_track::paste(double t, Alg_event_list *seq) assert(get_type() == 't'); // seq can be an Alg_event_list, an Alg_track, or an Alg_seq // if it is an Alg_event_list, units_are_seconds must match - bool prev_units_are_seconds = false; + bool prev_units_are_seconds; if (seq->get_type() == 'e') { assert(seq->get_owner()->get_units_are_seconds() == units_are_seconds); + prev_units_are_seconds = seq->get_owner()->get_units_are_seconds(); } else { // make it match Alg_track_ptr tr = (Alg_track_ptr) seq; prev_units_are_seconds = tr->get_units_are_seconds(); @@ -1887,17 +1984,19 @@ Alg_event_list *Alg_track::find(double t, double len, bool all, void Alg_time_sigs::expand() { + assert(maxlen >= len); maxlen = (maxlen + 5); // extra growth for small sizes maxlen += (maxlen >> 2); // add 25% Alg_time_sig_ptr new_time_sigs = new Alg_time_sig[maxlen]; // now do copy memcpy(new_time_sigs, time_sigs, len * sizeof(Alg_time_sig)); - if (time_sigs) delete[] time_sigs; + if (time_sigs) + delete[] time_sigs; time_sigs = new_time_sigs; } -void Alg_time_sigs::insert(double beat, double num, double den) +void Alg_time_sigs::insert(double beat, double num, double den, bool force) { // find insertion point: for (int i = 0; i < len; i++) { @@ -1917,17 +2016,17 @@ void Alg_time_sigs::insert(double beat, double num, double den) // check if redundant with implied initial 4/4 time sig: (i == 0 && num == 4 && den == 4 && within(fmod(beat, 4), 0, ALG_EPS))) { - return; // redundant inserts are ignored here + if (!force) return; // redundant inserts can be ignored here } // make room for new event if (maxlen <= len) expand(); - len++; // insert new event at i memmove(&time_sigs[i + 1], &time_sigs[i], sizeof(Alg_time_sig) * (len - i)); time_sigs[i].beat = beat; time_sigs[i].num = num; time_sigs[i].den = den; + len++; return; } } @@ -1959,55 +2058,225 @@ int Alg_time_sigs::find_beat(double beat) } -void Alg_time_sigs::cut(double start, double end) -{ - // remove time_sig's from start to start+len -- these must be - // in beats (not seconds) - // now rewrite time_sig[]: copy from i_in to i_out (more or less) - int i_in = 0; - int i_out = 0; - // first, figure out where to begin cut region - i_in = find_beat(start); - i_out = i_in; +double Alg_time_sigs::get_bar_len(double beat) +{ + int i = find_beat(beat); + double num = 4.0; + double den = 4.0; + if (i != 0) { + num = time_sigs[i - 1].num; + den = time_sigs[i - 1].den; + } + return 4 * num / den; +} + +void Alg_time_sigs::cut(double start, double end, double dur) +{ + // remove time_sig's from start to end -- these must be + // in beats (not seconds). + // The duration of the whole sequence is dur (beats). + + // If the first bar line after end comes before a time signature + // and does not fall on a bar line, insert a time signature at + // the time of the bar line to retain relative bar line positions + + int i = find_beat(end); + // i is where you would insert a new time sig at beat, + // Case 1: beat coincides with a time sig at i. Time signature + // at beat means that there is a barline at beat, so when beat + // is shifted to start, the relative barline positions are preserved + if (len > 0 && + within(end, time_sigs[i].beat, ALG_EPS)) { + // beat coincides with time signature change, so end is on a barline + /* do nothing */ ; + // Case 2: there is no time signature before end + } else if (i == 0 && (len == 0 || + time_sigs[0].beat > end)) { + // If the next time signature does not fall on a barline, + // then end must not be on a barline, so there is a partial + // measure from end to the next barline. We need + // a time signature there to preserve relative barline + // locations. It may be that the next bar after start is + // due to another time signature, in which case we do not + // need to insert anything. + double measures = end / 4.0; + double imeasures = ROUND(measures); + if (!within(measures, imeasures, ALG_EPS)) { + // start is not on a barline, maybe add one here: + double bar_loc = (int(measures) + 1) * 4.0; + if (bar_loc < dur - ALG_EPS && + (len == 0 || time_sigs[0].beat > bar_loc + ALG_EPS)) { + insert(bar_loc, 4, 4, true); // forced insert + } + } + // This case should never be true because if i == 0, either there + // are no time signatures before beat (Case 2), + // or there is one time signature at beat (Case 1) + } else if (i == 0) { + /* do nothing (might be good to assert(false)) */ ; + // Case 3: i-1 must be the effective time sig position + } else { + // get the time signature in effect at end + Alg_time_sig &tsp = time_sigs[i - 1]; + double beats_per_measure = (tsp.num * 4) / tsp.den; + double measures = (end - tsp.beat) / beats_per_measure; + int imeasures = ROUND(measures); + if (!within(measures, imeasures, ALG_EPS)) { + // end is not on a measure, so we need to insert a time sig + // to force a bar line at the first measure location after + // beat, if any + double bar_loc = tsp.beat + beats_per_measure * (int(measures) + 1); + // insert new time signature at bar_loc + // It will have the same time signature, but the position will + // force a barline to match the barline before the shift + // However, we should not insert a barline if there is a + // time signature earlier than the barline time + if (i < len /* time_sigs[i] is the last one */ && + time_sigs[i].beat < bar_loc - ALG_EPS) { + /* do not insert because there's already a time signature */; + } else if (bar_loc < dur - ALG_EPS) { + insert(bar_loc, tsp.num, tsp.den, true); // forced insert + } + } + // else beat coincides with a barline, so no need for an extra + // time signature to force barline alignment + } + + // Figure out if time signature at start matches + // the time signature at end. If not, we need to insert a + // time signature at end to force the correct time signature + // there. + // Find time signature at start: + double start_num = 4.0; // default if no time signature specified + double start_den = 4.0; + i = find_beat(start); + // A time signature at start would go at index i, so the effective + // time signature prior to start is at i - 1. If i == 0, the default + // time signature is in effect prior to start. + if (i != 0) { + start_num = time_sigs[i - 1].num; + start_den = time_sigs[i - 1].den; + } + // Find the time signature at end: + double end_num = 4.0; // default if no time signature specified + double end_den = 4.0; + int j = find_beat(end); + if (j != 0) { + end_num = time_sigs[j - 1].num; + end_den = time_sigs[j - 1].den; + } + // compare: If meter changes and there is no time signature at end, + // insert a time signature at end + if (end < dur - ALG_EPS && + (start_num != end_num || start_den != end_den) && + (j >= len || !within(time_sigs[j].beat, end, ALG_EPS))) { + insert(end, end_num, end_den, true); + } + + // Remove time signatures from start to end (not including one AT + // end, if there is one there. Be careful with ALG_EPS on that one.) + + // since we may have inserted a time signature, find position again: + int i0 = find_beat(start); + int i1 = i0; // scan to end of cut region - while (i_in < len && time_sigs[i_in].beat < end) { - i_in = i_in + 1; - } - // change time_sig at start if necessary - // there's a time_sig that was skipped if i_in > i_out. - // if that's true and the next time change is at end, we're - // ok because it will be copied, but if the next time change - // is after end, then maybe we should insert a time change - // corresponding to what's in effect at end. We can skip this - // insert if it corresponds to whatever is in effect at start - if (i_in > i_out && i_in < len && - time_sigs[i_in].beat > end + ALG_EPS && - (i_out == 0 || time_sigs[i_out - 1].num != time_sigs[i_in - 1].num || - time_sigs[i_out - 1].den != time_sigs[i_in - 1].den)) { - time_sigs[i_out] = time_sigs[i_in - 1]; - time_sigs[i_out].beat = start; + while (i1 < len && time_sigs[i1].beat < end - ALG_EPS) { + i1++; } // scan from end to len(time_sig) - while (i_in < length()) { - Alg_time_sig &ts = time_sigs[i_in]; - ts.beat = ts.beat - (end - start); - time_sigs[i_out] = ts; - i_in = i_in + 1; - i_out = i_out + 1; + while (i1 < len) { + Alg_time_sig &ts = time_sigs[i1]; + ts.beat -= (end - start); + time_sigs[i0] = ts; + i0++; + i1++; } - len = i_out; + len = i1; } void Alg_time_sigs::trim(double start, double end) { - // remove time_sig's not in [start, start+end) + // remove time_sig's not in [start, end), but retain + // barline positions relative to the notes. This means that + // if the meter (time signature) changes between start and + // end that we need to insert a time signature at start. + // Also, if trim() would cause barlines to move, we need to + // insert a time signature on a barline (timesignatures + // imply the beginning of a bar even if the previous bar + // does not have enough beats. Note that bars do not need + // to have an integer number of beats). + // // units must be in beats (not seconds) - // copy from i_in to i_out as we scan time_sig array - int i_in = 0; - int i_out = 0; + // + // Uses Alg_time_sigs::cut() to avoid writing a special case + double dur = end + 1000; + if (len > 0) { + dur = time_sigs[len - 1].beat + 1000; + } + cut(end, dur, dur); + cut(0, start, dur); + +#ifdef IGNORE_THIS_OLD_CODE // first, skip time signatures up to start - i_in = find_beat(start); + int i = find_beat(start); + // i is where you would insert a new time sig at beat, + // Case 1: beat coincides with a time sig at i. Time signature + // at beat means that there is a barline at beat, so when beat + // is shifted to 0, the relative barline positions are preserved + if (len > 0 && + within(start, time_sigs[i].beat, ALG_EPS)) { + // beat coincides with time signature change, so offset must + // be a multiple of beats + /* do nothing */ ; + // Case 2: there is no time signature before start + } else if (i == 0 && (len == 0 || + time_sigs[0].beat > start)) { + // If the next time signature does not fall on a barline, + // then start must not be on a barline, so there is a partial + // measure from start to the next barline. We need + // a time signature there to preserve relative barline + // locations. It may be that the next bar after start is + // due to another time signature, in which case we do not + // need to insert anything. + double measures = start / 4.0; + double imeasures = ROUND(measures); + if (!within(measures, imeasures, ALG_EPS)) { + // start is not on a barline, maybe add one here: + double bar_loc = (int(measures) + 1) * 4.0; + if (len == 0 || time_sigs[1].beat > bar_loc + ALG_EPS) { + insert(bar_loc, 4, 4, true); + } + } + // This case should never be true because if i == 0, either there + // are no time signatures before beat (Case 2), + // or there is one time signature at beat (Case 1) + } else if (i == 0) { + /* do nothing (might be good to assert(false)) */ ; + // Case 3: i-1 must be the effective time sig position + } else { + i -= 1; // index the time signature in effect at start + Alg_time_sig &tsp = time_sigs[i]; + double beats_per_measure = (tsp.num * 4) / tsp.den; + double measures = (start - tsp.beat) / beats_per_measure; + int imeasures = ROUND(measures); + if (!within(measures, imeasures, ALG_EPS)) { + // beat is not on a measure, so we need to insert a time sig + // to force a bar line at the first measure location after + // beat, if any + double bar_loc = tsp.beat + beats_per_measure * (int(measures) + 1); + // insert new time signature at bar_loc + // It will have the same time signature, but the position will + // force a barline to match the barline before the shift + insert(bar_loc, tsp.num, tsp.den, true); + } + // else beat coincides with a barline, so no need for an extra + // time signature to force barline alignment + } + // since we may have inserted a time signature, find position again: + int i_in = find_beat(start); + int i_out = 0; + // put time_sig at start if necessary // if 0 < i_in < len, then the time sig at i_in is either // at start or after start. @@ -2034,7 +2303,7 @@ void Alg_time_sigs::trim(double start, double end) time_sigs[0].beat = 0.0; i_out = 1; } - // scan to end of cut region + // copy from i_in to i_out as we scan time_sig array to end of cut region while (i_in < len && time_sigs[i_in].beat < end - ALG_EPS) { Alg_time_sig &ts = time_sigs[i_in]; ts.beat = ts.beat - start; @@ -2043,6 +2312,7 @@ void Alg_time_sigs::trim(double start, double end) i_out++; } len = i_out; +#endif } @@ -2052,7 +2322,7 @@ void Alg_time_sigs::paste(double start, Alg_seq *seq) // show(); Alg_time_sigs &from = seq->time_sig; // printf("time_sig::insert from\n"); - from.show(); + // from.show(); // insert time signatures from seq into this time_sigs at start if (len == 0 && from.len == 0) { return; // default applies @@ -2061,6 +2331,13 @@ void Alg_time_sigs::paste(double start, Alg_seq *seq) // remember the time signature at the splice point double num_after_splice = 4; double den_after_splice = 4; // default + double num_before_splice = 4; + double den_before_splice = 4; // default + // this is computed for use in aligning beats after the inserted + // time signatures and duration. It is the position of time signature + // in effect immediately after start (the time signature will be + // before start or at start) + double beat_after_splice = 0.0; // three cases: // 1) time sig at splice is at i-1 // for this, we must have len>0 & i>0 @@ -2073,13 +2350,23 @@ void Alg_time_sigs::paste(double start, Alg_seq *seq) if (len > 0 && i > 0 && ((i < len && time_sigs[i].beat > start + ALG_EPS) || (i == len))) { + // no time_signature at i num_after_splice = time_sigs[i-1].num; den_after_splice = time_sigs[i-1].den; + beat_after_splice = time_sigs[i - 1].beat; + num_before_splice = num_after_splice; + den_before_splice = den_after_splice; } else if (i < len && time_sigs[i].beat <= start + ALG_EPS) { + // time_signature at i is at "start" beats num_after_splice = time_sigs[i].num; den_after_splice = time_sigs[i].den; + beat_after_splice = start; + if (i > 0) { // time signature before start is at i - 1 + num_before_splice = time_sigs[i-1].num; + den_before_splice = time_sigs[i-1].den; + } } - // i is where insert will go, time_sig[i].beat > start + // i is where insert will go, time_sig[i].beat >= start // begin by adding duration to time_sig's at i and above // move time signatures forward by duration of seq double dur = seq->get_beat_dur(); @@ -2089,46 +2376,189 @@ void Alg_time_sigs::paste(double start, Alg_seq *seq) } //printf("time_sig::insert after making space\n"); //show(); - // now insert initial time_signature at start. This may create + // If time signature of "from" is not the effective time signature + // at start, insert a time_signature at start. This may create // an extra measure if seq does not begin on a measure boundary - insert(start, 4, 4); // in case seq uses default starting signature + double num_of_insert = 4.0; + double den_of_insert = 4.0; + double beat_of_insert = 0.0; + /* int first_from_index = 0; // where to start copying from TODO: LMMS commented out unused variable */ + if (from.length() > 0 && from[0].beat < ALG_EPS) { + // there is an initial time signature in "from" + num_of_insert = from[0].num; + den_of_insert = from[0].den; + // since we are handling the first time signature in from, + // we can start copying at index == 1: + /* first_from_index = 1; TODO: LMMS commented out unused variable */ + } + // compare time signatures to see if we need a change at start: + if (num_before_splice != num_of_insert || + den_before_splice != den_of_insert) { + // note that this will overwrite an existing time signature if + // it is within ALG_EPS of start -- this is correct because the + // existing time signature will already be recorded as + // num_after_splice and den_after_splice + insert(start, num_of_insert, den_of_insert); + } //printf("time_sig::insert after 4/4 at start\n"); //show(); // insert time signatures from seq offset by start - for (i = 0; i < from.length(); i++) { - insert(start + from[i].beat, from[i].num, from[i].den); + for (i = 0; i < from.length() && from[i].beat < dur - ALG_EPS; i++) { + num_of_insert = from[i].num; // keep latest time signature info + den_of_insert = from[i].den; + beat_of_insert = from[i].beat; + insert(start + beat_of_insert, num_of_insert, den_of_insert); } //printf("time_sig::insert after pasting in sigs\n"); //show(); - // now insert time signature at end of splice - insert(start + dur, num_after_splice, den_after_splice); + // now insert time signature at end of splice if necessary + // if the time signature changes, we need to insert a time signature + // immediately: + if (num_of_insert != num_after_splice && + den_of_insert != den_after_splice) { + insert(start + dur, num_after_splice, den_after_splice); + num_of_insert = num_after_splice; + den_of_insert = den_after_splice; + beat_of_insert = start + dur; + } + // if the insert had a partial number of measures, we might need an + // additional time signature to realign the barlines after the insert + // To decide, we compare the beat of the first barline on or after + // start before the splice to the beat of the first barline on or + // after start + dur after the splice. In a sense, this is the "same" + // barline, so it should be shifted exactly by dur. + // First, compute the beat of the first barline on or after start: + double beats_per_measure = (num_after_splice * 4) / den_after_splice; + double measures = (start - beat_after_splice) / beats_per_measure; + // Measures might be slightly negative due to rounding. Use max() + // to eliminate any negative rounding error: + int imeasures = int(MAX(measures, 0.0)); + double old_bar_loc = beat_after_splice + (imeasures * beats_per_measure); + if (old_bar_loc < start) old_bar_loc += beats_per_measure; + // now old_bar_loc is the original first bar position after start + // Do similar calculation for position after end after the insertion: + // beats_per_measure already calculated because signatures match + measures = (start + dur - beat_of_insert) / beats_per_measure; + imeasures = int(MAX(measures, 0.0)); + double new_bar_loc = beat_of_insert + (imeasures * beats_per_measure); + if (new_bar_loc < start + dur) new_bar_loc += beats_per_measure; + // old_bar_loc should be shifted by dur: + old_bar_loc += dur; + // now the two bar locations should be equal, but due to rounding, + // they could be off by one measure + double diff = (new_bar_loc - old_bar_loc) + beats_per_measure; + double diff_in_measures = diff / beats_per_measure; + // if diff_in_measures is not (approximately) integer, we need to + // force a barline (time signature) after start + dur to maintain + // the relationship between barliness and notes + if (!within(diff_in_measures, ROUND(diff_in_measures), ALG_EPS)) { + // recall that old_bar_loc is shifted by dur + insert(old_bar_loc, num_after_splice, den_after_splice); + } //printf("time_sig::insert after sig at end of splice\n"); //show(); } -void Alg_time_sigs::insert_beats(double beat, double len) +void Alg_time_sigs::insert_beats(double start, double dur) { - int i; - // find the time_sig entry in effect at t - for (i = 0; i < len; i++) { - if (time_sigs[i].beat < beat + ALG_EPS) { - break; + int i = find_beat(start); + + // time_sigs[i] is after beat and needs to shift + // Compute the time of the first bar at or after beat so that + // a bar can be placed at bar_loc + dur + double tsnum = 4.0; + double tsden = 4.0; + double tsbeat = 0.0; // defaults + + // three cases: + // 1) time sig at splice is at i-1 + // for this, we must have len>0 & i>0 + // two sub-cases: + // A) i < len && time_sig[i].beat > start + // B) i == len + // 2) time_sig at splice is at i + // for this, i < len && time_sig[i].beat ~= start + // 3) time_sig at splice is default 4/4 + if (len > 0 && i > 0 && + ((i < len && time_sigs[i].beat > start + ALG_EPS) || + (i == len))) { + // no time_signature at i + tsnum = time_sigs[i-1].num; + tsden = time_sigs[i-1].den; + tsbeat = time_sigs[i-1].beat; + } else if (i < len && time_sigs[i].beat <= start + ALG_EPS) { + // time_signature at i is at "start" beats + tsnum = time_sigs[i].num; + tsden = time_sigs[i].den; + tsbeat = start; + i++; // we want i to be index of next time signature after start + } + // invariant: i is index of next time signature after start + + // increase beat times from i to len - 1 by dur + for (int j = i; j < len; j++) { + time_sigs[j].beat += dur; + } + + // insert a time signature to maintain bar positions if necessary + double beats_per_measure = (tsnum * 4) / tsden; + double measures = dur / beats_per_measure; // shift distance + int imeasures = ROUND(measures); + if (!within(measures, imeasures, ALG_EPS)) { + // shift is not a whole number of measures, so we may need to insert + // time signature after silence + // compute measures from time signature to next bar after time + measures = (start - tsbeat) / beats_per_measure; + // round up and add to tsbeat to get time of next bar + double bar_loc = tsbeat + beats_per_measure * (int(measures) + 1); + // translate bar_loc by len: + bar_loc += dur; // this is where we want a bar to be, but maybe + // there is a time signature change before bar, in which case we + // should not insert a new time signature + // The next time signature after start is at i if i < len + if (i < len && time_sigs[i].beat < bar_loc) { + /* do not insert */; + } else { + insert(bar_loc, tsnum, tsden); } } - // now, increase beat times by len - for (; i < len; i++) { - time_sigs[i].beat += len; +} + + +double Alg_time_sigs::nearest_beat(double beat) +{ + int i = find_beat(beat); + // i is where we would insert time signature at beat + // case 1: there is no time signature + if (i == 0 && len == 0) { + return ROUND(beat); + // case 2: beat falls approximately on time signature + } else if (i < len && within(time_sigs[i].beat, beat, ALG_EPS)) { + return time_sigs[i].beat; + // case 3: beat is after no time signature and before one + } else if (i == 0) { + double trial_beat = ROUND(beat); + // it is possible that we rounded up past a time signature + if (trial_beat > time_sigs[0].beat - ALG_EPS) { + return time_sigs[0].beat; + } + return trial_beat; } + // case 4: beat is after some time signature + double trial_beat = time_sigs[i - 1].beat + + ROUND(beat - time_sigs[i - 1].beat); + // rounding may advance trial_beat past next time signature: + if (i < len && trial_beat > time_sigs[i].beat - ALG_EPS) { + return time_sigs[i].beat; + } + return trial_beat; } Alg_tracks::~Alg_tracks() { - // Alg_events objects (track data) are not deleted, only the array - if (tracks) { - delete[] tracks; - } + reset(); } @@ -2193,16 +2623,165 @@ void Alg_tracks::reset() // all track events are incorporated into the seq, // so all we need to delete are the arrays of pointers for (int i = 0; i < len; i++) { + // printf("deleting track at %d (%x, this %x) = %x\n", i, &(tracks[i]), + // this, tracks[i]); delete tracks[i]; } if (tracks) delete [] tracks; tracks = NULL; len = 0; - maxlen = 0; // Modified by Ning Hu Nov.19 2002 + maxlen = 0; } -Alg_seq::Alg_seq(const char *filename, bool smf) +void Alg_tracks::set_in_use(bool flag) +{ + for (int i = 0; i < len; i++) { + tracks[i]->in_use = flag; + } +} + + +void Alg_iterator::expand_to(int new_max) +{ + maxlen = new_max; + Alg_pending_event_ptr new_pending_events = new Alg_pending_event[maxlen]; + // now do copy + memcpy(new_pending_events, pending_events, + len * sizeof(Alg_pending_event)); + if (pending_events) { + delete[] pending_events; + } + pending_events = new_pending_events; +} + + +void Alg_iterator::expand() +{ + maxlen = (maxlen + 5); // extra growth for small sizes + maxlen += (maxlen >> 2); // add 25% + expand_to(maxlen); +} + + +Alg_iterator::~Alg_iterator() +{ + if (pending_events) { + delete[] pending_events; + } +} + + +/* in the heap, the children of N are (N+1)*2 and (N+1)*2-1, so + * the parent of N is (N+1)/2-1. This would be easier if arrays + * were 1-based instead of 0-based + */ +#define HEAP_PARENT(loc) ((((loc) + 1) / 2) - 1) +#define FIRST_CHILD(loc) (((loc) * 2) + 1) + +void Alg_iterator::show() +{ + for (int i = 0; i < len; i++) { + Alg_pending_event_ptr p = &(pending_events[i]); + printf(" %d: %p[%ld]@%g on %d\n", i, p->events, p->index, + p->offset, p->note_on); + } +} + + +bool Alg_iterator::earlier(int i, int j) +// see if event i is earlier than event j +{ + // note-offs are scheduled ALG_EPS early so that if a note-off is + // followed immediately with the same timestamp by a note-on (common + // in MIDI files), the note-off will be scheduled first + + double t_i = pending_events[i].time; + double t_j = pending_events[j].time; + + if (t_i < t_j) return true; + // not sure if this case really exists or this is the best rule, but + // we want to give precedence to note-off events + else if (t_i == t_j && pending_events[j].note_on) return true; + return false; +} + + +void Alg_iterator::insert(Alg_events_ptr events, long index, + bool note_on, void *cookie, double offset) +{ + if (len == maxlen) expand(); + pending_events[len].events = events; + pending_events[len].index = index; + pending_events[len].note_on = note_on; + pending_events[len].cookie = cookie; + pending_events[len].offset = offset; + Alg_event_ptr event = (*events)[index]; + pending_events[len].time = (note_on ? event->time : + event->get_end_time() - ALG_EPS) + offset; + /* BEGIN DEBUG * + printf("insert %p=%p[%d] @ %g\n", event, events, index, + pending_events[len].time); + printf(" is_note %d note_on %d time %g dur %g end_time %g offset %g\n", + event->is_note(), note_on, event->time, event->get_duration(), + event->get_end_time(), offset); + } + * END DEBUG */ + int loc = len; + int loc_parent = HEAP_PARENT(loc); + len++; + // sift up: + while (loc > 0 && + earlier(loc, loc_parent)) { + // swap loc with loc_parent + Alg_pending_event temp = pending_events[loc]; + pending_events[loc] = pending_events[loc_parent]; + pending_events[loc_parent] = temp; + loc = loc_parent; + loc_parent = HEAP_PARENT(loc); + } +} + + +bool Alg_iterator::remove_next(Alg_events_ptr &events, long &index, + bool ¬e_on, void *&cookie, + double &offset, double &time) +{ + if (len == 0) return false; // empty! + events = pending_events[0].events; + index = pending_events[0].index; + note_on = pending_events[0].note_on; + offset = pending_events[0].offset; + cookie = pending_events[0].cookie; + offset = pending_events[0].offset; + time = pending_events[0].time; + len--; + pending_events[0] = pending_events[len]; + // sift down + long loc = 0; + long loc_child = FIRST_CHILD(loc); + while (loc_child < len) { + if (loc_child + 1 < len) { + if (earlier(loc_child + 1, loc_child)) { + loc_child++; + } + } + if (earlier(loc_child, loc)) { + Alg_pending_event temp = pending_events[loc]; + pending_events[loc] = pending_events[loc_child]; + pending_events[loc_child] = temp; + loc = loc_child; + loc_child = FIRST_CHILD(loc); + } else { + loc_child = len; + } + } + // printf("After remove:"); show(); + return true; +} + + +Alg_seq::Alg_seq(const char *filename, bool smf, double *offset_ptr) { basic_initialization(); ifstream inf(filename, smf ? ios::binary | ios::in : ios::in); @@ -2212,20 +2791,22 @@ Alg_seq::Alg_seq(const char *filename, bool smf) } if (smf) { error = alg_smf_read(inf, this); + if (offset_ptr) *offset_ptr = 0.0; } else { - error = alg_read(inf, this); + error = alg_read(inf, this, offset_ptr); } inf.close(); } -Alg_seq::Alg_seq(istream &file, bool smf) +Alg_seq::Alg_seq(istream &file, bool smf, double *offset_ptr) { basic_initialization(); if (smf) { error = alg_smf_read(file, this); + if (offset_ptr) *offset_ptr = 0.0; } else { - error = alg_read(file, this); + error = alg_read(file, this, offset_ptr); } } @@ -2284,9 +2865,9 @@ Alg_track_ptr Alg_seq::track(int i) return &(track_list[i]); } +//#pragma warning(disable: 4715) // ok not to return a value here -#pragma GCC diagnostic ignored "-Wreturn-type" // ok not to return a value here -Alg_event_ptr &Alg_seq::operator[](int i) +Alg_event_ptr const &Alg_seq::operator[](int i) { int ntracks = track_list.length(); int tr = 0; @@ -2299,8 +2880,10 @@ Alg_event_ptr &Alg_seq::operator[](int i) } tr++; } - assert(false); // out of bounds + assert(false); // out of bounds + return NULL; } +//#pragma warning(default: 4715) void Alg_seq::convert_to_beats() @@ -2369,11 +2952,12 @@ Alg_seq_ptr Alg_seq::cut(double start, double len, bool all) // return sequence from start to start+len and modify this // sequence by removing that time-span { + double dur = get_dur(); // fix parameters to fall within existing sequence - if (start > get_dur()) return NULL; // nothing to cut + if (start > dur) return NULL; // nothing to cut if (start < 0) start = 0; // can't start before sequence starts - if (start + len > get_dur()) // can't cut after end: - len = get_dur() - start; + if (start + len > dur) // can't cut after end: + len = dur - start; Alg_seq_ptr result = new Alg_seq(); Alg_time_map_ptr map = new Alg_time_map(get_time_map()); @@ -2399,11 +2983,13 @@ Alg_seq_ptr Alg_seq::cut(double start, double len, bool all) // we use len. double ts_start = start; double ts_end = start + len; + double ts_dur = dur; double ts_last_note_off = start + result->last_note_off; if (units_are_seconds) { ts_start = time_map->time_to_beat(ts_start); ts_end = time_map->time_to_beat(ts_end); ts_last_note_off = time_map->time_to_beat(ts_last_note_off); + ts_dur = time_map->time_to_beat(ts_dur); } // result is shifted from start to 0 and has length len, but // time_sig and time_map are copies from this. Adjust time_sig, @@ -2425,9 +3011,9 @@ Alg_seq_ptr Alg_seq::cut(double start, double len, bool all) // we sliced out a portion of each track, so now we need to // slice out the corresponding sections of time_sig and time_map // as well as to adjust the duration. - time_sig.cut(ts_start, ts_end); + time_sig.cut(ts_start, ts_end, ts_dur); time_map->cut(start, len, units_are_seconds); - set_dur(get_dur() - len); + set_dur(dur - len); return result; } @@ -2456,9 +3042,11 @@ void Alg_seq::insert_silence(double t, double len) } else { time_map->insert_beats(t_beats, len_beats); } - if (time_sig.length() > 0) { - time_sig.insert_beats(t_beats, len_beats); - } + time_sig.insert_beats(t_beats, len_beats); + // Final duration is defined to be t + len + whatever was + // in the sequence after t (if any). This translates to + // t + len + max(dur - t, 0) + set_dur(t + len + MAX(get_dur() - t, 0.0)); } @@ -2516,9 +3104,9 @@ Alg_seq *Alg_seq::copy(double start, double len, bool all) void Alg_seq::paste(double start, Alg_seq *seq) { - // insert seq at time; open up space for it - // to manipulate time map, we need units as beats - // save original form so we can convert back if necessary + // Insert seq at time, opening up space for it. + // To manipulate time map, we need units as beats. + // Save original form so we can convert back if necessary. bool units_should_be_seconds = units_are_seconds; bool seq_units_should_be_seconds = seq->get_units_are_seconds(); if (units_are_seconds) { @@ -2595,10 +3183,11 @@ void Alg_seq::clear_track(int track_num, double start, double len, bool all) void Alg_seq::clear(double start, double len, bool all) { // Fix parameters to fall within existing sequence - if (start > get_dur()) return; // nothing to cut + double dur = get_dur(); + if (start > dur) return; // nothing to cut if (start < 0) start = 0; // can't start before sequence starts - if (start + len > get_dur()) // can't cut after end: - len = get_dur() - start; + if (start + len > dur) // can't cut after end: + len = dur - start; for (int i = 0; i < tracks(); i++) clear_track(i, start, len, all); @@ -2606,17 +3195,19 @@ void Alg_seq::clear(double start, double len, bool all) // Put units in beats to match time_sig's. double ts_start = start; double ts_end = start + len; + double ts_dur = dur; if (units_are_seconds) { ts_start = time_map->time_to_beat(ts_start); ts_end = time_map->time_to_beat(ts_end); + ts_dur = time_map->time_to_beat(ts_dur); } // we sliced out a portion of each track, so now we need to // slice out the corresponding sections of time_sig and time_map // as well as to adjust the duration. - time_sig.cut(ts_start, ts_end); + time_sig.cut(ts_start, ts_end, ts_dur); time_map->cut(start, len, units_are_seconds); - set_dur(get_dur() - len); + set_dur(dur - len); } @@ -2674,6 +3265,26 @@ bool Alg_seq::insert_beat(double time, double beat) } +// input is time, return value is time +double Alg_seq::nearest_beat_time(double time, double *beat) +{ + double b = time_map->time_to_beat(time); + b = time_sig.nearest_beat(b); + if (beat) *beat = b; + return time_map->beat_to_time(b); +} + + +bool Alg_seq::stretch_region(double b0, double b1, double dur) +{ + bool units_should_be_seconds = units_are_seconds; + convert_to_beats(); + bool result = time_map->stretch_region(b0, b1, dur); + if (units_should_be_seconds) convert_to_seconds(); + return result; +} + + bool Alg_seq::insert_tempo(double bpm, double beat) { double bps = bpm / 60.0; // convert to beats per second @@ -2724,6 +3335,12 @@ void Alg_seq::add_event(Alg_event_ptr event, int track_num) } +double Alg_seq::get_tempo(double beat) +{ + return time_map->get_tempo(beat); +} + + bool Alg_seq::set_tempo(double bpm, double start_beat, double end_beat) // set tempo from start_beat to end_beat { @@ -2731,12 +3348,21 @@ bool Alg_seq::set_tempo(double bpm, double start_beat, double end_beat) if (start_beat >= end_beat) return false; bool units_should_be_seconds = units_are_seconds; convert_to_beats(); + double dur = get_dur(); bool result = time_map->set_tempo(bpm, start_beat, end_beat); + // preserve sequence duration in beats when tempo changes + set_dur(dur); if (units_should_be_seconds) convert_to_seconds(); return result; } +double Alg_seq::get_bar_len(double beat) +{ + return time_sig.get_bar_len(beat); +} + + void Alg_seq::set_time_sig(double beat, double num, double den) { time_sig.insert(beat, num, den); @@ -2799,43 +3425,61 @@ void Alg_seq::set_events(Alg_event_ptr *events, long len, long max) */ -void Alg_seq::iteration_begin() +void Alg_iterator::begin_seq(Alg_seq_ptr s, void *cookie, double offset) { // keep an array of indexes into tracks - current = new long[track_list.length()]; + // printf("new pending\n"); int i; - for (i = 0; i < track_list.length(); i++) { - current[i] = 0; + for (i = 0; i < s->track_list.length(); i++) { + if (s->track_list[i].length() > 0) { + insert(&(s->track_list[i]), 0, true, cookie, offset); + } } } -Alg_event_ptr Alg_seq::iteration_next() +Alg_event_ptr Alg_iterator::next(bool *note_on, void **cookie_ptr, + double *offset_ptr, double end_time) // return the next event in time from any track { - long cur; // a track index - // find lowest next time of any track: - double next = 1000000.0; - int i, track = 0; - for (i = 0; i < track_list.length(); i++) { - Alg_track &tr = track_list[i]; - cur = current[i]; - if (cur < tr.length() && tr[cur]->time < next) { - next = tr[cur]->time; - track = i; - } - } - if (next < 1000000.0) { - return track_list[track][current[track]++]; - } else { + bool on; + double when; + if (!remove_next(events_ptr, index, on, cookie, offset, when)) { return NULL; } + if (note_on) *note_on = on; + Alg_event_ptr event = (*events_ptr)[index]; + if (on) { + if (note_off_flag && event->is_note() && + (end_time == 0 || + (*events_ptr)[index]->get_end_time() + offset < end_time)) { + // this was a note-on, so insert pending note-off + insert(events_ptr, index, false, cookie, offset); + } + // for both note-ons and updates, insert next event (at index + 1) + // DO NOT INCREMENT index: it must be preserved for request_note_off() + if (index + 1 < events_ptr->length() && + (end_time == 0 || // zero means ignore end time + // stop iterating when end time is reached + (*events_ptr)[index + 1]->time + offset < end_time)) { + insert(events_ptr, index + 1, true, cookie, offset); + } + } + if (cookie_ptr) *cookie_ptr = cookie; + if (offset_ptr) *offset_ptr = offset; + return event; } -void Alg_seq::iteration_end() +void Alg_iterator::request_note_off() +{ + assert(index >= 0 && index < events_ptr->length()); + insert(events_ptr, index, false, cookie, offset); +} + + +void Alg_iterator::end() { - delete[] current; } @@ -2848,17 +3492,25 @@ void Alg_seq::merge_tracks() } // preallocate array for efficiency: Alg_event_ptr *notes = new Alg_event_ptr[sum]; - iteration_begin(); + Alg_iterator iterator(this, false); + iterator.begin(); long notes_index = 0; Alg_event_ptr event; - while (( event = iteration_next() )) { + while ((event = iterator.next())) { notes[notes_index++] = event; } track_list.reset(); // don't need them any more add_track(0); track(0)->set_events(notes, sum, sum); - iteration_end(); + iterator.end(); +} + + +void Alg_seq::set_in_use(bool flag) +{ + Alg_track::set_in_use(flag); + track_list.set_in_use(flag); } diff --git a/plugins/MidiImport/portsmf/allegro.h b/plugins/MidiImport/portsmf/allegro.h index e83d4b46375..ed684fd8a88 100644 --- a/plugins/MidiImport/portsmf/allegro.h +++ b/plugins/MidiImport/portsmf/allegro.h @@ -46,11 +46,11 @@ // Just as serialization uses ser_buf for output, unserialization uses // unser_buf for reading. unser_buf is another static member of Alg_track. -#ifndef __ALLEGRO__ -#define __ALLEGRO__ -#include "debug.h" - -#include "lmmsconfig.h" +#ifndef ALLEGRO_H +#define ALLEGRO_H +#include +#include +#include #define ALG_EPS 0.000001 // epsilon #define ALG_DEFAULT_BPM 100.0 // default tempo @@ -67,7 +67,7 @@ char *heapify(const char *s); // put a string on the heap // the attribute 'tempor' (a real) is stored // as 'rtempor'. To get the string name, just // use attribute+1. -typedef char *Alg_attribute; +typedef const char *Alg_attribute; #define alg_attr_name(a) ((a) + 1) #define alg_attr_type(a) (*(a)) @@ -79,6 +79,19 @@ class Alg_atoms { maxlen = len = 0; atoms = NULL; } + // Note: the code is possibly more correct and faster without the + // following destructor, which will only run after the program takes + // a normal exit. Cleaning up after the program exit slows down the exit, + // and will cause problems if any other destructor tries to reference an + // Alg_atom (which will now be freed). The advantage of this code is + // that Alg_atoms will not be reported as memory leaks by automation + // that doesn't know better. -RBD + virtual ~Alg_atoms() { + for (int i = 0; i < len; i++) { + delete atoms[i]; + } + if (atoms) delete [] atoms; + } // insert/lookup an atttribute Alg_attribute insert_attribute(Alg_attribute attr); // insert/lookup attribute by name (without prefixed type) @@ -86,7 +99,7 @@ class Alg_atoms { private: long maxlen; long len; - char **atoms; + Alg_attribute *atoms; // insert an Attriubute not in table after moving attr to heap Alg_attribute insert_new(const char *name, char attr_type); @@ -101,18 +114,24 @@ extern Alg_atoms symbol_table; // Alg_parameter class typedef class Alg_parameter { public: - ~Alg_parameter(); + // This constructor guarantees that an Alg_parameter can be + // deleted safely without further initialization. It does not + // do anything useful, so it is expected that the creator will + // set attr and store a value in the appropriate union field. Alg_attribute attr; union { double r;// real - char *s; // string + const char *s; // string long i; // integer bool l; // logical - char *a; // symbol (atom) + const char *a; // symbol (atom) }; // anonymous union + + Alg_parameter() { attr = "i"; } + ~Alg_parameter(); void copy(Alg_parameter *); // copy from another parameter - char attr_type() { return alg_attr_type(attr); } - char *attr_name() { return alg_attr_name(attr); } + const char attr_type() { return alg_attr_type(attr); } + const char *attr_name() { return alg_attr_name(attr); } void set_attr(Alg_attribute a) { attr = a; } void show(); } *Alg_parameter_ptr; @@ -139,15 +158,17 @@ typedef class Alg_parameters { // attribute. If you have already done the symbol table lookup/insert // you can do these operations faster (in which case we should add // another set of functions that take attributes as arguments.) - static void insert_real(Alg_parameters **list, char *name, double r); + static void insert_real(Alg_parameters **list, const char *name, double r); // insert string will copy string to heap - static void insert_string(Alg_parameters **list, char *name, char *s); - static void insert_integer(Alg_parameters **list, char *name, long i); - static void insert_logical(Alg_parameters **list, char *name, bool l); - static void insert_atom(Alg_parameters **list, char *name, char *s); + static void insert_string(Alg_parameters **list, const char *name, + const char *s); + static void insert_integer(Alg_parameters **list, const char *name, long i); + static void insert_logical(Alg_parameters **list, const char *name, bool l); + static void insert_atom(Alg_parameters **list, const char *name, + const char *s); static Alg_parameters *remove_key(Alg_parameters **list, const char *name); // find an attribute/value pair - Alg_parameter_ptr find(Alg_attribute *attr); + Alg_parameter_ptr find(Alg_attribute attr); } *Alg_parameters_ptr; @@ -198,11 +219,11 @@ typedef class Alg_event { // attribute (first argument) must agree in type with the second arg. // The last letter of the attribute implies the type (see below). void set_parameter(Alg_parameter_ptr new_parameter); - void set_string_value(char *attr, char *value); - void set_real_value(char *attr, double value); - void set_logical_value(char *attr, bool value); - void set_integer_value(char *attr, long value); - void set_atom_value(char *attr, char *atom); + void set_string_value(const char *attr, const char *value); + void set_real_value(const char *attr, double value); + void set_logical_value(const char *attr, bool value); + void set_integer_value(const char *attr, long value); + void set_atom_value(const char *attr, const char *atom); // Some note methods. These fail (via assert()) if this is not a note: // @@ -222,17 +243,22 @@ typedef class Alg_event { // types. Attribute names end with a type designation: 's', 'r', 'l', // 'i', or 'a'. // - bool has_attribute(char *attr); // test if note has attribute/value pair - char get_attribute_type(char *attr); // get the associated type: + bool has_attribute(const char *attr); // test if note has attribute/value pair + char get_attribute_type(const char *attr); // get the associated type: // 's' = string, // 'r' = real (double), 'l' = logical (bool), 'i' = integer (long), // 'a' = atom (char *), a unique string stored in Alg_seq - char *get_string_value(char *attr, char *value = NULL); // get the string value - double get_real_value(char *attr, double value = 0.0); // get the real value - bool get_logical_value(char *attr, bool value = false); // get the logical value - long get_integer_value(char *attr, long value = 0); // get the integer value - char *get_atom_value(char *attr, char *value = NULL); // get the atom value - void delete_attribute(char *attr); // delete an attribute/value pair + // get the string value + const char *get_string_value(const char *attr, const char *value = NULL); + // get the real value + double get_real_value(const char *attr, double value = 0.0); + // get the logical value + bool get_logical_value(const char *attr, bool value = false); + // get the integer value + long get_integer_value(const char *attr, long value = 0); + // get the atom value + const char *get_atom_value(const char *attr, const char *value = NULL); + void delete_attribute(const char *attr); // delete an attribute/value pair // (ignore if no matching attribute/value pair exists) // Some attribute/value methods. These fail if this is not an update. @@ -243,13 +269,13 @@ typedef class Alg_event { char get_update_type(); // get the update's type: 's' = string, // 'r' = real (double), 'l' = logical (bool), 'i' = integer (long), // 'a' = atom (char *), a unique string stored in Alg_seq - char *get_string_value(); // get the update's string value + const char *get_string_value(); // get the update's string value // Notes: Caller does not own the return value. Do not modify. // Do not use after underlying Alg_seq is modified. double get_real_value(); // get the update's real value bool get_logical_value(); // get the update's logical value long get_integer_value(); // get the update's integer value - char *get_atom_value(); // get the update's atom value + const char *get_atom_value(); // get the update's atom value // Notes: Caller does not own the return value. Do not modify. // The return value's lifetime is forever. @@ -305,6 +331,9 @@ typedef class Alg_events { // creating a new track and adding notes to it. It is *not* // updated after uninsert(), so use it with care. double last_note_off; + // initially false, in_use can be used to mark "do not delete". If an + // Alg_events instance is deleted while "in_use", an assertion will fail. + bool in_use; virtual int length() { return len; } Alg_event_ptr &operator[](int i) { assert(i >= 0 && i < len); @@ -314,10 +343,11 @@ typedef class Alg_events { maxlen = len = 0; events = NULL; last_note_off = 0; + in_use = false; } // destructor deletes the events array, but not the // events themselves - ~Alg_events(); + virtual ~Alg_events(); void set_events(Alg_event_ptr *e, long l, long m) { if (events) delete [] events; events = e; len = l; maxlen = m; } @@ -361,7 +391,7 @@ typedef class Alg_event_list : public Alg_events { // When applied to an Alg_seq, events are enumerated track // by track with increasing indices. This operation is not // particularly fast on an Alg_seq. - virtual Alg_event_ptr &operator[](int i); + virtual Alg_event_ptr const &operator[](int i); Alg_event_list() { sequence_number = 0; beat_dur = 0.0; real_dur = 0.0; events_owner = NULL; type = 'e'; } Alg_event_list(Alg_track *owner); @@ -468,8 +498,11 @@ typedef class Alg_time_map { // you want tracks to be in beat units. void insert_beat(double time, double beat); // add a point to the map bool insert_tempo(double tempo, double beat); // insert a tempo change + // get the tempo starting at beat + double get_tempo(double beat); // set the tempo over a region bool set_tempo(double tempo, double start_beat, double end_beat); + bool stretch_region(double b0, double b1, double dur); void cut(double start, double len, bool units_are_seconds); void trim(double start, double end, bool units_are_seconds); void paste(double start, Alg_track *tr); @@ -488,20 +521,76 @@ typedef class Alg_time_map { } *Alg_time_map_ptr; -typedef class Serial_buffer { -private: +// Serial_buffer is an abstract class with common elements of +// Serial_read_buffer and Serial_write_buffer +class Serial_buffer { + protected: char *buffer; char *ptr; long len; -public: + public: Serial_buffer() { buffer = NULL; ptr = NULL; len = 0; } - void init_for_write() { ptr = buffer; } + virtual ~Serial_buffer() { } + long get_posn() { return (long) (ptr - buffer); } long get_len() { return len; } +}; + + +typedef class Serial_read_buffer : public Serial_buffer { +public: + // note that a Serial_read_buffer is initialized for reading by + // setting buffer, but it is not the Serial_read_buffer's responsibility + // to delete the buffer (owner might want to reuse it), so the destructor + // does nothing. + virtual ~Serial_read_buffer() { } +#if defined(_WIN32) +//#pragma warning(disable: 546) // cast to int is OK, we only want low 7 bits +//#pragma warning(disable: 4311) // type cast pointer to long warning +#endif + void get_pad() { while ((intptr_t) ptr & 7) ptr++; } +#if defined(_WIN32) +//#pragma warning(default: 4311 546) +#endif + // Prepare to read n bytes from buf. The caller must manage buf: it is + // valid until reading is finished, and it is caller's responsibility + // to free buf when it is no longer needed. + void init_for_read(void *buf, long n) { + buffer = (char *) buf; + ptr = (char *) buf; + len = n; + } + char get_char() { return *ptr++; } + void unget_chars(int n) { ptr -= n; } // undo n get_char() calls + long get_int32() { long i = *((long *) ptr); ptr += 4; return i; } + float get_float() { float f = *((float *) ptr); ptr += 4; return f; } + double get_double() { double d = *((double *) ptr); ptr += sizeof(double); + return d; } + const char *get_string() { char *s = ptr; char *fence = buffer + len; + assert(ptr < fence); (void)fence; // unused variable + while (*ptr++) assert(ptr < fence); + get_pad(); + return s; } + void check_input_buffer(long needed) { + assert(get_posn() + needed <= len); } +} *Serial_read_buffer_ptr; + + +typedef class Serial_write_buffer: public Serial_buffer { + public: + // Note: allegro.cpp declares one static instance of Serial_buffer to + // reduce large memory (re)allocations when serializing tracks for UNDO. + // This destructor will only run when the program exits, which will only + // add overhead to the exit process, but it will eliminate an incorrect + // report of memory leakage from automation that doesn't know better. -RBD + virtual ~Serial_write_buffer() { + if (buffer) delete [] buffer; + } + void init_for_write() { ptr = buffer; } // store_long writes a long at a given offset void store_long(long offset, long value) { assert(offset <= get_posn() - 4); @@ -509,20 +598,33 @@ typedef class Serial_buffer { *loc = value; } void check_buffer(long needed); - void set_string(char *s) { + void set_string(const char *s) { char *fence = buffer + len; - assert(ptr < fence); + assert(ptr < fence); (void)fence; // unused variable + // two brackets surpress a g++ warning, because this is an + // assignment operator inside a test. while ((*ptr++ = *s++)) assert(ptr < fence); - // assert((char *)(((long) (ptr + 7)) & ~7) <= fence); + // 4311 is type cast pointer to long warning + // 4312 is type cast long to pointer warning +#if defined(_WIN32) +//#pragma warning(disable: 4311 4312) +#endif + assert((char *)(((long) (ptr + 7)) & ~7) <= fence); +#if defined(_WIN32) +//#pragma warning(default: 4311 4312) +#endif pad(); } void set_int32(long v) { *((long *) ptr) = v; ptr += 4; } void set_double(double v) { *((double *) ptr) = v; ptr += 8; } void set_float(float v) { *((float *) ptr) = v; ptr += 4; } void set_char(char v) { *ptr++ = v; } -#ifdef LMMS_BUILD_WIN64 - void pad() { while (((long long) ptr) & 7) set_char(0); } -#else - void pad() { while (((long) ptr) & 7) set_char(0); } +#if defined(_WIN32) +//#pragma warning(disable: 546) // cast to int is OK, we only want low 7 bits +//#pragma warning(disable: 4311) // type cast pointer to long warning +#endif + void pad() { while ((intptr_t) ptr & 7) set_char(0); } +#if defined(_WIN32) +//#pragma warning(default: 4311 546) #endif void *to_heap(long *len) { *len = get_posn(); @@ -530,29 +632,7 @@ typedef class Serial_buffer { memcpy(newbuf, buffer, *len); return newbuf; } - void init_for_read(void *buf, long n) { - buffer = (char *) buf; - ptr = (char *) buf; - len = n; - } - char get_char() { return *ptr++; } - long get_int32() { long i = *((long *) ptr); ptr += 4; return i; } - float get_float() { float f = *((float *) ptr); ptr += 4; return f; } - double get_double() { double d = *((double *) ptr); ptr += sizeof(double); - return d; } - char *get_string() { char *s = ptr; char *fence = buffer + len; - assert(ptr < fence); - while (*ptr++) assert(ptr < fence); - get_pad(); - return s; } -#ifdef LMMS_BUILD_WIN64 - void get_pad() { while (((long long) ptr) & 7) ptr++; } -#else - void get_pad() { while (((long) ptr) & 7) ptr++; } -#endif - void check_input_buffer(long needed) { - assert(get_posn() + needed <= len); } -} *Serial_buffer_ptr; +} *Serial_write_buffer_ptr; typedef class Alg_seq *Alg_seq_ptr; @@ -564,7 +644,8 @@ typedef class Alg_track : public Alg_event_list { long get_int32(char **p, long *b); double get_double(char **p, long *b); float get_float(char **p, long *b); - static Serial_buffer ser_buf; + static Serial_read_buffer ser_read_buf; + static Serial_write_buffer ser_write_buf; void serialize_parameter(Alg_parameter *parm); // *buffer_ptr points to binary data, bytes_ptr points to how many // bytes have been used so far, len is length of binary data @@ -572,7 +653,7 @@ typedef class Alg_track : public Alg_event_list { public: void serialize_track(); void unserialize_track(); - virtual Alg_event_ptr &operator[](int i) { + virtual Alg_event_ptr const &operator[](int i) { assert(i >= 0 && i < len); return events[i]; } @@ -587,7 +668,9 @@ typedef class Alg_track : public Alg_event_list { // copy constructor: event_list is copied, map is installed and referenced Alg_track(Alg_event_list_ref event_list, Alg_time_map_ptr map, bool units_are_seconds); - virtual ~Alg_track() { set_time_map(NULL); } + virtual ~Alg_track() { // note: do not call set_time_map(NULL)! + if (time_map) time_map->dereference(); + time_map = NULL; } // Returns a buffer containing a serialization of the // file. It will be an ASCII representation unless text is true. @@ -726,6 +809,7 @@ typedef class Alg_track : public Alg_event_list { virtual Alg_event_list *find(double t, double len, bool all, long channel_mask, long event_type_mask); + virtual void set_in_use(bool flag) { in_use = flag; } // // MIDI playback // @@ -785,11 +869,15 @@ class Alg_time_sigs { void show(); long length() { return len; } int find_beat(double beat); - void insert(double beat, double num, double den); - void cut(double start, double end); // remove from start to end + // get the number of beats per measure starting at beat + double get_bar_len(double beat); + void insert(double beat, double num, double den, bool force = false); + void cut(double start, double end, double dur); // remove from start to end void trim(double start, double end); // retain just start to end void paste(double start, Alg_seq *seq); void insert_beats(double beat, double len); // insert len beats at beat + // find the nearest beat (see Alg_seq::nearest_beat) to beat + double nearest_beat(double beat); }; @@ -816,26 +904,103 @@ typedef class Alg_tracks { void append(Alg_track_ptr track); void add_track(int track_num, Alg_time_map_ptr time_map, bool seconds); void reset(); + void set_in_use(bool flag); // handy to set in_use flag on all tracks } *Alg_tracks_ptr; typedef enum { alg_no_error = 0, // no error reading Allegro or MIDI file alg_error_open = -800, // could not open Allegro or MIDI file - alg_error_syntax // something found in the file that could not be parsed; - // generally you should ignore syntax errors or look at the printed error messages - // because there are some things in standard midi files that we do not handle; - // (maybe we should only set alg_error_syntax when there is a real problem with - // the file as opposed to when there is some warning message for the user) + alg_error_syntax // something found in the file that could not be parsed; + // generally you should ignore syntax errors or look at the printed error + // messages because there are some things in standard midi files that we do + // not handle; (maybe we should only set alg_error_syntax when there is a + // real problem with the file as opposed to when there is some warning + // message for the user) } Alg_error; +typedef struct Alg_pending_event { + void *cookie; // client-provided sequence identifier + Alg_events *events; // the array of events + long index; // offset of this event + bool note_on; // is this a note-on or a note-off (if applicable)? + double offset; // time offset for events + double time; // time for this event +} *Alg_pending_event_ptr; + + +typedef class Alg_iterator { +private: + long maxlen; + void expand(); + void expand_to(int new_max); + long len; + Alg_seq_ptr seq; + Alg_pending_event *pending_events; + // the next four fields are mainly for request_note_off() + Alg_events_ptr events_ptr; // remembers events containing current event + long index; // remembers index of current event + void *cookie; // remembers the cookie associated with next event + double offset; + void show(); + bool earlier(int i, int j); + void insert(Alg_events_ptr events, long index, bool note_on, + void *cookie, double offset); + // returns the info on the next pending event in the priority queue + bool remove_next(Alg_events_ptr &events, long &index, bool ¬e_on, + void *&cookie, double &offset, double &time); +public: + bool note_off_flag; // remembers if we are iterating over note-off + // events as well as note-on and update events + long length() { return len; } + Alg_iterator(Alg_seq_ptr s, bool note_off) { + seq = s; + note_off_flag = note_off; + maxlen = len = 0; + pending_events = NULL; + } + // Normally, iteration is over the events in the one sequence used + // to instatiate the iterator (see above), but with this method, you + // can add more sequences to the iteration. Events are returned in + // time order, so effectively sequence events are merged. + // The optional offset is added to each event time of sequence s + // before merging/sorting. You should call begin_seq() for each + // sequence to be included in the iteration unless you call begin() + // (see below). + void begin_seq(Alg_seq_ptr s, void *cookie = NULL, double offset = 0.0); + ~Alg_iterator(); + // Prepare to enumerate events in order. If note_off_flag is true, then + // iteration_next will merge note-off events into the sequence. If you + // call begin(), you should not normally call begin_seq(). See above. + void begin(void *cookie = NULL) { begin_seq(seq, cookie); } + // return next event (or NULL). If iteration_begin was called with + // note_off_flag = true, and if note_on is not NULL, then *note_on + // is set to true when the result value represents a note-on or update. + // (With note_off_flag, each Alg_note event is returned twice, once + // at the note-on time, with *note_on == true, and once at the note-off + // time, with *note_on == false. If a cookie_ptr is passed, then the + // cookie corresponding to the event is stored at that address + // If end_time is 0, iterate through the entire sequence, but if + // end_time is non_zero, stop iterating at the last event before end_time + Alg_event_ptr next(bool *note_on = NULL, void **cookie_ptr = NULL, + double *offset_ptr = NULL, double end_time = 0); + // Sometimes, the caller wants to receive note-off events for a subset + // of the notes, typically the notes that are played and need to be + // turned off. In this case, when a note is turned on, the client + // should call request_note_off(). This will insert a note-off into + // the queue for the most recent note returned by next(). + void request_note_off(); + void end(); // clean up after enumerating events +} *Alg_iterator_ptr; + + // An Alg_seq is an array of Alg_events, each a sequence of Alg_event, // with a tempo map and a sequence of time signatures // typedef class Alg_seq : public Alg_track { protected: - long *current; // array of indexes used by iteration methods + Alg_iterator_ptr pending; // iterator used internally by Alg_seq methods void serialize_seq(); Alg_error error; // error code set by file readers // an internal function used for writing Allegro track names @@ -860,9 +1025,11 @@ typedef class Alg_seq : public Alg_track { Alg_seq(Alg_track_ref track) { seq_from_track(track); } Alg_seq(Alg_track_ptr track) { seq_from_track(*track); } void seq_from_track(Alg_track_ref tr); - Alg_seq(std::istream &file, bool smf); // create from file - Alg_seq(const char *filename, bool smf); // create from filename - ~Alg_seq(); + // create from file: + Alg_seq(std::istream &file, bool smf, double *offset_ptr = NULL); + // create from filename + Alg_seq(const char *filename, bool smf, double *offset_ptr = NULL); + virtual ~Alg_seq(); int get_read_error() { return error; } void serialize(void **buffer, long *bytes); void copy_time_sigs_to(Alg_seq *dest); // a utility function @@ -874,10 +1041,10 @@ typedef class Alg_seq : public Alg_track { void unserialize_seq(); // write an ascii representation to file - void write(std::ostream &file, bool in_secs); + void write(std::ostream &file, bool in_secs, double offset = 0.0); // returns true on success - bool write(const char *filename); - void smf_write(std::ofstream &file); + bool write(const char *filename, double offset = 0.0); + void smf_write(std::ostream &file); bool smf_write(const char *filename); // Returns the number of tracks @@ -892,7 +1059,7 @@ typedef class Alg_seq : public Alg_track { // caller must not delete the result. Alg_track_ptr track(int); - virtual Alg_event_ptr &operator[](int i); + virtual Alg_event_ptr const &operator[](int i); virtual void convert_to_seconds(); virtual void convert_to_beats(); @@ -917,23 +1084,34 @@ typedef class Alg_seq : public Alg_track { // find index of first score event after time long seek_time(double time, int track_num); bool insert_beat(double time, double beat); + // return the time of the beat nearest to time, also returns beat + // number through beat. This will correspond to an integer number + // of beats from the nearest previous time signature or 0.0, but + // since time signatures need not be on integer beat boundaries + // the beat location may not be on an integer beat (beat locations + // are measured from the beginning which is beat 0. + double nearest_beat_time(double time, double *beat); // warning: insert_tempo may change representation from seconds to beats bool insert_tempo(double bpm, double beat); - + // change the duration from b0 to b1 (beats) to dur (seconds) by + // scaling the intervening tempos + bool stretch_region(double b0, double b1, double dur); // add_event takes a pointer to an event on the heap. The event is not // copied, and this Alg_seq becomes the owner and freer of the event. void add_event(Alg_event_ptr event, int track_num); void add(Alg_event_ptr event) { assert(false); } // call add_event instead - // warning: set_tempo may change representation from seconds to beats + // get the tempo starting at beat + double get_tempo(double beat); bool set_tempo(double bpm, double start_beat, double end_beat); + + // get the bar length in beats starting at beat + double get_bar_len(double beat); void set_time_sig(double beat, double num, double den); void beat_to_measure(double beat, long *measure, double *m_beat, double *num, double *den); // void set_events(Alg_event_ptr *events, long len, long max); void merge_tracks(); // move all track data into one track - void iteration_begin(); // prepare to enumerate events in order - Alg_event_ptr iteration_next(); // return next event (or NULL) - void iteration_end(); // clean up after enumerating events + void set_in_use(bool flag); // set in_use flag on all tracks } *Alg_seq_ptr, &Alg_seq_ref; diff --git a/plugins/MidiImport/portsmf/allegrord.cpp b/plugins/MidiImport/portsmf/allegrord.cpp index 7a1f5beed6f..2dc683afd69 100644 --- a/plugins/MidiImport/portsmf/allegrord.cpp +++ b/plugins/MidiImport/portsmf/allegrord.cpp @@ -1,753 +1,780 @@ -#include "debug.h" -#include "stdlib.h" -#include "string.h" -#include "ctype.h" -#include "trace.h" -#include -#include -#include -#include "strparse.h" -#include "allegro.h" -#include "algrd_internal.h" - -using namespace std; - -#define streql(s1, s2) (strcmp(s1, s2) == 0) -#define field_max 80 - -class Alg_reader { -public: - istream *file; - string input_line; - int line_no; - String_parse line_parser; - bool line_parser_flag; - string field; - bool error_flag; - Alg_seq_ptr seq; - double tsnum; - double tsden; - - Alg_reader(istream *a_file, Alg_seq_ptr new_seq); - void readline(); - Alg_parameters_ptr process_attributes(Alg_parameters_ptr attributes, - double time); - bool parse(); - long parse_chan(string &field); - long parse_int(string &field); - int find_real_in(string &field, int n); - double parse_real(string &field); - void parse_error(string &field, long offset, const char *message); - double parse_dur(string &field, double base); - double parse_after_dur(double dur, string &field, int n, double base); - double parse_loud(string &field); - long parse_key(string &field); - double parse_pitch(string &field); - long parse_after_key(int key, string &field, int n); - long find_int_in(string &field, int n); - bool parse_attribute(string &field, Alg_parameter_ptr parm); - bool parse_val(Alg_parameter_ptr param, string &s, int i); - bool check_type(char type_char, Alg_parameter_ptr param); -}; - - -double Alg_reader::parse_pitch(string &field) -{ - if (isdigit(field[1])) { - int last = find_real_in(field, 1); - string real_string = field.substr(1, last - 1); - return atof(real_string.c_str()); - } else { - return (double) parse_key(field); - } -} - - -// it is the responsibility of the caller to delete -// the seq -Alg_reader::Alg_reader(istream *a_file, Alg_seq_ptr new_seq) -{ - file = a_file; // save the file - line_parser_flag = false; - line_no = 0; - tsnum = 4; // default time signature - tsden = 4; - seq = new_seq; -} - - -Alg_error alg_read(istream &file, Alg_seq_ptr new_seq) - // read a sequence from allegro file -{ - assert(new_seq); - Alg_reader alg_reader(&file, new_seq); - bool err = alg_reader.parse(); - return (err ? alg_error_syntax : alg_no_error); -} - - -void Alg_reader::readline() -{ - // a word about memory management: this Alg_reader has a - // member variable input_line that holds a line of input - // it is reused for each line. input_line is parsed by - // line_parser, which holds a reference to input_line - line_parser_flag = false; - if (getline(*file, input_line)) { - line_parser.init(&input_line); - line_parser_flag = true; - error_flag = false; - } -} - - -Alg_parameters_ptr Alg_reader::process_attributes( - Alg_parameters_ptr attributes, double time) -{ - // print "process_attributes:", attributes - bool ts_flag = false; - if (attributes) { - Alg_parameters_ptr a; - bool in_seconds = seq->get_units_are_seconds(); - if ((a = Alg_parameters::remove_key(&attributes, "tempor"))) { - double tempo = a->parm.r; - seq->insert_tempo(tempo, seq->get_time_map()->time_to_beat(time)); - } - if ((a = Alg_parameters::remove_key(&attributes, "beatr"))) { - double beat = a->parm.r; - seq->insert_beat(time, beat); - } - if ((a = Alg_parameters::remove_key(&attributes, "timesig_numr"))) { - tsnum = a->parm.r; - ts_flag = true; - } - if ((a = Alg_parameters::remove_key(&attributes, "timesig_denr"))) { - tsden = a->parm.r; - ts_flag = true; - } - if (ts_flag) { - seq->set_time_sig(seq->get_time_map()->time_to_beat(time), - tsnum, tsden); - } - if (in_seconds) seq->convert_to_seconds(); - } - return attributes; // in case it was modified -} - - -bool Alg_reader::parse() -{ - int voice = 0; - int key = 60; - double loud = 100.0; - double pitch = 60.0; - double dur = 1.0; - double time = 0.0; - int track_num = 0; - seq->convert_to_seconds(); - //seq->set_real_dur(0.0); // just in case it's not initialized already - readline(); - bool valid = false; // ignore blank lines - while (line_parser_flag) { - bool time_flag = false; - bool next_flag = false; - double next; - bool voice_flag = false; - bool loud_flag = false; - bool dur_flag = false; - bool new_pitch_flag = false; // "P" syntax or "A"-"G" syntax - double new_pitch = 0.0; - bool new_key_flag = false; // "K" syntax - int new_key = 0; - Alg_parameters_ptr attributes = NULL; - if (line_parser.peek() == '#') { - // look for #track - line_parser.get_nonspace_quoted(field); - if (streql(field.c_str(), "#track")) { - line_parser.get_nonspace_quoted(field); // number - field.insert(0, " "); // need char at beginning because - // parse_int ignores the first character of the argument - track_num = parse_int(field); - seq->add_track(track_num); - } - // maybe we have a sequence or track name - line_parser.get_remainder(field); - // if there is a non-space character after #track n then - // use it as sequence or track name. Note that because we - // skip over spaces, a sequence or track name cannot begin - // with leading blanks. Another decision is that the name - // must be at time zero - if (field.length() > 0) { - // insert the field as sequence name or track name - Alg_update_ptr update = new Alg_update; - update->chan = -1; - update->time = 0; - update->set_identifier(-1); - // sequence name is whatever is on track 0 - // other tracks have track names - const char *attr = - (track_num == 0 ? "seqnames" : "tracknames"); - update->parameter.set_attr(symbol_table.insert_string(attr)); - update->parameter.s = heapify(field.c_str()); - seq->add_event(update, track_num); - } - } else { - // we must have a track to insert into - if (seq->tracks() == 0) seq->add_track(0); - line_parser.get_nonspace_quoted(field); - char pk = line_parser.peek(); - // attributes are parsed as two adjacent nonspace_quoted tokens - // so we have to conditionally call get_nonspace_quoted() again - if (pk && !isspace(pk)) { - string field2; - line_parser.get_nonspace_quoted(field2); - field.append(field2); - } - while (field[0]) { - char first = toupper(field[0]); - if (strchr("ABCDEFGKLPUSIQHW-", first)) { - valid = true; // it's a note or event - } - if (first == 'V') { - if (voice_flag) { - parse_error(field, 0, "Voice specified twice"); - } else { - voice = parse_chan(field); - } - voice_flag = true; - } else if (first == 'T') { - if (time_flag) { - parse_error(field, 0, "Time specified twice"); - } else { - time = parse_dur(field, 0.0); - } - time_flag = true; - } else if (first == 'N') { - if (next_flag) { - parse_error(field, 0, "Next specified twice"); - } else { - next = parse_dur(field, time); - } - next_flag = true; - } else if (first == 'K') { - if (new_key_flag) { - parse_error(field, 0, "Key specified twice"); - } else { - new_key = parse_key(field); - new_key_flag = true; - } - } else if (first == 'L') { - if (loud_flag) { - parse_error(field, 0, "Loudness specified twice"); - } else { - loud = parse_loud(field); - } - loud_flag = true; - } else if (first == 'P') { - if (new_pitch_flag) { - parse_error(field, 0, "Pitch specified twice"); - } else { - new_pitch = parse_pitch(field); - new_pitch_flag = true; - } - } else if (first == 'U') { - if (dur_flag) { - parse_error(field, 0, "Dur specified twice"); - } else { - dur = parse_dur(field, time); - dur_flag = true; - } - } else if (strchr("SIQHW", first)) { - if (dur_flag) { - parse_error(field, 0, "Dur specified twice"); - } else { - // prepend 'U' to field, copy EOS too - field.insert(0, 1, 'U'); - dur = parse_dur(field, time); - dur_flag = true; - } - } else if (strchr("ABCDEFG", first)) { - if (new_pitch_flag) { - parse_error(field, 0, "Pitch specified twice"); - } else { - // prepend 'P' to field - field.insert(0, 1, 'P'); - new_pitch = parse_pitch(field); - new_pitch_flag = true; - } - } else if (first == '-') { - Alg_parameter parm; - if (parse_attribute(field, &parm)) { // enter attribute-value pair - attributes = new Alg_parameters(attributes); - attributes->parm = parm; - parm.s = NULL; // protect string from deletion by destructor - } - } else { - parse_error(field, 0, "Unknown field"); - } - - if (error_flag) { - field[0] = 0; // exit the loop - } else { - line_parser.get_nonspace_quoted(field); - pk = line_parser.peek(); - // attributes are parsed as two adjacent nonspace_quoted - // tokens so we have to conditionally call - // get_nonspace_quoted() again - if (pk && !isspace(pk)) { - string field2; - line_parser.get_nonspace_quoted(field2); - field.append(field2); - } - } - } - // a case analysis: - // Key < 128 implies pitch unless pitch is explicitly given - // Pitch implies Key unless key is explicitly given, - // Pitch is rounded to nearest integer to determine the Key - // if necessary, so MIDI files will lose the pitch fraction - // A-G is a Pitch specification (therefore it implies Key) - // K60 P60 -- both are specified, use 'em - // K60 P60 C4 -- overconstrained, an error - // K60 C4 -- OK, but K60 is already implied by C4 - // K60 -- OK, pitch is 60 - // C4 P60 -- over constrained - // P60 -- OK, key is 60 - // P60.1 -- OK, key is 60 - // C4 -- OK, key is 60, pitch is 60 - // -- OK, key and pitch from before - // K200 P60 -- ok, pitch is 60 - // K200 with neither P60 nor C4 uses - // pitch from before - - // figure out what the key/instance is: - if (new_key_flag) { // it was directly specified - key = new_key; - } else if (new_pitch_flag) { - // pitch was specified, but key was not; get key from pitch - key = (int) (new_pitch + 0.5); // round to integer key number - } - if (new_pitch_flag) { - pitch = new_pitch; - } else if (key < 128 && new_key_flag) { - // no explicit pitch, but key < 128, so it implies pitch - pitch = key; - new_pitch_flag = true; - } - // now we've acquired new parameters - // if (it is a note, then enter the note - if (valid) { - // change tempo or beat - attributes = process_attributes(attributes, time); - // if there's a duration or pitch, make a note: - if (new_pitch_flag || dur_flag) { - Alg_note_ptr note_ptr = new Alg_note; - note_ptr->chan = voice; - note_ptr->time = time; - note_ptr->dur = dur; - note_ptr->set_identifier(key); - note_ptr->pitch = pitch; - note_ptr->loud = loud; - note_ptr->parameters = attributes; - seq->add_event(note_ptr, track_num); // sort later - if (seq->get_real_dur() < (time + dur)) seq->set_real_dur(time + dur); - } else { - int update_key = -1; - // key must appear explicitly; otherwise - // update applies to channel - if (new_key_flag) { - update_key = key; - } - if (loud_flag) { - Alg_update_ptr new_upd = new Alg_update; - new_upd->chan = voice; - new_upd->time = time; - new_upd->set_identifier(update_key); - new_upd->parameter.set_attr(symbol_table.insert_string("loudr")); - new_upd->parameter.r = pitch; - seq->add_event(new_upd, track_num); - if (seq->get_real_dur() < time) seq->set_real_dur(time); - } - if (attributes) { - while (attributes) { - Alg_update_ptr new_upd = new Alg_update; - new_upd->chan = voice; - new_upd->time = time; - new_upd->set_identifier(update_key); - new_upd->parameter = attributes->parm; - seq->add_event(new_upd, track_num); - Alg_parameters_ptr p = attributes; - attributes = attributes->next; - p->parm.s = NULL; // so we don't delete the string - delete p; - } - } - } - if (next_flag) { - time = time + next; - } else if (dur_flag || new_pitch_flag) { // a note: incr by dur - time = time + dur; - } - } - } - readline(); - } - if (!error_flag) { // why not convert even if there was an error? -RBD - seq->convert_to_seconds(); // make sure format is correct - } - // real_dur is valid, translate to beat_dur - seq->set_beat_dur((seq->get_time_map())->time_to_beat(seq->get_real_dur())); - return error_flag; -} - - -long Alg_reader::parse_chan(string &field) -{ - const char *int_string = field.c_str() + 1; - const char *msg = "Integer or - expected"; - const char *p = int_string; - char c; - // check that all chars in int_string are digits or '-': - while ((c = *p++)) { - if (!isdigit(c) && c != '-') { - parse_error(field, p - field.c_str() - 1, msg); - return 0; - } - } - p--; // p now points to end-of-string character - if (p - int_string == 0) { - // bad: string length is zero - parse_error(field, 1, msg); - return 0; - } - if (p - int_string == 1 && int_string[0] == '-') { - // special case: entire string is "-", interpret as -1 - return -1; - } - return atoi(int_string); -} - - -long Alg_reader::parse_int(string &field) -{ - const char *int_string = field.c_str() + 1; - const char *msg = "Integer expected"; - const char *p = int_string; - char c; - // check that all chars in int_string are digits: - while ((c = *p++)) { - if (!isdigit(c)) { - parse_error(field, p - field.c_str() - 1, msg); - return 0; - } - } - p--; // p now points to end-of-string character - if (p - int_string == 0) { - // bad: string length is zero - parse_error(field, 1, msg); - return 0; - } - return atoi(int_string); -} - - -int Alg_reader::find_real_in(string &field, int n) -{ - // scans from offset n to the end of a real constant - bool decimal = false; - int len = field.length(); - for (int i = n; i < len; i++) { - char c = field[i]; - if (!isdigit(c)) { - if (c == '.' && !decimal) { - decimal = true; - } else { - return i; - } - } - } - return field.length(); -} - - -double Alg_reader::parse_real(string &field) -{ - const char *msg = "Real expected"; - int last = find_real_in(field, 1); - string real_string = field.substr(1, last - 1); - if (last <= 1 || last < (int) field.length()) { - parse_error(field, 1, msg); - return 0; - } - return atof(real_string.c_str()); -} - - -void Alg_reader::parse_error(string &field, long offset, const char *message) -{ - int position = line_parser.pos - field.length() + offset; - error_flag = true; - puts(line_parser.str->c_str()); - for (int i = 0; i < position; i++) { - putc(' ', stdout); - } - putc('^', stdout); - printf(" %s\n", message); -} - - -double duration_lookup[] = { 0.25, 0.5, 1.0, 2.0, 4.0 }; - - -double Alg_reader::parse_dur(string &field, double base) -{ - const char *msg = "Duration expected"; - const char *durs = "SIQHW"; - const char *p; - int last; - double dur; - if (field.length() < 2) { - // fall through to error message - return -1; - } else if (isdigit(field[1])) { - last = find_real_in(field, 1); - string real_string = field.substr(1, last - 1); - dur = atof(real_string.c_str()); - // convert dur from seconds to beats - dur = seq->get_time_map()->time_to_beat(base + dur) - - seq->get_time_map()->time_to_beat(base); - } else if ((p = strchr(durs, toupper(field[1])))) { - dur = duration_lookup[p - durs]; - last = 2; - } else { - parse_error(field, 1, msg); - return 0; - } - dur = parse_after_dur(dur, field, last, base); - dur = seq->get_time_map()->beat_to_time( - seq->get_time_map()->time_to_beat(base) + dur) - base; - return dur; -} - - -double Alg_reader::parse_after_dur(double dur, string &field, - int n, double base) -{ - if ((int) field.length() == n) { - return dur; - } - if (toupper(field[n]) == 'T') { - return parse_after_dur(dur * 2/3, field, n + 1, base); - } - if (field[n] == '.') { - return parse_after_dur(dur * 1.5, field, n + 1, base); - } - if (isdigit(field[n])) { - int last = find_real_in(field, n); - string a_string = field.substr(n, last - n); - double f = atof(a_string.c_str()); - return parse_after_dur(dur * f, field, last, base); - } - if (field[n] == '+') { - string a_string = field.substr(n + 1); - return dur + parse_dur( - a_string, seq->get_time_map()->beat_to_time( - seq->get_time_map()->time_to_beat(base) + dur)); - } - parse_error(field, n, "Unexpected character in duration"); - return dur; -} - -struct loud_lookup_struct { - const char *str; - int val; -} loud_lookup[] = { {"FFF", 127}, {"FF", 120}, {"F", 110}, {"MF", 100}, - {"MP", 90}, {"P", 80}, {"PP", 70}, {"PPP", 60}, - {NULL, 0} }; - - -double Alg_reader::parse_loud(string &field) -{ - const char *msg = "Loudness expected"; - if (isdigit(field[1])) { - return parse_int(field); - } else { - string dyn = field.substr(1); - transform(dyn.begin(), dyn.end(), dyn.begin(), ::toupper); - for (int i = 0; loud_lookup[i].str; i++) { - if (streql(loud_lookup[i].str, dyn.c_str())) { - return (double) loud_lookup[i].val; - } - } - } - parse_error(field, 1, msg); - return 100.0; -} - - -int key_lookup[] = {21, 23, 12, 14, 16, 17, 19}; - - -// the field can be K or K[A-G] or P[A-G] -// (this can be called from parse_pitch() to handle [A-G]) -// Notice that the routine ignores the first character: K or P -// -long Alg_reader::parse_key(string &field) -{ - const char *msg = "Pitch expected"; - const char *pitches = "ABCDEFG"; - const char *p; - if (isdigit(field[1])) { - // This routine would not have been called if field = "P" - // so it must be "K" so must be an integer. - return parse_int(field); - } else if ((p = strchr(pitches, toupper(field[1])))) { - long key = key_lookup[p - pitches]; - key = parse_after_key(key, field, 2); - return key; - } - parse_error(field, 1, msg); - return 0; -} - - -long Alg_reader::parse_after_key(int key, string &field, int n) -{ - if ((int) field.length() == n) { - return key; - } - char c = toupper(field[n]); - if (c == 'S') { - return parse_after_key(key + 1, field, n + 1); - } - if (c == 'F') { - return parse_after_key(key - 1, field, n + 1); - } - if (isdigit(field[n])) { - int last = find_int_in(field, n); - string octave = field.substr(n, last - n); - int oct = atoi(octave.c_str()); - return parse_after_key(key + oct * 12, field, last); - } - parse_error(field, n, "Unexpected character in pitch"); - return key; -} - - -long Alg_reader::find_int_in(string &field, int n) -{ - while ((int) field.length() > n && isdigit(field[n])) { - n = n + 1; - } - return n; -} - - -bool Alg_reader::parse_attribute(string &field, Alg_parameter_ptr param) -{ - int i = 1; - while (i < (int) field.length()) { - if (field[i] == ':') { - string attr = field.substr(1, i - 1); - char type_char = field[i - 1]; - if (strchr("iarsl", type_char)) { - param->set_attr(symbol_table.insert_string(attr.c_str())); - parse_val(param, field, i + 1); - } else { - parse_error(field, 0, "attribute needs to end with typecode: i,a,r,s, or l"); - } - return !error_flag; - } - i = i + 1; - } - return false; -} - - -bool Alg_reader::parse_val(Alg_parameter_ptr param, string &s, int i) -{ - int len = (int) s.length(); - if (i >= len) { - return false; - } - if (s[i] == '"') { - if (!check_type('s', param)) { - return false; - } - // note: (len - i) includes 2 quote characters but no EOS character - // so total memory to allocate is (len - i) - 1 - char *r = new char[(len - i) - 1]; - strncpy(r, s.c_str() + i + 1, (len - i) - 2); - r[(len - i) - 2] = 0; // terminate the string - param->s = r; - } else if (s[i] == '\'') { - if (!check_type('a', param)) { - return false; - } - string r = s.substr(i + 1, len - i - 2); - param->a = symbol_table.insert_string(r.c_str()); - } else if (param->attr_type() == 'l') { - if (streql(s.c_str() + i, "true") || - streql(s.c_str() + i, "t")) { - param->l = true; - } else if (streql(s.c_str() + i, "false") || - streql(s.c_str() + i, "nil")) { - param->l = false; - } else return false; - } else if (isdigit(s[i]) || s[i] == '-' || s[i] == '.') { - int pos = i; - bool period = false; - if (s[pos] == '-') { - pos++; - } - while (pos < len) { - if (isdigit(s[pos])) { - ; - } else if (!period && s[pos] == '.') { - period = true; - } else { - parse_error(s, pos, "Unexpected char in number"); - return false; - } - pos = pos + 1; - } - string r = s.substr(i, len - i); - if (period) { - if (!check_type('r', param)) { - return false; - } - param->r = atof(r.c_str()); - } else { - if (param->attr_type() == 'r') { - param->r = atoi(r.c_str()); - } else if (!check_type('i', param)) { - return false; - } else { - param->i = atoi(r.c_str()); - } - } - } else { - parse_error(s, i, "invalid value"); - return false; - } - return true; -} - - -bool Alg_reader::check_type(char type_char, Alg_parameter_ptr param) -{ - return param->attr_type() == type_char; -} - - -//duration_lookup = {"S": 0.5, "I": 0.5, "Q": 1, "H": 2, "W": 4} -//key_lookup = {"C": 12, "D": 14, "E": 16, "F": 17, "G": 19, "A": 21, "B": 23} - -/* -def test(): - reader = Alg_reader(open("data\\test.gro", "r")) - reader.parse() - score = reader->seq.notes - print "score:", score - reader = nil -*/ +#include "assert.h" +#include "stdlib.h" +#include "string.h" +#include "ctype.h" +#include "trace.h" +#include +#include +#include +#include "strparse.h" +#include "allegro.h" +#include "algrd_internal.h" + +using namespace std; + +#define streql(s1, s2) (strcmp(s1, s2) == 0) +#define field_max 80 + +class Alg_reader { +public: + istream *file; + string input_line; + int line_no; + String_parse line_parser; + bool line_parser_flag; + string field; + bool error_flag; + Alg_seq_ptr seq; + double tsnum; + double tsden; + double offset; + bool offset_found; + + Alg_reader(istream *a_file, Alg_seq_ptr new_seq); + void readline(); + Alg_parameters_ptr process_attributes(Alg_parameters_ptr attributes, + double time); + bool parse(); + long parse_chan(string &field); + long parse_int(string &field); + int find_real_in(string &field, int n); + double parse_real(string &field); + void parse_error(string &field, long offset, char *message); + void parse_error(string &field, long offset, const char *message); + double parse_dur(string &field, double base); + double parse_after_dur(double dur, string &field, int n, double base); + double parse_loud(string &field); + long parse_key(string &field); + double parse_pitch(string &field); + long parse_after_key(int key, string &field, int n); + long find_int_in(string &field, int n); + bool parse_attribute(string &field, Alg_parameter_ptr parm); + bool parse_val(Alg_parameter_ptr param, string &s, int i); + bool check_type(char type_char, Alg_parameter_ptr param); +}; + + +double Alg_reader::parse_pitch(string &field) +{ + if (isdigit(field[1])) { + int last = find_real_in(field, 1); + string real_string = field.substr(1, last - 1); + return atof(real_string.c_str()); + } else { + return (double) parse_key(field); + } +} + + +// it is the responsibility of the caller to delete +// the seq +Alg_reader::Alg_reader(istream *a_file, Alg_seq_ptr new_seq) +{ + file = a_file; // save the file + line_parser_flag = false; + line_no = 0; + tsnum = 4; // default time signature + tsden = 4; + seq = new_seq; + offset = 0.0; + offset_found = false; +} + + +Alg_error alg_read(istream &file, Alg_seq_ptr new_seq, double *offset_ptr) + // read a sequence from allegro file +{ + assert(new_seq); + Alg_reader alg_reader(&file, new_seq); + bool err = alg_reader.parse(); + if (!err && offset_ptr) { + *offset_ptr = alg_reader.offset; + } + return (err ? alg_error_syntax : alg_no_error); +} + + +void Alg_reader::readline() +{ + // a word about memory management: this Alg_reader has a + // member variable input_line that holds a line of input + // it is reused for each line. input_line is parsed by + // line_parser, which holds a reference to input_line + line_parser_flag = false; + if (getline(*file, input_line)) { + line_parser.init(&input_line); + line_parser_flag = true; + error_flag = false; + } +} + + +Alg_parameters_ptr Alg_reader::process_attributes( + Alg_parameters_ptr attributes, double time) +{ + // print "process_attributes:", attributes + bool ts_flag = false; + if (attributes) { + Alg_parameters_ptr a; + bool in_seconds = seq->get_units_are_seconds(); + if ((a = Alg_parameters::remove_key(&attributes, "tempor"))) { + double tempo = a->parm.r; + seq->insert_tempo(tempo, seq->get_time_map()->time_to_beat(time)); + } + if ((a = Alg_parameters::remove_key(&attributes, "beatr"))) { + double beat = a->parm.r; + seq->insert_beat(time, beat); + } + if ((a = Alg_parameters::remove_key(&attributes, "timesig_numr"))) { + tsnum = a->parm.r; + ts_flag = true; + } + if ((a = Alg_parameters::remove_key(&attributes, "timesig_denr"))) { + tsden = a->parm.r; + ts_flag = true; + } + if (ts_flag) { + seq->set_time_sig(seq->get_time_map()->time_to_beat(time), + tsnum, tsden); + } + if (in_seconds) seq->convert_to_seconds(); + } + return attributes; // in case it was modified +} + + +bool Alg_reader::parse() +{ + int voice = 0; + int key = 60; + double loud = 100.0; + double pitch = 60.0; + double dur = 1.0; + double time = 0.0; + int track_num = 0; + seq->convert_to_seconds(); + //seq->set_real_dur(0.0); // just in case it's not initialized already + readline(); + bool valid = false; // ignore blank lines + while (line_parser_flag) { + bool time_flag = false; + bool next_flag = false; + double next = 0; + bool voice_flag = false; + bool loud_flag = false; + bool dur_flag = false; + bool new_pitch_flag = false; // "P" syntax or "A"-"G" syntax + double new_pitch = 0.0; + bool new_key_flag = false; // "K" syntax + int new_key = 0; + Alg_parameters_ptr attributes = NULL; + if (line_parser.peek() == '#') { + // look for #track + line_parser.get_nonspace_quoted(field); + if (streql(field.c_str(), "#track")) { + line_parser.get_nonspace_quoted(field); // number + field.insert(0, " "); // need char at beginning because + // parse_int ignores the first character of the argument + track_num = parse_int(field); + seq->add_track(track_num); + + // maybe we have a sequence or track name + line_parser.get_remainder(field); + // if there is a non-space character after #track n then + // use it as sequence or track name. Note that because we + // skip over spaces, a sequence or track name cannot begin + // with leading blanks. Another decision is that the name + // must be at time zero + if (field.length() > 0) { + // insert the field as sequence name or track name + Alg_update_ptr update = new Alg_update; + update->chan = -1; + update->time = 0; + update->set_identifier(-1); + // sequence name is whatever is on track 0 + // other tracks have track names + const char *attr = + (track_num == 0 ? "seqnames" : "tracknames"); + update->parameter.set_attr( + symbol_table.insert_string(attr)); + update->parameter.s = heapify(field.c_str()); + seq->add_event(update, track_num); + } + } else if (streql(field.c_str(), "#offset")) { + if (offset_found) { + parse_error(field, 0, "#offset specified twice"); + } + offset_found = true; + line_parser.get_nonspace_quoted(field); // number + field.insert(0, " "); // need char at beginning because + // parse_real ignores first character in the argument + offset = parse_real(field); + } + } else { + // we must have a track to insert into + if (seq->tracks() == 0) seq->add_track(0); + line_parser.get_nonspace_quoted(field); + char pk = line_parser.peek(); + // attributes are parsed as two adjacent nonspace_quoted tokens + // so we have to conditionally call get_nonspace_quoted() again + if (pk && !isspace(pk)) { + string field2; + line_parser.get_nonspace_quoted(field2); + field.append(field2); + } + while (field[0]) { + char first = toupper(field[0]); + if (strchr("ABCDEFGKLPUSIQHW-", first)) { + valid = true; // it's a note or event + } + if (first == 'V') { + if (voice_flag) { + parse_error(field, 0, "Voice specified twice"); + } else { + voice = parse_chan(field); + } + voice_flag = true; + } else if (first == 'T') { + if (time_flag) { + parse_error(field, 0, "Time specified twice"); + } else { + time = parse_dur(field, 0.0); + } + time_flag = true; + } else if (first == 'N') { + if (next_flag) { + parse_error(field, 0, "Next specified twice"); + } else { + next = parse_dur(field, time); + } + next_flag = true; + } else if (first == 'K') { + if (new_key_flag) { + parse_error(field, 0, "Key specified twice"); + } else { + new_key = parse_key(field); + new_key_flag = true; + } + } else if (first == 'L') { + if (loud_flag) { + parse_error(field, 0, "Loudness specified twice"); + } else { + loud = parse_loud(field); + } + loud_flag = true; + } else if (first == 'P') { + if (new_pitch_flag) { + parse_error(field, 0, "Pitch specified twice"); + } else { + new_pitch = parse_pitch(field); + new_pitch_flag = true; + } + } else if (first == 'U') { + if (dur_flag) { + parse_error(field, 0, "Dur specified twice"); + } else { + dur = parse_dur(field, time); + dur_flag = true; + } + } else if (strchr("SIQHW", first)) { + if (dur_flag) { + parse_error(field, 0, "Dur specified twice"); + } else { + // prepend 'U' to field, copy EOS too + field.insert((unsigned int) 0, 1, 'U'); + dur = parse_dur(field, time); + dur_flag = true; + } + } else if (strchr("ABCDEFG", first)) { + if (new_pitch_flag) { + parse_error(field, 0, "Pitch specified twice"); + } else { + // prepend 'P' to field + field.insert((unsigned int) 0, 1, 'P'); + new_pitch = parse_pitch(field); + new_pitch_flag = true; + } + } else if (first == '-') { + Alg_parameter parm; + if (parse_attribute(field, &parm)) { // enter attribute-value pair + attributes = new Alg_parameters(attributes); + attributes->parm = parm; + parm.s = NULL; // protect string from deletion by destructor + } + } else { + parse_error(field, 0, "Unknown field"); + } + + if (error_flag) { + field[0] = 0; // exit the loop + } else { + line_parser.get_nonspace_quoted(field); + pk = line_parser.peek(); + // attributes are parsed as two adjacent nonspace_quoted + // tokens so we have to conditionally call + // get_nonspace_quoted() again + if (pk && !isspace(pk)) { + string field2; + line_parser.get_nonspace_quoted(field2); + field.append(field2); + } + } + } + // a case analysis: + // Key < 128 implies pitch unless pitch is explicitly given + // Pitch implies Key unless key is explicitly given, + // Pitch is rounded to nearest integer to determine the Key + // if necessary, so MIDI files will lose the pitch fraction + // A-G is a Pitch specification (therefore it implies Key) + // K60 P60 -- both are specified, use 'em + // K60 P60 C4 -- overconstrained, an error + // K60 C4 -- OK, but K60 is already implied by C4 + // K60 -- OK, pitch is 60 + // C4 P60 -- over constrained + // P60 -- OK, key is 60 + // P60.1 -- OK, key is 60 + // C4 -- OK, key is 60, pitch is 60 + // -- OK, key and pitch from before + // K200 P60 -- ok, pitch is 60 + // K200 with neither P60 nor C4 uses + // pitch from before + + // figure out what the key/instance is: + if (new_key_flag) { // it was directly specified + key = new_key; + } else if (new_pitch_flag) { + // pitch was specified, but key was not; get key from pitch + key = (int) (new_pitch + 0.5); // round to integer key number + } + if (new_pitch_flag) { + pitch = new_pitch; + } else if (key < 128 && new_key_flag) { + // no explicit pitch, but key < 128, so it implies pitch + pitch = key; + new_pitch_flag = true; + } + // now we've acquired new parameters + // if (it is a note, then enter the note + if (valid) { + // change tempo or beat + attributes = process_attributes(attributes, time); + // if there's a duration or pitch, make a note: + if (new_pitch_flag || dur_flag) { + Alg_note_ptr note_ptr = new Alg_note; + note_ptr->chan = voice; + note_ptr->time = time; + note_ptr->dur = dur; + note_ptr->set_identifier(key); + note_ptr->pitch = (float) pitch; + note_ptr->loud = (float) loud; + note_ptr->parameters = attributes; + seq->add_event(note_ptr, track_num); // sort later + if (seq->get_real_dur() < (time + dur)) seq->set_real_dur(time + dur); + } else { + int update_key = -1; + // key must appear explicitly; otherwise + // update applies to channel + if (new_key_flag) { + update_key = key; + } + if (loud_flag) { + Alg_update_ptr new_upd = new Alg_update; + new_upd->chan = voice; + new_upd->time = time; + new_upd->set_identifier(update_key); + new_upd->parameter.set_attr(symbol_table.insert_string("loudr")); + new_upd->parameter.r = pitch; + seq->add_event(new_upd, track_num); + if (seq->get_real_dur() < time) seq->set_real_dur(time); + } + if (attributes) { + while (attributes) { + Alg_update_ptr new_upd = new Alg_update; + new_upd->chan = voice; + new_upd->time = time; + new_upd->set_identifier(update_key); + new_upd->parameter = attributes->parm; + seq->add_event(new_upd, track_num); + Alg_parameters_ptr p = attributes; + attributes = attributes->next; + p->parm.s = NULL; // so we don't delete the string + delete p; + } + } + } + if (next_flag) { + time = time + next; + } else if (dur_flag || new_pitch_flag) { // a note: incr by dur + time = time + dur; + } + } + } + readline(); + } + if (!error_flag) { // why not convert even if there was an error? -RBD + seq->convert_to_seconds(); // make sure format is correct + } + // real_dur is valid, translate to beat_dur + seq->set_beat_dur((seq->get_time_map())->time_to_beat(seq->get_real_dur())); + return error_flag; +} + + +long Alg_reader::parse_chan(string &field) +{ + const char *int_string = field.c_str() + 1; + const char *msg = "Integer or - expected"; + const char *p = int_string; + char c; + // check that all chars in int_string are digits or '-': + while ((c = *p++)) { + if (!isdigit(c) && c != '-') { + parse_error(field, p - field.c_str() - 1, msg); + return 0; + } + } + p--; // p now points to end-of-string character + if (p - int_string == 0) { + // bad: string length is zero + parse_error(field, 1, msg); + return 0; + } + if (p - int_string == 1 && int_string[0] == '-') { + // special case: entire string is "-", interpret as -1 + return -1; + } + return atoi(int_string); +} + + +long Alg_reader::parse_int(string &field) +{ + const char *int_string = field.c_str() + 1; + const char *msg = "Integer expected"; + const char *p = int_string; + char c; + // check that all chars in int_string are digits: + while ((c = *p++)) { + if (!isdigit(c)) { + parse_error(field, p - field.c_str() - 1, msg); + return 0; + } + } + p--; // p now points to end-of-string character + if (p - int_string == 0) { + // bad: string length is zero + parse_error(field, 1, msg); + return 0; + } + return atoi(int_string); +} + + +int Alg_reader::find_real_in(string &field, int n) +{ + // scans from offset n to the end of a real constant + bool decimal = false; + int len = field.length(); + if (n < len && field[n] == '-') n += 1; // parse one minus sign + for (int i = n; i < len; i++) { + char c = field[i]; + if (!isdigit(c)) { + if (c == '.' && !decimal) { + decimal = true; + } else { + return i; + } + } + } + return len; +} + + +double Alg_reader::parse_real(string &field) +{ + const char *msg = "Real expected"; + int last = find_real_in(field, 1); + string real_string = field.substr(1, last - 1); + if (last <= 1 || last < (int) field.length()) { + parse_error(field, 1, msg); + return 0; + } + return atof(real_string.c_str()); +} + + +void Alg_reader::parse_error(string &field, long offset, char *message) +{ + int position = line_parser.pos - field.length() + offset; + error_flag = true; + puts(line_parser.str->c_str()); + for (int i = 0; i < position; i++) { + putc(' ', stdout); + } + putc('^', stdout); + printf(" %s\n", message); +} + +void Alg_reader::parse_error(string &field, long offset, const char *message) +{ + parse_error(field, offset, const_cast(message)); +} + + +double duration_lookup[] = { 0.25, 0.5, 1.0, 2.0, 4.0 }; + + +double Alg_reader::parse_dur(string &field, double base) +{ + const char *msg = "Duration expected"; + const char *durs = "SIQHW"; + const char *p; + int last; + double dur; + if (field.length() < 2) { + // fall through to error message + return -1; + } else if (isdigit(field[1])) { + last = find_real_in(field, 1); + string real_string = field.substr(1, last - 1); + dur = atof(real_string.c_str()); + // convert dur from seconds to beats + dur = seq->get_time_map()->time_to_beat(base + dur) - + seq->get_time_map()->time_to_beat(base); + } else if ((p = strchr(durs, toupper(field[1])))) { + dur = duration_lookup[p - durs]; + last = 2; + } else { + parse_error(field, 1, msg); + return 0; + } + dur = parse_after_dur(dur, field, last, base); + dur = seq->get_time_map()->beat_to_time( + seq->get_time_map()->time_to_beat(base) + dur) - base; + return dur; +} + + +double Alg_reader::parse_after_dur(double dur, string &field, + int n, double base) +{ + if ((int) field.length() == n) { + return dur; + } + if (toupper(field[n]) == 'T') { + return parse_after_dur(dur * 2/3, field, n + 1, base); + } + if (field[n] == '.') { + return parse_after_dur(dur * 1.5, field, n + 1, base); + } + if (isdigit(field[n])) { + int last = find_real_in(field, n); + string a_string = field.substr(n, last - n); + double f = atof(a_string.c_str()); + return parse_after_dur(dur * f, field, last, base); + } + if (field[n] == '+') { + string a_string = field.substr(n + 1); + return dur + parse_dur( + a_string, seq->get_time_map()->beat_to_time( + seq->get_time_map()->time_to_beat(base) + dur)); + } + parse_error(field, n, "Unexpected character in duration"); + return dur; +} + +struct loud_lookup_struct { + const char *str; + int val; +} loud_lookup[] = { {"FFF", 127}, {"FF", 120}, {"F", 110}, {"MF", 100}, + {"MP", 90}, {"P", 80}, {"PP", 70}, {"PPP", 60}, + {NULL, 0} }; + + +double Alg_reader::parse_loud(string &field) +{ + const char *msg = "Loudness expected"; + if (isdigit(field[1])) { + return parse_int(field); + } else { + string dyn = field.substr(1); + transform(dyn.begin(), dyn.end(), dyn.begin(), ::toupper); + for (int i = 0; loud_lookup[i].str; i++) { + if (streql(loud_lookup[i].str, dyn.c_str())) { + return (double) loud_lookup[i].val; + } + } + } + parse_error(field, 1, msg); + return 100.0; +} + + +int key_lookup[] = {21, 23, 12, 14, 16, 17, 19}; + + +// the field can be K or K[A-G] or P[A-G] +// (this can be called from parse_pitch() to handle [A-G]) +// Notice that the routine ignores the first character: K or P +// +long Alg_reader::parse_key(string &field) +{ + const char *msg = "Pitch expected"; + const char *pitches = "ABCDEFG"; + const char *p; + if (isdigit(field[1])) { + // This routine would not have been called if field = "P" + // so it must be "K" so must be an integer. + return parse_int(field); + } else if ((p = strchr(pitches, toupper(field[1])))) { + long key = key_lookup[p - pitches]; + key = parse_after_key(key, field, 2); + return key; + } + parse_error(field, 1, msg); + return 0; +} + + +long Alg_reader::parse_after_key(int key, string &field, int n) +{ + if ((int) field.length() == n) { + return key; + } + char c = toupper(field[n]); + if (c == 'S') { + return parse_after_key(key + 1, field, n + 1); + } + if (c == 'F') { + return parse_after_key(key - 1, field, n + 1); + } + if (isdigit(field[n])) { + int last = find_int_in(field, n); + string octave = field.substr(n, last - n); + int oct = atoi(octave.c_str()); + return parse_after_key(key + oct * 12, field, last); + } + parse_error(field, n, "Unexpected character in pitch"); + return key; +} + + +long Alg_reader::find_int_in(string &field, int n) +{ + while ((int) field.length() > n && isdigit(field[n])) { + n = n + 1; + } + return n; +} + + +bool Alg_reader::parse_attribute(string &field, Alg_parameter_ptr param) +{ + int i = 1; + while (i < (int) field.length()) { + if (field[i] == ':') { + string attr = field.substr(1, i - 1); + char type_char = field[i - 1]; + if (strchr("iarsl", type_char)) { + param->set_attr(symbol_table.insert_string(attr.c_str())); + parse_val(param, field, i + 1); + } else { + parse_error(field, 0, "attribute needs to end with typecode: i,a,r,s, or l"); + } + return !error_flag; + } + i = i + 1; + } + return false; +} + + +bool Alg_reader::parse_val(Alg_parameter_ptr param, string &s, int i) +{ + int len = (int) s.length(); + if (i >= len) { + return false; + } + if (s[i] == '"') { + if (!check_type('s', param)) { + return false; + } + // note: (len - i) includes 2 quote characters but no EOS character + // so total memory to allocate is (len - i) - 1 + char *r = new char[(len - i) - 1]; + strncpy(r, s.c_str() + i + 1, (len - i) - 2); + r[(len - i) - 2] = 0; // terminate the string + param->s = r; + } else if (s[i] == '\'') { + if (!check_type('a', param)) { + return false; + } + string r = s.substr(i + 1, len - i - 2); + param->a = symbol_table.insert_string(r.c_str()); + } else if (param->attr_type() == 'l') { + if (streql(s.c_str() + i, "true") || + streql(s.c_str() + i, "t")) { + param->l = true; + } else if (streql(s.c_str() + i, "false") || + streql(s.c_str() + i, "nil")) { + param->l = false; + } else return false; + } else if (isdigit(s[i]) || s[i] == '-' || s[i] == '.') { + int pos = i; + bool period = false; + /* int sign = 1; LMMS unused variable */ + if (s[pos] == '-') { + /* sign = -1; LMMS unused variable */ + pos++; + } + while (pos < len) { + if (isdigit(s[pos])) { + ; + } else if (!period && s[pos] == '.') { + period = true; + } else { + parse_error(s, pos, "Unexpected char in number"); + return false; + } + pos = pos + 1; + } + string r = s.substr(i, len - i); + if (period) { + if (!check_type('r', param)) { + return false; + } + param->r = atof(r.c_str()); + } else { + if (param->attr_type() == 'r') { + param->r = atoi(r.c_str()); + } else if (!check_type('i', param)) { + return false; + } else { + param->i = atoi(r.c_str()); + } + } + } else { + parse_error(s, i, "invalid value"); + return false; + } + return true; +} + + +bool Alg_reader::check_type(char type_char, Alg_parameter_ptr param) +{ + return param->attr_type() == type_char; +} + + +//duration_lookup = {"S": 0.5, "I": 0.5, "Q": 1, "H": 2, "W": 4} +//key_lookup = {"C": 12, "D": 14, "E": 16, "F": 17, "G": 19, "A": 21, "B": 23} + +/* +def test(): + reader = Alg_reader(open("data\\test.gro", "r")) + reader.parse() + score = reader->seq.notes + print "score:", score + reader = nil +*/ diff --git a/plugins/MidiImport/portsmf/allegrosmfrd.cpp b/plugins/MidiImport/portsmf/allegrosmfrd.cpp index 49e2ef03ee6..279462762a7 100644 --- a/plugins/MidiImport/portsmf/allegrosmfrd.cpp +++ b/plugins/MidiImport/portsmf/allegrosmfrd.cpp @@ -1,445 +1,461 @@ -// midifile reader - -#include "stdlib.h" -#include "stdio.h" -#include "string.h" -#include "debug.h" -#include -#include -#include "allegro.h" -#include "algsmfrd_internal.h" -#include "mfmidi.h" -#include "trace.h" - -using namespace std; - -typedef class Alg_pending { -public: - Alg_note_ptr note; - class Alg_pending *next; - Alg_pending(Alg_note_ptr n, class Alg_pending *list) { - note = n; next = list; } -} *Alg_pending_ptr; - - -class Alg_midifile_reader: public Midifile_reader { -public: - istream *file; - Alg_seq_ptr seq; - int divisions; - Alg_pending_ptr pending; - Alg_track_ptr track; - int track_number; // the number of the (current) track - // chan is actual_channel + channel_offset_per_track * track_num + - // channel_offset_per_track * port - long channel_offset_per_track; // used to encode track number into channel - // default is 0, set this to 0 to merge all tracks to 16 channels - long channel_offset_per_port; // used to encode port number into channel - // default is 16, set to 0 to ignore port prefix meta events - // while reading, this is channel_offset_per_track * track_num - int channel_offset; - - Alg_midifile_reader(istream &f, Alg_seq_ptr new_seq) { - file = &f; - pending = NULL; - seq = new_seq; - channel_offset_per_track = 0; - channel_offset_per_port = 16; - track_number = -1; // no tracks started yet, 1st will be #0 - meta_channel = -1; - port = 0; - } - // delete destroys the seq member as well, so set it to NULL if you - // copied the pointer elsewhere - ~Alg_midifile_reader(); - // the following is used to load the Alg_seq from the file: - bool parse(); - - void set_nomerge(bool flag) { Mf_nomerge = flag; } - void set_skipinit(bool flag) { Mf_skipinit = flag; } - long get_currtime() { return Mf_currtime; } - -protected: - int meta_channel; // the channel for meta events, set by MIDI chan prefix - int port; // value from the portprefix meta event - - double get_time(); - void update(int chan, int key, Alg_parameter_ptr param); - void *Mf_malloc(size_t size) { return malloc(size); } - void Mf_free(void *obj, size_t size) { free(obj); } - /* Methods to be called while processing the MIDI file. */ - void Mf_starttrack(); - void Mf_endtrack(); - int Mf_getc(); - void Mf_chanprefix(int chan); - void Mf_portprefix(int port); - void Mf_eot(); - void Mf_error(const char *); - void Mf_header(int,int,int); - void Mf_on(int,int,int); - void Mf_off(int,int,int); - void Mf_pressure(int,int,int); - void Mf_controller(int,int,int); - void Mf_pitchbend(int,int,int); - void Mf_program(int,int); - void Mf_chanpressure(int,int); - void binary_msg(int len, char *msg, const char *attr_string); - void Mf_sysex(int,char*); - void Mf_arbitrary(int,char*); - void Mf_metamisc(int,int,char*); - void Mf_seqnum(int); - void Mf_smpte(int,int,int,int,int); - void Mf_timesig(int,int,int,int); - void Mf_tempo(int); - void Mf_keysig(int,int); - void Mf_sqspecific(int,char*); - void Mf_text(int,int,char*); -}; - - -Alg_midifile_reader::~Alg_midifile_reader() -{ - while (pending) { - Alg_pending_ptr to_be_freed = pending; - pending = pending->next; - delete to_be_freed; - } - finalize(); // free Mf reader memory -} - - -bool Alg_midifile_reader::parse() -{ - channel_offset = 0; - seq->convert_to_beats(); - midifile(); - seq->set_real_dur(seq->get_time_map()->beat_to_time(seq->get_beat_dur())); - return midifile_error != 0; -} - - -void Alg_midifile_reader::Mf_starttrack() -{ - // printf("starting new track\n"); - // create a new track that will share the sequence time map - // since time is in beats, the seconds parameter is false - track_number++; - seq->add_track(track_number); // make sure track exists - track = seq->track(track_number); // keep pointer to current track - meta_channel = -1; - port = 0; -} - - -void Alg_midifile_reader::Mf_endtrack() -{ - // note: track is already part of seq, so do not add it here - // printf("finished track, length %d number %d\n", track->len, track_num / 100); - channel_offset += seq->channel_offset_per_track; - track = NULL; - double now = get_time(); - if (seq->get_beat_dur() < now) seq->set_beat_dur(now); - meta_channel = -1; - port = 0; -} - - -int Alg_midifile_reader::Mf_getc() -{ - return file->get(); -} - - -void Alg_midifile_reader::Mf_chanprefix(int chan) -{ - meta_channel = chan; -} - - -void Alg_midifile_reader::Mf_portprefix(int p) -{ - port = p; -} - - -void Alg_midifile_reader::Mf_eot() -{ - meta_channel = -1; - port = 0; -} - - -void Alg_midifile_reader::Mf_error(const char *msg) -{ - fprintf(stdout, "Midifile reader error: %s\n", msg); -} - - -void Alg_midifile_reader::Mf_header(int format, int ntrks, int division) -{ - if (format > 1) { - char msg[80]; - sprintf(msg, "file format %d not implemented", format); - Mf_error(msg); - } - divisions = division; -} - - -double Alg_midifile_reader::get_time() -{ - double beat = ((double) get_currtime()) / divisions; - return beat; -} - - -void Alg_midifile_reader::Mf_on(int chan, int key, int vel) -{ - assert(!seq->get_units_are_seconds()); - if (vel == 0) { - Mf_off(chan, key, vel); - return; - } - Alg_note_ptr note = new Alg_note(); - pending = new Alg_pending(note, pending); - /* trace("on: %d at %g\n", key, get_time()); */ - note->time = get_time(); - note->chan = chan + channel_offset + port * channel_offset_per_port; - note->dur = 0; - note->set_identifier(key); - note->pitch = (float) key; - note->loud = (float) vel; - track->append(note); - meta_channel = -1; -} - - -void Alg_midifile_reader::Mf_off(int chan, int key, int vel) -{ - double time = get_time(); - Alg_pending_ptr *p = &pending; - while (*p) { - if ((*p)->note->get_identifier() == key && - (*p)->note->chan == - chan + channel_offset + port * channel_offset_per_port) { - (*p)->note->dur = time - (*p)->note->time; - // trace("updated %d dur %g\n", (*p)->note->key, (*p)->note->dur); - Alg_pending_ptr to_be_freed = *p; - *p = to_be_freed->next; - delete to_be_freed; - } else { - p = &((*p)->next); - } - } - meta_channel = -1; -} - - -void Alg_midifile_reader::update(int chan, int key, Alg_parameter_ptr param) -{ - Alg_update_ptr update = new Alg_update; - update->time = get_time(); - update->chan = chan; - if (chan != -1) { - update->chan = chan + channel_offset + port * channel_offset_per_port; - } - update->set_identifier(key); - update->parameter = *param; - // prevent the destructor from destroying the string twice! - // the new Update takes the string from param - if (param->attr_type() == 's') param->s = NULL; - track->append(update); -} - - -void Alg_midifile_reader::Mf_pressure(int chan, int key, int val) -{ - Alg_parameter parameter; - parameter.set_attr(symbol_table.insert_string("pressurer")); - parameter.r = val / 127.0; - update(chan, key, ¶meter); - meta_channel = -1; -} - - -void Alg_midifile_reader::Mf_controller(int chan, int control, int val) -{ - Alg_parameter parameter; - char name[32]; - sprintf(name, "control%dr", control); - parameter.set_attr(symbol_table.insert_string(name)); - parameter.r = val / 127.0; - update(chan, -1, ¶meter); - meta_channel = -1; -} - - -void Alg_midifile_reader::Mf_pitchbend(int chan, int c1, int c2) -{ - Alg_parameter parameter; - parameter.set_attr(symbol_table.insert_string("bendr")); - parameter.r = ((c2 << 7) + c1) / 8192.0 - 1.0; - update(chan, -1, ¶meter); - meta_channel = -1; -} - - -void Alg_midifile_reader::Mf_program(int chan, int program) -{ - Alg_parameter parameter; - parameter.set_attr(symbol_table.insert_string("programi")); - parameter.i = program; - update(chan, -1, ¶meter); - meta_channel = -1; -} - - -void Alg_midifile_reader::Mf_chanpressure(int chan, int val) -{ - Alg_parameter parameter; - parameter.set_attr(symbol_table.insert_string("pressurer")); - parameter.r = val / 127.0; - update(chan, -1, ¶meter); - meta_channel = -1; -} - - -void Alg_midifile_reader::binary_msg(int len, char *msg, - const char *attr_string) -{ - Alg_parameter parameter; - char *hexstr = new char[len * 2 + 1]; - for (int i = 0; i < len; i++) { - sprintf(hexstr + 2 * i, "%02x", (0xFF & msg[i])); - } - parameter.s = hexstr; - parameter.set_attr(symbol_table.insert_string(attr_string)); - update(meta_channel, -1, ¶meter); -} - - -void Alg_midifile_reader::Mf_sysex(int len, char *msg) -{ - // sysex messages become updates with attribute sysexs and a hex string - binary_msg(len, msg, "sysexs"); -} - - -void Alg_midifile_reader::Mf_arbitrary(int len, char *msg) -{ - Mf_error("arbitrary data ignored"); -} - - -void Alg_midifile_reader::Mf_metamisc(int type, int len, char *msg) -{ - char text[128]; - sprintf(text, "metamsic data, type 0x%x, ignored", type); - Mf_error(text); -} - - -void Alg_midifile_reader::Mf_seqnum(int n) -{ - Mf_error("seqnum data ignored"); -} - - -static const char *fpsstr[4] = {"24", "25", "29.97", "30"}; - -void Alg_midifile_reader::Mf_smpte(int hours, int mins, int secs, - int frames, int subframes) -{ - // string will look like "24fps:01h:27m:07s:19.00f" - // 30fps (drop frame) is notated as "29.97fps" - char text[32]; - int fps = (hours >> 6) & 3; - hours &= 0x1F; - sprintf(text, "%sfps:%02dh:%02dm:%02ds:%02d.%02df", - fpsstr[fps], hours, mins, secs, frames, subframes); - Alg_parameter smpteoffset; - smpteoffset.s = heapify(text); - smpteoffset.set_attr(symbol_table.insert_string("smpteoffsets")); - update(meta_channel, -1, &smpteoffset); - // Mf_error("SMPTE data ignored"); -} - - -void Alg_midifile_reader::Mf_timesig(int i1, int i2, int i3, int i4) -{ - seq->set_time_sig(get_currtime() / divisions, i1, 1 << i2); -} - - -void Alg_midifile_reader::Mf_tempo(int tempo) -{ - double beat = get_currtime(); - beat = beat / divisions; // convert to quarters - // 6000000 us/min / n us/beat => beat / min - double bpm = 60000000.0 / tempo; - seq->insert_tempo(bpm, beat); -} - - -void Alg_midifile_reader::Mf_keysig(int key, int mode) -{ - Alg_parameter key_parm; - key_parm.set_attr(symbol_table.insert_string("keysigi")); - // use 0 for C major, 1 for G, -1 for F, etc., that is, - // the number of sharps, where flats are negative sharps - key_parm.i = key; //<<<---- fix this - // use -1 to mean "all channels" - update(meta_channel, -1, &key_parm); - Alg_parameter mode_parm; - mode_parm.set_attr(symbol_table.insert_string("modea")); - mode_parm.a = (mode == 0 ? symbol_table.insert_string("major") : - symbol_table.insert_string("minor")); - update(meta_channel, -1, &mode_parm); -} - - -void Alg_midifile_reader::Mf_sqspecific(int len, char *msg) -{ - // sequencer specific messages become updates with attribute sqspecifics - // and a hex string for the value - binary_msg(len, msg, "sqspecifics"); -} - - -char *heapify2(int len, char *s) -{ - char *h = new char[len + 1]; - memcpy(h, s, len); - h[len] = 0; - return h; -} - - -void Alg_midifile_reader::Mf_text(int type, int len, char *msg) -{ - Alg_parameter text; - text.s = heapify2(len, msg); - const char *attr = "miscs"; - if (type == 1) attr = "texts"; - else if (type == 2) attr = "copyrights"; - else if (type == 3) - attr = (track_number == 0 ? "seqnames" : "tracknames"); - else if (type == 4) attr = "instruments"; - else if (type == 5) attr = "lyrics"; - else if (type == 6) attr = "markers"; - else if (type == 7) attr = "cues"; - text.set_attr(symbol_table.insert_string(attr)); - update(meta_channel, -1, &text); -} - - -// parse file into a seq. -Alg_error alg_smf_read(istream &file, Alg_seq_ptr new_seq) -{ - assert(new_seq); - Alg_midifile_reader ar(file, new_seq); - bool err = ar.parse(); - ar.seq->set_real_dur(ar.seq->get_time_map()-> - beat_to_time(ar.seq->get_beat_dur())); - return (err ? alg_error_syntax : alg_no_error); -} +// midifile reader + +#include "stdlib.h" +#include "stdio.h" +#include "string.h" +#include "assert.h" +#include +#include +#include "allegro.h" +#include "algsmfrd_internal.h" +#include "mfmidi.h" +#include "trace.h" + +using namespace std; + +typedef class Alg_note_list { +public: + Alg_note_ptr note; + class Alg_note_list *next; + Alg_note_list(Alg_note_ptr n, class Alg_note_list *list) { + note = n; next = list; } +} *Alg_note_list_ptr; + + +class Alg_midifile_reader: public Midifile_reader { +public: + istream *file; + Alg_seq_ptr seq; + int divisions; + Alg_note_list_ptr note_list; + Alg_track_ptr track; + int track_number; // the number of the (current) track + // chan is actual_channel + channel_offset_per_track * track_num + + // channel_offset_per_track * port + long channel_offset_per_track; // used to encode track number into channel + // default is 0, set this to 0 to merge all tracks to 16 channels + long channel_offset_per_port; // used to encode port number into channel + // default is 16, set to 0 to ignore port prefix meta events + // while reading, this is channel_offset_per_track * track_num + int channel_offset; + + Alg_midifile_reader(istream &f, Alg_seq_ptr new_seq) { + file = &f; + note_list = NULL; + seq = new_seq; + channel_offset_per_track = 0; + channel_offset_per_port = 16; + track_number = -1; // no tracks started yet, 1st will be #0 + meta_channel = -1; + port = 0; + } + // delete destroys the seq member as well, so set it to NULL if you + // copied the pointer elsewhere + ~Alg_midifile_reader(); + // the following is used to load the Alg_seq from the file: + bool parse(); + + void set_nomerge(bool flag) { Mf_nomerge = flag; } + void set_skipinit(bool flag) { Mf_skipinit = flag; } + long get_currtime() { return Mf_currtime; } + +protected: + int meta_channel; // the channel for meta events, set by MIDI chan prefix + int port; // value from the portprefix meta event + + double get_time(); + void update(int chan, int key, Alg_parameter_ptr param); + void *Mf_malloc(size_t size) { return malloc(size); } + void Mf_free(void *obj, size_t size) { free(obj); } + /* Methods to be called while processing the MIDI file. */ + void Mf_starttrack(); + void Mf_endtrack(); + int Mf_getc(); + void Mf_chanprefix(int chan); + void Mf_portprefix(int port); + void Mf_eot(); + void Mf_error(char *); + void Mf_error(const char *); + void Mf_header(int,int,int); + void Mf_on(int,int,int); + void Mf_off(int,int,int); + void Mf_pressure(int,int,int); + void Mf_controller(int,int,int); + void Mf_pitchbend(int,int,int); + void Mf_program(int,int); + void Mf_chanpressure(int,int); + void binary_msg(int len, unsigned char *msg, const char *attr_string); + void Mf_sysex(int,unsigned char*); + void Mf_arbitrary(int,unsigned char*); + void Mf_metamisc(int,int,unsigned char*); + void Mf_seqnum(int); + void Mf_smpte(int,int,int,int,int); + void Mf_timesig(int,int,int,int); + void Mf_tempo(int); + void Mf_keysig(int,int); + void Mf_sqspecific(int,unsigned char*); + void Mf_text(int,int,unsigned char*); +}; + + +Alg_midifile_reader::~Alg_midifile_reader() +{ + while (note_list) { + Alg_note_list_ptr to_be_freed = note_list; + note_list = note_list->next; + delete to_be_freed; + } + finalize(); // free Mf reader memory +} + + +bool Alg_midifile_reader::parse() +{ + channel_offset = 0; + seq->convert_to_beats(); + midifile(); + seq->set_real_dur(seq->get_time_map()->beat_to_time(seq->get_beat_dur())); + return midifile_error != 0; +} + + +void Alg_midifile_reader::Mf_starttrack() +{ + // printf("starting new track\n"); + // create a new track that will share the sequence time map + // since time is in beats, the seconds parameter is false + track_number++; + seq->add_track(track_number); // make sure track exists + track = seq->track(track_number); // keep pointer to current track + meta_channel = -1; + port = 0; +} + + +void Alg_midifile_reader::Mf_endtrack() +{ + // note: track is already part of seq, so do not add it here + // printf("finished track, length %d number %d\n", track->len, track_num / 100); + channel_offset += seq->channel_offset_per_track; + track = NULL; + double now = get_time(); + if (seq->get_beat_dur() < now) seq->set_beat_dur(now); + meta_channel = -1; + port = 0; +} + + +int Alg_midifile_reader::Mf_getc() +{ + return file->get(); +} + + +void Alg_midifile_reader::Mf_chanprefix(int chan) +{ + meta_channel = chan; +} + + +void Alg_midifile_reader::Mf_portprefix(int p) +{ + port = p; +} + + +void Alg_midifile_reader::Mf_eot() +{ + meta_channel = -1; + port = 0; +} + + +void Alg_midifile_reader::Mf_error(char *msg) +{ + fprintf(stdout, "Midifile reader error: %s\n", msg); +} + +void Alg_midifile_reader::Mf_error(const char *msg) +{ + Mf_error(const_cast(msg)); +} + + +void Alg_midifile_reader::Mf_header(int format, int ntrks, int division) +{ + if (format > 1) { + char msg[80]; +//#pragma warning(disable: 4996) // msg is long enough + sprintf(msg, "file format %d not implemented", format); +//#pragma warning(default: 4996) + Mf_error(msg); + } + divisions = division; +} + + +double Alg_midifile_reader::get_time() +{ + double beat = ((double) get_currtime()) / divisions; + return beat; +} + + +void Alg_midifile_reader::Mf_on(int chan, int key, int vel) +{ + assert(!seq->get_units_are_seconds()); + if (vel == 0) { + Mf_off(chan, key, vel); + return; + } + Alg_note_ptr note = new Alg_note(); + note_list = new Alg_note_list(note, note_list); + /* trace("on: %d at %g\n", key, get_time()); */ + note->time = get_time(); + note->chan = chan + channel_offset + port * channel_offset_per_port; + note->dur = 0; + note->set_identifier(key); + note->pitch = (float) key; + note->loud = (float) vel; + track->append(note); + meta_channel = -1; +} + + +void Alg_midifile_reader::Mf_off(int chan, int key, int vel) +{ + double time = get_time(); + Alg_note_list_ptr *p = ¬e_list; + while (*p) { + if ((*p)->note->get_identifier() == key && + (*p)->note->chan == + chan + channel_offset + port * channel_offset_per_port) { + (*p)->note->dur = time - (*p)->note->time; + // trace("updated %d dur %g\n", (*p)->note->key, (*p)->note->dur); + Alg_note_list_ptr to_be_freed = *p; + *p = to_be_freed->next; + delete to_be_freed; + } else { + p = &((*p)->next); + } + } + meta_channel = -1; +} + + +void Alg_midifile_reader::update(int chan, int key, Alg_parameter_ptr param) +{ + Alg_update_ptr update = new Alg_update; + update->time = get_time(); + update->chan = chan; + if (chan != -1) { + update->chan = chan + channel_offset + port * channel_offset_per_port; + } + update->set_identifier(key); + update->parameter = *param; + // prevent the destructor from destroying the string twice! + // the new Update takes the string from param + if (param->attr_type() == 's') param->s = NULL; + track->append(update); +} + + +void Alg_midifile_reader::Mf_pressure(int chan, int key, int val) +{ + Alg_parameter parameter; + parameter.set_attr(symbol_table.insert_string("pressurer")); + parameter.r = val / 127.0; + update(chan, key, ¶meter); + meta_channel = -1; +} + + +void Alg_midifile_reader::Mf_controller(int chan, int control, int val) +{ + Alg_parameter parameter; + char name[32]; +//#pragma warning(disable: 4996) // name is long enough + sprintf(name, "control%dr", control); +//#pragma warning(default: 4996) + parameter.set_attr(symbol_table.insert_string(name)); + parameter.r = val / 127.0; + update(chan, -1, ¶meter); + meta_channel = -1; +} + + +void Alg_midifile_reader::Mf_pitchbend(int chan, int c1, int c2) +{ + Alg_parameter parameter; + parameter.set_attr(symbol_table.insert_string("bendr")); + parameter.r = ((c2 << 7) + c1) / 8192.0 - 1.0; + update(chan, -1, ¶meter); + meta_channel = -1; +} + + +void Alg_midifile_reader::Mf_program(int chan, int program) +{ + Alg_parameter parameter; + parameter.set_attr(symbol_table.insert_string("programi")); + parameter.i = program; + update(chan, -1, ¶meter); + meta_channel = -1; +} + + +void Alg_midifile_reader::Mf_chanpressure(int chan, int val) +{ + Alg_parameter parameter; + parameter.set_attr(symbol_table.insert_string("pressurer")); + parameter.r = val / 127.0; + update(chan, -1, ¶meter); + meta_channel = -1; +} + + +void Alg_midifile_reader::binary_msg(int len, unsigned char *msg, + const char *attr_string) +{ + Alg_parameter parameter; + char *hexstr = new char[len * 2 + 1]; + for (int i = 0; i < len; i++) { +//#pragma warning(disable: 4996) // hexstr is long enough + sprintf(hexstr + 2 * i, "%02x", (0xFF & msg[i])); +//#pragma warning(default: 4996) + } + parameter.s = hexstr; + parameter.set_attr(symbol_table.insert_string(attr_string)); + update(meta_channel, -1, ¶meter); +} + + +void Alg_midifile_reader::Mf_sysex(int len, unsigned char *msg) +{ + // sysex messages become updates with attribute sysexs and a hex string + binary_msg(len, msg, "sysexs"); +} + + +void Alg_midifile_reader::Mf_arbitrary(int len, unsigned char *msg) +{ + Mf_error("arbitrary data ignored"); +} + + +void Alg_midifile_reader::Mf_metamisc(int type, int len, unsigned char *msg) +{ + char text[128]; +//#pragma warning(disable: 4996) // text is long enough + sprintf(text, "metamsic data, type 0x%x, ignored", type); +//#pragma warning(default: 4996) + Mf_error(text); +} + + +void Alg_midifile_reader::Mf_seqnum(int n) +{ + Mf_error("seqnum data ignored"); +} + + +static const char *fpsstr[4] = {"24", "25", "29.97", "30"}; + +void Alg_midifile_reader::Mf_smpte(int hours, int mins, int secs, + int frames, int subframes) +{ + // string will look like "24fps:01h:27m:07s:19.00f" + // 30fps (drop frame) is notated as "29.97fps" + char text[32]; + int fps = (hours >> 6) & 3; + hours &= 0x1F; +//#pragma warning(disable: 4996) // text is long enough + sprintf(text, "%sfps:%02dh:%02dm:%02ds:%02d.%02df", + fpsstr[fps], hours, mins, secs, frames, subframes); +//#pragma warning(default: 4996) + Alg_parameter smpteoffset; + smpteoffset.s = heapify(text); + smpteoffset.set_attr(symbol_table.insert_string("smpteoffsets")); + update(meta_channel, -1, &smpteoffset); + // Mf_error("SMPTE data ignored"); +} + + +void Alg_midifile_reader::Mf_timesig(int i1, int i2, int i3, int i4) +{ + seq->set_time_sig(double(get_currtime()) / divisions, i1, 1 << i2); +} + + +void Alg_midifile_reader::Mf_tempo(int tempo) +{ + double beat = get_currtime(); + beat = beat / divisions; // convert to quarters + // 6000000 us/min / n us/beat => beat / min + double bpm = 60000000.0 / tempo; + seq->insert_tempo(bpm, beat); +} + + +void Alg_midifile_reader::Mf_keysig(int key, int mode) +{ + Alg_parameter key_parm; + key_parm.set_attr(symbol_table.insert_string("keysigi")); + // use 0 for C major, 1 for G, -1 for F, etc., that is, + // the number of sharps, where flats are negative sharps + key_parm.i = key; //<<<---- fix this + // use -1 to mean "all channels" + update(meta_channel, -1, &key_parm); + Alg_parameter mode_parm; + mode_parm.set_attr(symbol_table.insert_string("modea")); + mode_parm.a = (mode == 0 ? symbol_table.insert_string("major") : + symbol_table.insert_string("minor")); + update(meta_channel, -1, &mode_parm); +} + + +void Alg_midifile_reader::Mf_sqspecific(int len, unsigned char *msg) +{ + // sequencer specific messages become updates with attribute sqspecifics + // and a hex string for the value + binary_msg(len, msg, "sqspecifics"); +} + + +char *heapify2(int len, unsigned char *s) +{ + char *h = new char[len + 1]; + memcpy(h, s, len); + h[len] = 0; + return h; +} + + +void Alg_midifile_reader::Mf_text(int type, int len, unsigned char *msg) +{ + Alg_parameter text; + text.s = heapify2(len, msg); + const char *attr = "miscs"; + if (type == 1) attr = "texts"; + else if (type == 2) attr = "copyrights"; + else if (type == 3) + attr = (track_number == 0 ? "seqnames" : "tracknames"); + else if (type == 4) attr = "instruments"; + else if (type == 5) attr = "lyrics"; + else if (type == 6) attr = "markers"; + else if (type == 7) attr = "cues"; + text.set_attr(symbol_table.insert_string(attr)); + update(meta_channel, -1, &text); +} + + +// parse file into a seq. +Alg_error alg_smf_read(istream &file, Alg_seq_ptr new_seq) +{ + assert(new_seq); + Alg_midifile_reader ar(file, new_seq); + bool err = ar.parse(); + ar.seq->set_real_dur(ar.seq->get_time_map()-> + beat_to_time(ar.seq->get_beat_dur())); + return (err ? alg_error_syntax : alg_no_error); +} diff --git a/plugins/MidiImport/portsmf/allegrosmfwr.cpp b/plugins/MidiImport/portsmf/allegrosmfwr.cpp index 5a76c44ed9f..7cac9a0412f 100644 --- a/plugins/MidiImport/portsmf/allegrosmfwr.cpp +++ b/plugins/MidiImport/portsmf/allegrosmfwr.cpp @@ -34,7 +34,7 @@ class Alg_smf_write { // chan is actual_channel + channels_per_track * track_number // default is 100, set this to 0 to merge all tracks to 16 channels - void write(ofstream &file /* , midiFileFormat = 1 */); + void write(ostream &file /* , midiFileFormat = 1 */); private: long previous_divs; // time in ticks of most recently written event @@ -46,7 +46,7 @@ class Alg_smf_write { void write_note(Alg_note_ptr note, bool on); void write_update(Alg_update_ptr update); void write_text(Alg_update_ptr update, char type); - void write_binary(int type_byte, char *msg); + void write_binary(int type_byte, const char *msg); void write_midi_channel_prefix(Alg_update_ptr update); void write_smpteoffset(Alg_update_ptr update, char *s); void write_data(int data); @@ -162,7 +162,7 @@ void Alg_smf_write::write_note(Alg_note_ptr note, bool on) //printf("deltaDivisions: %d, beats elapsed: %g, on? %c\n", deltaDivisions, note->time, on); - char chan = (note->chan & 15); + char chan = char(note->chan & 15); int pitch = int(note->pitch + 0.5); if (pitch < 0) { pitch = pitch % 12; @@ -184,8 +184,8 @@ void Alg_smf_write::write_midi_channel_prefix(Alg_update_ptr update) { if (update->chan >= 0) { // write MIDI Channel Prefix write_delta(update->time); - out_file->put(0xFF); // Meta Event - out_file->put(0x20); // Type code for MIDI Channel Prefix + out_file->put('\xFF'); // Meta Event + out_file->put('\x20'); // Type code for MIDI Channel Prefix out_file->put(1); // length out_file->put(to_midi_channel(update->chan)); // one thing odd about the Std MIDI File spec is that once @@ -201,7 +201,7 @@ void Alg_smf_write::write_text(Alg_update_ptr update, char type) { write_midi_channel_prefix(update); write_delta(update->time); - out_file->put(0xFF); + out_file->put('\xFF'); out_file->put(type); out_file->put((char) strlen(update->parameter.s)); *out_file << update->parameter.s; @@ -212,8 +212,8 @@ void Alg_smf_write::write_smpteoffset(Alg_update_ptr update, char *s) { write_midi_channel_prefix(update); write_delta(update->time); - out_file->put(0xFF); // meta event - out_file->put(0x54); // smpte offset type code + out_file->put('\xFF'); // meta event + out_file->put('\x54'); // smpte offset type code out_file->put(5); // length for (int i = 0; i < 5; i++) *out_file << s[i]; } @@ -255,13 +255,13 @@ static char hex_to_nibble(char c) } -static char hex_to_char(char *s) +static char hex_to_char(const char *s) { return (hex_to_nibble(s[0]) << 4) + hex_to_nibble(s[1]); } -void Alg_smf_write::write_binary(int type_byte, char *msg) +void Alg_smf_write::write_binary(int type_byte, const char *msg) { int len = strlen(msg) / 2; out_file->put(type_byte); @@ -275,7 +275,7 @@ void Alg_smf_write::write_binary(int type_byte, char *msg) void Alg_smf_write::write_update(Alg_update_ptr update) { - char *name = update->parameter.attr_name(); + const char *name = update->parameter.attr_name(); /****Non-Meta Events****/ if (!strcmp(name, "pressurer")) { @@ -312,7 +312,7 @@ void Alg_smf_write::write_update(Alg_update_ptr update) write_data(val); } else if (!strcmp(name, "sysexs") && update->parameter.attr_type() == 's') { - char *s = update->parameter.s; + const char *s = update->parameter.s; if (s[0] && s[1] && toupper(s[0]) == 'F' && s[1] == '0') { s += 2; // skip the initial "F0" byte in message: it is implied } @@ -320,9 +320,9 @@ void Alg_smf_write::write_update(Alg_update_ptr update) write_binary(0xF0, s); } else if (!strcmp(name, "sqspecifics") && update->parameter.attr_type() == 's') { - char *s = update->parameter.s; + const char *s = update->parameter.s; write_delta(update->time); - out_file->put(0xFF); + out_file->put('\xFF'); write_binary(0x7F, s); /****Text Events****/ @@ -349,7 +349,7 @@ void Alg_smf_write::write_update(Alg_update_ptr update) // smpteoffset is specified as "24fps:00h:10m:00s:11.00f" // the following simple parser does not reject all badly // formatted strings, but it should parse good strings ok - char *s = update->parameter.s; + const char *s = update->parameter.s; int len = strlen(s); char smpteoffset[5]; if (len < 24) return; // not long enough, must be bad format @@ -390,8 +390,8 @@ void Alg_smf_write::write_update(Alg_update_ptr update) } if (keysig != -99 && keysig_mode) { // write when both are defined write_delta(keysig_when); - out_file->put(0xFF); - out_file->put(0x59); + out_file->put('\xFF'); + out_file->put('\x59'); out_file->put(2); // mask off high bits so that this value appears to be positive // i.e. -1 -> 0xFF (otherwise, write_data will clip -1 to 0) @@ -482,9 +482,9 @@ void Alg_smf_write::write_tempo(int divs, int tempo) // printf("Inserting tempo %f after %f clocks.\n", tempo, delta); write_varinum(divs - previous_divs); previous_divs = divs; - out_file->put(0xFF); - out_file->put(0x51); - out_file->put(0x03); + out_file->put('\xFF'); + out_file->put('\x51'); + out_file->put('\x03'); write_24bit((int)tempo); } @@ -512,12 +512,11 @@ void Alg_smf_write::write_tempo_change(int i) void Alg_smf_write::write_time_signature(int i) { Alg_time_sigs &ts = seq->time_sig; + write_delta(ts[i].beat); // write the time signature - long divs = ROUND(ts[i].beat * division); - write_varinum(divs - previous_divs); - out_file->put(0xFF); - out_file->put(0x58); // time signature - out_file->put(4); // length of message + out_file->put('\xFF'); + out_file->put('\x58'); // time signature + out_file->put('\x04'); // length of message out_file->put(ROUND(ts[i].num)); int den = ROUND(ts[i].den); int den_byte = 0; @@ -532,7 +531,7 @@ void Alg_smf_write::write_time_signature(int i) -void Alg_smf_write::write(ofstream &file) +void Alg_smf_write::write(ostream &file) { int track_len_offset; int track_end_offset; @@ -564,9 +563,9 @@ void Alg_smf_write::write(ofstream &file) // End of track event write_varinum(0); // delta time - out_file->put(0xFF); - out_file->put(0x2F); - out_file->put(0x00); + out_file->put('\xFF'); + out_file->put('\x2F'); + out_file->put('\x00'); // Go back and write in the length of the track track_end_offset = out_file->tellp(); @@ -632,7 +631,7 @@ void Alg_smf_write::write_varinum(int value) } -void Alg_seq::smf_write(ofstream &file) +void Alg_seq::smf_write(ostream &file) { Alg_smf_write writer(this); writer.write(file); @@ -646,4 +645,3 @@ bool Alg_seq::smf_write(const char *filename) outf.close(); return true; } - diff --git a/plugins/MidiImport/portsmf/allegrowr.cpp b/plugins/MidiImport/portsmf/allegrowr.cpp index 3b266f84cac..3142cfd7307 100644 --- a/plugins/MidiImport/portsmf/allegrowr.cpp +++ b/plugins/MidiImport/portsmf/allegrowr.cpp @@ -1,6 +1,6 @@ // allegrowr.cpp -- write sequence to an Allegro file (text) -#include "debug.h" +#include "assert.h" #include "stdlib.h" #include #include @@ -56,32 +56,34 @@ Alg_event_ptr Alg_seq::write_track_name(ostream &file, int n, // find a name and write it, return a pointer to it so the track // writer knows what update (if any) to skip { - Alg_event_ptr e = NULL; + Alg_event_ptr e = NULL; // e is the result, default is NULL file << "#track " << n; const char *attr = symbol_table.insert_string( n == 0 ? "seqnames" : "tracknames"); // search for name in events with timestamp of 0 for (int i = 0; i < events.length(); i++) { - e = events[i]; - if (e->time > 0) break; - if (e->is_update()) { - Alg_update_ptr u = (Alg_update_ptr) e; + Alg_event_ptr ue = events[i]; + if (ue->time > 0) break; + if (ue->is_update()) { + Alg_update_ptr u = (Alg_update_ptr) ue; if (u->parameter.attr == attr) { file << " " << u->parameter.s; + e = ue; // return the update event we found break; } } } - file << endl; - return e; + file << endl; // end of line containing #track [] + return e; // return parameter event with name if one was found } -void Alg_seq::write(ostream &file, bool in_secs) +void Alg_seq::write(ostream &file, bool in_secs, double offset) { int i, j; if (in_secs) convert_to_seconds(); else convert_to_beats(); + file << "#offset " << offset << endl; Alg_event_ptr update_to_skip = write_track_name(file, 0, track_list[0]); Alg_beats &beats = time_map->beats; for (i = 0; i < beats.len - 1; i++) { @@ -171,11 +173,11 @@ void Alg_seq::write(ostream &file, bool in_secs) } } -bool Alg_seq::write(const char *filename) +bool Alg_seq::write(const char *filename, double offset) { ofstream file(filename); if (file.fail()) return false; - write(file, units_are_seconds); - file.close(); - return true; + write(file, units_are_seconds, offset); + file.close(); + return true; } diff --git a/plugins/MidiImport/portsmf/mfmidi.cpp b/plugins/MidiImport/portsmf/mfmidi.cpp index 52f93b83764..7ea4b6ba357 100644 --- a/plugins/MidiImport/portsmf/mfmidi.cpp +++ b/plugins/MidiImport/portsmf/mfmidi.cpp @@ -13,6 +13,7 @@ #include "stdio.h" #include "mfmidi.h" #include "string.h" +#include "assert.h" #define MIDIFILE_ERROR -1 @@ -38,6 +39,7 @@ int Midifile_reader::readmt(const char *s, int skip) /* read through the "MThd" or "MTrk" header string */ /* if skip == 1, we attempt to skip initial garbage. */ { + assert(strlen(s) == 4); // must be "MThd" or "MTrk" int nread = 0; char b[4]; char buff[32]; @@ -66,8 +68,10 @@ int Midifile_reader::readmt(const char *s, int skip) goto retry; } err: +//#pragma warning(disable: 4996) // strcpy is safe since strings have known lengths (void) strcpy(buff,errmsg); (void) strcat(buff,s); +//#pragma warning(default: 4996) // turn it back on mferror(buff); return(0); } @@ -189,7 +193,7 @@ void Midifile_reader::readtrack() msginit(); while ( Mf_toberead > lookfor ) { - char c = egetc(); + unsigned char c = egetc(); if (midifile_error) return; msgadd(c); } @@ -253,15 +257,17 @@ void Midifile_reader::readtrack() void Midifile_reader::badbyte(int c) { char buff[32]; - +//#pragma warning(disable: 4996) // safe in this case (void) sprintf(buff,"unexpected byte: 0x%02x",c); +//#pragma warning(default: 4996) mferror(buff); } void Midifile_reader::metaevent(int type) { int leng = msgleng(); - char *m = msg(); + // made this unsigned to avoid sign extend + unsigned char *m = msg(); switch ( type ) { case 0x00: @@ -408,12 +414,17 @@ int Midifile_reader::read16bit() return to16bit(c1,c2); } -void Midifile_reader::mferror(const char *s) +void Midifile_reader::mferror(char *s) { Mf_error(s); midifile_error = 1; } +void Midifile_reader::mferror(const char *s) +{ + mferror(const_cast(s)); +} + /* The code below allows collection of a system exclusive message of */ /* arbitrary length. The Msgbuff is expanded as necessary. The only */ /* visible data/routines are msginit(), msgadd(), msg(), msgleng(). */ @@ -444,7 +455,7 @@ void Midifile_reader::msginit() Msgindex = 0; } -char *Midifile_reader::msg() +unsigned char *Midifile_reader::msg() { return(Msgbuff); } @@ -464,21 +475,16 @@ void Midifile_reader::msgadd(int c) void Midifile_reader::msgenlarge() { - char *newmess; - char *oldmess = Msgbuff; + unsigned char *newmess; + unsigned char *oldmess = Msgbuff; int oldleng = Msgsize; Msgsize += MSGINCREMENT; - newmess = (char *) Mf_malloc((sizeof(char) * Msgsize) ); + newmess = (unsigned char *) Mf_malloc((sizeof(unsigned char) * Msgsize) ); /* copy old message into larger new one */ if ( oldmess != 0 ) { - register char *p = newmess; - register char *q = oldmess; - register char *endq = &oldmess[oldleng]; - - for ( ; q!=endq ; p++,q++ ) - *p = *q; + memcpy(newmess, oldmess, oldleng); Mf_free(oldmess, oldleng); } Msgbuff = newmess; diff --git a/plugins/MidiImport/portsmf/mfmidi.h b/plugins/MidiImport/portsmf/mfmidi.h index d0049294bc2..744411e3bba 100644 --- a/plugins/MidiImport/portsmf/mfmidi.h +++ b/plugins/MidiImport/portsmf/mfmidi.h @@ -46,7 +46,7 @@ class Midifile_reader { virtual void Mf_chanprefix(int) = 0; virtual void Mf_portprefix(int) = 0; virtual void Mf_eot() = 0; - virtual void Mf_error(const char *) = 0; + virtual void Mf_error(char *) = 0; virtual void Mf_header(int,int,int) = 0; virtual void Mf_on(int,int,int) = 0; virtual void Mf_off(int,int,int) = 0; @@ -55,16 +55,16 @@ class Midifile_reader { virtual void Mf_pitchbend(int,int,int) = 0; virtual void Mf_program(int,int) = 0; virtual void Mf_chanpressure(int,int) = 0; - virtual void Mf_sysex(int,char*) = 0; - virtual void Mf_arbitrary(int,char*) = 0; - virtual void Mf_metamisc(int,int,char*) = 0; + virtual void Mf_sysex(int,unsigned char*) = 0; + virtual void Mf_arbitrary(int,unsigned char*) = 0; + virtual void Mf_metamisc(int,int,unsigned char*) = 0; virtual void Mf_seqnum(int) = 0; virtual void Mf_smpte(int,int,int,int,int) = 0; virtual void Mf_timesig(int,int,int,int) = 0; virtual void Mf_tempo(int) = 0; virtual void Mf_keysig(int,int) = 0; - virtual void Mf_sqspecific(int,char*) = 0; - virtual void Mf_text(int,int,char*) = 0; + virtual void Mf_sqspecific(int,unsigned char*) = 0; + virtual void Mf_text(int,int,unsigned char*) = 0; private: long Mf_toberead; @@ -73,7 +73,7 @@ class Midifile_reader { long read32bit(); int read16bit(); void msgenlarge(); - char *msg(); + unsigned char *msg(); int readheader(); void readtrack(); void sysex(); @@ -81,16 +81,17 @@ class Midifile_reader { int egetc(); int msgleng(); - int readmt(const char *, int); + int readmt(const char*,int); long to32bit(int,int,int,int); int to16bit(int,int); + void mferror(char *); void mferror(const char *); void badbyte(int); void metaevent(int); void msgadd(int); void chanmessage(int,int,int); - char *Msgbuff; + unsigned char *Msgbuff; long Msgsize; long Msgindex; }; diff --git a/plugins/MidiImport/portsmf/strparse.cpp b/plugins/MidiImport/portsmf/strparse.cpp index 7665b4ae058..592a21d62f4 100644 --- a/plugins/MidiImport/portsmf/strparse.cpp +++ b/plugins/MidiImport/portsmf/strparse.cpp @@ -1,5 +1,5 @@ -#include #include +#include // #include -- for debugging (cout) #include "ctype.h" using namespace std; @@ -48,10 +48,10 @@ void String_parse::get_nonspace_quoted(string &field) } -char *escape_chars[] = { (char *) "\\n", (char *)"\\t", (char *)"\\\\", (char *)"\\r", (char *) "\\\""}; +static const char *const escape_chars[] = {"\\n", "\\t", "\\\\", "\\r", "\\\""}; -void string_escape(string &result, char *str, const char *quote) +void string_escape(string &result, const char *str, const char *quote) { int length = (int) strlen(str); if (quote[0]) { @@ -59,8 +59,8 @@ void string_escape(string &result, char *str, const char *quote) } for (int i = 0; i < length; i++) { if (!isalnum((unsigned char) str[i])) { - char *chars = (char *)"\n\t\\\r\""; - char *special = strchr(chars, str[i]); + const char *const chars = "\n\t\\\r\""; + const char *const special = strchr(chars, str[i]); if (special) { result.append(escape_chars[special - chars]); } else { @@ -78,7 +78,7 @@ void String_parse::get_remainder(std::string &field) field.clear(); skip_space(); int len = str->length() - pos; - if ((*str)[len - 1] == '\n') { // if str ends in newline, + if ((len > 0) && ((*str)[len - 1] == '\n')) { // if str ends in newline, len--; // reduce length to ignore newline } field.insert(0, *str, pos, len); diff --git a/plugins/MidiImport/portsmf/strparse.h b/plugins/MidiImport/portsmf/strparse.h index 74f01591974..0c64b07b934 100644 --- a/plugins/MidiImport/portsmf/strparse.h +++ b/plugins/MidiImport/portsmf/strparse.h @@ -15,4 +15,4 @@ class String_parse { void get_remainder(std::string &field); }; -void string_escape(std::string &result, char *s, const char *quote); +void string_escape(std::string &result, const char *s, const char *quote); diff --git a/plugins/MidiImport/portsmf/trace.cpp b/plugins/MidiImport/portsmf/trace.cpp index 7c1999db570..38c050fe466 100644 --- a/plugins/MidiImport/portsmf/trace.cpp +++ b/plugins/MidiImport/portsmf/trace.cpp @@ -15,7 +15,7 @@ void trace(char *format, ...) char msg[256]; va_list args; va_start(args, format); - _vsnprintf(msg, 256, format, args); + _vsnprintf_s(msg, 256, _TRUNCATE, format, args); va_end(args); #ifdef _DEBUG _CrtDbgReport(_CRT_WARN, NULL, NULL, NULL, msg); diff --git a/plugins/MultitapEcho/MultitapEcho.cpp b/plugins/MultitapEcho/MultitapEcho.cpp index bff032deed9..eb6c51cba82 100644 --- a/plugins/MultitapEcho/MultitapEcho.cpp +++ b/plugins/MultitapEcho/MultitapEcho.cpp @@ -34,7 +34,7 @@ Plugin::Descriptor PLUGIN_EXPORT multitapecho_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Multitap Echo", - QT_TRANSLATE_NOOP( "pluginBrowser", "A multitap echo delay plugin" ), + QT_TRANSLATE_NOOP( "PluginBrowser", "A multitap echo delay plugin" ), "Vesa Kivimäki ", 0x0100, Plugin::Effect, diff --git a/plugins/OpulenZ/OpulenZ.cpp b/plugins/OpulenZ/OpulenZ.cpp index 4dde05b0f3b..de3cce9ce56 100644 --- a/plugins/OpulenZ/OpulenZ.cpp +++ b/plugins/OpulenZ/OpulenZ.cpp @@ -68,7 +68,7 @@ Plugin::Descriptor PLUGIN_EXPORT opulenz_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "OpulenZ", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "2-operator FM Synth" ), "Raine M. Ekman ", 0x0100, @@ -293,7 +293,7 @@ int OpulenzInstrument::pushVoice(int v) { return i; } -bool OpulenzInstrument::handleMidiEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset ) +bool OpulenzInstrument::handleMidiEvent( const MidiEvent& event, const TimePos& time, f_cnt_t offset ) { emulatorMutex.lock(); int key, vel, voice, tmp_pb; diff --git a/plugins/OpulenZ/OpulenZ.h b/plugins/OpulenZ/OpulenZ.h index 2273b355aff..1776df93fa9 100644 --- a/plugins/OpulenZ/OpulenZ.h +++ b/plugins/OpulenZ/OpulenZ.h @@ -56,7 +56,7 @@ class OpulenzInstrument : public Instrument return IsSingleStreamed | IsMidiBased; } - virtual bool handleMidiEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset = 0 ); + virtual bool handleMidiEvent( const MidiEvent& event, const TimePos& time, f_cnt_t offset = 0 ); virtual void play( sampleFrame * _working_buffer ); void saveSettings( QDomDocument & _doc, QDomElement & _this ); diff --git a/plugins/ReverbSC/ReverbSC.cpp b/plugins/ReverbSC/ReverbSC.cpp index 3d56fd0d0ae..f54002199d5 100644 --- a/plugins/ReverbSC/ReverbSC.cpp +++ b/plugins/ReverbSC/ReverbSC.cpp @@ -35,7 +35,7 @@ Plugin::Descriptor PLUGIN_EXPORT reverbsc_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "ReverbSC", - QT_TRANSLATE_NOOP( "pluginBrowser", "Reverb algorithm by Sean Costello" ), + QT_TRANSLATE_NOOP( "PluginBrowser", "Reverb algorithm by Sean Costello" ), "Paul Batchelor", 0x0123, Plugin::Effect, diff --git a/plugins/sid/3off.png b/plugins/Sid/3off.png similarity index 100% rename from plugins/sid/3off.png rename to plugins/Sid/3off.png diff --git a/plugins/sid/3offred.png b/plugins/Sid/3offred.png similarity index 100% rename from plugins/sid/3offred.png rename to plugins/Sid/3offred.png diff --git a/plugins/sid/6581.png b/plugins/Sid/6581.png similarity index 100% rename from plugins/sid/6581.png rename to plugins/Sid/6581.png diff --git a/plugins/sid/6581red.png b/plugins/Sid/6581red.png similarity index 100% rename from plugins/sid/6581red.png rename to plugins/Sid/6581red.png diff --git a/plugins/sid/8580.png b/plugins/Sid/8580.png similarity index 100% rename from plugins/sid/8580.png rename to plugins/Sid/8580.png diff --git a/plugins/sid/8580red.png b/plugins/Sid/8580red.png similarity index 100% rename from plugins/sid/8580red.png rename to plugins/Sid/8580red.png diff --git a/plugins/Sid/CMakeLists.txt b/plugins/Sid/CMakeLists.txt new file mode 100644 index 00000000000..c9fce7bb77d --- /dev/null +++ b/plugins/Sid/CMakeLists.txt @@ -0,0 +1,51 @@ +INCLUDE(BuildPlugin) + +INCLUDE_DIRECTORIES(resid) + +BUILD_PLUGIN(sid + SidInstrument.cpp + SidInstrument.h + resid/envelope.h + resid/extfilt.h + resid/filter.h + resid/pot.h + resid/siddefs.h + resid/sid.h + resid/spline.h + resid/voice.h + resid/wave.h + resid/envelope.cc + resid/extfilt.cc + resid/filter.cc + resid/pot.cc + resid/sid.cc + resid/version.cc + resid/voice.cc + resid/wave6581_PS_.cc + resid/wave6581_PST.cc + resid/wave6581_P_T.cc + resid/wave6581__ST.cc + resid/wave8580_PS_.cc + resid/wave8580_PST.cc + resid/wave8580_P_T.cc + resid/wave8580__ST.cc + resid/wave.cc + MOCFILES SidInstrument.h + EMBEDDED_RESOURCES *.png) + +# Parse VERSION +FILE(READ "resid/CMakeLists.txt" lines) +STRING(REGEX MATCH "set\\(MAJOR_VER [A-Za-z0-9_]*\\)" MAJOR_RAW ${lines}) +STRING(REGEX MATCH "set\\(MINOR_VER [A-Za-z0-9_]*\\)" MINOR_RAW ${lines}) +STRING(REGEX MATCH "set\\(PATCH_VER [A-Za-z0-9_]*\\)" PATCH_RAW ${lines}) +SEPARATE_ARGUMENTS(MAJOR_RAW) +SEPARATE_ARGUMENTS(MINOR_RAW) +SEPARATE_ARGUMENTS(PATCH_RAW) +LIST(GET MAJOR_RAW 1 MAJOR_RAW) +LIST(GET MINOR_RAW 1 MINOR_RAW) +LIST(GET PATCH_RAW 1 PATCH_RAW) +STRING(REPLACE ")" "" MAJOR_VER "${MAJOR_RAW}") +STRING(REPLACE ")" "" MINOR_VER "${MINOR_RAW}") +STRING(REPLACE ")" "" PATCH_VER "${PATCH_RAW}") + +TARGET_COMPILE_DEFINITIONS(sid PRIVATE VERSION="${MAJOR_VER}.${MINOR_VER}.${PATCH_VER}") diff --git a/plugins/sid/sid_instrument.cpp b/plugins/Sid/SidInstrument.cpp similarity index 94% rename from plugins/sid/sid_instrument.cpp rename to plugins/Sid/SidInstrument.cpp index 27f874e12dc..c2620021499 100644 --- a/plugins/sid/sid_instrument.cpp +++ b/plugins/Sid/SidInstrument.cpp @@ -1,5 +1,5 @@ /* - * sid_instrument.cpp - ResID based software-synthesizer + * SidInstrument.cpp - ResID based software-synthesizer * * Copyright (c) 2008 Csaba Hruska * Attila Herman @@ -32,7 +32,7 @@ #include "sid.h" -#include "sid_instrument.h" +#include "SidInstrument.h" #include "Engine.h" #include "InstrumentTrack.h" #include "Knob.h" @@ -75,7 +75,7 @@ Plugin::Descriptor PLUGIN_EXPORT sid_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "SID", - QT_TRANSLATE_NOOP( "pluginBrowser", "Emulation of the MOS6581 and MOS8580 " + QT_TRANSLATE_NOOP( "PluginBrowser", "Emulation of the MOS6581 and MOS8580 " "SID.\nThis chip was used in the Commodore 64 computer." ), "Csaba Hruska " @@ -119,7 +119,7 @@ voiceObject::~voiceObject() } -sidInstrument::sidInstrument( InstrumentTrack * _instrument_track ) : +SidInstrument::SidInstrument( InstrumentTrack * _instrument_track ) : Instrument( _instrument_track, &sid_plugin_descriptor ), // filter m_filterFCModel( 1024.0f, 0.0f, 2047.0f, 1.0f, this, tr( "Cutoff frequency" ) ), @@ -138,12 +138,12 @@ sidInstrument::sidInstrument( InstrumentTrack * _instrument_track ) : } -sidInstrument::~sidInstrument() +SidInstrument::~SidInstrument() { } -void sidInstrument::saveSettings( QDomDocument & _doc, +void SidInstrument::saveSettings( QDomDocument & _doc, QDomElement & _this ) { // voices @@ -189,7 +189,7 @@ void sidInstrument::saveSettings( QDomDocument & _doc, -void sidInstrument::loadSettings( const QDomElement & _this ) +void SidInstrument::loadSettings( const QDomElement & _this ) { // voices for( int i = 0; i < 3; ++i ) @@ -223,7 +223,7 @@ void sidInstrument::loadSettings( const QDomElement & _this ) -QString sidInstrument::nodeName() const +QString SidInstrument::nodeName() const { return( sid_plugin_descriptor.name ); } @@ -231,7 +231,7 @@ QString sidInstrument::nodeName() const -f_cnt_t sidInstrument::desiredReleaseFrames() const +f_cnt_t SidInstrument::desiredReleaseFrames() const { const float samplerate = Engine::mixer()->processingSampleRate(); int maxrel = 0; @@ -247,7 +247,7 @@ f_cnt_t sidInstrument::desiredReleaseFrames() const -static int sid_fillbuffer(unsigned char* sidreg, cSID *sid, int tdelta, short *ptr, int samples) +static int sid_fillbuffer(unsigned char* sidreg, SID *sid, int tdelta, short *ptr, int samples) { int tdelta2; int result; @@ -302,7 +302,7 @@ static int sid_fillbuffer(unsigned char* sidreg, cSID *sid, int tdelta, short *p -void sidInstrument::playNote( NotePlayHandle * _n, +void SidInstrument::playNote( NotePlayHandle * _n, sampleFrame * _working_buffer ) { const f_cnt_t tfp = _n->totalFramesPlayed(); @@ -312,7 +312,7 @@ void sidInstrument::playNote( NotePlayHandle * _n, if ( tfp == 0 ) { - cSID *sid = new cSID(); + SID *sid = new SID(); sid->set_sampling_parameters( clockrate, SAMPLE_FAST, samplerate ); sid->set_chip_model( MOS8580 ); sid->enable_filter( true ); @@ -322,7 +322,7 @@ void sidInstrument::playNote( NotePlayHandle * _n, const fpp_t frames = _n->framesLeftForCurrentPeriod(); const f_cnt_t offset = _n->noteOffset(); - cSID *sid = static_cast( _n->m_pluginData ); + SID *sid = static_cast( _n->m_pluginData ); int delta_t = clockrate * frames / samplerate + 4; // avoid variable length array for msvc compat short* buf = reinterpret_cast(_working_buffer + offset); @@ -446,17 +446,17 @@ void sidInstrument::playNote( NotePlayHandle * _n, -void sidInstrument::deleteNotePluginData( NotePlayHandle * _n ) +void SidInstrument::deleteNotePluginData( NotePlayHandle * _n ) { - delete static_cast( _n->m_pluginData ); + delete static_cast( _n->m_pluginData ); } -PluginView * sidInstrument::instantiateView( QWidget * _parent ) +PluginView * SidInstrument::instantiateView( QWidget * _parent ) { - return( new sidInstrumentView( this, _parent ) ); + return( new SidInstrumentView( this, _parent ) ); } @@ -481,7 +481,7 @@ class sidKnob : public Knob -sidInstrumentView::sidInstrumentView( Instrument * _instrument, +SidInstrumentView::SidInstrumentView( Instrument * _instrument, QWidget * _parent ) : InstrumentViewFixedSize( _instrument, _parent ) { @@ -657,13 +657,13 @@ sidInstrumentView::sidInstrumentView( Instrument * _instrument, } -sidInstrumentView::~sidInstrumentView() +SidInstrumentView::~SidInstrumentView() { } -void sidInstrumentView::updateKnobHint() +void SidInstrumentView::updateKnobHint() { - sidInstrument * k = castModel(); + SidInstrument * k = castModel(); for( int i = 0; i < 3; ++i ) { @@ -702,9 +702,9 @@ void sidInstrumentView::updateKnobHint() -void sidInstrumentView::updateKnobToolTip() +void SidInstrumentView::updateKnobToolTip() { - sidInstrument * k = castModel(); + SidInstrument * k = castModel(); for( int i = 0; i < 3; ++i ) { ToolTip::add( m_voiceKnobs[i].m_sustKnob, @@ -722,9 +722,9 @@ void sidInstrumentView::updateKnobToolTip() -void sidInstrumentView::modelChanged() +void SidInstrumentView::modelChanged() { - sidInstrument * k = castModel(); + SidInstrument * k = castModel(); m_volKnob->setModel( &k->m_volumeModel ); m_resKnob->setModel( &k->m_filterResonanceModel ); @@ -796,7 +796,7 @@ extern "C" // necessary for getting instance out of shared lib PLUGIN_EXPORT Plugin * lmms_plugin_main( Model *m, void * ) { - return( new sidInstrument( static_cast( m ) ) ); + return( new SidInstrument( static_cast( m ) ) ); } diff --git a/plugins/sid/sid_instrument.h b/plugins/Sid/SidInstrument.h similarity index 89% rename from plugins/sid/sid_instrument.h rename to plugins/Sid/SidInstrument.h index 479d09c5df1..c0998f0265d 100644 --- a/plugins/sid/sid_instrument.h +++ b/plugins/Sid/SidInstrument.h @@ -1,5 +1,5 @@ /* - * sid_Instrument.h - ResID based software-synthesizer + * SidInstrument.h - ResID based software-synthesizer * * Copyright (c) 2008 Csaba Hruska * Attila Herman @@ -33,7 +33,7 @@ #include "Knob.h" -class sidInstrumentView; +class SidInstrumentView; class NotePlayHandle; class automatableButtonGroup; class PixmapButton; @@ -67,11 +67,11 @@ class voiceObject : public Model BoolModel m_filteredModel; BoolModel m_testModel; - friend class sidInstrument; - friend class sidInstrumentView; + friend class SidInstrument; + friend class SidInstrumentView; } ; -class sidInstrument : public Instrument +class SidInstrument : public Instrument { Q_OBJECT public: @@ -89,8 +89,8 @@ class sidInstrument : public Instrument }; - sidInstrument( InstrumentTrack * _instrument_track ); - virtual ~sidInstrument(); + SidInstrument( InstrumentTrack * _instrument_track ); + virtual ~SidInstrument(); virtual void playNote( NotePlayHandle * _n, sampleFrame * _working_buffer ); @@ -126,18 +126,18 @@ class sidInstrument : public Instrument IntModel m_chipModel; - friend class sidInstrumentView; + friend class SidInstrumentView; } ; -class sidInstrumentView : public InstrumentViewFixedSize +class SidInstrumentView : public InstrumentViewFixedSize { Q_OBJECT public: - sidInstrumentView( Instrument * _instrument, QWidget * _parent ); - virtual ~sidInstrumentView(); + SidInstrumentView( Instrument * _instrument, QWidget * _parent ); + virtual ~SidInstrumentView(); private: virtual void modelChanged(); diff --git a/plugins/sid/artwork.png b/plugins/Sid/artwork.png similarity index 100% rename from plugins/sid/artwork.png rename to plugins/Sid/artwork.png diff --git a/plugins/sid/bp.png b/plugins/Sid/bp.png similarity index 100% rename from plugins/sid/bp.png rename to plugins/Sid/bp.png diff --git a/plugins/sid/bpred.png b/plugins/Sid/bpred.png similarity index 100% rename from plugins/sid/bpred.png rename to plugins/Sid/bpred.png diff --git a/plugins/sid/filterred.png b/plugins/Sid/filterred.png similarity index 100% rename from plugins/sid/filterred.png rename to plugins/Sid/filterred.png diff --git a/plugins/sid/hp.png b/plugins/Sid/hp.png similarity index 100% rename from plugins/sid/hp.png rename to plugins/Sid/hp.png diff --git a/plugins/sid/hpred.png b/plugins/Sid/hpred.png similarity index 100% rename from plugins/sid/hpred.png rename to plugins/Sid/hpred.png diff --git a/plugins/sid/logo.png b/plugins/Sid/logo.png similarity index 100% rename from plugins/sid/logo.png rename to plugins/Sid/logo.png diff --git a/plugins/sid/lp.png b/plugins/Sid/lp.png similarity index 100% rename from plugins/sid/lp.png rename to plugins/Sid/lp.png diff --git a/plugins/sid/lpred.png b/plugins/Sid/lpred.png similarity index 100% rename from plugins/sid/lpred.png rename to plugins/Sid/lpred.png diff --git a/plugins/sid/noise.png b/plugins/Sid/noise.png similarity index 100% rename from plugins/sid/noise.png rename to plugins/Sid/noise.png diff --git a/plugins/sid/noisered.png b/plugins/Sid/noisered.png similarity index 100% rename from plugins/sid/noisered.png rename to plugins/Sid/noisered.png diff --git a/plugins/sid/pulse.png b/plugins/Sid/pulse.png similarity index 100% rename from plugins/sid/pulse.png rename to plugins/Sid/pulse.png diff --git a/plugins/sid/pulsered.png b/plugins/Sid/pulsered.png similarity index 100% rename from plugins/sid/pulsered.png rename to plugins/Sid/pulsered.png diff --git a/plugins/Sid/resid b/plugins/Sid/resid new file mode 160000 index 00000000000..02afcc5cefa --- /dev/null +++ b/plugins/Sid/resid @@ -0,0 +1 @@ +Subproject commit 02afcc5cefac34bd0c665dc0fa6b748d238c1831 diff --git a/plugins/sid/ring.png b/plugins/Sid/ring.png similarity index 100% rename from plugins/sid/ring.png rename to plugins/Sid/ring.png diff --git a/plugins/sid/ringred.png b/plugins/Sid/ringred.png similarity index 100% rename from plugins/sid/ringred.png rename to plugins/Sid/ringred.png diff --git a/plugins/sid/saw.png b/plugins/Sid/saw.png similarity index 100% rename from plugins/sid/saw.png rename to plugins/Sid/saw.png diff --git a/plugins/sid/sawred.png b/plugins/Sid/sawred.png similarity index 100% rename from plugins/sid/sawred.png rename to plugins/Sid/sawred.png diff --git a/plugins/sid/sync.png b/plugins/Sid/sync.png similarity index 100% rename from plugins/sid/sync.png rename to plugins/Sid/sync.png diff --git a/plugins/sid/syncred.png b/plugins/Sid/syncred.png similarity index 100% rename from plugins/sid/syncred.png rename to plugins/Sid/syncred.png diff --git a/plugins/sid/test.png b/plugins/Sid/test.png similarity index 100% rename from plugins/sid/test.png rename to plugins/Sid/test.png diff --git a/plugins/sid/testred.png b/plugins/Sid/testred.png similarity index 100% rename from plugins/sid/testred.png rename to plugins/Sid/testred.png diff --git a/plugins/sid/triangle.png b/plugins/Sid/triangle.png similarity index 100% rename from plugins/sid/triangle.png rename to plugins/Sid/triangle.png diff --git a/plugins/sid/trianglered.png b/plugins/Sid/trianglered.png similarity index 100% rename from plugins/sid/trianglered.png rename to plugins/Sid/trianglered.png diff --git a/plugins/SpectrumAnalyzer/Analyzer.cpp b/plugins/SpectrumAnalyzer/Analyzer.cpp index 656d18bd4d6..87a8542e913 100644 --- a/plugins/SpectrumAnalyzer/Analyzer.cpp +++ b/plugins/SpectrumAnalyzer/Analyzer.cpp @@ -42,7 +42,7 @@ extern "C" { { "spectrumanalyzer", "Spectrum Analyzer", - QT_TRANSLATE_NOOP("pluginBrowser", "A graphical spectrum analyzer."), + QT_TRANSLATE_NOOP("PluginBrowser", "A graphical spectrum analyzer."), "Martin Pavelek ", 0x0112, Plugin::Effect, diff --git a/plugins/SpectrumAnalyzer/SaControlsDialog.cpp b/plugins/SpectrumAnalyzer/SaControlsDialog.cpp index f1aad2a01b5..ddd1489e85d 100644 --- a/plugins/SpectrumAnalyzer/SaControlsDialog.cpp +++ b/plugins/SpectrumAnalyzer/SaControlsDialog.cpp @@ -151,8 +151,8 @@ SaControlsDialog::SaControlsDialog(SaControls *controls, SaProcessor *processor) ComboBox *freqRangeCombo = new ComboBox(this, tr("Frequency range")); freqRangeCombo->setToolTip(tr("Frequency range")); - freqRangeCombo->setMinimumSize(100, 22); - freqRangeCombo->setMaximumSize(200, 22); + freqRangeCombo->setMinimumSize(100, ComboBox::DEFAULT_HEIGHT); + freqRangeCombo->setMaximumSize(200, ComboBox::DEFAULT_HEIGHT); freqRangeCombo->setModel(&controls->m_freqRangeModel); config_layout->addWidget(freqRangeCombo, 0, 3, 2, 1); @@ -171,8 +171,8 @@ SaControlsDialog::SaControlsDialog(SaControls *controls, SaProcessor *processor) ComboBox *ampRangeCombo = new ComboBox(this, tr("Amplitude range")); ampRangeCombo->setToolTip(tr("Amplitude range")); - ampRangeCombo->setMinimumSize(100, 22); - ampRangeCombo->setMaximumSize(200, 22); + ampRangeCombo->setMinimumSize(100, ComboBox::DEFAULT_HEIGHT); + ampRangeCombo->setMaximumSize(200, ComboBox::DEFAULT_HEIGHT); ampRangeCombo->setModel(&controls->m_ampRangeModel); config_layout->addWidget(ampRangeCombo, 2, 3, 2, 1); @@ -201,8 +201,8 @@ SaControlsDialog::SaControlsDialog(SaControls *controls, SaProcessor *processor) ComboBox *windowCombo = new ComboBox(this, tr("FFT window type")); windowCombo->setToolTip(tr("FFT window type")); - windowCombo->setMinimumSize(100, 22); - windowCombo->setMaximumSize(200, 22); + windowCombo->setMinimumSize(100, ComboBox::DEFAULT_HEIGHT); + windowCombo->setMaximumSize(200, ComboBox::DEFAULT_HEIGHT); windowCombo->setModel(&controls->m_windowModel); config_layout->addWidget(windowCombo, 2, 5, 2, 1); processor->rebuildWindow(); diff --git a/plugins/Vectorscope/VectorView.cpp b/plugins/Vectorscope/VectorView.cpp index 9a3f855eb98..330c666cf12 100644 --- a/plugins/Vectorscope/VectorView.cpp +++ b/plugins/Vectorscope/VectorView.cpp @@ -168,7 +168,7 @@ void VectorView::paintEvent(QPaintEvent *event) // To better preserve shapes, the log scale is applied to the distance from origin, // not the individual channels. const float distance = sqrt(inLeft * inLeft + inRight * inRight); - const float distanceLog = log10(1 + 9 * abs(distance)); + const float distanceLog = log10(1 + 9 * std::abs(distance)); const float angleCos = inLeft / distance; const float angleSin = inRight / distance; left = distanceLog * angleCos * (activeSize - 1) / 4; @@ -222,7 +222,7 @@ void VectorView::paintEvent(QPaintEvent *event) float inRight = inBuffer[frame][1] * m_zoom; if (logScale) { const float distance = sqrt(inLeft * inLeft + inRight * inRight); - const float distanceLog = log10(1 + 9 * abs(distance)); + const float distanceLog = log10(1 + 9 * std::abs(distance)); const float angleCos = inLeft / distance; const float angleSin = inRight / distance; left = distanceLog * angleCos * (activeSize - 1) / 4; diff --git a/plugins/Vectorscope/Vectorscope.cpp b/plugins/Vectorscope/Vectorscope.cpp index f8bc30c40df..30d33aa2d8f 100644 --- a/plugins/Vectorscope/Vectorscope.cpp +++ b/plugins/Vectorscope/Vectorscope.cpp @@ -33,7 +33,7 @@ extern "C" { { STRINGIFY(PLUGIN_NAME), "Vectorscope", - QT_TRANSLATE_NOOP("pluginBrowser", "A stereo field visualizer."), + QT_TRANSLATE_NOOP("PluginBrowser", "A stereo field visualizer."), "Martin Pavelek ", 0x0100, Plugin::Effect, diff --git a/plugins/VstEffect/VstEffect.cpp b/plugins/VstEffect/VstEffect.cpp index 80f209a7b1c..fb805aed3c3 100644 --- a/plugins/VstEffect/VstEffect.cpp +++ b/plugins/VstEffect/VstEffect.cpp @@ -41,7 +41,7 @@ Plugin::Descriptor PLUGIN_EXPORT vsteffect_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "VST", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "plugin for using arbitrary VST effects inside LMMS." ), "Tobias Doerffel ", 0x0200, diff --git a/plugins/VstEffect/VstEffectControls.cpp b/plugins/VstEffect/VstEffectControls.cpp index a0f97ce715e..e9133ff325e 100644 --- a/plugins/VstEffect/VstEffectControls.cpp +++ b/plugins/VstEffect/VstEffectControls.cpp @@ -350,7 +350,7 @@ manageVSTEffectView::manageVSTEffectView( VstEffect * _eff, VstEffectControls * const QMap & dump = m_effect->m_plugin->parameterDump(); m_vi->paramCount = dump.size(); - vstKnobs = new Knob *[ m_vi->paramCount ]; + vstKnobs = new CustomTextKnob *[ m_vi->paramCount ]; bool hasKnobModel = true; if (m_vi->knobFModel == NULL) { @@ -366,15 +366,15 @@ manageVSTEffectView::manageVSTEffectView( VstEffect * _eff, VstEffectControls * sprintf( paramStr, "param%d", i); s_dumpValues = dump[ paramStr ].split( ":" ); - vstKnobs[ i ] = new Knob( knobBright_26, widget, s_dumpValues.at( 1 ) ); - vstKnobs[ i ]->setHintText( s_dumpValues.at( 1 ) + ":", "" ); + vstKnobs[ i ] = new CustomTextKnob( knobBright_26, widget, s_dumpValues.at( 1 ) ); + vstKnobs[ i ]->setDescription( s_dumpValues.at( 1 ) + ":" ); vstKnobs[ i ]->setLabel( s_dumpValues.at( 1 ).left( 15 ) ); if( !hasKnobModel ) { sprintf( paramStr, "%d", i); m_vi->knobFModel[ i ] = new FloatModel( LocaleHelper::toFloat(s_dumpValues.at(2)), - 0.0f, 1.0f, 0.01f, _eff, tr( paramStr ) ); + 0.0f, 1.0f, 0.01f, _eff, paramStr ); } FloatModel * model = m_vi->knobFModel[i]; @@ -382,6 +382,7 @@ manageVSTEffectView::manageVSTEffectView( VstEffect * _eff, VstEffectControls * [this, model]() { setParameter( model ); }, Qt::DirectConnection); vstKnobs[ i ] ->setModel( model ); } + syncParameterText(); int i = 0; for( int lrow = 1; lrow < ( int( m_vi->paramCount / 10 ) + 1 ) + 1; lrow++ ) @@ -444,6 +445,7 @@ void manageVSTEffectView::syncPlugin( void ) m_vi2->knobFModel[ i ]->setInitValue( f_value ); } } + syncParameterText(); } @@ -479,9 +481,40 @@ void manageVSTEffectView::setParameter( Model * action ) if ( m_effect->m_plugin != NULL ) { m_effect->m_plugin->setParam( knobUNID, m_vi2->knobFModel[knobUNID]->value() ); + syncParameterText(); } } +void manageVSTEffectView::syncParameterText() +{ + m_effect->m_plugin->loadParameterLabels(); + m_effect->m_plugin->loadParameterDisplays(); + + QString paramLabelStr = m_effect->m_plugin->allParameterLabels(); + QString paramDisplayStr = m_effect->m_plugin->allParameterDisplays(); + + QStringList paramLabelList; + QStringList paramDisplayList; + + for( int i = 0; i < paramLabelStr.size(); ) + { + const int length = paramLabelStr[i].digitValue(); + paramLabelList.append(paramLabelStr.mid(i + 1, length)); + i += length + 1; + } + + for( int i = 0; i < paramDisplayStr.size(); ) + { + const int length = paramDisplayStr[i].digitValue(); + paramDisplayList.append(paramDisplayStr.mid(i + 1, length)); + i += length + 1; + } + + for( int i = 0; i < paramLabelList.size(); ++i ) + { + vstKnobs[i]->setValueText(paramDisplayList[i] + ' ' + paramLabelList[i]); + } +} diff --git a/plugins/VstEffect/VstEffectControls.h b/plugins/VstEffect/VstEffectControls.h index 092669f949f..cb98d0f439a 100644 --- a/plugins/VstEffect/VstEffectControls.h +++ b/plugins/VstEffect/VstEffectControls.h @@ -34,7 +34,7 @@ #include #include -#include "Knob.h" +#include "CustomTextKnob.h" #include #include #include @@ -111,6 +111,7 @@ protected slots: void syncPlugin( void ); void displayAutomatedOnly( void ); void setParameter( Model * action ); + void syncParameterText(); void closeWindow(); private: @@ -129,7 +130,7 @@ protected slots: QPushButton * m_syncButton; QPushButton * m_displayAutomatedOnly; QPushButton * m_closeButton; - Knob ** vstKnobs; + CustomTextKnob ** vstKnobs; } ; diff --git a/plugins/Xpressive/Xpressive.cpp b/plugins/Xpressive/Xpressive.cpp index a80a0ae4152..e4eff06bdc8 100644 --- a/plugins/Xpressive/Xpressive.cpp +++ b/plugins/Xpressive/Xpressive.cpp @@ -53,7 +53,7 @@ extern "C" { Plugin::Descriptor PLUGIN_EXPORT xpressive_plugin_descriptor = { STRINGIFY( - PLUGIN_NAME), "Xpressive", QT_TRANSLATE_NOOP("pluginBrowser", + PLUGIN_NAME), "Xpressive", QT_TRANSLATE_NOOP("PluginBrowser", "Mathematical expression parser"), "Orr Dvori", 0x0100, Plugin::Instrument, new PluginPixmapLoader("logo"), NULL, NULL }; @@ -818,7 +818,7 @@ void XpressiveView::usrWaveClicked() { } QString XpressiveHelpView::s_helpText= -"O1, O2 - Two output waves. Panning is controled by PN1 and PN2.
" +"O1, O2 - Two output waves. Panning is controlled by PN1 and PN2.
" "W1, W2, W3 - Wave samples evaluated by expression. In these samples, t variable ranges [0,1).
" "These waves can be used as functions inside the output waves (O1, O2). The wave period is 1.
" "

Available variables:


" @@ -829,10 +829,10 @@ QString XpressiveHelpView::s_helpText= "srate - Sample rate. In wave expression it returns the wave's number of samples.
" "tempo - Song's Tempo. Available only in the output expressions.
" "v - Note's volume. Note that the output is already multiplied by the volume. Available only in the output expressions.
" -"rel - Gives 0.0 while the key is holded, and 1.0 after the key release. Available only in the output expressions.
" -"trel - Time after release. While the note is holded, it gives 0.0. Afterwards, it start counting seconds.
" +"rel - Gives 0.0 while the key is held, and 1.0 after the key release. Available only in the output expressions.
" +"trel - Time after release. While the note is held, it gives 0.0. Afterwards, it starts counting seconds.
" "The time it takes to shift from 0.0 to 1.0 after key release is determined by the REL knob
" -"seed - A random value that remains consistent in the lifetime of a single wave. meant to be used with randsv
" +"seed - A random value that remains consistent in the lifetime of a single wave. Meant to be used with randsv
" "A1, A2, A3 - General purpose knobs. You can reference them only in O1 and O2. In range [-1,1].
" "

Available functions:


" "W1, W2, W3 - As mentioned before. You can reference them only in O1 and O2.
" @@ -877,6 +877,11 @@ XpressiveHelpView::XpressiveHelpView():QTextEdit(s_helpText) parentWidget()->setAttribute( Qt::WA_DeleteOnClose, false ); parentWidget()->setWindowIcon( PLUGIN_NAME::getIconPixmap( "logo" ) ); parentWidget()->setFixedSize( 300, 500); + + // No maximize button + Qt::WindowFlags flags = parentWidget()->windowFlags(); + flags &= ~Qt::WindowMaximizeButtonHint; + parentWidget()->setWindowFlags( flags ); } void XpressiveView::helpClicked() { diff --git a/plugins/audio_file_processor/audio_file_processor.cpp b/plugins/audio_file_processor/audio_file_processor.cpp index c8850392eb4..97b2759b2dd 100644 --- a/plugins/audio_file_processor/audio_file_processor.cpp +++ b/plugins/audio_file_processor/audio_file_processor.cpp @@ -22,6 +22,7 @@ * */ +#include "audio_file_processor.h" #include #include @@ -31,18 +32,19 @@ #include -#include "audio_file_processor.h" #include "ConfigManager.h" +#include "DataFile.h" #include "Engine.h" -#include "Song.h" +#include "gui_templates.h" #include "InstrumentTrack.h" +#include "interpolation.h" #include "Mixer.h" #include "NotePlayHandle.h" -#include "interpolation.h" -#include "gui_templates.h" -#include "ToolTip.h" +#include "PathUtil.h" +#include "Song.h" #include "StringPairDrag.h" -#include "DataFile.h" +#include "ToolTip.h" +#include "Clipboard.h" #include "embed.h" #include "plugin_export.h" @@ -54,7 +56,7 @@ Plugin::Descriptor PLUGIN_EXPORT audiofileprocessor_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "AudioFileProcessor", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "Simple sampler with various settings for " "using samples (e.g. drums) in an " "instrument-track" ), @@ -86,24 +88,24 @@ audioFileProcessor::audioFileProcessor( InstrumentTrack * _instrument_track ) : m_nextPlayBackwards( false ) { connect( &m_reverseModel, SIGNAL( dataChanged() ), - this, SLOT( reverseModelChanged() ) ); + this, SLOT( reverseModelChanged() ), Qt::DirectConnection ); connect( &m_ampModel, SIGNAL( dataChanged() ), - this, SLOT( ampModelChanged() ) ); + this, SLOT( ampModelChanged() ), Qt::DirectConnection ); connect( &m_startPointModel, SIGNAL( dataChanged() ), - this, SLOT( startPointChanged() ) ); + this, SLOT( startPointChanged() ), Qt::DirectConnection ); connect( &m_endPointModel, SIGNAL( dataChanged() ), - this, SLOT( endPointChanged() ) ); + this, SLOT( endPointChanged() ), Qt::DirectConnection ); connect( &m_loopPointModel, SIGNAL( dataChanged() ), - this, SLOT( loopPointChanged() ) ); + this, SLOT( loopPointChanged() ), Qt::DirectConnection ); connect( &m_stutterModel, SIGNAL( dataChanged() ), - this, SLOT( stutterModelChanged() ) ); - + this, SLOT( stutterModelChanged() ), Qt::DirectConnection ); + //interpolation modes m_interpolationModel.addItem( tr( "None" ) ); m_interpolationModel.addItem( tr( "Linear" ) ); m_interpolationModel.addItem( tr( "Sinc" ) ); m_interpolationModel.setValue( 1 ); - + pointChanged(); } @@ -237,7 +239,7 @@ void audioFileProcessor::loadSettings( const QDomElement & _this ) { setAudioFile( _this.attribute( "src" ), false ); - QString absolutePath = m_sampleBuffer.tryToMakeAbsolute( m_sampleBuffer.audioFile() ); + QString absolutePath = PathUtil::toAbsolute( m_sampleBuffer.audioFile() ); if ( !QFileInfo( absolutePath ).exists() ) { QString message = tr( "Sample not found: %1" ).arg( m_sampleBuffer.audioFile() ); @@ -329,7 +331,7 @@ void audioFileProcessor::setAudioFile( const QString & _audio_file, m_sampleBuffer.audioFile().isEmpty() ) ) { // then set it to new one - instrumentTrack()->setName( QFileInfo( _audio_file).fileName() ); + instrumentTrack()->setName( PathUtil::cleanName( _audio_file ) ); } // else we don't touch the track-name, because the user named it self @@ -363,7 +365,7 @@ void audioFileProcessor::stutterModelChanged() } -void audioFileProcessor::startPointChanged( void ) +void audioFileProcessor::startPointChanged( void ) { // check if start is over end and swap values if so if( m_startPointModel.value() > m_endPointModel.value() ) @@ -390,7 +392,7 @@ void audioFileProcessor::startPointChanged( void ) { m_endPointModel.setValue( qMin( m_endPointModel.value() + 0.001f, 1.0f ) ); } - + pointChanged(); } @@ -540,7 +542,7 @@ AudioFileProcessorView::AudioFileProcessorView( Instrument * _instrument, // interpolation selector m_interpBox = new ComboBox( this ); - m_interpBox->setGeometry( 142, 62, 82, 22 ); + m_interpBox->setGeometry( 142, 62, 82, ComboBox::DEFAULT_HEIGHT ); m_interpBox->setFont( pointSize<8>( m_interpBox->font() ) ); // wavegraph @@ -567,10 +569,13 @@ AudioFileProcessorView::~AudioFileProcessorView() void AudioFileProcessorView::dragEnterEvent( QDragEnterEvent * _dee ) { - if( _dee->mimeData()->hasFormat( StringPairDrag::mimeType() ) ) + // For mimeType() and MimeType enum class + using namespace Clipboard; + + if( _dee->mimeData()->hasFormat( mimeType( MimeType::StringPair ) ) ) { QString txt = _dee->mimeData()->data( - StringPairDrag::mimeType() ); + mimeType( MimeType::StringPair ) ); if( txt.section( ':', 0, 0 ) == QString( "tco_%1" ).arg( Track::SampleTrack ) ) { @@ -866,7 +871,7 @@ void AudioFileProcessorWaveView::mouseMoveEvent( QMouseEvent * _me ) void AudioFileProcessorWaveView::wheelEvent( QWheelEvent * _we ) { - zoom( _we->delta() > 0 ); + zoom( _we->angleDelta().y() > 0 ); update(); } @@ -1284,7 +1289,3 @@ PLUGIN_EXPORT Plugin * lmms_plugin_main(Model * model, void *) } - - - - diff --git a/plugins/bit_invader/bit_invader.cpp b/plugins/bit_invader/bit_invader.cpp index caa272fa7f0..948b845f471 100644 --- a/plugins/bit_invader/bit_invader.cpp +++ b/plugins/bit_invader/bit_invader.cpp @@ -44,6 +44,8 @@ #include "plugin_export.h" +static const int wavetableSize = 200; + extern "C" { @@ -51,7 +53,7 @@ Plugin::Descriptor PLUGIN_EXPORT bitinvader_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "BitInvader", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "Customizable wavetable synthesizer" ), "Andreas Brandmaier ", 0x0100, @@ -72,8 +74,8 @@ bSynth::bSynth( float * _shape, NotePlayHandle * _nph, bool _interpolation, sample_rate( _sample_rate ), interpolation( _interpolation) { - sample_shape = new float[200]; - for (int i=0; i < 200; ++i) + sample_shape = new float[wavetableSize]; + for (int i=0; i < wavetableSize; ++i) { sample_shape[i] = _shape[i] * _factor; } @@ -138,18 +140,18 @@ sample_t bSynth::nextStringSample( float sample_length ) 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, 200, this ), + m_sampleLength(128, 4, wavetableSize, 1, this, tr("Sample length")), + m_graph(-1.0f, 1.0f, wavetableSize, this), m_interpolation( false, this ), m_normalize( false, this ) { - + lengthChanged(); m_graph.setWaveToSine(); connect( &m_sampleLength, SIGNAL( dataChanged( ) ), - this, SLOT( lengthChanged( ) ) ); + this, SLOT( lengthChanged( ) ), Qt::DirectConnection ); connect( &m_graph, SIGNAL( samplesChanged( int, int ) ), this, SLOT( samplesChanged( int, int ) ) ); @@ -177,8 +179,8 @@ void bitInvader::saveSettings( QDomDocument & _doc, QDomElement & _this ) // Save sample shape base64-encoded QString sampleString; - base64::encode( (const char *)m_graph.samples(), - m_graph.length() * sizeof(float), sampleString ); + base64::encode((const char *)m_graph.samples(), + wavetableSize * sizeof(float), sampleString); _this.setAttribute( "sampleShape", sampleString ); @@ -194,6 +196,9 @@ void bitInvader::saveSettings( QDomDocument & _doc, QDomElement & _this ) void bitInvader::loadSettings( const QDomElement & _this ) { + // Clear wavetable before loading a new + m_graph.clear(); + // Load sample length m_sampleLength.loadSettings( _this, "sampleLength" ); @@ -204,8 +209,9 @@ void bitInvader::loadSettings( const QDomElement & _this ) char * dst = 0; base64::decode( _this.attribute( "sampleShape"), &dst, &size ); - m_graph.setLength( sampleLength ); - m_graph.setSamples( (float*) dst ); + m_graph.setLength(size / sizeof(float)); + m_graph.setSamples(reinterpret_cast(dst)); + m_graph.setLength(sampleLength); delete[] dst; // Load LED normalize @@ -240,7 +246,7 @@ void bitInvader::samplesChanged( int _begin, int _end ) void bitInvader::normalize() { // analyze - float max = 0; + float max = std::numeric_limits::epsilon(); const float* samples = m_graph.samples(); for(int i=0; i < m_graph.length(); i++) { diff --git a/plugins/carlabase/CMakeLists.txt b/plugins/carlabase/CMakeLists.txt index 28a1bc88c51..d382fceb8c5 100644 --- a/plugins/carlabase/CMakeLists.txt +++ b/plugins/carlabase/CMakeLists.txt @@ -14,13 +14,22 @@ if(LMMS_HAVE_WEAKCARLA) ${CMAKE_CURRENT_SOURCE_DIR}/carla/source/utils ${CMAKE_CURRENT_SOURCE_DIR}/carla/source/backend ) - ADD_LIBRARY(carla_native-plugin SHARED DummyCarla.cpp) - TARGET_INCLUDE_DIRECTORIES(carla_native-plugin PUBLIC ${CARLA_INCLUDE_DIRS}) - INSTALL(TARGETS carla_native-plugin + + IF(LMMS_BUILD_WIN32) + # use carla.dll + SET(CMAKE_SHARED_LIBRARY_PREFIX "") + SET(CARLA_NATIVE_LIB carla) + ELSE() + # use libcarla_native-plugin + SET(CARLA_NATIVE_LIB carla_native-plugin) + ENDIF() + ADD_LIBRARY(${CARLA_NATIVE_LIB} SHARED DummyCarla.cpp) + TARGET_INCLUDE_DIRECTORIES(${CARLA_NATIVE_LIB} PUBLIC ${CARLA_INCLUDE_DIRS}) + INSTALL(TARGETS ${CARLA_NATIVE_LIB} LIBRARY DESTINATION "${PLUGIN_DIR}/optional" RUNTIME DESTINATION "${PLUGIN_DIR}/optional" ) - SET(CARLA_LIBRARIES carla_native-plugin) + SET(CARLA_LIBRARIES ${CARLA_NATIVE_LIB}) # Set parent scope variables so carlarack and carlapatchbay can see them SET(CARLA_LIBRARIES ${CARLA_LIBRARIES} PARENT_SCOPE) endif() @@ -45,6 +54,6 @@ if(LMMS_HAVE_CARLA OR LMMS_HAVE_WEAKCARLA) INSTALL_RPATH_USE_LINK_PATH TRUE INSTALL_RPATH "${CARLA_RPATH}") IF(LMMS_HAVE_WEAKCARLA) - ADD_DEPENDENCIES(carlabase carla_native-plugin) + ADD_DEPENDENCIES(carlabase ${CARLA_NATIVE_LIB}) ENDIF() endif() diff --git a/plugins/carlabase/carla.cpp b/plugins/carlabase/carla.cpp index a6faa4d275d..728a6d804af 100644 --- a/plugins/carlabase/carla.cpp +++ b/plugins/carlabase/carla.cpp @@ -29,6 +29,7 @@ #include "gui_templates.h" #include "InstrumentPlayHandle.h" #include "InstrumentTrack.h" +#include "MidiEventToByteSeq.h" #include "Mixer.h" #include @@ -141,20 +142,14 @@ CarlaInstrument::CarlaInstrument(InstrumentTrack* const instrumentTrack, const D fHost.uiParentId = 0; // carla/resources contains PyQt scripts required for launch - QString dllName(carla_get_library_filename()); - QString resourcesPath; + QDir path(carla_get_library_folder()); #if defined(CARLA_OS_LINUX) - // parse prefix from dll filename - QDir path = QFileInfo(dllName).dir(); path.cdUp(); path.cdUp(); - resourcesPath = path.absolutePath() + "/share/carla/resources"; -#elif defined(CARLA_OS_MAC) + QString resourcesPath = path.absolutePath() + "/share/carla/resources"; +#else // parse prefix from dll filename - QDir path = QFileInfo(dllName).dir(); - resourcesPath = path.absolutePath() + "/resources"; -#elif defined(CARLA_OS_WIN32) || defined(CARLA_OS_WIN64) - // not yet supported + QString resourcesPath = path.absolutePath() + "/resources"; #endif fHost.resourceDir = strdup(resourcesPath.toUtf8().constData()); fHost.get_buffer_size = host_get_buffer_size; @@ -360,7 +355,7 @@ void CarlaInstrument::play(sampleFrame* workingBuffer) instrumentTrack()->processAudioBuffer(workingBuffer, bufsize, NULL); } -bool CarlaInstrument::handleMidiEvent(const MidiEvent& event, const MidiTime&, f_cnt_t offset) +bool CarlaInstrument::handleMidiEvent(const MidiEvent& event, const TimePos&, f_cnt_t offset) { const QMutexLocker ml(&fMutex); @@ -372,69 +367,9 @@ bool CarlaInstrument::handleMidiEvent(const MidiEvent& event, const MidiTime&, f nEvent.port = 0; nEvent.time = offset; - nEvent.data[0] = event.type() | (event.channel() & 0x0F); - - switch (event.type()) - { - case MidiNoteOn: - if (event.velocity() > 0) - { - if (event.key() < 0 || event.key() > MidiMaxKey) - break; - - nEvent.data[1] = event.key(); - nEvent.data[2] = event.velocity(); - nEvent.size = 3; - break; - } - else - { - nEvent.data[0] = MidiNoteOff | (event.channel() & 0x0F); - // nobreak - } - - case MidiNoteOff: - if (event.key() < 0 || event.key() > MidiMaxKey) - break; - - nEvent.data[1] = event.key(); - nEvent.data[2] = event.velocity(); - nEvent.size = 3; - break; - - case MidiKeyPressure: - nEvent.data[1] = event.key(); - nEvent.data[2] = event.velocity(); - nEvent.size = 3; - break; - - case MidiControlChange: - nEvent.data[1] = event.controllerNumber(); - nEvent.data[2] = event.controllerValue(); - nEvent.size = 3; - break; - - case MidiProgramChange: - nEvent.data[1] = event.program(); - nEvent.size = 2; - break; - - case MidiChannelPressure: - nEvent.data[1] = event.channelPressure(); - nEvent.size = 2; - break; - - case MidiPitchBend: - nEvent.data[1] = event.pitchBend() & 0x7f; - nEvent.data[2] = event.pitchBend() >> 7; - nEvent.size = 3; - break; - - default: - // unhandled - --fMidiEventCount; - break; - } + std::size_t written = writeToByteSeq(event, nEvent.data, sizeof(NativeMidiEvent::data)); + if(written) { nEvent.size = written; } + else { --fMidiEventCount; } return true; } @@ -503,8 +438,20 @@ CarlaInstrumentView::~CarlaInstrumentView() void CarlaInstrumentView::toggleUI(bool visible) { - if (fHandle != NULL && fDescriptor->ui_show != NULL) + if (fHandle != NULL && fDescriptor->ui_show != NULL) { +// TODO: remove when fixed upstream +// change working path to location of carla.dll to avoid conflict with lmms +#if defined(CARLA_OS_WIN32) || defined(CARLA_OS_WIN64) + if (visible) { + QString backupDir = QDir::currentPath(); + QDir::setCurrent(carla_get_library_folder()); + fDescriptor->ui_show(fHandle, true); + QDir::setCurrent(backupDir); + return; + } +#endif fDescriptor->ui_show(fHandle, visible); + } } void CarlaInstrumentView::uiClosed() diff --git a/plugins/carlabase/carla.h b/plugins/carlabase/carla.h index 2c683add935..7efecf681d6 100644 --- a/plugins/carlabase/carla.h +++ b/plugins/carlabase/carla.h @@ -72,7 +72,7 @@ class CARLABASE_EXPORT CarlaInstrument : public Instrument virtual void saveSettings(QDomDocument& doc, QDomElement& parent); virtual void loadSettings(const QDomElement& elem); virtual void play(sampleFrame* workingBuffer); - virtual bool handleMidiEvent(const MidiEvent& event, const MidiTime& time, f_cnt_t offset); + virtual bool handleMidiEvent(const MidiEvent& event, const TimePos& time, f_cnt_t offset); virtual PluginView* instantiateView(QWidget* parent); signals: diff --git a/plugins/carlapatchbay/carlapatchbay.cpp b/plugins/carlapatchbay/carlapatchbay.cpp index ad0c1f6aef5..0090b3fcccf 100644 --- a/plugins/carlapatchbay/carlapatchbay.cpp +++ b/plugins/carlapatchbay/carlapatchbay.cpp @@ -35,7 +35,7 @@ Plugin::Descriptor PLUGIN_EXPORT carlapatchbay_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Carla Patchbay", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "Carla Patchbay Instrument" ), "falkTX ", CARLA_VERSION_HEX, diff --git a/plugins/carlarack/carlarack.cpp b/plugins/carlarack/carlarack.cpp index ee2a788354f..3b3f443abb4 100644 --- a/plugins/carlarack/carlarack.cpp +++ b/plugins/carlarack/carlarack.cpp @@ -35,7 +35,7 @@ Plugin::Descriptor PLUGIN_EXPORT carlarack_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Carla Rack", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "Carla Rack Instrument" ), "falkTX ", CARLA_VERSION_HEX, diff --git a/plugins/dynamics_processor/dynamics_processor.cpp b/plugins/dynamics_processor/dynamics_processor.cpp index 9bf7d9b3c90..38c74cf19de 100644 --- a/plugins/dynamics_processor/dynamics_processor.cpp +++ b/plugins/dynamics_processor/dynamics_processor.cpp @@ -38,7 +38,7 @@ Plugin::Descriptor PLUGIN_EXPORT dynamicsprocessor_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Dynamics Processor", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "plugin for processing dynamics in a flexible way" ), "Vesa Kivimäki ", 0x0100, diff --git a/plugins/kicker/kicker.cpp b/plugins/kicker/kicker.cpp index 5f36aae93f1..fe770c1ac1f 100644 --- a/plugins/kicker/kicker.cpp +++ b/plugins/kicker/kicker.cpp @@ -45,7 +45,7 @@ Plugin::Descriptor PLUGIN_EXPORT kicker_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Kicker", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "Versatile drum synthesizer" ), "Tobias Doerffel ", 0x0100, diff --git a/plugins/ladspa_browser/ladspa_browser.cpp b/plugins/ladspa_browser/ladspa_browser.cpp index d265bc0e3e2..b363336346f 100644 --- a/plugins/ladspa_browser/ladspa_browser.cpp +++ b/plugins/ladspa_browser/ladspa_browser.cpp @@ -49,7 +49,7 @@ Plugin::Descriptor PLUGIN_EXPORT ladspabrowser_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "LADSPA Plugin Browser", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "List installed LADSPA plugins" ), "Danny McRae ", 0x0100, diff --git a/plugins/ladspa_browser/ladspa_port_dialog.cpp b/plugins/ladspa_browser/ladspa_port_dialog.cpp index d7b124b3fa1..c213c6f0235 100644 --- a/plugins/ladspa_browser/ladspa_port_dialog.cpp +++ b/plugins/ladspa_browser/ladspa_port_dialog.cpp @@ -65,7 +65,7 @@ ladspaPortDialog::ladspaPortDialog( const ladspa_key_t & _key ) for( int col = 0; col < 7; ++col ) { QTableWidgetItem * item = new QTableWidgetItem; - item->setFlags( 0 ); + item->setFlags(QFlag(0)); settings->setItem( row, col, item ); } diff --git a/plugins/lb302/lb302.cpp b/plugins/lb302/lb302.cpp index ad3d33b0a04..e9a518e3d0c 100644 --- a/plugins/lb302/lb302.cpp +++ b/plugins/lb302/lb302.cpp @@ -74,7 +74,7 @@ //#define engine::mixer()->processingSampleRate() 44100.0f - +const float sampleRateCutoff = 44100.0f; extern "C" { @@ -83,7 +83,7 @@ Plugin::Descriptor PLUGIN_EXPORT lb302_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "LB302", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "Incomplete monophonic imitation tb303" ), "Paul Giblock ", 0x0100, @@ -228,8 +228,11 @@ void lb302Filter3Pole::envRecalc() // e0 is adjusted for Hz and doesn't need ENVINC w = vcf_e0 + vcf_c0; k = (fs->cutoff > 0.975)?0.975:fs->cutoff; + // sampleRateCutoff should not be changed to anything dynamic that is outside the + // scope of lb302 (like e.g. the mixers sample rate) as this changes the filters cutoff + // behavior without any modification to its controls. kfco = 50.f + (k)*((2300.f-1600.f*(fs->envmod))+(w) * - (700.f+1500.f*(k)+(1500.f+(k)*(Engine::mixer()->processingSampleRate()/2.f-6000.f)) * + (700.f+1500.f*(k)+(1500.f+(k)*(sampleRateCutoff/2.f-6000.f)) * (fs->envmod)) ); //+iacc*(.3+.7*kfco*kenvmod)*kaccent*kaccurve*2000 @@ -433,8 +436,11 @@ QString lb302Synth::nodeName() const // OBSOLETE. Break apart once we get Q_OBJECT to work. >:[ void lb302Synth::recalcFilter() { +#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0)) + vcf.loadRelaxed()->recalc(); +#else vcf.load()->recalc(); - +#endif // THIS IS OLD 3pole/24dB code, I may reintegrate it. Don't need it // right now. Should be toggled by LB_24_RES_TRICK at the moment. @@ -683,7 +689,11 @@ void lb302Synth::initNote( lb302Note *n) if(n->dead ==0){ // Swap next two blocks?? +#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0)) + vcf.loadRelaxed()->playNote(); +#else vcf.load()->playNote(); +#endif // Ensure envelope is recalculated vcf_envpos = ENVINC; diff --git a/plugins/monstro/Monstro.cpp b/plugins/monstro/Monstro.cpp index efb351fc839..816cfe5502d 100644 --- a/plugins/monstro/Monstro.cpp +++ b/plugins/monstro/Monstro.cpp @@ -45,7 +45,7 @@ Plugin::Descriptor PLUGIN_EXPORT monstro_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Monstro", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "Monstrous 3-oscillator synth with modulation matrix" ), "Vesa Kivimäki ", 0x0100, @@ -957,52 +957,52 @@ MonstroInstrument::MonstroInstrument( InstrumentTrack * _instrument_track ) : // updateVolumes - connect( &m_osc1Vol, SIGNAL( dataChanged() ), this, SLOT( updateVolume1() ) ); - connect( &m_osc1Pan, SIGNAL( dataChanged() ), this, SLOT( updateVolume1() ) ); - connect( &m_osc2Vol, SIGNAL( dataChanged() ), this, SLOT( updateVolume2() ) ); - connect( &m_osc2Pan, SIGNAL( dataChanged() ), this, SLOT( updateVolume2() ) ); - connect( &m_osc3Vol, SIGNAL( dataChanged() ), this, SLOT( updateVolume3() ) ); - connect( &m_osc3Pan, SIGNAL( dataChanged() ), this, SLOT( updateVolume3() ) ); + connect( &m_osc1Vol, SIGNAL( dataChanged() ), this, SLOT( updateVolume1() ), Qt::DirectConnection ); + connect( &m_osc1Pan, SIGNAL( dataChanged() ), this, SLOT( updateVolume1() ), Qt::DirectConnection ); + connect( &m_osc2Vol, SIGNAL( dataChanged() ), this, SLOT( updateVolume2() ), Qt::DirectConnection ); + connect( &m_osc2Pan, SIGNAL( dataChanged() ), this, SLOT( updateVolume2() ), Qt::DirectConnection ); + connect( &m_osc3Vol, SIGNAL( dataChanged() ), this, SLOT( updateVolume3() ), Qt::DirectConnection ); + connect( &m_osc3Pan, SIGNAL( dataChanged() ), this, SLOT( updateVolume3() ), Qt::DirectConnection ); // updateFreq - connect( &m_osc1Crs, SIGNAL( dataChanged() ), this, SLOT( updateFreq1() ) ); - connect( &m_osc2Crs, SIGNAL( dataChanged() ), this, SLOT( updateFreq2() ) ); - connect( &m_osc3Crs, SIGNAL( dataChanged() ), this, SLOT( updateFreq3() ) ); + connect( &m_osc1Crs, SIGNAL( dataChanged() ), this, SLOT( updateFreq1() ), Qt::DirectConnection ); + connect( &m_osc2Crs, SIGNAL( dataChanged() ), this, SLOT( updateFreq2() ), Qt::DirectConnection ); + connect( &m_osc3Crs, SIGNAL( dataChanged() ), this, SLOT( updateFreq3() ), Qt::DirectConnection ); - connect( &m_osc1Ftl, SIGNAL( dataChanged() ), this, SLOT( updateFreq1() ) ); - connect( &m_osc2Ftl, SIGNAL( dataChanged() ), this, SLOT( updateFreq2() ) ); + connect( &m_osc1Ftl, SIGNAL( dataChanged() ), this, SLOT( updateFreq1() ), Qt::DirectConnection ); + connect( &m_osc2Ftl, SIGNAL( dataChanged() ), this, SLOT( updateFreq2() ), Qt::DirectConnection ); - connect( &m_osc1Ftr, SIGNAL( dataChanged() ), this, SLOT( updateFreq1() ) ); - connect( &m_osc2Ftr, SIGNAL( dataChanged() ), this, SLOT( updateFreq2() ) ); + connect( &m_osc1Ftr, SIGNAL( dataChanged() ), this, SLOT( updateFreq1() ), Qt::DirectConnection ); + connect( &m_osc2Ftr, SIGNAL( dataChanged() ), this, SLOT( updateFreq2() ), Qt::DirectConnection ); // updatePO - connect( &m_osc1Spo, SIGNAL( dataChanged() ), this, SLOT( updatePO1() ) ); - connect( &m_osc2Spo, SIGNAL( dataChanged() ), this, SLOT( updatePO2() ) ); - connect( &m_osc3Spo, SIGNAL( dataChanged() ), this, SLOT( updatePO3() ) ); + connect( &m_osc1Spo, SIGNAL( dataChanged() ), this, SLOT( updatePO1() ), Qt::DirectConnection ); + connect( &m_osc2Spo, SIGNAL( dataChanged() ), this, SLOT( updatePO2() ), Qt::DirectConnection ); + connect( &m_osc3Spo, SIGNAL( dataChanged() ), this, SLOT( updatePO3() ), Qt::DirectConnection ); // updateEnvelope1 - connect( &m_env1Pre, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope1() ) ); - connect( &m_env1Att, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope1() ) ); - connect( &m_env1Hold, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope1() ) ); - connect( &m_env1Dec, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope1() ) ); - connect( &m_env1Rel, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope1() ) ); - connect( &m_env1Slope, SIGNAL( dataChanged() ), this, SLOT( updateSlope1() ) ); + connect( &m_env1Pre, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope1() ), Qt::DirectConnection ); + connect( &m_env1Att, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope1() ), Qt::DirectConnection ); + connect( &m_env1Hold, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope1() ), Qt::DirectConnection ); + connect( &m_env1Dec, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope1() ), Qt::DirectConnection ); + connect( &m_env1Rel, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope1() ), Qt::DirectConnection ); + connect( &m_env1Slope, SIGNAL( dataChanged() ), this, SLOT( updateSlope1() ), Qt::DirectConnection ); // updateEnvelope2 - connect( &m_env2Pre, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope2() ) ); - connect( &m_env2Att, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope2() ) ); - connect( &m_env2Hold, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope2() ) ); - connect( &m_env2Dec, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope2() ) ); - connect( &m_env2Rel, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope2() ) ); - connect( &m_env2Slope, SIGNAL( dataChanged() ), this, SLOT( updateSlope2() ) ); + connect( &m_env2Pre, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope2() ), Qt::DirectConnection ); + connect( &m_env2Att, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope2() ), Qt::DirectConnection ); + connect( &m_env2Hold, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope2() ), Qt::DirectConnection ); + connect( &m_env2Dec, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope2() ), Qt::DirectConnection ); + connect( &m_env2Rel, SIGNAL( dataChanged() ), this, SLOT( updateEnvelope2() ), Qt::DirectConnection ); + connect( &m_env2Slope, SIGNAL( dataChanged() ), this, SLOT( updateSlope2() ), Qt::DirectConnection ); // updateLFOAtts - connect( &m_lfo1Att, SIGNAL( dataChanged() ), this, SLOT( updateLFOAtts() ) ); - connect( &m_lfo2Att, SIGNAL( dataChanged() ), this, SLOT( updateLFOAtts() ) ); + connect( &m_lfo1Att, SIGNAL( dataChanged() ), this, SLOT( updateLFOAtts() ), Qt::DirectConnection ); + connect( &m_lfo2Att, SIGNAL( dataChanged() ), this, SLOT( updateLFOAtts() ), Qt::DirectConnection ); // updateSampleRate @@ -1664,7 +1664,7 @@ QWidget * MonstroView::setupOperatorsView( QWidget * _parent ) m_osc2VolKnob -> setVolumeKnob( true ); m_osc2WaveBox = new ComboBox( view ); - m_osc2WaveBox -> setGeometry( 204, O2ROW + 7, 42, 22 ); + m_osc2WaveBox -> setGeometry( 204, O2ROW + 7, 42, ComboBox::DEFAULT_HEIGHT ); m_osc2WaveBox->setFont( pointSize<8>( m_osc2WaveBox->font() ) ); maketinyled( m_osc2SyncHButton, 212, O2ROW - 3, tr( "Hard sync oscillator 2" ) ) @@ -1679,18 +1679,18 @@ QWidget * MonstroView::setupOperatorsView( QWidget * _parent ) m_osc3VolKnob -> setVolumeKnob( true ); m_osc3Wave1Box = new ComboBox( view ); - m_osc3Wave1Box -> setGeometry( 160, O3ROW + 7, 42, 22 ); + m_osc3Wave1Box -> setGeometry( 160, O3ROW + 7, 42, ComboBox::DEFAULT_HEIGHT ); m_osc3Wave1Box->setFont( pointSize<8>( m_osc3Wave1Box->font() ) ); m_osc3Wave2Box = new ComboBox( view ); - m_osc3Wave2Box -> setGeometry( 204, O3ROW + 7, 42, 22 ); + m_osc3Wave2Box -> setGeometry( 204, O3ROW + 7, 42, ComboBox::DEFAULT_HEIGHT ); m_osc3Wave2Box->setFont( pointSize<8>( m_osc3Wave2Box->font() ) ); maketinyled( m_osc3SyncHButton, 212, O3ROW - 3, tr( "Hard sync oscillator 3" ) ) maketinyled( m_osc3SyncRButton, 191, O3ROW - 3, tr( "Reverse sync oscillator 3" ) ) m_lfo1WaveBox = new ComboBox( view ); - m_lfo1WaveBox -> setGeometry( 2, LFOROW + 7, 42, 22 ); + m_lfo1WaveBox -> setGeometry( 2, LFOROW + 7, 42, ComboBox::DEFAULT_HEIGHT ); m_lfo1WaveBox->setFont( pointSize<8>( m_lfo1WaveBox->font() ) ); maketsknob( m_lfo1AttKnob, LFOCOL1, LFOROW, tr( "Attack" ), " ms", "lfoKnob" ) @@ -1698,7 +1698,7 @@ QWidget * MonstroView::setupOperatorsView( QWidget * _parent ) makeknob( m_lfo1PhsKnob, LFOCOL3, LFOROW, tr( "Phase" ), tr( " deg" ), "lfoKnob" ) m_lfo2WaveBox = new ComboBox( view ); - m_lfo2WaveBox -> setGeometry( 127, LFOROW + 7, 42, 22 ); + m_lfo2WaveBox -> setGeometry( 127, LFOROW + 7, 42, ComboBox::DEFAULT_HEIGHT ); m_lfo2WaveBox->setFont( pointSize<8>( m_lfo2WaveBox->font() ) ); maketsknob( m_lfo2AttKnob, LFOCOL4, LFOROW, tr( "Attack" ), " ms", "lfoKnob" ) diff --git a/plugins/monstro/Monstro.h b/plugins/monstro/Monstro.h index fc0cc13b06d..0bb1a8dccbb 100644 --- a/plugins/monstro/Monstro.h +++ b/plugins/monstro/Monstro.h @@ -39,7 +39,6 @@ #include "Oscillator.h" #include "lmms_math.h" #include "BandLimitedWave.h" -#include "stdshims.h" // // UI Macros @@ -310,35 +309,35 @@ class MonstroInstrument : public Instrument Q_OBJECT #define setwavemodel( name ) \ - name .addItem( tr( "Sine wave" ), make_unique( "sin" ) ); \ - name .addItem( tr( "Bandlimited Triangle wave" ), make_unique( "tri" ) ); \ - name .addItem( tr( "Bandlimited Saw wave" ), make_unique( "saw" ) ); \ - name .addItem( tr( "Bandlimited Ramp wave" ), make_unique( "ramp" ) ); \ - name .addItem( tr( "Bandlimited Square wave" ), make_unique( "sqr" ) ); \ - name .addItem( tr( "Bandlimited Moog saw wave" ), make_unique( "moog" ) ); \ - name .addItem( tr( "Soft square wave" ), make_unique( "sqrsoft" ) ); \ - name .addItem( tr( "Absolute sine wave" ), make_unique( "sinabs" ) ); \ - name .addItem( tr( "Exponential wave" ), make_unique( "exp" ) ); \ - name .addItem( tr( "White noise" ), make_unique( "noise" ) ); \ - name .addItem( tr( "Digital Triangle wave" ), make_unique( "tri" ) ); \ - name .addItem( tr( "Digital Saw wave" ), make_unique( "saw" ) ); \ - name .addItem( tr( "Digital Ramp wave" ), make_unique( "ramp" ) ); \ - name .addItem( tr( "Digital Square wave" ), make_unique( "sqr" ) ); \ - name .addItem( tr( "Digital Moog saw wave" ), make_unique( "moog" ) ); + name .addItem( tr( "Sine wave" ), std::make_unique( "sin" ) ); \ + name .addItem( tr( "Bandlimited Triangle wave" ), std::make_unique( "tri" ) ); \ + name .addItem( tr( "Bandlimited Saw wave" ), std::make_unique( "saw" ) ); \ + name .addItem( tr( "Bandlimited Ramp wave" ), std::make_unique( "ramp" ) ); \ + name .addItem( tr( "Bandlimited Square wave" ), std::make_unique( "sqr" ) ); \ + name .addItem( tr( "Bandlimited Moog saw wave" ), std::make_unique( "moog" ) ); \ + name .addItem( tr( "Soft square wave" ), std::make_unique( "sqrsoft" ) ); \ + name .addItem( tr( "Absolute sine wave" ), std::make_unique( "sinabs" ) ); \ + name .addItem( tr( "Exponential wave" ), std::make_unique( "exp" ) ); \ + name .addItem( tr( "White noise" ), std::make_unique( "noise" ) ); \ + name .addItem( tr( "Digital Triangle wave" ), std::make_unique( "tri" ) ); \ + name .addItem( tr( "Digital Saw wave" ), std::make_unique( "saw" ) ); \ + name .addItem( tr( "Digital Ramp wave" ), std::make_unique( "ramp" ) ); \ + name .addItem( tr( "Digital Square wave" ), std::make_unique( "sqr" ) ); \ + name .addItem( tr( "Digital Moog saw wave" ), std::make_unique( "moog" ) ); #define setlfowavemodel( name ) \ - name .addItem( tr( "Sine wave" ), make_unique( "sin" ) ); \ - name .addItem( tr( "Triangle wave" ), make_unique( "tri" ) ); \ - name .addItem( tr( "Saw wave" ), make_unique( "saw" ) ); \ - name .addItem( tr( "Ramp wave" ), make_unique( "ramp" ) ); \ - name .addItem( tr( "Square wave" ), make_unique( "sqr" ) ); \ - name .addItem( tr( "Moog saw wave" ), make_unique( "moog" ) ); \ - name .addItem( tr( "Soft square wave" ), make_unique( "sqrsoft" ) ); \ - name .addItem( tr( "Abs. sine wave" ), make_unique( "sinabs" ) ); \ - name .addItem( tr( "Exponential wave" ), make_unique( "exp" ) ); \ - name .addItem( tr( "Random" ), make_unique( "rand" ) ); \ - name .addItem( tr( "Random smooth" ), make_unique( "rand" ) ); + name .addItem( tr( "Sine wave" ), std::make_unique( "sin" ) ); \ + name .addItem( tr( "Triangle wave" ), std::make_unique( "tri" ) ); \ + name .addItem( tr( "Saw wave" ), std::make_unique( "saw" ) ); \ + name .addItem( tr( "Ramp wave" ), std::make_unique( "ramp" ) ); \ + name .addItem( tr( "Square wave" ), std::make_unique( "sqr" ) ); \ + name .addItem( tr( "Moog saw wave" ), std::make_unique( "moog" ) ); \ + name .addItem( tr( "Soft square wave" ), std::make_unique( "sqrsoft" ) ); \ + name .addItem( tr( "Abs. sine wave" ), std::make_unique( "sinabs" ) ); \ + name .addItem( tr( "Exponential wave" ), std::make_unique( "exp" ) ); \ + name .addItem( tr( "Random" ), std::make_unique( "rand" ) ); \ + name .addItem( tr( "Random smooth" ), std::make_unique( "rand" ) ); public: MonstroInstrument( InstrumentTrack * _instrument_track ); diff --git a/plugins/nes/Nes.cpp b/plugins/nes/Nes.cpp index d4bcc6881d1..802986304e1 100644 --- a/plugins/nes/Nes.cpp +++ b/plugins/nes/Nes.cpp @@ -44,7 +44,7 @@ Plugin::Descriptor PLUGIN_EXPORT nes_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Nescaline", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "A NES-like synthesizer" ), "Vesa Kivimäki ", 0x0100, @@ -537,9 +537,9 @@ NesInstrument::NesInstrument( InstrumentTrack * instrumentTrack ) : m_masterVol( 1.0f, 0.0f, 2.0f, 0.01f, this, tr( "Master volume" ) ), m_vibrato( 0.0f, 0.0f, 15.0f, 1.0f, this, tr( "Vibrato" ) ) { - connect( &m_ch1Crs, SIGNAL( dataChanged() ), this, SLOT( updateFreq1() ) ); - connect( &m_ch2Crs, SIGNAL( dataChanged() ), this, SLOT( updateFreq2() ) ); - connect( &m_ch3Crs, SIGNAL( dataChanged() ), this, SLOT( updateFreq3() ) ); + connect( &m_ch1Crs, SIGNAL( dataChanged() ), this, SLOT( updateFreq1() ), Qt::DirectConnection ); + connect( &m_ch2Crs, SIGNAL( dataChanged() ), this, SLOT( updateFreq2() ), Qt::DirectConnection ); + connect( &m_ch3Crs, SIGNAL( dataChanged() ), this, SLOT( updateFreq3() ), Qt::DirectConnection ); updateFreq1(); updateFreq2(); diff --git a/plugins/organic/organic.cpp b/plugins/organic/organic.cpp index 6eb933afad3..c78d5c056b1 100644 --- a/plugins/organic/organic.cpp +++ b/plugins/organic/organic.cpp @@ -51,7 +51,7 @@ Plugin::Descriptor PLUGIN_EXPORT organic_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Organic", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "Additive Synthesizer for organ-like sounds" ), "Andreas Brandmaier ", 0x0100, diff --git a/plugins/patman/patman.cpp b/plugins/patman/patman.cpp index 8a0c7134011..b694ee2a00f 100644 --- a/plugins/patman/patman.cpp +++ b/plugins/patman/patman.cpp @@ -3,7 +3,7 @@ * * Copyright (c) 2007-2008 Javier Serrano Polo * Copyright (c) 2009-2014 Tobias Doerffel - * + * * This file is part of LMMS - https://lmms.io * * This program is free software; you can redistribute it and/or @@ -32,15 +32,16 @@ #include "ConfigManager.h" #include "endian_handling.h" #include "Engine.h" +#include "FileDialog.h" #include "gui_templates.h" #include "InstrumentTrack.h" #include "NotePlayHandle.h" +#include "PathUtil.h" #include "PixmapButton.h" #include "Song.h" #include "StringPairDrag.h" #include "ToolTip.h" -#include "FileDialog.h" -#include "ConfigManager.h" +#include "Clipboard.h" #include "embed.h" @@ -54,7 +55,7 @@ Plugin::Descriptor PLUGIN_EXPORT patman_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "PatMan", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "GUS-compatible patch instrument" ), "Javier Serrano Polo ", 0x0100, @@ -192,14 +193,13 @@ void patmanInstrument::setFile( const QString & _patch_file, bool _rename ) m_patchFile == "" ) ) { // then set it to new one - instrumentTrack()->setName( QFileInfo( _patch_file - ).fileName() ); + instrumentTrack()->setName( PathUtil::cleanName( _patch_file ) ); } // else we don't touch the instrument-track-name, because the user // named it self - m_patchFile = SampleBuffer::tryToMakeRelative( _patch_file ); - LoadErrors error = loadPatch( SampleBuffer::tryToMakeAbsolute( _patch_file ) ); + m_patchFile = PathUtil::toShortestRelative( _patch_file ); + LoadErrors error = loadPatch( PathUtil::toAbsolute( _patch_file ) ); if( error ) { printf("Load error\n"); @@ -581,10 +581,13 @@ void PatmanView::updateFilename( void ) void PatmanView::dragEnterEvent( QDragEnterEvent * _dee ) { - if( _dee->mimeData()->hasFormat( StringPairDrag::mimeType() ) ) + // For mimeType() and MimeType enum class + using namespace Clipboard; + + if( _dee->mimeData()->hasFormat( mimeType( MimeType::StringPair ) ) ) { QString txt = _dee->mimeData()->data( - StringPairDrag::mimeType() ); + mimeType( MimeType::StringPair ) ); if( txt.section( ':', 0, 0 ) == "samplefile" ) { _dee->acceptProposedAction(); @@ -625,8 +628,8 @@ void PatmanView::paintEvent( QPaintEvent * ) QPainter p( this ); p.setFont( pointSize<8>( font() ) ); - p.drawText( 8, 116, 235, 16, - Qt::AlignLeft | Qt::TextSingleLine | Qt::AlignVCenter, + p.drawText( 8, 116, 235, 16, + Qt::AlignLeft | Qt::TextSingleLine | Qt::AlignVCenter, m_displayFilename ); } @@ -641,8 +644,3 @@ void PatmanView::modelChanged( void ) connect( m_pi, SIGNAL( fileChanged() ), this, SLOT( updateFilename() ) ); } - - - - - diff --git a/plugins/peak_controller_effect/peak_controller_effect.cpp b/plugins/peak_controller_effect/peak_controller_effect.cpp index 9d1e6ccf465..01d24600e4e 100644 --- a/plugins/peak_controller_effect/peak_controller_effect.cpp +++ b/plugins/peak_controller_effect/peak_controller_effect.cpp @@ -41,7 +41,7 @@ Plugin::Descriptor PLUGIN_EXPORT peakcontrollereffect_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Peak Controller", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "Plugin for controlling knobs with sound peaks" ), "Paul Giblock ", 0x0100, diff --git a/plugins/sf2_player/patches_dialog.h b/plugins/sf2_player/patches_dialog.h index a2c88a79d1e..76387e830c4 100644 --- a/plugins/sf2_player/patches_dialog.h +++ b/plugins/sf2_player/patches_dialog.h @@ -43,7 +43,7 @@ class patchesDialog : public QDialog, private Ui::patchesDialog public: // Constructor. - patchesDialog(QWidget *pParent = 0, Qt::WindowFlags wflags = 0); + patchesDialog(QWidget *pParent = 0, Qt::WindowFlags wflags = QFlag(0)); // Destructor. virtual ~patchesDialog(); diff --git a/plugins/sf2_player/sf2_player.cpp b/plugins/sf2_player/sf2_player.cpp index 99af2278145..7a07b0ec697 100644 --- a/plugins/sf2_player/sf2_player.cpp +++ b/plugins/sf2_player/sf2_player.cpp @@ -23,6 +23,8 @@ * */ +#include "sf2_player.h" + #include #include #include @@ -30,14 +32,14 @@ #include "ConfigManager.h" #include "FileDialog.h" -#include "sf2_player.h" #include "ConfigManager.h" #include "Engine.h" #include "InstrumentTrack.h" #include "InstrumentPlayHandle.h" +#include "Knob.h" #include "Mixer.h" #include "NotePlayHandle.h" -#include "Knob.h" +#include "PathUtil.h" #include "SampleBuffer.h" #include "Song.h" @@ -55,7 +57,7 @@ Plugin::Descriptor PLUGIN_EXPORT sf2player_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Sf2 Player", - QT_TRANSLATE_NOOP( "pluginBrowser", "Player for SoundFont files" ), + QT_TRANSLATE_NOOP( "PluginBrowser", "Player for SoundFont files" ), "Paul Giblock ", 0x0100, Plugin::Instrument, @@ -372,8 +374,8 @@ void sf2Instrument::openFile( const QString & _sf2File, bool updateTrackName ) emit fileLoading(); // Used for loading file - char * sf2Ascii = qstrdup( qPrintable( SampleBuffer::tryToMakeAbsolute( _sf2File ) ) ); - QString relativePath = SampleBuffer::tryToMakeRelative( _sf2File ); + char * sf2Ascii = qstrdup( qPrintable( PathUtil::toAbsolute( _sf2File ) ) ); + QString relativePath = PathUtil::toShortestRelative( _sf2File ); // free reference to soundfont if one is selected freeFont(); @@ -396,18 +398,24 @@ void sf2Instrument::openFile( const QString & _sf2File, bool updateTrackName ) // Add to map, if doesn't exist. else { - m_fontId = fluid_synth_sfload( m_synth, sf2Ascii, true ); - - if( fluid_synth_sfcount( m_synth ) > 0 ) + bool loaded = false; + if( fluid_is_soundfont( sf2Ascii ) ) { - // Grab this sf from the top of the stack and add to list - m_font = new sf2Font( fluid_synth_get_sfont( m_synth, 0 ) ); - s_fonts.insert( relativePath, m_font ); + m_fontId = fluid_synth_sfload( m_synth, sf2Ascii, true ); + + if( fluid_synth_sfcount( m_synth ) > 0 ) + { + // Grab this sf from the top of the stack and add to list + m_font = new sf2Font( fluid_synth_get_sfont( m_synth, 0 ) ); + s_fonts.insert( relativePath, m_font ); + loaded = true; + } } - else + + if(!loaded) { - collectErrorForUI( sf2Instrument::tr( "A soundfont %1 could not be loaded." ).arg( QFileInfo( _sf2File ).baseName() ) ); - // TODO: Why is the filename missing when the file does not exist? + collectErrorForUI( sf2Instrument::tr( "A soundfont %1 could not be loaded." ). + arg( QFileInfo( _sf2File ).baseName() ) ); } } @@ -429,7 +437,7 @@ void sf2Instrument::openFile( const QString & _sf2File, bool updateTrackName ) if( updateTrackName || instrumentTrack()->displayName() == displayName() ) { - instrumentTrack()->setName( QFileInfo( _sf2File ).baseName() ); + instrumentTrack()->setName( PathUtil::cleanName( _sf2File ) ); } } @@ -1139,7 +1147,7 @@ void sf2InstrumentView::showFileDialog() if( k->m_filename != "" ) { - QString f = SampleBuffer::tryToMakeAbsolute( k->m_filename ); + QString f = PathUtil::toAbsolute( k->m_filename ); ofd.setDirectory( QFileInfo( f ).absolutePath() ); ofd.selectFile( QFileInfo( f ).fileName() ); } diff --git a/plugins/sfxr/sfxr.cpp b/plugins/sfxr/sfxr.cpp index 1aacdc12c3b..1cd58eef405 100644 --- a/plugins/sfxr/sfxr.cpp +++ b/plugins/sfxr/sfxr.cpp @@ -48,7 +48,6 @@ float frnd(float range) #include "ToolTip.h" #include "Song.h" #include "MidiEvent.h" -#include "MidiTime.h" #include "Mixer.h" #include "embed.h" @@ -62,7 +61,7 @@ Plugin::Descriptor PLUGIN_EXPORT sfxr_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "sfxr", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "LMMS port of sfxr" ), "Wong Cho Ching", 0x0100, diff --git a/plugins/sid/CMakeLists.txt b/plugins/sid/CMakeLists.txt deleted file mode 100644 index 3198723c05e..00000000000 --- a/plugins/sid/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -INCLUDE(BuildPlugin) - -BUILD_PLUGIN(sid sid_instrument.cpp sid_instrument.h envelope.h extfilt.h filter.h pot.h siddefs.h sid.h spline.h voice.h wave.h envelope.cc extfilt.cc filter.cc pot.cc sid.cc version.cc voice.cc wave6581_PS_.cc wave6581_PST.cc wave6581_P_T.cc wave6581__ST.cc wave8580_PS_.cc wave8580_PST.cc wave8580_P_T.cc wave8580__ST.cc wave.cc MOCFILES sid_instrument.h EMBEDDED_RESOURCES *.png) - - diff --git a/plugins/sid/envelope.cc b/plugins/sid/envelope.cc deleted file mode 100644 index e466bd67dc4..00000000000 --- a/plugins/sid/envelope.cc +++ /dev/null @@ -1,227 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#define __ENVELOPE_CC__ -#include "envelope.h" - -// ---------------------------------------------------------------------------- -// Constructor. -// ---------------------------------------------------------------------------- -EnvelopeGenerator::EnvelopeGenerator() -{ - reset(); -} - -// ---------------------------------------------------------------------------- -// SID reset. -// ---------------------------------------------------------------------------- -void EnvelopeGenerator::reset() -{ - envelope_counter = 0; - - attack = 0; - decay = 0; - sustain = 0; - release = 0; - - gate = 0; - - rate_counter = 0; - exponential_counter = 0; - exponential_counter_period = 1; - - state = RELEASE; - rate_period = rate_counter_period[release]; - hold_zero = true; -} - - -// Rate counter periods are calculated from the Envelope Rates table in -// the Programmer's Reference Guide. The rate counter period is the number of -// cycles between each increment of the envelope counter. -// The rates have been verified by sampling ENV3. -// -// The rate counter is a 16 bit register which is incremented each cycle. -// When the counter reaches a specific comparison value, the envelope counter -// is incremented (attack) or decremented (decay/release) and the -// counter is zeroed. -// -// NB! Sampling ENV3 shows that the calculated values are not exact. -// It may seem like most calculated values have been rounded (.5 is rounded -// down) and 1 has beed added to the result. A possible explanation for this -// is that the SID designers have used the calculated values directly -// as rate counter comparison values, not considering a one cycle delay to -// zero the counter. This would yield an actual period of comparison value + 1. -// -// The time of the first envelope count can not be exactly controlled, except -// possibly by resetting the chip. Because of this we cannot do cycle exact -// sampling and must devise another method to calculate the rate counter -// periods. -// -// The exact rate counter periods can be determined e.g. by counting the number -// of cycles from envelope level 1 to envelope level 129, and dividing the -// number of cycles by 128. CIA1 timer A and B in linked mode can perform -// the cycle count. This is the method used to find the rates below. -// -// To avoid the ADSR delay bug, sampling of ENV3 should be done using -// sustain = release = 0. This ensures that the attack state will not lower -// the current rate counter period. -// -// The ENV3 sampling code below yields a maximum timing error of 14 cycles. -// lda #$01 -// l1: cmp $d41c -// bne l1 -// ... -// lda #$ff -// l2: cmp $d41c -// bne l2 -// -// This yields a maximum error for the calculated rate period of 14/128 cycles. -// The described method is thus sufficient for exact calculation of the rate -// periods. -// -reg16 EnvelopeGenerator::rate_counter_period[] = { - 9, // 2ms*1.0MHz/256 = 7.81 - 32, // 8ms*1.0MHz/256 = 31.25 - 63, // 16ms*1.0MHz/256 = 62.50 - 95, // 24ms*1.0MHz/256 = 93.75 - 149, // 38ms*1.0MHz/256 = 148.44 - 220, // 56ms*1.0MHz/256 = 218.75 - 267, // 68ms*1.0MHz/256 = 265.63 - 313, // 80ms*1.0MHz/256 = 312.50 - 392, // 100ms*1.0MHz/256 = 390.63 - 977, // 250ms*1.0MHz/256 = 976.56 - 1954, // 500ms*1.0MHz/256 = 1953.13 - 3126, // 800ms*1.0MHz/256 = 3125.00 - 3907, // 1 s*1.0MHz/256 = 3906.25 - 11720, // 3 s*1.0MHz/256 = 11718.75 - 19532, // 5 s*1.0MHz/256 = 19531.25 - 31251 // 8 s*1.0MHz/256 = 31250.00 -}; - - -// For decay and release, the clock to the envelope counter is sequentially -// divided by 1, 2, 4, 8, 16, 30, 1 to create a piece-wise linear approximation -// of an exponential. The exponential counter period is loaded at the envelope -// counter values 255, 93, 54, 26, 14, 6, 0. The period can be different for the -// same envelope counter value, depending on whether the envelope has been -// rising (attack -> release) or sinking (decay/release). -// -// Since it is not possible to reset the rate counter (the test bit has no -// influence on the envelope generator whatsoever) a method must be devised to -// do cycle exact sampling of ENV3 to do the investigation. This is possible -// with knowledge of the rate period for A=0, found above. -// -// The CPU can be synchronized with ENV3 by first synchronizing with the rate -// counter by setting A=0 and wait in a carefully timed loop for the envelope -// counter _not_ to change for 9 cycles. We can then wait for a specific value -// of ENV3 with another timed loop to fully synchronize with ENV3. -// -// At the first period when an exponential counter period larger than one -// is used (decay or release), one extra cycle is spent before the envelope is -// decremented. The envelope output is then delayed one cycle until the state -// is changed to attack. Now one cycle less will be spent before the envelope -// is incremented, and the situation is normalized. -// The delay is probably caused by the comparison with the exponential counter, -// and does not seem to affect the rate counter. This has been verified by -// timing 256 consecutive complete envelopes with A = D = R = 1, S = 0, using -// CIA1 timer A and B in linked mode. If the rate counter is not affected the -// period of each complete envelope is -// (255 + 162*1 + 39*2 + 28*4 + 12*8 + 8*16 + 6*30)*32 = 756*32 = 32352 -// which corresponds exactly to the timed value divided by the number of -// complete envelopes. -// NB! This one cycle delay is not modeled. - - -// From the sustain levels it follows that both the low and high 4 bits of the -// envelope counter are compared to the 4-bit sustain value. -// This has been verified by sampling ENV3. -// -reg8 EnvelopeGenerator::sustain_level[] = { - 0x00, - 0x11, - 0x22, - 0x33, - 0x44, - 0x55, - 0x66, - 0x77, - 0x88, - 0x99, - 0xaa, - 0xbb, - 0xcc, - 0xdd, - 0xee, - 0xff, -}; - - -// ---------------------------------------------------------------------------- -// Register functions. -// ---------------------------------------------------------------------------- -void EnvelopeGenerator::writeCONTROL_REG(reg8 control) -{ - reg8 gate_next = control & 0x01; - - // The rate counter is never reset, thus there will be a delay before the - // envelope counter starts counting up (attack) or down (release). - - // Gate bit on: Start attack, decay, sustain. - if (!gate && gate_next) { - state = ATTACK; - rate_period = rate_counter_period[attack]; - - // Switching to attack state unlocks the zero freeze. - hold_zero = false; - } - // Gate bit off: Start release. - else if (gate && !gate_next) { - state = RELEASE; - rate_period = rate_counter_period[release]; - } - - gate = gate_next; -} - -void EnvelopeGenerator::writeATTACK_DECAY(reg8 attack_decay) -{ - attack = (attack_decay >> 4) & 0x0f; - decay = attack_decay & 0x0f; - if (state == ATTACK) { - rate_period = rate_counter_period[attack]; - } - else if (state == DECAY_SUSTAIN) { - rate_period = rate_counter_period[decay]; - } -} - -void EnvelopeGenerator::writeSUSTAIN_RELEASE(reg8 sustain_release) -{ - sustain = (sustain_release >> 4) & 0x0f; - release = sustain_release & 0x0f; - if (state == RELEASE) { - rate_period = rate_counter_period[release]; - } -} - -reg8 EnvelopeGenerator::readENV() -{ - return output(); -} diff --git a/plugins/sid/envelope.h b/plugins/sid/envelope.h deleted file mode 100644 index 63a30578b7f..00000000000 --- a/plugins/sid/envelope.h +++ /dev/null @@ -1,305 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#ifndef __ENVELOPE_H__ -#define __ENVELOPE_H__ - -#include "siddefs.h" - -// ---------------------------------------------------------------------------- -// A 15 bit counter is used to implement the envelope rates, in effect -// dividing the clock to the envelope counter by the currently selected rate -// period. -// In addition, another counter is used to implement the exponential envelope -// decay, in effect further dividing the clock to the envelope counter. -// The period of this counter is set to 1, 2, 4, 8, 16, 30 at the envelope -// counter values 255, 93, 54, 26, 14, 6, respectively. -// ---------------------------------------------------------------------------- -class EnvelopeGenerator -{ -public: - EnvelopeGenerator(); - - enum State { ATTACK, DECAY_SUSTAIN, RELEASE }; - - RESID_INLINE void clock(); - RESID_INLINE void clock(cycle_count delta_t); - void reset(); - - void writeCONTROL_REG(reg8); - void writeATTACK_DECAY(reg8); - void writeSUSTAIN_RELEASE(reg8); - reg8 readENV(); - - // 8-bit envelope output. - RESID_INLINE reg8 output(); - -protected: - reg16 rate_counter; - reg16 rate_period; - reg8 exponential_counter; - reg8 exponential_counter_period; - reg8 envelope_counter; - bool hold_zero; - - reg4 attack; - reg4 decay; - reg4 sustain; - reg4 release; - - reg8 gate; - - State state; - - // Lookup table to convert from attack, decay, or release value to rate - // counter period. - static reg16 rate_counter_period[]; - - // The 16 selectable sustain levels. - static reg8 sustain_level[]; - -friend class cSID; -}; - - -// ---------------------------------------------------------------------------- -// Inline functions. -// The following functions are defined inline because they are called every -// time a sample is calculated. -// ---------------------------------------------------------------------------- - -#if RESID_INLINING || defined(__ENVELOPE_CC__) - -// ---------------------------------------------------------------------------- -// SID clocking - 1 cycle. -// ---------------------------------------------------------------------------- -RESID_INLINE -void EnvelopeGenerator::clock() -{ - // Check for ADSR delay bug. - // If the rate counter comparison value is set below the current value of the - // rate counter, the counter will continue counting up until it wraps around - // to zero at 2^15 = 0x8000, and then count rate_period - 1 before the - // envelope can finally be stepped. - // This has been verified by sampling ENV3. - // - if (++rate_counter & 0x8000) { - ++rate_counter &= 0x7fff; - } - - if (rate_counter != rate_period) { - return; - } - - rate_counter = 0; - - // The first envelope step in the attack state also resets the exponential - // counter. This has been verified by sampling ENV3. - // - if (state == ATTACK || ++exponential_counter == exponential_counter_period) - { - exponential_counter = 0; - - // Check whether the envelope counter is frozen at zero. - if (hold_zero) { - return; - } - - switch (state) { - case ATTACK: - // The envelope counter can flip from 0xff to 0x00 by changing state to - // release, then to attack. The envelope counter is then frozen at - // zero; to unlock this situation the state must be changed to release, - // then to attack. This has been verified by sampling ENV3. - // - ++envelope_counter &= 0xff; - if (envelope_counter == 0xff) { - state = DECAY_SUSTAIN; - rate_period = rate_counter_period[decay]; - } - break; - case DECAY_SUSTAIN: - if (envelope_counter != sustain_level[sustain]) { - --envelope_counter; - } - break; - case RELEASE: - // The envelope counter can flip from 0x00 to 0xff by changing state to - // attack, then to release. The envelope counter will then continue - // counting down in the release state. - // This has been verified by sampling ENV3. - // NB! The operation below requires two's complement integer. - // - --envelope_counter &= 0xff; - break; - } - - // Check for change of exponential counter period. - switch (envelope_counter) { - case 0xff: - exponential_counter_period = 1; - break; - case 0x5d: - exponential_counter_period = 2; - break; - case 0x36: - exponential_counter_period = 4; - break; - case 0x1a: - exponential_counter_period = 8; - break; - case 0x0e: - exponential_counter_period = 16; - break; - case 0x06: - exponential_counter_period = 30; - break; - case 0x00: - exponential_counter_period = 1; - - // When the envelope counter is changed to zero, it is frozen at zero. - // This has been verified by sampling ENV3. - hold_zero = true; - break; - } - } -} - - -// ---------------------------------------------------------------------------- -// SID clocking - delta_t cycles. -// ---------------------------------------------------------------------------- -RESID_INLINE -void EnvelopeGenerator::clock(cycle_count delta_t) -{ - // Check for ADSR delay bug. - // If the rate counter comparison value is set below the current value of the - // rate counter, the counter will continue counting up until it wraps around - // to zero at 2^15 = 0x8000, and then count rate_period - 1 before the - // envelope can finally be stepped. - // This has been verified by sampling ENV3. - // - - // NB! This requires two's complement integer. - int rate_step = rate_period - rate_counter; - if (rate_step <= 0) { - rate_step += 0x7fff; - } - - while (delta_t) { - if (delta_t < rate_step) { - rate_counter += delta_t; - if (rate_counter & 0x8000) { - ++rate_counter &= 0x7fff; - } - return; - } - - rate_counter = 0; - delta_t -= rate_step; - - // The first envelope step in the attack state also resets the exponential - // counter. This has been verified by sampling ENV3. - // - if (state == ATTACK || ++exponential_counter == exponential_counter_period) - { - exponential_counter = 0; - - // Check whether the envelope counter is frozen at zero. - if (hold_zero) { - rate_step = rate_period; - continue; - } - - switch (state) { - case ATTACK: - // The envelope counter can flip from 0xff to 0x00 by changing state to - // release, then to attack. The envelope counter is then frozen at - // zero; to unlock this situation the state must be changed to release, - // then to attack. This has been verified by sampling ENV3. - // - ++envelope_counter &= 0xff; - if (envelope_counter == 0xff) { - state = DECAY_SUSTAIN; - rate_period = rate_counter_period[decay]; - } - break; - case DECAY_SUSTAIN: - if (envelope_counter != sustain_level[sustain]) { - --envelope_counter; - } - break; - case RELEASE: - // The envelope counter can flip from 0x00 to 0xff by changing state to - // attack, then to release. The envelope counter will then continue - // counting down in the release state. - // This has been verified by sampling ENV3. - // NB! The operation below requires two's complement integer. - // - --envelope_counter &= 0xff; - break; - } - - // Check for change of exponential counter period. - switch (envelope_counter) { - case 0xff: - exponential_counter_period = 1; - break; - case 0x5d: - exponential_counter_period = 2; - break; - case 0x36: - exponential_counter_period = 4; - break; - case 0x1a: - exponential_counter_period = 8; - break; - case 0x0e: - exponential_counter_period = 16; - break; - case 0x06: - exponential_counter_period = 30; - break; - case 0x00: - exponential_counter_period = 1; - - // When the envelope counter is changed to zero, it is frozen at zero. - // This has been verified by sampling ENV3. - hold_zero = true; - break; - } - } - - rate_step = rate_period; - } -} - - -// ---------------------------------------------------------------------------- -// Read the envelope generator output. -// ---------------------------------------------------------------------------- -RESID_INLINE -reg8 EnvelopeGenerator::output() -{ - return envelope_counter; -} - -#endif // RESID_INLINING || defined(__ENVELOPE_CC__) - -#endif // not __ENVELOPE_H__ diff --git a/plugins/sid/extfilt.cc b/plugins/sid/extfilt.cc deleted file mode 100644 index b875ee2ac96..00000000000 --- a/plugins/sid/extfilt.cc +++ /dev/null @@ -1,79 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#define __EXTFILT_CC__ -#include "extfilt.h" - - -// ---------------------------------------------------------------------------- -// Constructor. -// ---------------------------------------------------------------------------- -ExternalFilter::ExternalFilter() -{ - reset(); - enable_filter(true); - set_chip_model(MOS6581); - - // Low-pass: R = 10kOhm, C = 1000pF; w0l = 1/RC = 1/(1e4*1e-9) = 100000 - // High-pass: R = 1kOhm, C = 10uF; w0h = 1/RC = 1/(1e3*1e-5) = 100 - // Multiply with 1.048576 to facilitate division by 1 000 000 by right- - // shifting 20 times (2 ^ 20 = 1048576). - - w0lp = 104858; - w0hp = 105; -} - - -// ---------------------------------------------------------------------------- -// Enable filter. -// ---------------------------------------------------------------------------- -void ExternalFilter::enable_filter(bool enable) -{ - enabled = enable; -} - - -// ---------------------------------------------------------------------------- -// Set chip model. -// ---------------------------------------------------------------------------- -void ExternalFilter::set_chip_model(chip_model model) -{ - if (model == MOS6581) { - // Maximum mixer DC output level; to be removed if the external - // filter is turned off: ((wave DC + voice DC)*voices + mixer DC)*volume - // See voice.cc and filter.cc for an explanation of the values. - mixer_DC = ((((0x800 - 0x380) + 0x800)*0xff*3 - 0xfff*0xff/18) >> 7)*0x0f; - } - else { - // No DC offsets in the MOS8580. - mixer_DC = 0; - } -} - - -// ---------------------------------------------------------------------------- -// SID reset. -// ---------------------------------------------------------------------------- -void ExternalFilter::reset() -{ - // State of filter. - Vlp = 0; - Vhp = 0; - Vo = 0; -} diff --git a/plugins/sid/extfilt.h b/plugins/sid/extfilt.h deleted file mode 100644 index adf602f191d..00000000000 --- a/plugins/sid/extfilt.h +++ /dev/null @@ -1,164 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#ifndef __EXTFILT_H__ -#define __EXTFILT_H__ - -#include "siddefs.h" - -// ---------------------------------------------------------------------------- -// The audio output stage in a Commodore 64 consists of two STC networks, -// a low-pass filter with 3-dB frequency 16kHz followed by a high-pass -// filter with 3-dB frequency 16Hz (the latter provided an audio equipment -// input impedance of 1kOhm). -// The STC networks are connected with a BJT supposedly meant to act as -// a unity gain buffer, which is not really how it works. A more elaborate -// model would include the BJT, however DC circuit analysis yields BJT -// base-emitter and emitter-base impedances sufficiently low to produce -// additional low-pass and high-pass 3dB-frequencies in the order of hundreds -// of kHz. This calls for a sampling frequency of several MHz, which is far -// too high for practical use. -// ---------------------------------------------------------------------------- -class ExternalFilter -{ -public: - ExternalFilter(); - - void enable_filter(bool enable); - void set_chip_model(chip_model model); - - RESID_INLINE void clock(sound_sample Vi); - RESID_INLINE void clock(cycle_count delta_t, sound_sample Vi); - void reset(); - - // Audio output (20 bits). - RESID_INLINE sound_sample output(); - -protected: - // Filter enabled. - bool enabled; - - // Maximum mixer DC offset. - sound_sample mixer_DC; - - // State of filters. - sound_sample Vlp; // lowpass - sound_sample Vhp; // highpass - sound_sample Vo; - - // Cutoff frequencies. - sound_sample w0lp; - sound_sample w0hp; - -friend class cSID; -}; - - -// ---------------------------------------------------------------------------- -// Inline functions. -// The following functions are defined inline because they are called every -// time a sample is calculated. -// ---------------------------------------------------------------------------- - -#if RESID_INLINING || defined(__EXTFILT_CC__) - -// ---------------------------------------------------------------------------- -// SID clocking - 1 cycle. -// ---------------------------------------------------------------------------- -RESID_INLINE -void ExternalFilter::clock(sound_sample Vi) -{ - // This is handy for testing. - if (!enabled) { - // Remove maximum DC level since there is no filter to do it. - Vlp = Vhp = 0; - Vo = Vi - mixer_DC; - return; - } - - // delta_t is converted to seconds given a 1MHz clock by dividing - // with 1 000 000. - - // Calculate filter outputs. - // Vo = Vlp - Vhp; - // Vlp = Vlp + w0lp*(Vi - Vlp)*delta_t; - // Vhp = Vhp + w0hp*(Vlp - Vhp)*delta_t; - - sound_sample dVlp = (w0lp >> 8)*(Vi - Vlp) >> 12; - sound_sample dVhp = w0hp*(Vlp - Vhp) >> 20; - Vo = Vlp - Vhp; - Vlp += dVlp; - Vhp += dVhp; -} - -// ---------------------------------------------------------------------------- -// SID clocking - delta_t cycles. -// ---------------------------------------------------------------------------- -RESID_INLINE -void ExternalFilter::clock(cycle_count delta_t, - sound_sample Vi) -{ - // This is handy for testing. - if (!enabled) { - // Remove maximum DC level since there is no filter to do it. - Vlp = Vhp = 0; - Vo = Vi - mixer_DC; - return; - } - - // Maximum delta cycles for the external filter to work satisfactorily - // is approximately 8. - cycle_count delta_t_flt = 8; - - while (delta_t) { - if (delta_t < delta_t_flt) { - delta_t_flt = delta_t; - } - - // delta_t is converted to seconds given a 1MHz clock by dividing - // with 1 000 000. - - // Calculate filter outputs. - // Vo = Vlp - Vhp; - // Vlp = Vlp + w0lp*(Vi - Vlp)*delta_t; - // Vhp = Vhp + w0hp*(Vlp - Vhp)*delta_t; - - sound_sample dVlp = (w0lp*delta_t_flt >> 8)*(Vi - Vlp) >> 12; - sound_sample dVhp = w0hp*delta_t_flt*(Vlp - Vhp) >> 20; - Vo = Vlp - Vhp; - Vlp += dVlp; - Vhp += dVhp; - - delta_t -= delta_t_flt; - } -} - - -// ---------------------------------------------------------------------------- -// Audio output (19.5 bits). -// ---------------------------------------------------------------------------- -RESID_INLINE -sound_sample ExternalFilter::output() -{ - return Vo; -} - -#endif // RESID_INLINING || defined(__EXTFILT_CC__) - -#endif // not __EXTFILT_H__ diff --git a/plugins/sid/filter.cc b/plugins/sid/filter.cc deleted file mode 100644 index fb548e30acd..00000000000 --- a/plugins/sid/filter.cc +++ /dev/null @@ -1,305 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#define __FILTER_CC__ -#include "filter.h" - -// Maximum cutoff frequency is specified as -// FCmax = 2.6e-5/C = 2.6e-5/2200e-12 = 11818. -// -// Measurements indicate a cutoff frequency range of approximately -// 220Hz - 18kHz on a MOS6581 fitted with 470pF capacitors. The function -// mapping FC to cutoff frequency has the shape of the tanh function, with -// a discontinuity at FCHI = 0x80. -// In contrast, the MOS8580 almost perfectly corresponds with the -// specification of a linear mapping from 30Hz to 12kHz. -// -// The mappings have been measured by feeding the SID with an external -// signal since the chip itself is incapable of generating waveforms of -// higher fundamental frequency than 4kHz. It is best to use the bandpass -// output at full resonance to pick out the cutoff frequency at any given -// FC setting. -// -// The mapping function is specified with spline interpolation points and -// the function values are retrieved via table lookup. -// -// NB! Cutoff frequency characteristics may vary, we have modeled two -// particular Commodore 64s. - -fc_point Filter::f0_points_6581[] = -{ - // FC f FCHI FCLO - // ---------------------------- - { 0, 220 }, // 0x00 - repeated end point - { 0, 220 }, // 0x00 - { 128, 230 }, // 0x10 - { 256, 250 }, // 0x20 - { 384, 300 }, // 0x30 - { 512, 420 }, // 0x40 - { 640, 780 }, // 0x50 - { 768, 1600 }, // 0x60 - { 832, 2300 }, // 0x68 - { 896, 3200 }, // 0x70 - { 960, 4300 }, // 0x78 - { 992, 5000 }, // 0x7c - { 1008, 5400 }, // 0x7e - { 1016, 5700 }, // 0x7f - { 1023, 6000 }, // 0x7f 0x07 - { 1023, 6000 }, // 0x7f 0x07 - discontinuity - { 1024, 4600 }, // 0x80 - - { 1024, 4600 }, // 0x80 - { 1032, 4800 }, // 0x81 - { 1056, 5300 }, // 0x84 - { 1088, 6000 }, // 0x88 - { 1120, 6600 }, // 0x8c - { 1152, 7200 }, // 0x90 - { 1280, 9500 }, // 0xa0 - { 1408, 12000 }, // 0xb0 - { 1536, 14500 }, // 0xc0 - { 1664, 16000 }, // 0xd0 - { 1792, 17100 }, // 0xe0 - { 1920, 17700 }, // 0xf0 - { 2047, 18000 }, // 0xff 0x07 - { 2047, 18000 } // 0xff 0x07 - repeated end point -}; - -fc_point Filter::f0_points_8580[] = -{ - // FC f FCHI FCLO - // ---------------------------- - { 0, 0 }, // 0x00 - repeated end point - { 0, 0 }, // 0x00 - { 128, 800 }, // 0x10 - { 256, 1600 }, // 0x20 - { 384, 2500 }, // 0x30 - { 512, 3300 }, // 0x40 - { 640, 4100 }, // 0x50 - { 768, 4800 }, // 0x60 - { 896, 5600 }, // 0x70 - { 1024, 6500 }, // 0x80 - { 1152, 7500 }, // 0x90 - { 1280, 8400 }, // 0xa0 - { 1408, 9200 }, // 0xb0 - { 1536, 9800 }, // 0xc0 - { 1664, 10500 }, // 0xd0 - { 1792, 11000 }, // 0xe0 - { 1920, 11700 }, // 0xf0 - { 2047, 12500 }, // 0xff 0x07 - { 2047, 12500 } // 0xff 0x07 - repeated end point -}; - - -// ---------------------------------------------------------------------------- -// Constructor. -// ---------------------------------------------------------------------------- -Filter::Filter() -{ - fc = 0; - - res = 0; - - filt = 0; - - voice3off = 0; - - hp_bp_lp = 0; - - vol = 0; - - // State of filter. - Vhp = 0; - Vbp = 0; - Vlp = 0; - Vnf = 0; - - enable_filter(true); - - // Create mappings from FC to cutoff frequency. - interpolate(f0_points_6581, f0_points_6581 - + sizeof(f0_points_6581)/sizeof(*f0_points_6581) - 1, - PointPlotter(f0_6581), 1.0); - interpolate(f0_points_8580, f0_points_8580 - + sizeof(f0_points_8580)/sizeof(*f0_points_8580) - 1, - PointPlotter(f0_8580), 1.0); - - set_chip_model(MOS6581); -} - - -// ---------------------------------------------------------------------------- -// Enable filter. -// ---------------------------------------------------------------------------- -void Filter::enable_filter(bool enable) -{ - enabled = enable; -} - - -// ---------------------------------------------------------------------------- -// Set chip model. -// ---------------------------------------------------------------------------- -void Filter::set_chip_model(chip_model model) -{ - if (model == MOS6581) { - // The mixer has a small input DC offset. This is found as follows: - // - // The "zero" output level of the mixer measured on the SID audio - // output pin is 5.50V at zero volume, and 5.44 at full - // volume. This yields a DC offset of (5.44V - 5.50V) = -0.06V. - // - // The DC offset is thus -0.06V/1.05V ~ -1/18 of the dynamic range - // of one voice. See voice.cc for measurement of the dynamic - // range. - - mixer_DC = -0xfff*0xff/18 >> 7; - - f0 = f0_6581; - f0_points = f0_points_6581; - f0_count = sizeof(f0_points_6581)/sizeof(*f0_points_6581); - } - else { - // No DC offsets in the MOS8580. - mixer_DC = 0; - - f0 = f0_8580; - f0_points = f0_points_8580; - f0_count = sizeof(f0_points_8580)/sizeof(*f0_points_8580); - } - - set_w0(); - set_Q(); -} - - -// ---------------------------------------------------------------------------- -// SID reset. -// ---------------------------------------------------------------------------- -void Filter::reset() -{ - fc = 0; - - res = 0; - - filt = 0; - - voice3off = 0; - - hp_bp_lp = 0; - - vol = 0; - - // State of filter. - Vhp = 0; - Vbp = 0; - Vlp = 0; - Vnf = 0; - - set_w0(); - set_Q(); -} - - -// ---------------------------------------------------------------------------- -// Register functions. -// ---------------------------------------------------------------------------- -void Filter::writeFC_LO(reg8 fc_lo) -{ - fc = ( fc & 0x7f8 ) | ( fc_lo & 0x007 ); - set_w0(); -} - -void Filter::writeFC_HI(reg8 fc_hi) -{ - fc = ( (fc_hi << 3) & 0x7f8 ) | ( fc & 0x007 ); - set_w0(); -} - -void Filter::writeRES_FILT(reg8 res_filt) -{ - res = (res_filt >> 4) & 0x0f; - set_Q(); - - filt = res_filt & 0x0f; -} - -void Filter::writeMODE_VOL(reg8 mode_vol) -{ - voice3off = mode_vol & 0x80; - - hp_bp_lp = (mode_vol >> 4) & 0x07; - - vol = mode_vol & 0x0f; -} - -// Set filter cutoff frequency. -void Filter::set_w0() -{ - const double pi = 3.1415926535897932385; - - // Multiply with 1.048576 to facilitate division by 1 000 000 by right- - // shifting 20 times (2 ^ 20 = 1048576). - w0 = static_cast(2*pi*f0[fc]*1.048576); - - // Limit f0 to 16kHz to keep 1 cycle filter stable. - const sound_sample w0_max_1 = static_cast(2*pi*16000*1.048576); - w0_ceil_1 = w0 <= w0_max_1 ? w0 : w0_max_1; - - // Limit f0 to 4kHz to keep delta_t cycle filter stable. - const sound_sample w0_max_dt = static_cast(2*pi*4000*1.048576); - w0_ceil_dt = w0 <= w0_max_dt ? w0 : w0_max_dt; -} - -// Set filter resonance. -void Filter::set_Q() -{ - // Q is controlled linearly by res. Q has approximate range [0.707, 1.7]. - // As resonance is increased, the filter must be clocked more often to keep - // stable. - - // The coefficient 1024 is dispensed of later by right-shifting 10 times - // (2 ^ 10 = 1024). - _1024_div_Q = static_cast(1024.0/(0.707 + 1.0*res/0x0f)); -} - -// ---------------------------------------------------------------------------- -// Spline functions. -// ---------------------------------------------------------------------------- - -// ---------------------------------------------------------------------------- -// Return the array of spline interpolation points used to map the FC register -// to filter cutoff frequency. -// ---------------------------------------------------------------------------- -void Filter::fc_default(const fc_point*& points, int& count) -{ - points = f0_points; - count = f0_count; -} - -// ---------------------------------------------------------------------------- -// Given an array of interpolation points p with n points, the following -// statement will specify a new FC mapping: -// interpolate(p, p + n - 1, filter.fc_plotter(), 1.0); -// Note that the x range of the interpolation points *must* be [0, 2047], -// and that additional end points *must* be present since the end points -// are not interpolated. -// ---------------------------------------------------------------------------- -PointPlotter Filter::fc_plotter() -{ - return PointPlotter(f0); -} diff --git a/plugins/sid/filter.h b/plugins/sid/filter.h deleted file mode 100644 index 8d8aece3dbe..00000000000 --- a/plugins/sid/filter.h +++ /dev/null @@ -1,531 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#ifndef __FILTER_H__ -#define __FILTER_H__ - -#include "siddefs.h" -#include "spline.h" - -// ---------------------------------------------------------------------------- -// The SID filter is modeled with a two-integrator-loop biquadratic filter, -// which has been confirmed by Bob Yannes to be the actual circuit used in -// the SID chip. -// -// Measurements show that excellent emulation of the SID filter is achieved, -// except when high resonance is combined with high sustain levels. -// In this case the SID op-amps are performing less than ideally and are -// causing some peculiar behavior of the SID filter. This however seems to -// have more effect on the overall amplitude than on the color of the sound. -// -// The theory for the filter circuit can be found in "Microelectric Circuits" -// by Adel S. Sedra and Kenneth C. Smith. -// The circuit is modeled based on the explanation found there except that -// an additional inverter is used in the feedback from the bandpass output, -// allowing the summer op-amp to operate in single-ended mode. This yields -// inverted filter outputs with levels independent of Q, which corresponds with -// the results obtained from a real SID. -// -// We have been able to model the summer and the two integrators of the circuit -// to form components of an IIR filter. -// Vhp is the output of the summer, Vbp is the output of the first integrator, -// and Vlp is the output of the second integrator in the filter circuit. -// -// According to Bob Yannes, the active stages of the SID filter are not really -// op-amps. Rather, simple NMOS inverters are used. By biasing an inverter -// into its region of quasi-linear operation using a feedback resistor from -// input to output, a MOS inverter can be made to act like an op-amp for -// small signals centered around the switching threshold. -// -// Qualified guesses at SID filter schematics are depicted below. -// -// SID filter -// ---------- -// -// ----------------------------------------------- -// | | -// | ---Rq-- | -// | | | | -// | --------------|--R-----[A>--|--R-----[A>--| -// | | | | -// vi -----R1-- | | | -// -// vhp vbp vlp -// -// -// vi - input voltage -// vhp - highpass output -// vbp - bandpass output -// vlp - lowpass output -// [A> - op-amp -// R1 - summer resistor -// Rq - resistor array controlling resonance (4 resistors) -// R - NMOS FET voltage controlled resistor controlling cutoff frequency -// Rs - shunt resitor -// C - capacitor -// -// -// -// SID integrator -// -------------- -// -// V+ -// -// | -// | -// -----| -// | | -// | ||-- -// -|| -// ---C--- ||-> -// | | | -// |---Rs-----------|---- vo -// | | -// | ||-- -// vi ---- -----|------------|| -// | ^ | ||-> -// |___| | | -// ----- | | -// | | | -// |---R2-- | -// | -// R1 V- -// | -// | -// -// Vw -// -// ---------------------------------------------------------------------------- -class Filter -{ -public: - Filter(); - - void enable_filter(bool enable); - void set_chip_model(chip_model model); - - RESID_INLINE - void clock(sound_sample voice1, sound_sample voice2, sound_sample voice3, - sound_sample ext_in); - RESID_INLINE - void clock(cycle_count delta_t, - sound_sample voice1, sound_sample voice2, sound_sample voice3, - sound_sample ext_in); - void reset(); - - // Write registers. - void writeFC_LO(reg8); - void writeFC_HI(reg8); - void writeRES_FILT(reg8); - void writeMODE_VOL(reg8); - - // SID audio output (16 bits). - sound_sample output(); - - // Spline functions. - void fc_default(const fc_point*& points, int& count); - PointPlotter fc_plotter(); - -protected: - void set_w0(); - void set_Q(); - - // Filter enabled. - bool enabled; - - // Filter cutoff frequency. - reg12 fc; - - // Filter resonance. - reg8 res; - - // Selects which inputs to route through filter. - reg8 filt; - - // Switch voice 3 off. - reg8 voice3off; - - // Highpass, bandpass, and lowpass filter modes. - reg8 hp_bp_lp; - - // Output master volume. - reg4 vol; - - // Mixer DC offset. - sound_sample mixer_DC; - - // State of filter. - sound_sample Vhp; // highpass - sound_sample Vbp; // bandpass - sound_sample Vlp; // lowpass - sound_sample Vnf; // not filtered - - // Cutoff frequency, resonance. - sound_sample w0, w0_ceil_1, w0_ceil_dt; - sound_sample _1024_div_Q; - - // Cutoff frequency tables. - // FC is an 11 bit register. - sound_sample f0_6581[2048]; - sound_sample f0_8580[2048]; - sound_sample* f0; - static fc_point f0_points_6581[]; - static fc_point f0_points_8580[]; - fc_point* f0_points; - int f0_count; - -friend class cSID; -}; - - -// ---------------------------------------------------------------------------- -// Inline functions. -// The following functions are defined inline because they are called every -// time a sample is calculated. -// ---------------------------------------------------------------------------- - -#if RESID_INLINING || defined(__FILTER_CC__) - -// ---------------------------------------------------------------------------- -// SID clocking - 1 cycle. -// ---------------------------------------------------------------------------- -RESID_INLINE -void Filter::clock(sound_sample voice1, - sound_sample voice2, - sound_sample voice3, - sound_sample ext_in) -{ - // Scale each voice down from 20 to 13 bits. - voice1 >>= 7; - voice2 >>= 7; - - // NB! Voice 3 is not silenced by voice3off if it is routed through - // the filter. - if (voice3off && !(filt & 0x04)) { - voice3 = 0; - } - else { - voice3 >>= 7; - } - - ext_in >>= 7; - - // This is handy for testing. - if (!enabled) { - Vnf = voice1 + voice2 + voice3 + ext_in; - Vhp = Vbp = Vlp = 0; - return; - } - - // Route voices into or around filter. - // The code below is expanded to a switch for faster execution. - // (filt1 ? Vi : Vnf) += voice1; - // (filt2 ? Vi : Vnf) += voice2; - // (filt3 ? Vi : Vnf) += voice3; - - sound_sample Vi; - - switch (filt) { - default: - case 0x0: - Vi = 0; - Vnf = voice1 + voice2 + voice3 + ext_in; - break; - case 0x1: - Vi = voice1; - Vnf = voice2 + voice3 + ext_in; - break; - case 0x2: - Vi = voice2; - Vnf = voice1 + voice3 + ext_in; - break; - case 0x3: - Vi = voice1 + voice2; - Vnf = voice3 + ext_in; - break; - case 0x4: - Vi = voice3; - Vnf = voice1 + voice2 + ext_in; - break; - case 0x5: - Vi = voice1 + voice3; - Vnf = voice2 + ext_in; - break; - case 0x6: - Vi = voice2 + voice3; - Vnf = voice1 + ext_in; - break; - case 0x7: - Vi = voice1 + voice2 + voice3; - Vnf = ext_in; - break; - case 0x8: - Vi = ext_in; - Vnf = voice1 + voice2 + voice3; - break; - case 0x9: - Vi = voice1 + ext_in; - Vnf = voice2 + voice3; - break; - case 0xa: - Vi = voice2 + ext_in; - Vnf = voice1 + voice3; - break; - case 0xb: - Vi = voice1 + voice2 + ext_in; - Vnf = voice3; - break; - case 0xc: - Vi = voice3 + ext_in; - Vnf = voice1 + voice2; - break; - case 0xd: - Vi = voice1 + voice3 + ext_in; - Vnf = voice2; - break; - case 0xe: - Vi = voice2 + voice3 + ext_in; - Vnf = voice1; - break; - case 0xf: - Vi = voice1 + voice2 + voice3 + ext_in; - Vnf = 0; - break; - } - - // delta_t = 1 is converted to seconds given a 1MHz clock by dividing - // with 1 000 000. - - // Calculate filter outputs. - // Vhp = Vbp/Q - Vlp - Vi; - // dVbp = -w0*Vhp*dt; - // dVlp = -w0*Vbp*dt; - - sound_sample dVbp = (w0_ceil_1*Vhp >> 20); - sound_sample dVlp = (w0_ceil_1*Vbp >> 20); - Vbp -= dVbp; - Vlp -= dVlp; - Vhp = (Vbp*_1024_div_Q >> 10) - Vlp - Vi; -} - -// ---------------------------------------------------------------------------- -// SID clocking - delta_t cycles. -// ---------------------------------------------------------------------------- -RESID_INLINE -void Filter::clock(cycle_count delta_t, - sound_sample voice1, - sound_sample voice2, - sound_sample voice3, - sound_sample ext_in) -{ - // Scale each voice down from 20 to 13 bits. - voice1 >>= 7; - voice2 >>= 7; - - // NB! Voice 3 is not silenced by voice3off if it is routed through - // the filter. - if (voice3off && !(filt & 0x04)) { - voice3 = 0; - } - else { - voice3 >>= 7; - } - - ext_in >>= 7; - - // Enable filter on/off. - // This is not really part of SID, but is useful for testing. - // On slow CPUs it may be necessary to bypass the filter to lower the CPU - // load. - if (!enabled) { - Vnf = voice1 + voice2 + voice3 + ext_in; - Vhp = Vbp = Vlp = 0; - return; - } - - // Route voices into or around filter. - // The code below is expanded to a switch for faster execution. - // (filt1 ? Vi : Vnf) += voice1; - // (filt2 ? Vi : Vnf) += voice2; - // (filt3 ? Vi : Vnf) += voice3; - - sound_sample Vi; - - switch (filt) { - default: - case 0x0: - Vi = 0; - Vnf = voice1 + voice2 + voice3 + ext_in; - break; - case 0x1: - Vi = voice1; - Vnf = voice2 + voice3 + ext_in; - break; - case 0x2: - Vi = voice2; - Vnf = voice1 + voice3 + ext_in; - break; - case 0x3: - Vi = voice1 + voice2; - Vnf = voice3 + ext_in; - break; - case 0x4: - Vi = voice3; - Vnf = voice1 + voice2 + ext_in; - break; - case 0x5: - Vi = voice1 + voice3; - Vnf = voice2 + ext_in; - break; - case 0x6: - Vi = voice2 + voice3; - Vnf = voice1 + ext_in; - break; - case 0x7: - Vi = voice1 + voice2 + voice3; - Vnf = ext_in; - break; - case 0x8: - Vi = ext_in; - Vnf = voice1 + voice2 + voice3; - break; - case 0x9: - Vi = voice1 + ext_in; - Vnf = voice2 + voice3; - break; - case 0xa: - Vi = voice2 + ext_in; - Vnf = voice1 + voice3; - break; - case 0xb: - Vi = voice1 + voice2 + ext_in; - Vnf = voice3; - break; - case 0xc: - Vi = voice3 + ext_in; - Vnf = voice1 + voice2; - break; - case 0xd: - Vi = voice1 + voice3 + ext_in; - Vnf = voice2; - break; - case 0xe: - Vi = voice2 + voice3 + ext_in; - Vnf = voice1; - break; - case 0xf: - Vi = voice1 + voice2 + voice3 + ext_in; - Vnf = 0; - break; - } - - // Maximum delta cycles for the filter to work satisfactorily under current - // cutoff frequency and resonance constraints is approximately 8. - cycle_count delta_t_flt = 8; - - while (delta_t) { - if (delta_t < delta_t_flt) { - delta_t_flt = delta_t; - } - - // delta_t is converted to seconds given a 1MHz clock by dividing - // with 1 000 000. This is done in two operations to avoid integer - // multiplication overflow. - - // Calculate filter outputs. - // Vhp = Vbp/Q - Vlp - Vi; - // dVbp = -w0*Vhp*dt; - // dVlp = -w0*Vbp*dt; - sound_sample w0_delta_t = w0_ceil_dt*delta_t_flt >> 6; - - sound_sample dVbp = (w0_delta_t*Vhp >> 14); - sound_sample dVlp = (w0_delta_t*Vbp >> 14); - Vbp -= dVbp; - Vlp -= dVlp; - Vhp = (Vbp*_1024_div_Q >> 10) - Vlp - Vi; - - delta_t -= delta_t_flt; - } -} - - -// ---------------------------------------------------------------------------- -// SID audio output (20 bits). -// ---------------------------------------------------------------------------- -RESID_INLINE -sound_sample Filter::output() -{ - // This is handy for testing. - if (!enabled) { - return (Vnf + mixer_DC)*static_cast(vol); - } - - // Mix highpass, bandpass, and lowpass outputs. The sum is not - // weighted, this can be confirmed by sampling sound output for - // e.g. bandpass, lowpass, and bandpass+lowpass from a SID chip. - - // The code below is expanded to a switch for faster execution. - // if (hp) Vf += Vhp; - // if (bp) Vf += Vbp; - // if (lp) Vf += Vlp; - - sound_sample Vf; - - switch (hp_bp_lp) { - default: - case 0x0: - Vf = 0; - break; - case 0x1: - Vf = Vlp; - break; - case 0x2: - Vf = Vbp; - break; - case 0x3: - Vf = Vlp + Vbp; - break; - case 0x4: - Vf = Vhp; - break; - case 0x5: - Vf = Vlp + Vhp; - break; - case 0x6: - Vf = Vbp + Vhp; - break; - case 0x7: - Vf = Vlp + Vbp + Vhp; - break; - } - - // Sum non-filtered and filtered output. - // Multiply the sum with volume. - return (Vnf + Vf + mixer_DC)*static_cast(vol); -} - -#endif // RESID_INLINING || defined(__FILTER_CC__) - -#endif // not __FILTER_H__ diff --git a/plugins/sid/filter.png b/plugins/sid/filter.png deleted file mode 100644 index ff5c760db9b..00000000000 Binary files a/plugins/sid/filter.png and /dev/null differ diff --git a/plugins/sid/pot.cc b/plugins/sid/pot.cc deleted file mode 100644 index b60b2ec75c9..00000000000 --- a/plugins/sid/pot.cc +++ /dev/null @@ -1,26 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#include "pot.h" - -reg8 Potentiometer::readPOT() -{ - // NB! Not modeled. - return 0xff; -} diff --git a/plugins/sid/pot.h b/plugins/sid/pot.h deleted file mode 100644 index 6d44cb1a070..00000000000 --- a/plugins/sid/pot.h +++ /dev/null @@ -1,31 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#ifndef __POT_H__ -#define __POT_H__ - -#include "siddefs.h" - -class Potentiometer -{ -public: - reg8 readPOT(); -}; - -#endif diff --git a/plugins/sid/sid.cc b/plugins/sid/sid.cc deleted file mode 100644 index c6e234fe0ca..00000000000 --- a/plugins/sid/sid.cc +++ /dev/null @@ -1,1019 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#include "sid.h" -#include - - -const int cSID::FIR_N = 125; -const int cSID::FIR_RES_INTERPOLATE = 285; -const int cSID::FIR_RES_FAST = 51473; -const int cSID::FIR_SHIFT = 15; -const int cSID::RINGSIZE = 16384; - - // Fixpoint constants (16.16 bits). -const int cSID::FIXP_SHIFT = 16; -const int cSID::FIXP_MASK = 0xffff; - - -// ---------------------------------------------------------------------------- -// Constructor. -// ---------------------------------------------------------------------------- -cSID::cSID() -{ - // Initialize pointers. - sample = 0; - fir = 0; - - voice[0].set_sync_source(&voice[2]); - voice[1].set_sync_source(&voice[0]); - voice[2].set_sync_source(&voice[1]); - - set_sampling_parameters(985248, SAMPLE_FAST, 44100); - - bus_value = 0; - bus_value_ttl = 0; - - ext_in = 0; -} - - -// ---------------------------------------------------------------------------- -// Destructor. -// ---------------------------------------------------------------------------- -cSID::~cSID() -{ - delete[] sample; - delete[] fir; -} - - -// ---------------------------------------------------------------------------- -// Set chip model. -// ---------------------------------------------------------------------------- -void cSID::set_chip_model(chip_model model) -{ - for (int i = 0; i < 3; i++) { - voice[i].set_chip_model(model); - } - - filter.set_chip_model(model); - extfilt.set_chip_model(model); -} - - -// ---------------------------------------------------------------------------- -// SID reset. -// ---------------------------------------------------------------------------- -void cSID::reset() -{ - for (int i = 0; i < 3; i++) { - voice[i].reset(); - } - filter.reset(); - extfilt.reset(); - - bus_value = 0; - bus_value_ttl = 0; -} - - -// ---------------------------------------------------------------------------- -// Write 16-bit sample to audio input. -// NB! The caller is responsible for keeping the value within 16 bits. -// Note that to mix in an external audio signal, the signal should be -// resampled to 1MHz first to avoid sampling noise. -// ---------------------------------------------------------------------------- -void cSID::input(int sample) -{ - // Voice outputs are 20 bits. Scale up to match three voices in order - // to facilitate simulation of the MOS8580 "digi boost" hardware hack. - ext_in = (sample << 4)*3; -} - -// ---------------------------------------------------------------------------- -// Read sample from audio output. -// Both 16-bit and n-bit output is provided. -// ---------------------------------------------------------------------------- -int cSID::output() -{ - const int range = 1 << 16; - const int half = range >> 1; - int sample = extfilt.output()/((4095*255 >> 7)*3*15*2/range); - if (sample >= half) { - return half - 1; - } - if (sample < -half) { - return -half; - } - return sample; -} - -int cSID::output(int bits) -{ - const int range = 1 << bits; - const int half = range >> 1; - int sample = extfilt.output()/((4095*255 >> 7)*3*15*2/range); - if (sample >= half) { - return half - 1; - } - if (sample < -half) { - return -half; - } - return sample; -} - - -// ---------------------------------------------------------------------------- -// Read registers. -// -// Reading a write only register returns the last byte written to any SID -// register. The individual bits in this value start to fade down towards -// zero after a few cycles. All bits reach zero within approximately -// $2000 - $4000 cycles. -// It has been claimed that this fading happens in an orderly fashion, however -// sampling of write only registers reveals that this is not the case. -// NB! This is not correctly modeled. -// The actual use of write only registers has largely been made in the belief -// that all SID registers are readable. To support this belief the read -// would have to be done immediately after a write to the same register -// (remember that an intermediate write to another register would yield that -// value instead). With this in mind we return the last value written to -// any SID register for $2000 cycles without modeling the bit fading. -// ---------------------------------------------------------------------------- -reg8 cSID::read(reg8 offset) -{ - switch (offset) { - case 0x19: - return potx.readPOT(); - case 0x1a: - return poty.readPOT(); - case 0x1b: - return voice[2].wave.readOSC(); - case 0x1c: - return voice[2].envelope.readENV(); - default: - return bus_value; - } -} - - -// ---------------------------------------------------------------------------- -// Write registers. -// ---------------------------------------------------------------------------- -void cSID::write(reg8 offset, reg8 value) -{ - bus_value = value; - bus_value_ttl = 0x2000; - - switch (offset) { - case 0x00: - voice[0].wave.writeFREQ_LO(value); - break; - case 0x01: - voice[0].wave.writeFREQ_HI(value); - break; - case 0x02: - voice[0].wave.writePW_LO(value); - break; - case 0x03: - voice[0].wave.writePW_HI(value); - break; - case 0x04: - voice[0].writeCONTROL_REG(value); - break; - case 0x05: - voice[0].envelope.writeATTACK_DECAY(value); - break; - case 0x06: - voice[0].envelope.writeSUSTAIN_RELEASE(value); - break; - case 0x07: - voice[1].wave.writeFREQ_LO(value); - break; - case 0x08: - voice[1].wave.writeFREQ_HI(value); - break; - case 0x09: - voice[1].wave.writePW_LO(value); - break; - case 0x0a: - voice[1].wave.writePW_HI(value); - break; - case 0x0b: - voice[1].writeCONTROL_REG(value); - break; - case 0x0c: - voice[1].envelope.writeATTACK_DECAY(value); - break; - case 0x0d: - voice[1].envelope.writeSUSTAIN_RELEASE(value); - break; - case 0x0e: - voice[2].wave.writeFREQ_LO(value); - break; - case 0x0f: - voice[2].wave.writeFREQ_HI(value); - break; - case 0x10: - voice[2].wave.writePW_LO(value); - break; - case 0x11: - voice[2].wave.writePW_HI(value); - break; - case 0x12: - voice[2].writeCONTROL_REG(value); - break; - case 0x13: - voice[2].envelope.writeATTACK_DECAY(value); - break; - case 0x14: - voice[2].envelope.writeSUSTAIN_RELEASE(value); - break; - case 0x15: - filter.writeFC_LO(value); - break; - case 0x16: - filter.writeFC_HI(value); - break; - case 0x17: - filter.writeRES_FILT(value); - break; - case 0x18: - filter.writeMODE_VOL(value); - break; - default: - break; - } -} - - -// ---------------------------------------------------------------------------- -// Constructor. -// ---------------------------------------------------------------------------- -cSID::State::State() -{ - int i; - - for (i = 0; i < 0x20; i++) { - sid_register[i] = 0; - } - - bus_value = 0; - bus_value_ttl = 0; - - for (i = 0; i < 3; i++) { - accumulator[i] = 0; - shift_register[i] = 0x7ffff8; - rate_counter[i] = 0; - rate_counter_period[i] = 9; - exponential_counter[i] = 0; - exponential_counter_period[i] = 1; - envelope_counter[i] = 0; - envelope_state[i] = EnvelopeGenerator::RELEASE; - hold_zero[i] = true; - } -} - - -// ---------------------------------------------------------------------------- -// Read state. -// ---------------------------------------------------------------------------- -cSID::State cSID::read_state() -{ - State state; - int i, j; - - for (i = 0, j = 0; i < 3; i++, j += 7) { - WaveformGenerator& wave = voice[i].wave; - EnvelopeGenerator& envelope = voice[i].envelope; - state.sid_register[j + 0] = wave.freq & 0xff; - state.sid_register[j + 1] = wave.freq >> 8; - state.sid_register[j + 2] = wave.pw & 0xff; - state.sid_register[j + 3] = wave.pw >> 8; - state.sid_register[j + 4] = - (wave.waveform << 4) - | (wave.test ? 0x08 : 0) - | (wave.ring_mod ? 0x04 : 0) - | (wave.sync ? 0x02 : 0) - | (envelope.gate ? 0x01 : 0); - state.sid_register[j + 5] = (envelope.attack << 4) | envelope.decay; - state.sid_register[j + 6] = (envelope.sustain << 4) | envelope.release; - } - - state.sid_register[j++] = filter.fc & 0x007; - state.sid_register[j++] = filter.fc >> 3; - state.sid_register[j++] = (filter.res << 4) | filter.filt; - state.sid_register[j++] = - (filter.voice3off ? 0x80 : 0) - | (filter.hp_bp_lp << 4) - | filter.vol; - - // These registers are superfluous, but included for completeness. - for (; j < 0x1d; j++) { - state.sid_register[j] = read(j); - } - for (; j < 0x20; j++) { - state.sid_register[j] = 0; - } - - state.bus_value = bus_value; - state.bus_value_ttl = bus_value_ttl; - - for (i = 0; i < 3; i++) { - state.accumulator[i] = voice[i].wave.accumulator; - state.shift_register[i] = voice[i].wave.shift_register; - state.rate_counter[i] = voice[i].envelope.rate_counter; - state.rate_counter_period[i] = voice[i].envelope.rate_period; - state.exponential_counter[i] = voice[i].envelope.exponential_counter; - state.exponential_counter_period[i] = voice[i].envelope.exponential_counter_period; - state.envelope_counter[i] = voice[i].envelope.envelope_counter; - state.envelope_state[i] = voice[i].envelope.state; - state.hold_zero[i] = voice[i].envelope.hold_zero; - } - - return state; -} - - -// ---------------------------------------------------------------------------- -// Write state. -// ---------------------------------------------------------------------------- -void cSID::write_state(const State& state) -{ - int i; - - for (i = 0; i <= 0x18; i++) { - write(i, state.sid_register[i]); - } - - bus_value = state.bus_value; - bus_value_ttl = state.bus_value_ttl; - - for (i = 0; i < 3; i++) { - voice[i].wave.accumulator = state.accumulator[i]; - voice[i].wave.shift_register = state.shift_register[i]; - voice[i].envelope.rate_counter = state.rate_counter[i]; - voice[i].envelope.rate_period = state.rate_counter_period[i]; - voice[i].envelope.exponential_counter = state.exponential_counter[i]; - voice[i].envelope.exponential_counter_period = state.exponential_counter_period[i]; - voice[i].envelope.envelope_counter = state.envelope_counter[i]; - voice[i].envelope.state = state.envelope_state[i]; - voice[i].envelope.hold_zero = state.hold_zero[i]; - } -} - - -// ---------------------------------------------------------------------------- -// Enable filter. -// ---------------------------------------------------------------------------- -void cSID::enable_filter(bool enable) -{ - filter.enable_filter(enable); -} - - -// ---------------------------------------------------------------------------- -// Enable external filter. -// ---------------------------------------------------------------------------- -void cSID::enable_external_filter(bool enable) -{ - extfilt.enable_filter(enable); -} - - -// ---------------------------------------------------------------------------- -// I0() computes the 0th order modified Bessel function of the first kind. -// This function is originally from resample-1.5/filterkit.c by J. O. Smith. -// ---------------------------------------------------------------------------- -double cSID::I0(double x) -{ - // Max error acceptable in I0. - const double I0e = 1e-6; - - double sum, u, halfx, temp; - int n; - - sum = u = n = 1; - halfx = x/2.0; - - do { - temp = halfx/n++; - u *= temp*temp; - sum += u; - } while (u >= I0e*sum); - - return sum; -} - - -// ---------------------------------------------------------------------------- -// Setting of SID sampling parameters. -// -// Use a clock freqency of 985248Hz for PAL C64, 1022730Hz for NTSC C64. -// The default end of passband frequency is pass_freq = 0.9*sample_freq/2 -// for sample frequencies up to ~ 44.1kHz, and 20kHz for higher sample -// frequencies. -// -// For resampling, the ratio between the clock frequency and the sample -// frequency is limited as follows: -// 125*clock_freq/sample_freq < 16384 -// E.g. provided a clock frequency of ~ 1MHz, the sample frequency can not -// be set lower than ~ 8kHz. A lower sample frequency would make the -// resampling code overfill its 16k sample ring buffer. -// -// The end of passband frequency is also limited: -// pass_freq <= 0.9*sample_freq/2 - -// E.g. for a 44.1kHz sampling rate the end of passband frequency is limited -// to slightly below 20kHz. This constraint ensures that the FIR table is -// not overfilled. -// ---------------------------------------------------------------------------- -bool cSID::set_sampling_parameters(double clock_freq, sampling_method method, - double sample_freq, double pass_freq, - double filter_scale) -{ - // Check resampling constraints. - if (method == SAMPLE_RESAMPLE_INTERPOLATE || method == SAMPLE_RESAMPLE_FAST) - { - // Check whether the sample ring buffer would overfill. - if (FIR_N*clock_freq/sample_freq >= RINGSIZE) { - return false; - } - - // The default passband limit is 0.9*sample_freq/2 for sample - // frequencies below ~ 44.1kHz, and 20kHz for higher sample frequencies. - if (pass_freq < 0) { - pass_freq = 20000; - if (2*pass_freq/sample_freq >= 0.9) { - pass_freq = 0.9*sample_freq/2; - } - } - // Check whether the FIR table would overfill. - else if (pass_freq > 0.9*sample_freq/2) { - return false; - } - - // The filter scaling is only included to avoid clipping, so keep - // it sane. - if (filter_scale < 0.9 || filter_scale > 1.0) { - return false; - } - } - - clock_frequency = clock_freq; - sampling = method; - - cycles_per_sample = - cycle_count(clock_freq/sample_freq*(1 << FIXP_SHIFT) + 0.5); - - sample_offset = 0; - sample_prev = 0; - - // FIR initialization is only necessary for resampling. - if (method != SAMPLE_RESAMPLE_INTERPOLATE && method != SAMPLE_RESAMPLE_FAST) - { - delete[] sample; - delete[] fir; - sample = 0; - fir = 0; - return true; - } - - const double pi = 3.1415926535897932385; - - // 16 bits -> -96dB stopband attenuation. - const double A = -20*log10(1.0/(1 << 16)); - // A fraction of the bandwidth is allocated to the transition band, - double dw = (1 - 2*pass_freq/sample_freq)*pi; - // The cutoff frequency is midway through the transition band. - double wc = (2*pass_freq/sample_freq + 1)*pi/2; - - // For calculation of beta and N see the reference for the kaiserord - // function in the MATLAB Signal Processing Toolbox: - // http://www.mathworks.com/access/helpdesk/help/toolbox/signal/kaiserord.html - const double beta = 0.1102*(A - 8.7); - const double I0beta = I0(beta); - - // The filter order will maximally be 124 with the current constraints. - // N >= (96.33 - 7.95)/(2.285*0.1*pi) -> N >= 123 - // The filter order is equal to the number of zero crossings, i.e. - // it should be an even number (sinc is symmetric about x = 0). - int N = int((A - 7.95)/(2.285*dw) + 0.5); - N += N & 1; - - double f_samples_per_cycle = sample_freq/clock_freq; - double f_cycles_per_sample = clock_freq/sample_freq; - - // The filter length is equal to the filter order + 1. - // The filter length must be an odd number (sinc is symmetric about x = 0). - fir_N = int(N*f_cycles_per_sample) + 1; - fir_N |= 1; - - // We clamp the filter table resolution to 2^n, making the fixpoint - // sample_offset a whole multiple of the filter table resolution. - int res = method == SAMPLE_RESAMPLE_INTERPOLATE ? - FIR_RES_INTERPOLATE : FIR_RES_FAST; - int n = (int)ceil(log(res/f_cycles_per_sample)/log(2)); - fir_RES = 1 << n; - - // Allocate memory for FIR tables. - delete[] fir; - fir = new short[fir_N*fir_RES]; - - // Calculate fir_RES FIR tables for linear interpolation. - for (int i = 0; i < fir_RES; i++) { - int fir_offset = i*fir_N + fir_N/2; - double j_offset = double(i)/fir_RES; - // Calculate FIR table. This is the sinc function, weighted by the - // Kaiser window. - for (int j = -fir_N/2; j <= fir_N/2; j++) { - double jx = j - j_offset; - double wt = wc*jx/f_cycles_per_sample; - double temp = jx/(fir_N/2); - double Kaiser = - fabs(temp) <= 1 ? I0(beta*sqrt(1 - temp*temp))/I0beta : 0; - double sincwt = - fabs(wt) >= 1e-6 ? sin(wt)/wt : 1; - double val = - (1 << FIR_SHIFT)*filter_scale*f_samples_per_cycle*wc/pi*sincwt*Kaiser; - fir[fir_offset + j] = short(val + 0.5); - } - } - - // Allocate sample buffer. - if (!sample) { - sample = new short[RINGSIZE*2]; - } - // Clear sample buffer. - for (int j = 0; j < RINGSIZE*2; j++) { - sample[j] = 0; - } - sample_index = 0; - - return true; -} - - -// ---------------------------------------------------------------------------- -// Adjustment of SID sampling frequency. -// -// In some applications, e.g. a C64 emulator, it can be desirable to -// synchronize sound with a timer source. This is supported by adjustment of -// the SID sampling frequency. -// -// NB! Adjustment of the sampling frequency may lead to noticeable shifts in -// frequency, and should only be used for interactive applications. Note also -// that any adjustment of the sampling frequency will change the -// characteristics of the resampling filter, since the filter is not rebuilt. -// ---------------------------------------------------------------------------- -void cSID::adjust_sampling_frequency(double sample_freq) -{ - cycles_per_sample = - cycle_count(clock_frequency/sample_freq*(1 << FIXP_SHIFT) + 0.5); -} - - -// ---------------------------------------------------------------------------- -// Return array of default spline interpolation points to map FC to -// filter cutoff frequency. -// ---------------------------------------------------------------------------- -void cSID::fc_default(const fc_point*& points, int& count) -{ - filter.fc_default(points, count); -} - - -// ---------------------------------------------------------------------------- -// Return FC spline plotter object. -// ---------------------------------------------------------------------------- -PointPlotter cSID::fc_plotter() -{ - return filter.fc_plotter(); -} - - -// ---------------------------------------------------------------------------- -// SID clocking - 1 cycle. -// ---------------------------------------------------------------------------- -void cSID::clock() -{ - int i; - - // Age bus value. - if (--bus_value_ttl <= 0) { - bus_value = 0; - bus_value_ttl = 0; - } - - // Clock amplitude modulators. - for (i = 0; i < 3; i++) { - voice[i].envelope.clock(); - } - - // Clock oscillators. - for (i = 0; i < 3; i++) { - voice[i].wave.clock(); - } - - // Synchronize oscillators. - for (i = 0; i < 3; i++) { - voice[i].wave.synchronize(); - } - - // Clock filter. - filter.clock(voice[0].output(), voice[1].output(), voice[2].output(), ext_in); - - // Clock external filter. - extfilt.clock(filter.output()); -} - - -// ---------------------------------------------------------------------------- -// SID clocking - delta_t cycles. -// ---------------------------------------------------------------------------- -void cSID::clock(cycle_count delta_t) -{ - int i; - - if (delta_t <= 0) { - return; - } - - // Age bus value. - bus_value_ttl -= delta_t; - if (bus_value_ttl <= 0) { - bus_value = 0; - bus_value_ttl = 0; - } - - // Clock amplitude modulators. - for (i = 0; i < 3; i++) { - voice[i].envelope.clock(delta_t); - } - - // Clock and synchronize oscillators. - // Loop until we reach the current cycle. - cycle_count delta_t_osc = delta_t; - while (delta_t_osc) { - cycle_count delta_t_min = delta_t_osc; - - // Find minimum number of cycles to an oscillator accumulator MSB toggle. - // We have to clock on each MSB on / MSB off for hard sync to operate - // correctly. - for (i = 0; i < 3; i++) { - WaveformGenerator& wave = voice[i].wave; - - // It is only necessary to clock on the MSB of an oscillator that is - // a sync source and has freq != 0. - if (!(wave.sync_dest->sync && wave.freq)) { - continue; - } - - reg16 freq = wave.freq; - reg24 accumulator = wave.accumulator; - - // Clock on MSB off if MSB is on, clock on MSB on if MSB is off. - reg24 delta_accumulator = - (accumulator & 0x800000 ? 0x1000000 : 0x800000) - accumulator; - - cycle_count delta_t_next = delta_accumulator/freq; - if (delta_accumulator%freq) { - ++delta_t_next; - } - - if (delta_t_next < delta_t_min) { - delta_t_min = delta_t_next; - } - } - - // Clock oscillators. - for (i = 0; i < 3; i++) { - voice[i].wave.clock(delta_t_min); - } - - // Synchronize oscillators. - for (i = 0; i < 3; i++) { - voice[i].wave.synchronize(); - } - - delta_t_osc -= delta_t_min; - } - - // Clock filter. - filter.clock(delta_t, - voice[0].output(), voice[1].output(), voice[2].output(), ext_in); - - // Clock external filter. - extfilt.clock(delta_t, filter.output()); -} - - -// ---------------------------------------------------------------------------- -// SID clocking with audio sampling. -// Fixpoint arithmetics is used. -// -// The example below shows how to clock the SID a specified amount of cycles -// while producing audio output: -// -// while (delta_t) { -// bufindex += sid.clock(delta_t, buf + bufindex, buflength - bufindex); -// write(dsp, buf, bufindex*2); -// bufindex = 0; -// } -// -// ---------------------------------------------------------------------------- -int cSID::clock(cycle_count& delta_t, short* buf, int n, int interleave) -{ - switch (sampling) { - default: - case SAMPLE_FAST: - return clock_fast(delta_t, buf, n, interleave); - case SAMPLE_INTERPOLATE: - return clock_interpolate(delta_t, buf, n, interleave); - case SAMPLE_RESAMPLE_INTERPOLATE: - return clock_resample_interpolate(delta_t, buf, n, interleave); - case SAMPLE_RESAMPLE_FAST: - return clock_resample_fast(delta_t, buf, n, interleave); - } -} - -// ---------------------------------------------------------------------------- -// SID clocking with audio sampling - delta clocking picking nearest sample. -// ---------------------------------------------------------------------------- -RESID_INLINE -int cSID::clock_fast(cycle_count& delta_t, short* buf, int n, - int interleave) -{ - int s = 0; - - for (;;) { - cycle_count next_sample_offset = sample_offset + cycles_per_sample + (1 << (FIXP_SHIFT - 1)); - cycle_count delta_t_sample = next_sample_offset >> FIXP_SHIFT; - if (delta_t_sample > delta_t) { - break; - } - if (s >= n) { - return s; - } - clock(delta_t_sample); - delta_t -= delta_t_sample; - sample_offset = (next_sample_offset & FIXP_MASK) - (1 << (FIXP_SHIFT - 1)); - buf[s++*interleave] = output(); - } - - clock(delta_t); - sample_offset -= delta_t << FIXP_SHIFT; - delta_t = 0; - return s; -} - - -// ---------------------------------------------------------------------------- -// SID clocking with audio sampling - cycle based with linear sample -// interpolation. -// -// Here the chip is clocked every cycle. This yields higher quality -// sound since the samples are linearly interpolated, and since the -// external filter attenuates frequencies above 16kHz, thus reducing -// sampling noise. -// ---------------------------------------------------------------------------- -RESID_INLINE -int cSID::clock_interpolate(cycle_count& delta_t, short* buf, int n, - int interleave) -{ - int s = 0; - int i; - - for (;;) { - cycle_count next_sample_offset = sample_offset + cycles_per_sample; - cycle_count delta_t_sample = next_sample_offset >> FIXP_SHIFT; - if (delta_t_sample > delta_t) { - break; - } - if (s >= n) { - return s; - } - for (i = 0; i < delta_t_sample - 1; i++) { - clock(); - } - if (i < delta_t_sample) { - sample_prev = output(); - clock(); - } - - delta_t -= delta_t_sample; - sample_offset = next_sample_offset & FIXP_MASK; - - short sample_now = output(); - buf[s++*interleave] = - sample_prev + (sample_offset*(sample_now - sample_prev) >> FIXP_SHIFT); - sample_prev = sample_now; - } - - for (i = 0; i < delta_t - 1; i++) { - clock(); - } - if (i < delta_t) { - sample_prev = output(); - clock(); - } - sample_offset -= delta_t << FIXP_SHIFT; - delta_t = 0; - return s; -} - - -// ---------------------------------------------------------------------------- -// SID clocking with audio sampling - cycle based with audio resampling. -// -// This is the theoretically correct (and computationally intensive) audio -// sample generation. The samples are generated by resampling to the specified -// sampling frequency. The work rate is inversely proportional to the -// percentage of the bandwidth allocated to the filter transition band. -// -// This implementation is based on the paper "A Flexible Sampling-Rate -// Conversion Method", by J. O. Smith and P. Gosset, or rather on the -// expanded tutorial on the "Digital Audio Resampling Home Page": -// http://www-ccrma.stanford.edu/~jos/resample/ -// -// By building shifted FIR tables with samples according to the -// sampling frequency, this implementation dramatically reduces the -// computational effort in the filter convolutions, without any loss -// of accuracy. The filter convolutions are also vectorizable on -// current hardware. -// -// Further possible optimizations are: -// * An equiripple filter design could yield a lower filter order, see -// http://www.mwrf.com/Articles/ArticleID/7229/7229.html -// * The Convolution Theorem could be used to bring the complexity of -// convolution down from O(n*n) to O(n*log(n)) using the Fast Fourier -// Transform, see http://en.wikipedia.org/wiki/Convolution_theorem -// * Simply resampling in two steps can also yield computational -// savings, since the transition band will be wider in the first step -// and the required filter order is thus lower in this step. -// Laurent Ganier has found the optimal intermediate sampling frequency -// to be (via derivation of sum of two steps): -// 2 * pass_freq + sqrt [ 2 * pass_freq * orig_sample_freq -// * (dest_sample_freq - 2 * pass_freq) / dest_sample_freq ] -// -// NB! the result of right shifting negative numbers is really -// implementation dependent in the C++ standard. -// ---------------------------------------------------------------------------- -RESID_INLINE -int cSID::clock_resample_interpolate(cycle_count& delta_t, short* buf, int n, - int interleave) -{ - int s = 0; - - for (;;) { - cycle_count next_sample_offset = sample_offset + cycles_per_sample; - cycle_count delta_t_sample = next_sample_offset >> FIXP_SHIFT; - if (delta_t_sample > delta_t) { - break; - } - if (s >= n) { - return s; - } - for (int i = 0; i < delta_t_sample; i++) { - clock(); - sample[sample_index] = sample[sample_index + RINGSIZE] = output(); - ++sample_index; - sample_index &= 0x3fff; - } - delta_t -= delta_t_sample; - sample_offset = next_sample_offset & FIXP_MASK; - - int fir_offset = sample_offset*fir_RES >> FIXP_SHIFT; - int fir_offset_rmd = sample_offset*fir_RES & FIXP_MASK; - short* fir_start = fir + fir_offset*fir_N; - short* sample_start = sample + sample_index - fir_N + RINGSIZE; - - // Convolution with filter impulse response. - int v1 = 0; - for (int j = 0; j < fir_N; j++) { - v1 += sample_start[j]*fir_start[j]; - } - - // Use next FIR table, wrap around to first FIR table using - // previous sample. - if (++fir_offset == fir_RES) { - fir_offset = 0; - --sample_start; - } - fir_start = fir + fir_offset*fir_N; - - // Convolution with filter impulse response. - int v2 = 0; - for (int j = 0; j < fir_N; j++) { - v2 += sample_start[j]*fir_start[j]; - } - - // Linear interpolation. - // fir_offset_rmd is equal for all samples, it can thus be factorized out: - // sum(v1 + rmd*(v2 - v1)) = sum(v1) + rmd*(sum(v2) - sum(v1)) - int v = v1 + (fir_offset_rmd*(v2 - v1) >> FIXP_SHIFT); - - v >>= FIR_SHIFT; - - // Saturated arithmetics to guard against 16 bit sample overflow. - const int half = 1 << 15; - if (v >= half) { - v = half - 1; - } - else if (v < -half) { - v = -half; - } - - buf[s++*interleave] = v; - } - - for (int i = 0; i < delta_t; i++) { - clock(); - sample[sample_index] = sample[sample_index + RINGSIZE] = output(); - ++sample_index; - sample_index &= 0x3fff; - } - sample_offset -= delta_t << FIXP_SHIFT; - delta_t = 0; - return s; -} - - -// ---------------------------------------------------------------------------- -// SID clocking with audio sampling - cycle based with audio resampling. -// ---------------------------------------------------------------------------- -RESID_INLINE -int cSID::clock_resample_fast(cycle_count& delta_t, short* buf, int n, - int interleave) -{ - int s = 0; - - for (;;) { - cycle_count next_sample_offset = sample_offset + cycles_per_sample; - cycle_count delta_t_sample = next_sample_offset >> FIXP_SHIFT; - if (delta_t_sample > delta_t) { - break; - } - if (s >= n) { - return s; - } - for (int i = 0; i < delta_t_sample; i++) { - clock(); - sample[sample_index] = sample[sample_index + RINGSIZE] = output(); - ++sample_index; - sample_index &= 0x3fff; - } - delta_t -= delta_t_sample; - sample_offset = next_sample_offset & FIXP_MASK; - - int fir_offset = sample_offset*fir_RES >> FIXP_SHIFT; - short* fir_start = fir + fir_offset*fir_N; - short* sample_start = sample + sample_index - fir_N + RINGSIZE; - - // Convolution with filter impulse response. - int v = 0; - for (int j = 0; j < fir_N; j++) { - v += sample_start[j]*fir_start[j]; - } - - v >>= FIR_SHIFT; - - // Saturated arithmetics to guard against 16 bit sample overflow. - const int half = 1 << 15; - if (v >= half) { - v = half - 1; - } - else if (v < -half) { - v = -half; - } - - buf[s++*interleave] = v; - } - - for (int i = 0; i < delta_t; i++) { - clock(); - sample[sample_index] = sample[sample_index + RINGSIZE] = output(); - ++sample_index; - sample_index &= 0x3fff; - } - sample_offset -= delta_t << FIXP_SHIFT; - delta_t = 0; - return s; -} diff --git a/plugins/sid/sid.h b/plugins/sid/sid.h deleted file mode 100644 index 0f596a55604..00000000000 --- a/plugins/sid/sid.h +++ /dev/null @@ -1,146 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#ifndef __SID_H__ -#define __SID_H__ - -#include "siddefs.h" -#include "voice.h" -#include "filter.h" -#include "extfilt.h" -#include "pot.h" - -class cSID -{ -public: - cSID(); - ~cSID(); - - void set_chip_model(chip_model model); - void enable_filter(bool enable); - void enable_external_filter(bool enable); - bool set_sampling_parameters(double clock_freq, sampling_method method, - double sample_freq, double pass_freq = -1, - double filter_scale = 0.97); - void adjust_sampling_frequency(double sample_freq); - - void fc_default(const fc_point*& points, int& count); - PointPlotter fc_plotter(); - - void clock(); - void clock(cycle_count delta_t); - int clock(cycle_count& delta_t, short* buf, int n, int interleave = 1); - void reset(); - - // Read/write registers. - reg8 read(reg8 offset); - void write(reg8 offset, reg8 value); - - // Read/write state. - class State - { - public: - State(); - - char sid_register[0x20]; - - reg8 bus_value; - cycle_count bus_value_ttl; - - reg24 accumulator[3]; - reg24 shift_register[3]; - reg16 rate_counter[3]; - reg16 rate_counter_period[3]; - reg16 exponential_counter[3]; - reg16 exponential_counter_period[3]; - reg8 envelope_counter[3]; - EnvelopeGenerator::State envelope_state[3]; - bool hold_zero[3]; - }; - - State read_state(); - void write_state(const State& state); - - // 16-bit input (EXT IN). - void input(int sample); - - // 16-bit output (AUDIO OUT). - int output(); - // n-bit output. - int output(int bits); - -protected: - static double I0(double x); - RESID_INLINE int clock_fast(cycle_count& delta_t, short* buf, int n, - int interleave); - RESID_INLINE int clock_interpolate(cycle_count& delta_t, short* buf, int n, - int interleave); - RESID_INLINE int clock_resample_interpolate(cycle_count& delta_t, short* buf, - int n, int interleave); - RESID_INLINE int clock_resample_fast(cycle_count& delta_t, short* buf, - int n, int interleave); - - Voice voice[3]; - Filter filter; - ExternalFilter extfilt; - Potentiometer potx; - Potentiometer poty; - - reg8 bus_value; - cycle_count bus_value_ttl; - - double clock_frequency; - - // External audio input. - int ext_in; - - // Resampling constants. - // The error in interpolated lookup is bounded by 1.234/L^2, - // while the error in non-interpolated lookup is bounded by - // 0.7854/L + 0.4113/L^2, see - // http://www-ccrma.stanford.edu/~jos/resample/Choice_Table_Size.html - // For a resolution of 16 bits this yields L >= 285 and L >= 51473, - // respectively. - static const int FIR_N; - static const int FIR_RES_INTERPOLATE; - static const int FIR_RES_FAST; - static const int FIR_SHIFT; - static const int RINGSIZE; - - // Fixpoint constants (16.16 bits). - static const int FIXP_SHIFT; - static const int FIXP_MASK; - - // Sampling variables. - sampling_method sampling; - cycle_count cycles_per_sample; - cycle_count sample_offset; - int sample_index; - short sample_prev; - int fir_N; - int fir_RES; - - // Ring buffer with overflow for contiguous storage of RINGSIZE samples. - short* sample; - - // FIR_RES filter tables (FIR_N*FIR_RES). - short* fir; -}; - -#endif // not __SID_H__ diff --git a/plugins/sid/siddefs.h b/plugins/sid/siddefs.h deleted file mode 100644 index e8a9ef57816..00000000000 --- a/plugins/sid/siddefs.h +++ /dev/null @@ -1,69 +0,0 @@ -#define VERSION "0.16" - -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 1999 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#ifndef __SIDDEFS_H__ -#define __SIDDEFS_H__ - -// Define bool, true, and false for C++ compilers that lack these keywords. -#define RESID_HAVE_BOOL 1 - -#if !RESID_HAVE_BOOL -typedef int bool; -const bool true = 1; -const bool false = 0; -#endif - -// We could have used the smallest possible data type for each SID register, -// however this would give a slower engine because of data type conversions. -// An int is assumed to be at least 32 bits (necessary in the types reg24, -// cycle_count, and sound_sample). GNU does not support 16-bit machines -// (GNU Coding Standards: Portability between CPUs), so this should be -// a valid assumption. - -typedef unsigned int reg4; -typedef unsigned int reg8; -typedef unsigned int reg12; -typedef unsigned int reg16; -typedef unsigned int reg24; - -typedef int cycle_count; -typedef int sound_sample; -typedef sound_sample fc_point[2]; - -enum chip_model { MOS6581, MOS8580 }; - -enum sampling_method { SAMPLE_FAST, SAMPLE_INTERPOLATE, - SAMPLE_RESAMPLE_INTERPOLATE, SAMPLE_RESAMPLE_FAST }; - -extern "C" -{ -#ifndef __VERSION_CC__ -extern const char* resid_version_string; -#else -const char* resid_version_string = VERSION; -#endif -} - -// Inlining on/off. -#define RESID_INLINING 1 -#define RESID_INLINE inline - -#endif // not __SIDDEFS_H__ diff --git a/plugins/sid/spline.h b/plugins/sid/spline.h deleted file mode 100644 index 93ba2776aa0..00000000000 --- a/plugins/sid/spline.h +++ /dev/null @@ -1,272 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#ifndef __SPLINE_H__ -#define __SPLINE_H__ - -// Our objective is to construct a smooth interpolating single-valued function -// y = f(x). -// -// Catmull-Rom splines are widely used for interpolation, however these are -// parametric curves [x(t) y(t) ...] and can not be used to directly calculate -// y = f(x). -// For a discussion of Catmull-Rom splines see Catmull, E., and R. Rom, -// "A Class of Local Interpolating Splines", Computer Aided Geometric Design. -// -// Natural cubic splines are single-valued functions, and have been used in -// several applications e.g. to specify gamma curves for image display. -// These splines do not afford local control, and a set of linear equations -// including all interpolation points must be solved before any point on the -// curve can be calculated. The lack of local control makes the splines -// more difficult to handle than e.g. Catmull-Rom splines, and real-time -// interpolation of a stream of data points is not possible. -// For a discussion of natural cubic splines, see e.g. Kreyszig, E., "Advanced -// Engineering Mathematics". -// -// Our approach is to approximate the properties of Catmull-Rom splines for -// piecewice cubic polynomials f(x) = ax^3 + bx^2 + cx + d as follows: -// Each curve segment is specified by four interpolation points, -// p0, p1, p2, p3. -// The curve between p1 and p2 must interpolate both p1 and p2, and in addition -// f'(p1.x) = k1 = (p2.y - p0.y)/(p2.x - p0.x) and -// f'(p2.x) = k2 = (p3.y - p1.y)/(p3.x - p1.x). -// -// The constraints are expressed by the following system of linear equations -// -// [ 1 xi xi^2 xi^3 ] [ d ] [ yi ] -// [ 1 2*xi 3*xi^2 ] * [ c ] = [ ki ] -// [ 1 xj xj^2 xj^3 ] [ b ] [ yj ] -// [ 1 2*xj 3*xj^2 ] [ a ] [ kj ] -// -// Solving using Gaussian elimination and back substitution, setting -// dy = yj - yi, dx = xj - xi, we get -// -// a = ((ki + kj) - 2*dy/dx)/(dx*dx); -// b = ((kj - ki)/dx - 3*(xi + xj)*a)/2; -// c = ki - (3*xi*a + 2*b)*xi; -// d = yi - ((xi*a + b)*xi + c)*xi; -// -// Having calculated the coefficients of the cubic polynomial we have the -// choice of evaluation by brute force -// -// for (x = x1; x <= x2; x += res) { -// y = ((a*x + b)*x + c)*x + d; -// plot(x, y); -// } -// -// or by forward differencing -// -// y = ((a*x1 + b)*x1 + c)*x1 + d; -// dy = (3*a*(x1 + res) + 2*b)*x1*res + ((a*res + b)*res + c)*res; -// d2y = (6*a*(x1 + res) + 2*b)*res*res; -// d3y = 6*a*res*res*res; -// -// for (x = x1; x <= x2; x += res) { -// plot(x, y); -// y += dy; dy += d2y; d2y += d3y; -// } -// -// See Foley, Van Dam, Feiner, Hughes, "Computer Graphics, Principles and -// Practice" for a discussion of forward differencing. -// -// If we have a set of interpolation points p0, ..., pn, we may specify -// curve segments between p0 and p1, and between pn-1 and pn by using the -// following constraints: -// f''(p0.x) = 0 and -// f''(pn.x) = 0. -// -// Substituting the results for a and b in -// -// 2*b + 6*a*xi = 0 -// -// we get -// -// ki = (3*dy/dx - kj)/2; -// -// or by substituting the results for a and b in -// -// 2*b + 6*a*xj = 0 -// -// we get -// -// kj = (3*dy/dx - ki)/2; -// -// Finally, if we have only two interpolation points, the cubic polynomial -// will degenerate to a straight line if we set -// -// ki = kj = dy/dx; -// - - -#if SPLINE_BRUTE_FORCE -#define interpolate_segment interpolate_brute_force -#else -#define interpolate_segment interpolate_forward_difference -#endif - - -// ---------------------------------------------------------------------------- -// Calculation of coefficients. -// ---------------------------------------------------------------------------- -inline -void cubic_coefficients(double x1, double y1, double x2, double y2, - double k1, double k2, - double& a, double& b, double& c, double& d) -{ - double dx = x2 - x1, dy = y2 - y1; - - a = ((k1 + k2) - 2*dy/dx)/(dx*dx); - b = ((k2 - k1)/dx - 3*(x1 + x2)*a)/2; - c = k1 - (3*x1*a + 2*b)*x1; - d = y1 - ((x1*a + b)*x1 + c)*x1; -} - -// ---------------------------------------------------------------------------- -// Evaluation of cubic polynomial by brute force. -// ---------------------------------------------------------------------------- -template -inline -void interpolate_brute_force(double x1, double y1, double x2, double y2, - double k1, double k2, - PointPlotter plot, double res) -{ - double a, b, c, d; - cubic_coefficients(x1, y1, x2, y2, k1, k2, a, b, c, d); - - // Calculate each point. - for (double x = x1; x <= x2; x += res) { - double y = ((a*x + b)*x + c)*x + d; - plot(x, y); - } -} - -// ---------------------------------------------------------------------------- -// Evaluation of cubic polynomial by forward differencing. -// ---------------------------------------------------------------------------- -template -inline -void interpolate_forward_difference(double x1, double y1, double x2, double y2, - double k1, double k2, - PointPlotter plot, double res) -{ - double a, b, c, d; - cubic_coefficients(x1, y1, x2, y2, k1, k2, a, b, c, d); - - double y = ((a*x1 + b)*x1 + c)*x1 + d; - double dy = (3*a*(x1 + res) + 2*b)*x1*res + ((a*res + b)*res + c)*res; - double d2y = (6*a*(x1 + res) + 2*b)*res*res; - double d3y = 6*a*res*res*res; - - // Calculate each point. - for (double x = x1; x <= x2; x += res) { - plot(x, y); - y += dy; dy += d2y; d2y += d3y; - } -} - -template -inline -double x(PointIter p) -{ - return (*p)[0]; -} - -template -inline -double y(PointIter p) -{ - return (*p)[1]; -} - -// ---------------------------------------------------------------------------- -// Evaluation of complete interpolating function. -// Note that since each curve segment is controlled by four points, the -// end points will not be interpolated. If extra control points are not -// desirable, the end points can simply be repeated to ensure interpolation. -// Note also that points of non-differentiability and discontinuity can be -// introduced by repeating points. -// ---------------------------------------------------------------------------- -template -inline -void interpolate(PointIter p0, PointIter pn, PointPlotter plot, double res) -{ - double k1, k2; - - // Set up points for first curve segment. - PointIter p1 = p0; ++p1; - PointIter p2 = p1; ++p2; - PointIter p3 = p2; ++p3; - - // Draw each curve segment. - for (; p2 != pn; ++p0, ++p1, ++p2, ++p3) { - // p1 and p2 equal; single point. - if (x(p1) == x(p2)) { - continue; - } - // Both end points repeated; straight line. - if (x(p0) == x(p1) && x(p2) == x(p3)) { - k1 = k2 = (y(p2) - y(p1))/(x(p2) - x(p1)); - } - // p0 and p1 equal; use f''(x1) = 0. - else if (x(p0) == x(p1)) { - k2 = (y(p3) - y(p1))/(x(p3) - x(p1)); - k1 = (3*(y(p2) - y(p1))/(x(p2) - x(p1)) - k2)/2; - } - // p2 and p3 equal; use f''(x2) = 0. - else if (x(p2) == x(p3)) { - k1 = (y(p2) - y(p0))/(x(p2) - x(p0)); - k2 = (3*(y(p2) - y(p1))/(x(p2) - x(p1)) - k1)/2; - } - // Normal curve. - else { - k1 = (y(p2) - y(p0))/(x(p2) - x(p0)); - k2 = (y(p3) - y(p1))/(x(p3) - x(p1)); - } - - interpolate_segment(x(p1), y(p1), x(p2), y(p2), k1, k2, plot, res); - } -} - -// ---------------------------------------------------------------------------- -// Class for plotting integers into an array. -// ---------------------------------------------------------------------------- -template -class PointPlotter -{ - protected: - F* f; - - public: - PointPlotter(F* arr) : f(arr) - { - } - - void operator ()(double x, double y) - { - // Clamp negative values to zero. - if (y < 0) { - y = 0; - } - - f[F(x)] = F(y); - } -}; - - -#endif // not __SPLINE_H__ diff --git a/plugins/sid/version.cc b/plugins/sid/version.cc deleted file mode 100644 index 3b61afd2499..00000000000 --- a/plugins/sid/version.cc +++ /dev/null @@ -1,21 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#define __VERSION_CC__ -#include "siddefs.h" diff --git a/plugins/sid/voice.cc b/plugins/sid/voice.cc deleted file mode 100644 index 9c0017f99b2..00000000000 --- a/plugins/sid/voice.cc +++ /dev/null @@ -1,132 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#define __VOICE_CC__ -#include "voice.h" - -// ---------------------------------------------------------------------------- -// Constructor. -// ---------------------------------------------------------------------------- -Voice::Voice() -{ - set_chip_model(MOS6581); -} - -// ---------------------------------------------------------------------------- -// Set chip model. -// ---------------------------------------------------------------------------- -void Voice::set_chip_model(chip_model model) -{ - wave.set_chip_model(model); - - if (model == MOS6581) { - // The waveform D/A converter introduces a DC offset in the signal - // to the envelope multiplying D/A converter. The "zero" level of - // the waveform D/A converter can be found as follows: - // - // Measure the "zero" voltage of voice 3 on the SID audio output - // pin, routing only voice 3 to the mixer ($d417 = $0b, $d418 = - // $0f, all other registers zeroed). - // - // Then set the sustain level for voice 3 to maximum and search for - // the waveform output value yielding the same voltage as found - // above. This is done by trying out different waveform output - // values until the correct value is found, e.g. with the following - // program: - // - // lda #$08 - // sta $d412 - // lda #$0b - // sta $d417 - // lda #$0f - // sta $d418 - // lda #$f0 - // sta $d414 - // lda #$21 - // sta $d412 - // lda #$01 - // sta $d40e - // - // ldx #$00 - // lda #$38 ; Tweak this to find the "zero" level - //l cmp $d41b - // bne l - // stx $d40e ; Stop frequency counter - freeze waveform output - // brk - // - // The waveform output range is 0x000 to 0xfff, so the "zero" - // level should ideally have been 0x800. In the measured chip, the - // waveform output "zero" level was found to be 0x380 (i.e. $d41b - // = 0x38) at 5.94V. - - wave_zero = 0x380; - - // The envelope multiplying D/A converter introduces another DC - // offset. This is isolated by the following measurements: - // - // * The "zero" output level of the mixer at full volume is 5.44V. - // * Routing one voice to the mixer at full volume yields - // 6.75V at maximum voice output (wave = 0xfff, sustain = 0xf) - // 5.94V at "zero" voice output (wave = any, sustain = 0x0) - // 5.70V at minimum voice output (wave = 0x000, sustain = 0xf) - // * The DC offset of one voice is (5.94V - 5.44V) = 0.50V - // * The dynamic range of one voice is |6.75V - 5.70V| = 1.05V - // * The DC offset is thus 0.50V/1.05V ~ 1/2 of the dynamic range. - // - // Note that by removing the DC offset, we get the following ranges for - // one voice: - // y > 0: (6.75V - 5.44V) - 0.50V = 0.81V - // y < 0: (5.70V - 5.44V) - 0.50V = -0.24V - // The scaling of the voice amplitude is not symmetric about y = 0; - // this follows from the DC level in the waveform output. - - voice_DC = 0x800*0xff; - } - else { - // No DC offsets in the MOS8580. - wave_zero = 0x800; - voice_DC = 0; - } -} - -// ---------------------------------------------------------------------------- -// Set sync source. -// ---------------------------------------------------------------------------- -void Voice::set_sync_source(Voice* source) -{ - wave.set_sync_source(&source->wave); -} - -// ---------------------------------------------------------------------------- -// Register functions. -// ---------------------------------------------------------------------------- -void Voice::writeCONTROL_REG(reg8 control) -{ - wave.writeCONTROL_REG(control); - envelope.writeCONTROL_REG(control); -} - -// ---------------------------------------------------------------------------- -// SID reset. -// ---------------------------------------------------------------------------- -void Voice::reset() -{ - wave.reset(); - envelope.reset(); -} diff --git a/plugins/sid/voice.h b/plugins/sid/voice.h deleted file mode 100644 index 599a77ab4a0..00000000000 --- a/plugins/sid/voice.h +++ /dev/null @@ -1,77 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#ifndef __VOICE_H__ -#define __VOICE_H__ - -#include "siddefs.h" -#include "wave.h" -#include "envelope.h" - -class Voice -{ -public: - Voice(); - - void set_chip_model(chip_model model); - void set_sync_source(Voice*); - void reset(); - - void writeCONTROL_REG(reg8); - - // Amplitude modulated waveform output. - // Range [-2048*255, 2047*255]. - RESID_INLINE sound_sample output(); - -protected: - WaveformGenerator wave; - EnvelopeGenerator envelope; - - // Waveform D/A zero level. - sound_sample wave_zero; - - // Multiplying D/A DC offset. - sound_sample voice_DC; - -friend class cSID; -}; - - -// ---------------------------------------------------------------------------- -// Inline functions. -// The following function is defined inline because it is called every -// time a sample is calculated. -// ---------------------------------------------------------------------------- - -#if RESID_INLINING || defined(__VOICE_CC__) - -// ---------------------------------------------------------------------------- -// Amplitude modulated waveform output. -// Ideal range [-2048*255, 2047*255]. -// ---------------------------------------------------------------------------- -RESID_INLINE -sound_sample Voice::output() -{ - // Multiply oscillator output with envelope output. - return (wave.output() - wave_zero)*envelope.output() + voice_DC; -} - -#endif // RESID_INLINING || defined(__VOICE_CC__) - -#endif // not __VOICE_H__ diff --git a/plugins/sid/wave.cc b/plugins/sid/wave.cc deleted file mode 100644 index a72abd6450a..00000000000 --- a/plugins/sid/wave.cc +++ /dev/null @@ -1,144 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#define __WAVE_CC__ -#include "wave.h" - -// ---------------------------------------------------------------------------- -// Constructor. -// ---------------------------------------------------------------------------- -WaveformGenerator::WaveformGenerator() -{ - sync_source = this; - - set_chip_model(MOS6581); - - reset(); -} - - -// ---------------------------------------------------------------------------- -// Set sync source. -// ---------------------------------------------------------------------------- -void WaveformGenerator::set_sync_source(WaveformGenerator* source) -{ - sync_source = source; - source->sync_dest = this; -} - - -// ---------------------------------------------------------------------------- -// Set chip model. -// ---------------------------------------------------------------------------- -void WaveformGenerator::set_chip_model(chip_model model) -{ - if (model == MOS6581) { - wave__ST = wave6581__ST; - wave_P_T = wave6581_P_T; - wave_PS_ = wave6581_PS_; - wave_PST = wave6581_PST; - } - else { - wave__ST = wave8580__ST; - wave_P_T = wave8580_P_T; - wave_PS_ = wave8580_PS_; - wave_PST = wave8580_PST; - } -} - - -// ---------------------------------------------------------------------------- -// Register functions. -// ---------------------------------------------------------------------------- -void WaveformGenerator::writeFREQ_LO(reg8 freq_lo) -{ - freq = ( freq & 0xff00 ) | ( freq_lo & 0x00ff ); -} - -void WaveformGenerator::writeFREQ_HI(reg8 freq_hi) -{ - freq = ( (freq_hi << 8) & 0xff00 ) | ( freq & 0x00ff ); -} - -void WaveformGenerator::writePW_LO(reg8 pw_lo) -{ - pw = ( pw & 0xf00 ) | ( pw_lo & 0x0ff ); -} - -void WaveformGenerator::writePW_HI(reg8 pw_hi) -{ - pw = ( (pw_hi << 8) & 0xf00 ) | ( pw & 0x0ff ); -} - -void WaveformGenerator::writeCONTROL_REG(reg8 control) -{ - waveform = (control >> 4) & 0x0f; - ring_mod = control & 0x04; - sync = control & 0x02; - - reg8 test_next = control & 0x08; - - // Test bit set. - // The accumulator and the shift register are both cleared. - // NB! The shift register is not really cleared immediately. It seems like - // the individual bits in the shift register start to fade down towards - // zero when test is set. All bits reach zero within approximately - // $2000 - $4000 cycles. - // This is not modeled. There should fortunately be little audible output - // from this peculiar behavior. - if (test_next) { - accumulator = 0; - shift_register = 0; - } - // Test bit cleared. - // The accumulator starts counting, and the shift register is reset to - // the value 0x7ffff8. - // NB! The shift register will not actually be set to this exact value if the - // shift register bits have not had time to fade to zero. - // This is not modeled. - else if (test) { - shift_register = 0x7ffff8; - } - - test = test_next; - - // The gate bit is handled by the EnvelopeGenerator. -} - -reg8 WaveformGenerator::readOSC() -{ - return output() >> 4; -} - -// ---------------------------------------------------------------------------- -// SID reset. -// ---------------------------------------------------------------------------- -void WaveformGenerator::reset() -{ - accumulator = 0; - shift_register = 0x7ffff8; - freq = 0; - pw = 0; - - test = 0; - ring_mod = 0; - sync = 0; - - msb_rising = false; -} diff --git a/plugins/sid/wave.h b/plugins/sid/wave.h deleted file mode 100644 index 9101b30851c..00000000000 --- a/plugins/sid/wave.h +++ /dev/null @@ -1,503 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#ifndef __WAVE_H__ -#define __WAVE_H__ - -#include "siddefs.h" - -// ---------------------------------------------------------------------------- -// A 24 bit accumulator is the basis for waveform generation. FREQ is added to -// the lower 16 bits of the accumulator each cycle. -// The accumulator is set to zero when TEST is set, and starts counting -// when TEST is cleared. -// The noise waveform is taken from intermediate bits of a 23 bit shift -// register. This register is clocked by bit 19 of the accumulator. -// ---------------------------------------------------------------------------- -class WaveformGenerator -{ -public: - WaveformGenerator(); - - void set_sync_source(WaveformGenerator*); - void set_chip_model(chip_model model); - - RESID_INLINE void clock(); - RESID_INLINE void clock(cycle_count delta_t); - RESID_INLINE void synchronize(); - void reset(); - - void writeFREQ_LO(reg8); - void writeFREQ_HI(reg8); - void writePW_LO(reg8); - void writePW_HI(reg8); - void writeCONTROL_REG(reg8); - reg8 readOSC(); - - // 12-bit waveform output. - RESID_INLINE reg12 output(); - -protected: - const WaveformGenerator* sync_source; - WaveformGenerator* sync_dest; - - // Tell whether the accumulator MSB was set high on this cycle. - bool msb_rising; - - reg24 accumulator; - reg24 shift_register; - - // Fout = (Fn*Fclk/16777216)Hz - reg16 freq; - // PWout = (PWn/40.95)% - reg12 pw; - - // The control register right-shifted 4 bits; used for output function - // table lookup. - reg8 waveform; - - // The remaining control register bits. - reg8 test; - reg8 ring_mod; - reg8 sync; - // The gate bit is handled by the EnvelopeGenerator. - - // 16 possible combinations of waveforms. - RESID_INLINE reg12 output____(); - RESID_INLINE reg12 output___T(); - RESID_INLINE reg12 output__S_(); - RESID_INLINE reg12 output__ST(); - RESID_INLINE reg12 output_P__(); - RESID_INLINE reg12 output_P_T(); - RESID_INLINE reg12 output_PS_(); - RESID_INLINE reg12 output_PST(); - RESID_INLINE reg12 outputN___(); - RESID_INLINE reg12 outputN__T(); - RESID_INLINE reg12 outputN_S_(); - RESID_INLINE reg12 outputN_ST(); - RESID_INLINE reg12 outputNP__(); - RESID_INLINE reg12 outputNP_T(); - RESID_INLINE reg12 outputNPS_(); - RESID_INLINE reg12 outputNPST(); - - // Sample data for combinations of waveforms. - static reg8 wave6581__ST[]; - static reg8 wave6581_P_T[]; - static reg8 wave6581_PS_[]; - static reg8 wave6581_PST[]; - - static reg8 wave8580__ST[]; - static reg8 wave8580_P_T[]; - static reg8 wave8580_PS_[]; - static reg8 wave8580_PST[]; - - reg8* wave__ST; - reg8* wave_P_T; - reg8* wave_PS_; - reg8* wave_PST; - -friend class Voice; -friend class cSID; -}; - - -// ---------------------------------------------------------------------------- -// Inline functions. -// The following functions are defined inline because they are called every -// time a sample is calculated. -// ---------------------------------------------------------------------------- - -#if RESID_INLINING || defined(__WAVE_CC__) - -// ---------------------------------------------------------------------------- -// SID clocking - 1 cycle. -// ---------------------------------------------------------------------------- -RESID_INLINE -void WaveformGenerator::clock() -{ - // No operation if test bit is set. - if (test) { - return; - } - - reg24 accumulator_prev = accumulator; - - // Calculate new accumulator value; - accumulator += freq; - accumulator &= 0xffffff; - - // Check whether the MSB is set high. This is used for synchronization. - msb_rising = !(accumulator_prev & 0x800000) && (accumulator & 0x800000); - - // Shift noise register once for each time accumulator bit 19 is set high. - if (!(accumulator_prev & 0x080000) && (accumulator & 0x080000)) { - reg24 bit0 = ((shift_register >> 22) ^ (shift_register >> 17)) & 0x1; - shift_register <<= 1; - shift_register &= 0x7fffff; - shift_register |= bit0; - } -} - -// ---------------------------------------------------------------------------- -// SID clocking - delta_t cycles. -// ---------------------------------------------------------------------------- -RESID_INLINE -void WaveformGenerator::clock(cycle_count delta_t) -{ - // No operation if test bit is set. - if (test) { - return; - } - - reg24 accumulator_prev = accumulator; - - // Calculate new accumulator value; - reg24 delta_accumulator = delta_t*freq; - accumulator += delta_accumulator; - accumulator &= 0xffffff; - - // Check whether the MSB is set high. This is used for synchronization. - msb_rising = !(accumulator_prev & 0x800000) && (accumulator & 0x800000); - - // Shift noise register once for each time accumulator bit 19 is set high. - // Bit 19 is set high each time 2^20 (0x100000) is added to the accumulator. - reg24 shift_period = 0x100000; - - while (delta_accumulator) { - if (delta_accumulator < shift_period) { - shift_period = delta_accumulator; - // Determine whether bit 19 is set on the last period. - // NB! Requires two's complement integer. - if (shift_period <= 0x080000) { - // Check for flip from 0 to 1. - if (((accumulator - shift_period) & 0x080000) || !(accumulator & 0x080000)) - { - break; - } - } - else { - // Check for flip from 0 (to 1 or via 1 to 0) or from 1 via 0 to 1. - if (((accumulator - shift_period) & 0x080000) && !(accumulator & 0x080000)) - { - break; - } - } - } - - // Shift the noise/random register. - // NB! The shift is actually delayed 2 cycles, this is not modeled. - reg24 bit0 = ((shift_register >> 22) ^ (shift_register >> 17)) & 0x1; - shift_register <<= 1; - shift_register &= 0x7fffff; - shift_register |= bit0; - - delta_accumulator -= shift_period; - } -} - - -// ---------------------------------------------------------------------------- -// Synchronize oscillators. -// This must be done after all the oscillators have been clock()'ed since the -// oscillators operate in parallel. -// Note that the oscillators must be clocked exactly on the cycle when the -// MSB is set high for hard sync to operate correctly. See SID::clock(). -// ---------------------------------------------------------------------------- -RESID_INLINE -void WaveformGenerator::synchronize() -{ - // A special case occurs when a sync source is synced itself on the same - // cycle as when its MSB is set high. In this case the destination will - // not be synced. This has been verified by sampling OSC3. - if (msb_rising && sync_dest->sync && !(sync && sync_source->msb_rising)) { - sync_dest->accumulator = 0; - } -} - - -// ---------------------------------------------------------------------------- -// Output functions. -// NB! The output from SID 8580 is delayed one cycle compared to SID 6581, -// this is not modeled. -// ---------------------------------------------------------------------------- - -// No waveform: -// Zero output. -// -RESID_INLINE -reg12 WaveformGenerator::output____() -{ - return 0x000; -} - -// Triangle: -// The upper 12 bits of the accumulator are used. -// The MSB is used to create the falling edge of the triangle by inverting -// the lower 11 bits. The MSB is thrown away and the lower 11 bits are -// left-shifted (half the resolution, full amplitude). -// Ring modulation substitutes the MSB with MSB EOR sync_source MSB. -// -RESID_INLINE -reg12 WaveformGenerator::output___T() -{ - reg24 msb = (ring_mod ? accumulator ^ sync_source->accumulator : accumulator) - & 0x800000; - return ((msb ? ~accumulator : accumulator) >> 11) & 0xfff; -} - -// Sawtooth: -// The output is identical to the upper 12 bits of the accumulator. -// -RESID_INLINE -reg12 WaveformGenerator::output__S_() -{ - return accumulator >> 12; -} - -// Pulse: -// The upper 12 bits of the accumulator are used. -// These bits are compared to the pulse width register by a 12 bit digital -// comparator; output is either all one or all zero bits. -// NB! The output is actually delayed one cycle after the compare. -// This is not modeled. -// -// The test bit, when set to one, holds the pulse waveform output at 0xfff -// regardless of the pulse width setting. -// -RESID_INLINE -reg12 WaveformGenerator::output_P__() -{ - return (test || (accumulator >> 12) >= pw) ? 0xfff : 0x000; -} - -// Noise: -// The noise output is taken from intermediate bits of a 23-bit shift register -// which is clocked by bit 19 of the accumulator. -// NB! The output is actually delayed 2 cycles after bit 19 is set high. -// This is not modeled. -// -// Operation: Calculate EOR result, shift register, set bit 0 = result. -// -// ----------------------->--------------------- -// | | -// ----EOR---- | -// | | | -// 2 2 2 1 1 1 1 1 1 1 1 1 1 | -// Register bits: 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 <--- -// | | | | | | | | -// OSC3 bits : 7 6 5 4 3 2 1 0 -// -// Since waveform output is 12 bits the output is left-shifted 4 times. -// -RESID_INLINE -reg12 WaveformGenerator::outputN___() -{ - return - ((shift_register & 0x400000) >> 11) | - ((shift_register & 0x100000) >> 10) | - ((shift_register & 0x010000) >> 7) | - ((shift_register & 0x002000) >> 5) | - ((shift_register & 0x000800) >> 4) | - ((shift_register & 0x000080) >> 1) | - ((shift_register & 0x000010) << 1) | - ((shift_register & 0x000004) << 2); -} - -// Combined waveforms: -// By combining waveforms, the bits of each waveform are effectively short -// circuited. A zero bit in one waveform will result in a zero output bit -// (thus the infamous claim that the waveforms are AND'ed). -// However, a zero bit in one waveform will also affect the neighboring bits -// in the output. The reason for this has not been determined. -// -// Example: -// -// 1 1 -// Bit # 1 0 9 8 7 6 5 4 3 2 1 0 -// ----------------------- -// Sawtooth 0 0 0 1 1 1 1 1 1 0 0 0 -// -// Triangle 0 0 1 1 1 1 1 1 0 0 0 0 -// -// AND 0 0 0 1 1 1 1 1 0 0 0 0 -// -// Output 0 0 0 0 1 1 1 0 0 0 0 0 -// -// -// This behavior would be quite difficult to model exactly, since the SID -// in this case does not act as a digital state machine. Tests show that minor -// (1 bit) differences can actually occur in the output from otherwise -// identical samples from OSC3 when waveforms are combined. To further -// complicate the situation the output changes slightly with time (more -// neighboring bits are successively set) when the 12-bit waveform -// registers are kept unchanged. -// -// It is probably possible to come up with a valid model for the -// behavior, however this would be far too slow for practical use since it -// would have to be based on the mutual influence of individual bits. -// -// The output is instead approximated by using the upper bits of the -// accumulator as an index to look up the combined output in a table -// containing actual combined waveform samples from OSC3. -// These samples are 8 bit, so 4 bits of waveform resolution is lost. -// All OSC3 samples are taken with FREQ=0x1000, adding a 1 to the upper 12 -// bits of the accumulator each cycle for a sample period of 4096 cycles. -// -// Sawtooth+Triangle: -// The sawtooth output is used to look up an OSC3 sample. -// -// Pulse+Triangle: -// The triangle output is right-shifted and used to look up an OSC3 sample. -// The sample is output if the pulse output is on. -// The reason for using the triangle output as the index is to handle ring -// modulation. Only the first half of the sample is used, which should be OK -// since the triangle waveform has half the resolution of the accumulator. -// -// Pulse+Sawtooth: -// The sawtooth output is used to look up an OSC3 sample. -// The sample is output if the pulse output is on. -// -// Pulse+Sawtooth+Triangle: -// The sawtooth output is used to look up an OSC3 sample. -// The sample is output if the pulse output is on. -// -RESID_INLINE -reg12 WaveformGenerator::output__ST() -{ - return wave__ST[output__S_()] << 4; -} - -RESID_INLINE -reg12 WaveformGenerator::output_P_T() -{ - return (wave_P_T[output___T() >> 1] << 4) & output_P__(); -} - -RESID_INLINE -reg12 WaveformGenerator::output_PS_() -{ - return (wave_PS_[output__S_()] << 4) & output_P__(); -} - -RESID_INLINE -reg12 WaveformGenerator::output_PST() -{ - return (wave_PST[output__S_()] << 4) & output_P__(); -} - -// Combined waveforms including noise: -// All waveform combinations including noise output zero after a few cycles. -// NB! The effects of such combinations are not fully explored. It is claimed -// that the shift register may be filled with zeroes and locked up, which -// seems to be true. -// We have not attempted to model this behavior, suffice to say that -// there is very little audible output from waveform combinations including -// noise. We hope that nobody is actually using it. -// -RESID_INLINE -reg12 WaveformGenerator::outputN__T() -{ - return 0; -} - -RESID_INLINE -reg12 WaveformGenerator::outputN_S_() -{ - return 0; -} - -RESID_INLINE -reg12 WaveformGenerator::outputN_ST() -{ - return 0; -} - -RESID_INLINE -reg12 WaveformGenerator::outputNP__() -{ - return 0; -} - -RESID_INLINE -reg12 WaveformGenerator::outputNP_T() -{ - return 0; -} - -RESID_INLINE -reg12 WaveformGenerator::outputNPS_() -{ - return 0; -} - -RESID_INLINE -reg12 WaveformGenerator::outputNPST() -{ - return 0; -} - -// ---------------------------------------------------------------------------- -// Select one of 16 possible combinations of waveforms. -// ---------------------------------------------------------------------------- -RESID_INLINE -reg12 WaveformGenerator::output() -{ - // It may seem cleaner to use an array of member functions to return - // waveform output; however a switch with inline functions is faster. - - switch (waveform) { - default: - case 0x0: - return output____(); - case 0x1: - return output___T(); - case 0x2: - return output__S_(); - case 0x3: - return output__ST(); - case 0x4: - return output_P__(); - case 0x5: - return output_P_T(); - case 0x6: - return output_PS_(); - case 0x7: - return output_PST(); - case 0x8: - return outputN___(); - case 0x9: - return outputN__T(); - case 0xa: - return outputN_S_(); - case 0xb: - return outputN_ST(); - case 0xc: - return outputNP__(); - case 0xd: - return outputNP_T(); - case 0xe: - return outputNPS_(); - case 0xf: - return outputNPST(); - } -} - -#endif // RESID_INLINING || defined(__WAVE_CC__) - -#endif // not __WAVE_H__ diff --git a/plugins/sid/wave6581_PST.cc b/plugins/sid/wave6581_PST.cc deleted file mode 100644 index 49a4ea246d9..00000000000 --- a/plugins/sid/wave6581_PST.cc +++ /dev/null @@ -1,536 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#include "wave.h" - -reg8 WaveformGenerator::wave6581_PST[] = -{ -/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, -/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x768: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x770: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x778: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x798: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, -/* 0x7f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, -/* 0x7f8: */ 0x00, 0x00, 0x00, 0x78, 0x78, 0x7e, 0x7f, 0x7f, -/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, -/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, -/* 0xff0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, -/* 0xff8: */ 0x00, 0x00, 0x00, 0x78, 0x78, 0x7e, 0x7f, 0x7f, -}; diff --git a/plugins/sid/wave6581_PS_.cc b/plugins/sid/wave6581_PS_.cc deleted file mode 100644 index ffccd23e8b1..00000000000 --- a/plugins/sid/wave6581_PS_.cc +++ /dev/null @@ -1,536 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#include "wave.h" - -reg8 WaveformGenerator::wave6581_PS_[] = -{ -/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, -/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, -/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, -/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1f, -/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, -/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, -/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, -/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, -/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, -/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, -/* 0x3f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3f, -/* 0x3f8: */ 0x00, 0x30, 0x38, 0x3f, 0x3e, 0x3f, 0x3f, 0x3f, -/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, -/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, -/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, -/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, -/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, -/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, -/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x5f, -/* 0x5f8: */ 0x00, 0x40, 0x40, 0x5f, 0x5c, 0x5f, 0x5f, 0x5f, -/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, -/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6b, -/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x6d, -/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0x6e8: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x6e, -/* 0x6f0: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x6f, -/* 0x6f8: */ 0x00, 0x60, 0x60, 0x6f, 0x60, 0x6f, 0x6f, 0x6f, -/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0x738: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x60, 0x73, -/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0x758: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x75, -/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, -/* 0x768: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x76, -/* 0x770: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x77, -/* 0x778: */ 0x00, 0x70, 0x70, 0x77, 0x70, 0x77, 0x77, 0x77, -/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, -/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, -/* 0x798: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x79, -/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, -/* 0x7a8: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x70, 0x70, 0x7a, -/* 0x7b0: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7b, -/* 0x7b8: */ 0x40, 0x70, 0x70, 0x7b, 0x78, 0x7b, 0x7b, 0x7b, -/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, -/* 0x7c8: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7c, -/* 0x7d0: */ 0x00, 0x00, 0x00, 0x70, 0x40, 0x70, 0x70, 0x7d, -/* 0x7d8: */ 0x40, 0x70, 0x78, 0x7d, 0x78, 0x7d, 0x7d, 0x7d, -/* 0x7e0: */ 0x00, 0x40, 0x40, 0x78, 0x60, 0x78, 0x78, 0x7e, -/* 0x7e8: */ 0x60, 0x78, 0x78, 0x7e, 0x7c, 0x7e, 0x7e, 0x7e, -/* 0x7f0: */ 0x70, 0x7c, 0x7c, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, -/* 0x7f8: */ 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, -/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, -/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, -/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, -/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1f, -/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, -/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, -/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, -/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, -/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, -/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, -/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3f, -/* 0xbf8: */ 0x00, 0x30, 0x38, 0x3f, 0x3e, 0x3f, 0x3f, 0x3f, -/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, -/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, -/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, -/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, -/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, -/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, -/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x5f, -/* 0xdf8: */ 0x00, 0x40, 0x40, 0x5f, 0x5c, 0x5f, 0x5f, 0x5f, -/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, -/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6b, -/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6d, -/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0xee8: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x6e, -/* 0xef0: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x6f, -/* 0xef8: */ 0x00, 0x60, 0x60, 0x6f, 0x60, 0x6f, 0x6f, 0x6f, -/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0xf38: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x60, 0x73, -/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0xf58: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x75, -/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, -/* 0xf68: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x76, -/* 0xf70: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x77, -/* 0xf78: */ 0x00, 0x70, 0x70, 0x77, 0x70, 0x77, 0x77, 0x77, -/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, -/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, -/* 0xf98: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x79, -/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, -/* 0xfa8: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x70, 0x70, 0x7a, -/* 0xfb0: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7b, -/* 0xfb8: */ 0x40, 0x70, 0x70, 0x7b, 0x78, 0x7b, 0x7b, 0x7b, -/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, -/* 0xfc8: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7c, -/* 0xfd0: */ 0x00, 0x00, 0x00, 0x70, 0x40, 0x70, 0x70, 0x7d, -/* 0xfd8: */ 0x40, 0x70, 0x78, 0x7d, 0x78, 0x7d, 0x7d, 0x7d, -/* 0xfe0: */ 0x00, 0x40, 0x40, 0x78, 0x60, 0x78, 0x78, 0x7e, -/* 0xfe8: */ 0x60, 0x78, 0x78, 0x7e, 0x7c, 0x7e, 0x7e, 0x7e, -/* 0xff0: */ 0x70, 0x7c, 0x7c, 0x7f, 0x7c, 0x7f, 0x7f, 0x7f, -/* 0xff8: */ 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, -}; diff --git a/plugins/sid/wave6581_P_T.cc b/plugins/sid/wave6581_P_T.cc deleted file mode 100644 index a8109eeb115..00000000000 --- a/plugins/sid/wave6581_P_T.cc +++ /dev/null @@ -1,536 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#include "wave.h" - -reg8 WaveformGenerator::wave6581_P_T[] = -{ -/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x38, 0x3f, -/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2f8: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x5f, -/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0x378: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x6f, -/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, -/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, -/* 0x3b8: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x70, 0x77, -/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, -/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, -/* 0x3d8: */ 0x00, 0x00, 0x00, 0x70, 0x40, 0x70, 0x70, 0x7b, -/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x70, -/* 0x3e8: */ 0x00, 0x40, 0x40, 0x70, 0x60, 0x70, 0x78, 0x7d, -/* 0x3f0: */ 0x00, 0x40, 0x60, 0x78, 0x60, 0x78, 0x78, 0x7e, -/* 0x3f8: */ 0x70, 0x7c, 0x7c, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, -/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x4f8: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x9f, -/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x578: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0xa0, 0xa0, 0xaf, -/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, -/* 0x5b0: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xa0, -/* 0x5b8: */ 0x00, 0x80, 0x80, 0xa0, 0x80, 0xa0, 0xb0, 0xb7, -/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x5c8: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xa0, -/* 0x5d0: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xa0, -/* 0x5d8: */ 0x00, 0x80, 0x80, 0xa0, 0x80, 0xb0, 0xb0, 0xbb, -/* 0x5e0: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0xb0, -/* 0x5e8: */ 0x80, 0x80, 0x80, 0xb0, 0x80, 0xb0, 0xb8, 0xbd, -/* 0x5f0: */ 0x80, 0x80, 0x80, 0xb8, 0xa0, 0xb8, 0xb8, 0xbe, -/* 0x5f8: */ 0xa0, 0xb8, 0xbc, 0xbf, 0xbe, 0xbf, 0xbf, 0xbf, -/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, -/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, -/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x668: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, -/* 0x670: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, -/* 0x678: */ 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xcf, -/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x698: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, -/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x6a8: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, -/* 0x6b0: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0xc0, 0xc0, -/* 0x6b8: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, 0xd7, -/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x6c8: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0xc0, 0xc0, -/* 0x6d0: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xc0, -/* 0x6d8: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, 0xd0, 0xdb, -/* 0x6e0: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xd0, -/* 0x6e8: */ 0x80, 0xc0, 0xc0, 0xd0, 0xc0, 0xd0, 0xd8, 0xdd, -/* 0x6f0: */ 0xc0, 0xc0, 0xc0, 0xd0, 0xc0, 0xd8, 0xd8, 0xde, -/* 0x6f8: */ 0xc0, 0xd8, 0xdc, 0xdf, 0xdc, 0xdf, 0xdf, 0xdf, -/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x718: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xe0, -/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x728: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0, -/* 0x730: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0, -/* 0x738: */ 0x80, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe7, -/* 0x740: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, -/* 0x748: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0, -/* 0x750: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0, -/* 0x758: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xeb, -/* 0x760: */ 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, -/* 0x768: */ 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xed, -/* 0x770: */ 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe8, 0xe8, 0xee, -/* 0x778: */ 0xe0, 0xe8, 0xec, 0xef, 0xec, 0xef, 0xef, 0xef, -/* 0x780: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0xc0, -/* 0x788: */ 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xf0, -/* 0x790: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xf0, -/* 0x798: */ 0xc0, 0xe0, 0xe0, 0xf0, 0xe0, 0xf0, 0xf0, 0xf3, -/* 0x7a0: */ 0x80, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xf0, -/* 0x7a8: */ 0xc0, 0xe0, 0xe0, 0xf0, 0xe0, 0xf0, 0xf0, 0xf5, -/* 0x7b0: */ 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf6, -/* 0x7b8: */ 0xf0, 0xf0, 0xf4, 0xf7, 0xf4, 0xf7, 0xf7, 0xf7, -/* 0x7c0: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, -/* 0x7c8: */ 0xe0, 0xe0, 0xe0, 0xf8, 0xf0, 0xf8, 0xf8, 0xf9, -/* 0x7d0: */ 0xe0, 0xf0, 0xf0, 0xf8, 0xf0, 0xf8, 0xf8, 0xfa, -/* 0x7d8: */ 0xf0, 0xf8, 0xf8, 0xfb, 0xf8, 0xfb, 0xfb, 0xfb, -/* 0x7e0: */ 0xe0, 0xf0, 0xf0, 0xf8, 0xf0, 0xf8, 0xfc, 0xfc, -/* 0x7e8: */ 0xf8, 0xfc, 0xfc, 0xfd, 0xfc, 0xfd, 0xfd, 0xfd, -/* 0x7f0: */ 0xf8, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, -/* 0x7f8: */ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -/* 0x800: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, -/* 0x808: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xf8, -/* 0x810: */ 0xfd, 0xfd, 0xfd, 0xfc, 0xfd, 0xfc, 0xfc, 0xf8, -/* 0x818: */ 0xfc, 0xfc, 0xfc, 0xf0, 0xf8, 0xf0, 0xf0, 0xe0, -/* 0x820: */ 0xfb, 0xfb, 0xfb, 0xf8, 0xfb, 0xf8, 0xf8, 0xf0, -/* 0x828: */ 0xfa, 0xf8, 0xf8, 0xf0, 0xf8, 0xf0, 0xf0, 0xe0, -/* 0x830: */ 0xf9, 0xf8, 0xf8, 0xf0, 0xf8, 0xf0, 0xe0, 0xe0, -/* 0x838: */ 0xf0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, -/* 0x840: */ 0xf7, 0xf7, 0xf7, 0xf4, 0xf7, 0xf4, 0xf0, 0xf0, -/* 0x848: */ 0xf6, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, 0xe0, -/* 0x850: */ 0xf5, 0xf0, 0xf0, 0xe0, 0xf0, 0xe0, 0xe0, 0xc0, -/* 0x858: */ 0xf0, 0xe0, 0xe0, 0xc0, 0xe0, 0xc0, 0xc0, 0x80, -/* 0x860: */ 0xf3, 0xf0, 0xf0, 0xe0, 0xf0, 0xe0, 0xe0, 0xc0, -/* 0x868: */ 0xf0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, -/* 0x870: */ 0xf0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, -/* 0x878: */ 0xc0, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, -/* 0x880: */ 0xef, 0xef, 0xef, 0xec, 0xef, 0xec, 0xe8, 0xe0, -/* 0x888: */ 0xee, 0xe8, 0xe8, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, -/* 0x890: */ 0xed, 0xe8, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, -/* 0x898: */ 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, -/* 0x8a0: */ 0xeb, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, -/* 0x8a8: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, -/* 0x8b0: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, -/* 0x8b8: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, -/* 0x8c0: */ 0xe7, 0xe0, 0xe0, 0xc0, 0xe0, 0xc0, 0xc0, 0x80, -/* 0x8c8: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, -/* 0x8d0: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, -/* 0x8d8: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8e0: */ 0xe0, 0xc0, 0xc0, 0x80, 0x80, 0x00, 0x00, 0x00, -/* 0x8e8: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8f0: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x900: */ 0xdf, 0xdf, 0xdf, 0xdc, 0xdf, 0xdc, 0xd8, 0xc0, -/* 0x908: */ 0xde, 0xd8, 0xd8, 0xc0, 0xd8, 0xc0, 0xc0, 0xc0, -/* 0x910: */ 0xdd, 0xd8, 0xd0, 0xc0, 0xd0, 0xc0, 0xc0, 0x80, -/* 0x918: */ 0xd0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, -/* 0x920: */ 0xdb, 0xd0, 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, -/* 0x928: */ 0xc0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, -/* 0x930: */ 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, -/* 0x938: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x940: */ 0xd7, 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, -/* 0x948: */ 0xc0, 0xc0, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, -/* 0x950: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, -/* 0x958: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x960: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, -/* 0x968: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x970: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x980: */ 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x00, -/* 0x988: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, -/* 0x990: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, -/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9a0: */ 0xc0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9c0: */ 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa00: */ 0xbf, 0xbf, 0xbf, 0xbe, 0xbf, 0xbc, 0xbc, 0xa0, -/* 0xa08: */ 0xbe, 0xbc, 0xb8, 0xa0, 0xb8, 0xa0, 0x80, 0x80, -/* 0xa10: */ 0xbd, 0xb8, 0xb0, 0x80, 0xb0, 0x80, 0x80, 0x80, -/* 0xa18: */ 0xb0, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, -/* 0xa20: */ 0xbb, 0xb0, 0xb0, 0x80, 0xa0, 0x80, 0x80, 0x00, -/* 0xa28: */ 0xa0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, -/* 0xa30: */ 0xa0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, -/* 0xa38: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa40: */ 0xb7, 0xb0, 0xa0, 0x80, 0xa0, 0x80, 0x80, 0x00, -/* 0xa48: */ 0xa0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, -/* 0xa50: */ 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa60: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa80: */ 0xaf, 0xa0, 0xa0, 0x80, 0x80, 0x80, 0x80, 0x00, -/* 0xa88: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa90: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaa0: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xac0: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb00: */ 0x9f, 0x90, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, -/* 0xb08: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb10: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb20: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb40: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb80: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc00: */ 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7c, 0x7c, 0x70, -/* 0xc08: */ 0x7e, 0x7c, 0x78, 0x60, 0x78, 0x60, 0x60, 0x00, -/* 0xc10: */ 0x7d, 0x78, 0x78, 0x60, 0x70, 0x40, 0x40, 0x00, -/* 0xc18: */ 0x70, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc20: */ 0x7b, 0x78, 0x70, 0x40, 0x70, 0x40, 0x00, 0x00, -/* 0xc28: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc30: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc40: */ 0x77, 0x70, 0x70, 0x00, 0x60, 0x00, 0x00, 0x00, -/* 0xc48: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc50: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc60: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc80: */ 0x6f, 0x60, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, -/* 0xc88: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc90: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd00: */ 0x5f, 0x58, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, -/* 0xd08: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe00: */ 0x3f, 0x3c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xff0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xff8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; diff --git a/plugins/sid/wave6581__ST.cc b/plugins/sid/wave6581__ST.cc deleted file mode 100644 index add4d387ad4..00000000000 --- a/plugins/sid/wave6581__ST.cc +++ /dev/null @@ -1,536 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#include "wave.h" - -reg8 WaveformGenerator::wave6581__ST[] = -{ -/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, -/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, -/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, -/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3f0: */ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, -/* 0x3f8: */ 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x3f, 0x3f, -/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, -/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x1f, -/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, -/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x768: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x770: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x778: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x798: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7e0: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, -/* 0x7e8: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, -/* 0x7f0: */ 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, -/* 0x7f8: */ 0x3e, 0x3e, 0x3f, 0x3f, 0x7f, 0x7f, 0x7f, 0x7f, -/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, -/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, -/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, -/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbf0: */ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, -/* 0xbf8: */ 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x3f, 0x3f, -/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, -/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdf8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x1f, -/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, -/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfe0: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, -/* 0xfe8: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, -/* 0xff0: */ 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, -/* 0xff8: */ 0x3e, 0x3e, 0x3f, 0x3f, 0x7f, 0x7f, 0x7f, 0x7f, -}; diff --git a/plugins/sid/wave8580_PST.cc b/plugins/sid/wave8580_PST.cc deleted file mode 100644 index a3958c1929f..00000000000 --- a/plugins/sid/wave8580_PST.cc +++ /dev/null @@ -1,536 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#include "wave.h" - -reg8 WaveformGenerator::wave8580_PST[] = -{ -/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, -/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x768: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x770: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x778: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x798: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x70, -/* 0x7f0: */ 0x60, 0x20, 0x70, 0x70, 0x70, 0x70, 0x70, 0x78, -/* 0x7f8: */ 0x78, 0x78, 0x7c, 0x7c, 0x7e, 0x7e, 0x7f, 0x7f, -/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1e, 0x3f, -/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0xdf8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x8c, 0x9f, -/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, -/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, -/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, -/* 0xe68: */ 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xe70: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xe78: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xe80: */ 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80, -/* 0xe88: */ 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xe90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xe98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xea0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xea8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xeb0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xeb8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xec0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xec8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xed0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xed8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xee0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xee8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0, -/* 0xef0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xef8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xcf, -/* 0xf00: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xf08: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xf10: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xf18: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xf20: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xf28: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xf30: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xf38: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xf40: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xf48: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xf50: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xf58: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xf60: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xf68: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, -/* 0xf70: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xf78: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe3, -/* 0xf80: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xf88: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xf90: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xf98: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xfa0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xfa8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xfb0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, -/* 0xfb8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0xfc0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0xfc8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0xfd0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0xfd8: */ 0xf0, 0xf0, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, -/* 0xfe0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, -/* 0xfe8: */ 0xf8, 0xf8, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, -/* 0xff0: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfe, 0xfe, 0xfe, -/* 0xff8: */ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -}; diff --git a/plugins/sid/wave8580_PS_.cc b/plugins/sid/wave8580_PS_.cc deleted file mode 100644 index 795044d6064..00000000000 --- a/plugins/sid/wave8580_PS_.cc +++ /dev/null @@ -1,536 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#include "wave.h" - -reg8 WaveformGenerator::wave8580_PS_[] = -{ -/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, -/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, -/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, -/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, -/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x1f, -/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, -/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, -/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0f, -/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, -/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, -/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, -/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, -/* 0x3f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, -/* 0x3f8: */ 0x00, 0x0c, 0x1c, 0x3f, 0x1e, 0x3f, 0x3f, 0x3f, -/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, -/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, -/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, -/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, -/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, -/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, -/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, -/* 0x5f8: */ 0x00, 0x00, 0x00, 0x5f, 0x0c, 0x5f, 0x5f, 0x5f, -/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, -/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, -/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, -/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, -/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, -/* 0x6f8: */ 0x00, 0x40, 0x40, 0x6f, 0x40, 0x6f, 0x6f, 0x6f, -/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, -/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x61, -/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0x768: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x70, -/* 0x770: */ 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x70, -/* 0x778: */ 0x40, 0x60, 0x60, 0x77, 0x60, 0x77, 0x77, 0x77, -/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, -/* 0x798: */ 0x00, 0x40, 0x40, 0x60, 0x40, 0x60, 0x60, 0x79, -/* 0x7a0: */ 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x60, -/* 0x7a8: */ 0x40, 0x40, 0x40, 0x60, 0x60, 0x60, 0x60, 0x78, -/* 0x7b0: */ 0x40, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, -/* 0x7b8: */ 0x60, 0x70, 0x70, 0x78, 0x70, 0x79, 0x7b, 0x7b, -/* 0x7c0: */ 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x70, -/* 0x7c8: */ 0x60, 0x60, 0x60, 0x70, 0x60, 0x70, 0x70, 0x7c, -/* 0x7d0: */ 0x60, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x7c, -/* 0x7d8: */ 0x70, 0x78, 0x78, 0x7c, 0x78, 0x7c, 0x7c, 0x7d, -/* 0x7e0: */ 0x70, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x7c, -/* 0x7e8: */ 0x78, 0x7c, 0x7c, 0x7e, 0x7c, 0x7e, 0x7e, 0x7e, -/* 0x7f0: */ 0x7c, 0x7c, 0x7c, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, -/* 0x7f8: */ 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0xff, -/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, -/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, -/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, -/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, -/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x8d, -/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x9e8: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x8e, -/* 0x9f0: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x8f, -/* 0x9f8: */ 0x80, 0x80, 0x80, 0x9f, 0x80, 0x9f, 0x9f, 0x9f, -/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0xa78: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x87, -/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0xab8: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x83, -/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, -/* 0xad8: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, -/* 0xae0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xae8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x84, -/* 0xaf0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x87, -/* 0xaf8: */ 0x80, 0x80, 0x80, 0x87, 0x80, 0x8f, 0xaf, 0xaf, -/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0xb18: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xb20: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x80, -/* 0xb28: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xb30: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xb38: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x83, -/* 0xb40: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xb48: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xb50: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xb58: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, -/* 0xb60: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xb68: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, -/* 0xb70: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, -/* 0xb78: */ 0x80, 0x80, 0x80, 0xa0, 0x80, 0xa3, 0xb7, 0xb7, -/* 0xb80: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xb88: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xb90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xb98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xb1, -/* 0xba0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xba8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xb0, -/* 0xbb0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xb0, -/* 0xbb8: */ 0x80, 0xa0, 0xa0, 0xb0, 0xa0, 0xb8, 0xb9, 0xbb, -/* 0xbc0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, -/* 0xbc8: */ 0x80, 0x80, 0x80, 0xa0, 0x80, 0xa0, 0xa0, 0xb8, -/* 0xbd0: */ 0x80, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xb8, -/* 0xbd8: */ 0xa0, 0xb0, 0xb0, 0xb8, 0xb0, 0xbc, 0xbc, 0xbd, -/* 0xbe0: */ 0xa0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb8, 0xb8, 0xbc, -/* 0xbe8: */ 0xb0, 0xb8, 0xb8, 0xbc, 0xb8, 0xbc, 0xbe, 0xbe, -/* 0xbf0: */ 0xb8, 0xbc, 0xbc, 0xbe, 0xbc, 0xbe, 0xbe, 0xbf, -/* 0xbf8: */ 0xbe, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, -/* 0xc00: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, -/* 0xc08: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, -/* 0xc10: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xc18: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xc20: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xc28: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xc30: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xc38: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, -/* 0xc40: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xc48: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xc50: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xc58: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xc60: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xc68: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xc70: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xc78: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc7, -/* 0xc80: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xc88: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xc90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xc98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xca0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xca8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xcb0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xcb8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc3, -/* 0xcc0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xcc8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, -/* 0xcd0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, -/* 0xcd8: */ 0x80, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xc1, -/* 0xce0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, -/* 0xce8: */ 0x80, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xcf0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc7, -/* 0xcf8: */ 0xc0, 0xc0, 0xc0, 0xc7, 0xc0, 0xcf, 0xcf, 0xcf, -/* 0xd00: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xd08: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xd10: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xd18: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, -/* 0xd20: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xd28: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, -/* 0xd30: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0, -/* 0xd38: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc3, -/* 0xd40: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, -/* 0xd48: */ 0x80, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xc0, -/* 0xd50: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xd58: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, -/* 0xd60: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xd68: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xd70: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xd78: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, 0xc7, 0xd7, -/* 0xd80: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xd88: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xd90: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xd98: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xda0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xda8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, -/* 0xdb0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, -/* 0xdb8: */ 0xc0, 0xc0, 0xc0, 0xd0, 0xc0, 0xd0, 0xd8, 0xdb, -/* 0xdc0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xdc8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd8, -/* 0xdd0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd8, -/* 0xdd8: */ 0xc0, 0xc0, 0xc0, 0xd8, 0xd0, 0xd8, 0xd8, 0xdd, -/* 0xde0: */ 0xc0, 0xc0, 0xc0, 0xd0, 0xc0, 0xd0, 0xd0, 0xdc, -/* 0xde8: */ 0xd0, 0xd8, 0xd8, 0xdc, 0xd8, 0xdc, 0xdc, 0xde, -/* 0xdf0: */ 0xd8, 0xdc, 0xdc, 0xde, 0xdc, 0xde, 0xde, 0xdf, -/* 0xdf8: */ 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, -/* 0xe00: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xe08: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xe10: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xe18: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xe20: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xe28: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xe30: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xe38: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe3, -/* 0xe40: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xe48: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xe50: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, -/* 0xe58: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe1, -/* 0xe60: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, -/* 0xe68: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xe70: */ 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xe78: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe3, 0xe7, -/* 0xe80: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, -/* 0xe88: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe0, -/* 0xe90: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe0, -/* 0xe98: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xea0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xea8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xeb0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xeb8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xeb, -/* 0xec0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xec8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xed0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xed8: */ 0xe0, 0xe0, 0xe0, 0xe8, 0xe0, 0xe8, 0xe8, 0xed, -/* 0xee0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xec, -/* 0xee8: */ 0xe0, 0xe0, 0xe0, 0xec, 0xe8, 0xec, 0xec, 0xee, -/* 0xef0: */ 0xe8, 0xe8, 0xe8, 0xec, 0xec, 0xee, 0xee, 0xef, -/* 0xef8: */ 0xec, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, -/* 0xf00: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xf08: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xf10: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xf18: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, -/* 0xf20: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, -/* 0xf28: */ 0xe0, 0xe0, 0xe0, 0xf0, 0xe0, 0xf0, 0xf0, 0xf0, -/* 0xf30: */ 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0xf38: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf3, -/* 0xf40: */ 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0xf48: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0xf50: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0xf58: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf5, -/* 0xf60: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0xf68: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf4, 0xf4, 0xf6, -/* 0xf70: */ 0xf0, 0xf0, 0xf0, 0xf4, 0xf0, 0xf4, 0xf6, 0xf7, -/* 0xf78: */ 0xf4, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, -/* 0xf80: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf8, -/* 0xf88: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf8, 0xf8, 0xf8, -/* 0xf90: */ 0xf0, 0xf0, 0xf0, 0xf8, 0xf0, 0xf8, 0xf8, 0xf8, -/* 0xf98: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, -/* 0xfa0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, -/* 0xfa8: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xfa, -/* 0xfb0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xfb, -/* 0xfb8: */ 0xf8, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, -/* 0xfc0: */ 0xf8, 0xf8, 0xf8, 0xfc, 0xf8, 0xfc, 0xfc, 0xfc, -/* 0xfc8: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, -/* 0xfd0: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, -/* 0xfd8: */ 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, -/* 0xfe0: */ 0xfc, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, -/* 0xfe8: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, -/* 0xff0: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -/* 0xff8: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -}; diff --git a/plugins/sid/wave8580_P_T.cc b/plugins/sid/wave8580_P_T.cc deleted file mode 100644 index a2fff3a231d..00000000000 --- a/plugins/sid/wave8580_P_T.cc +++ /dev/null @@ -1,536 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#include "wave.h" - -reg8 WaveformGenerator::wave8580_P_T[] = -{ -/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, -/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1f8: */ 0x00, 0x00, 0x00, 0x1c, 0x00, 0x3c, 0x3f, 0x3f, -/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x5e, 0x5f, -/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0x378: */ 0x00, 0x00, 0x00, 0x40, 0x40, 0x60, 0x60, 0x6f, -/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, -/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, -/* 0x3b0: */ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x60, -/* 0x3b8: */ 0x40, 0x40, 0x60, 0x60, 0x60, 0x60, 0x70, 0x77, -/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, -/* 0x3c8: */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x60, 0x60, 0x60, -/* 0x3d0: */ 0x40, 0x40, 0x40, 0x60, 0x60, 0x60, 0x60, 0x70, -/* 0x3d8: */ 0x60, 0x60, 0x60, 0x70, 0x70, 0x70, 0x78, 0x7b, -/* 0x3e0: */ 0x60, 0x60, 0x60, 0x70, 0x60, 0x70, 0x70, 0x70, -/* 0x3e8: */ 0x70, 0x70, 0x70, 0x78, 0x78, 0x78, 0x78, 0x7c, -/* 0x3f0: */ 0x78, 0x78, 0x78, 0x7c, 0x78, 0x7c, 0x7c, 0x7e, -/* 0x3f8: */ 0x7c, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, -/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, -/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x4d8: */ 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x4e0: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x4e8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x4f0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x4f8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x8e, 0x9f, -/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x528: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x80, -/* 0x530: */ 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x538: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x540: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x80, -/* 0x548: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x550: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x558: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x560: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x568: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x570: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x578: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xaf, -/* 0x580: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x588: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x590: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x598: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x5a0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x5a8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x5b0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x5b8: */ 0x80, 0x80, 0x80, 0xa0, 0xa0, 0xa0, 0xa0, 0xb7, -/* 0x5c0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x5c8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, -/* 0x5d0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, 0xa0, -/* 0x5d8: */ 0xa0, 0xa0, 0xa0, 0xb0, 0xa0, 0xb0, 0xb0, 0xbb, -/* 0x5e0: */ 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xb0, 0xb0, -/* 0x5e8: */ 0xa0, 0xb0, 0xb0, 0xb8, 0xb0, 0xb8, 0xb8, 0xbc, -/* 0x5f0: */ 0xb0, 0xb8, 0xb8, 0xb8, 0xb8, 0xbc, 0xbc, 0xbe, -/* 0x5f8: */ 0xbc, 0xbc, 0xbe, 0xbf, 0xbe, 0xbf, 0xbf, 0xbf, -/* 0x600: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x608: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x610: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x618: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x620: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x628: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x630: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x638: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0, -/* 0x640: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x648: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x650: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, -/* 0x658: */ 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x660: */ 0x80, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xc0, -/* 0x668: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x670: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x678: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xcf, -/* 0x680: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0, -/* 0x688: */ 0xc0, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x690: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x698: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x6a0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x6a8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x6b0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x6b8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd7, -/* 0x6c0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x6c8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x6d0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x6d8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, 0xd0, 0xd9, -/* 0x6e0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, -/* 0x6e8: */ 0xc0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd8, 0xd8, 0xdc, -/* 0x6f0: */ 0xd0, 0xd0, 0xd8, 0xd8, 0xd8, 0xdc, 0xdc, 0xde, -/* 0x6f8: */ 0xdc, 0xdc, 0xde, 0xdf, 0xde, 0xdf, 0xdf, 0xdf, -/* 0x700: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x708: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x710: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x718: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe0, -/* 0x720: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, -/* 0x728: */ 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0x730: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0x738: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe7, -/* 0x740: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0x748: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0x750: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0x758: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe8, -/* 0x760: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0x768: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe8, 0xec, -/* 0x770: */ 0xe0, 0xe0, 0xe0, 0xe8, 0xe8, 0xe8, 0xec, 0xee, -/* 0x778: */ 0xec, 0xec, 0xec, 0xee, 0xee, 0xef, 0xef, 0xef, -/* 0x780: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0x788: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, -/* 0x790: */ 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0x798: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0x7a0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0x7a8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf4, -/* 0x7b0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf4, -/* 0x7b8: */ 0xf0, 0xf4, 0xf4, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, -/* 0x7c0: */ 0xf0, 0xf0, 0xf0, 0xf8, 0xf0, 0xf8, 0xf8, 0xf8, -/* 0x7c8: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, -/* 0x7d0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, -/* 0x7d8: */ 0xf8, 0xf8, 0xf8, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, -/* 0x7e0: */ 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, -/* 0x7e8: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, -/* 0x7f0: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, -/* 0x7f8: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -/* 0x800: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -/* 0x808: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, -/* 0x810: */ 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, -/* 0x818: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, -/* 0x820: */ 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xf8, 0xf8, 0xf8, -/* 0x828: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, -/* 0x830: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, -/* 0x838: */ 0xf8, 0xf8, 0xf8, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0x840: */ 0xf7, 0xf7, 0xf7, 0xf6, 0xf6, 0xf4, 0xf4, 0xf0, -/* 0x848: */ 0xf4, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0x850: */ 0xf4, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0x858: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0x860: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0x868: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, -/* 0x870: */ 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0x878: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0x880: */ 0xef, 0xef, 0xef, 0xee, 0xee, 0xec, 0xec, 0xe8, -/* 0x888: */ 0xee, 0xec, 0xe8, 0xe8, 0xe8, 0xe0, 0xe0, 0xe0, -/* 0x890: */ 0xec, 0xe8, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0x898: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0x8a0: */ 0xe8, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0x8a8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0x8b0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0x8b8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0x8c0: */ 0xe7, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0x8c8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0x8d0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, -/* 0x8d8: */ 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x8e0: */ 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x8e8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x8f0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x8f8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x900: */ 0xdf, 0xdf, 0xdf, 0xde, 0xdf, 0xde, 0xdc, 0xdc, -/* 0x908: */ 0xde, 0xdc, 0xdc, 0xd8, 0xd8, 0xd8, 0xd0, 0xd0, -/* 0x910: */ 0xdc, 0xd8, 0xd8, 0xd0, 0xd0, 0xd0, 0xd0, 0xc0, -/* 0x918: */ 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x920: */ 0xd9, 0xd0, 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x928: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x930: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x938: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x940: */ 0xd7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x948: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x950: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x958: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x960: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x968: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x970: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, -/* 0x978: */ 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x980: */ 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x988: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x990: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0x998: */ 0xc0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x80, -/* 0x9a0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, -/* 0x9a8: */ 0xc0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x9b0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x9b8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x9c0: */ 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x9c8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x9d0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x9d8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x9e0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x9e8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x9f0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0x9f8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xa00: */ 0xbf, 0xbf, 0xbf, 0xbe, 0xbf, 0xbe, 0xbc, 0xbc, -/* 0xa08: */ 0xbe, 0xbc, 0xbc, 0xb8, 0xb8, 0xb8, 0xb8, 0xb0, -/* 0xa10: */ 0xbc, 0xb8, 0xb8, 0xb0, 0xb8, 0xb0, 0xb0, 0xb0, -/* 0xa18: */ 0xb0, 0xb0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, -/* 0xa20: */ 0xbb, 0xb0, 0xb0, 0xa0, 0xb0, 0xa0, 0xa0, 0xa0, -/* 0xa28: */ 0xa0, 0xa0, 0xa0, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xa30: */ 0xa0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xa38: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xa40: */ 0xb7, 0xb0, 0xa0, 0xa0, 0xa0, 0x80, 0x80, 0x80, -/* 0xa48: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xa50: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xa58: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xa60: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xa68: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xa70: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xa78: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xa80: */ 0xaf, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xa88: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xa90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xa98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xaa0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xaa8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xab0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xab8: */ 0x80, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, -/* 0xac0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xac8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, -/* 0xad0: */ 0x80, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, -/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xae0: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb00: */ 0x9f, 0x9e, 0x88, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xb08: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xb10: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xb18: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, -/* 0xb20: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, -/* 0xb28: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb30: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb40: */ 0x80, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, -/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb80: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc00: */ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7c, -/* 0xc08: */ 0x7e, 0x7c, 0x7c, 0x78, 0x7c, 0x78, 0x78, 0x78, -/* 0xc10: */ 0x7c, 0x78, 0x78, 0x78, 0x78, 0x70, 0x70, 0x70, -/* 0xc18: */ 0x78, 0x70, 0x70, 0x60, 0x70, 0x60, 0x60, 0x60, -/* 0xc20: */ 0x7b, 0x78, 0x70, 0x70, 0x70, 0x60, 0x60, 0x60, -/* 0xc28: */ 0x70, 0x60, 0x60, 0x60, 0x60, 0x40, 0x40, 0x40, -/* 0xc30: */ 0x60, 0x60, 0x60, 0x40, 0x40, 0x40, 0x40, 0x40, -/* 0xc38: */ 0x40, 0x40, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, -/* 0xc40: */ 0x77, 0x70, 0x60, 0x60, 0x60, 0x60, 0x40, 0x40, -/* 0xc48: */ 0x60, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, -/* 0xc50: */ 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc60: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc80: */ 0x6f, 0x64, 0x60, 0x40, 0x40, 0x00, 0x00, 0x00, -/* 0xc88: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd00: */ 0x5f, 0x5e, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe00: */ 0x3f, 0x3f, 0x3e, 0x00, 0x1c, 0x00, 0x00, 0x00, -/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf00: */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xfe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xff0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xff8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; diff --git a/plugins/sid/wave8580__ST.cc b/plugins/sid/wave8580__ST.cc deleted file mode 100644 index e50a21d8173..00000000000 --- a/plugins/sid/wave8580__ST.cc +++ /dev/null @@ -1,536 +0,0 @@ -// --------------------------------------------------------------------------- -// This file is part of reSID, a MOS6581 SID emulator engine. -// Copyright (C) 2004 Dag Lem -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// --------------------------------------------------------------------------- - -#include "wave.h" - -reg8 WaveformGenerator::wave8580__ST[] = -{ -/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, -/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x1f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, -/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, -/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x3f0: */ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, -/* 0x3f8: */ 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, -/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, -/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x5f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x1f, -/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x6f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, -/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x768: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x770: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x778: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x798: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x7e0: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, -/* 0x7e8: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, -/* 0x7f0: */ 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3e, -/* 0x7f8: */ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, -/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, -/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0x9f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, -/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, -/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xbf0: */ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, -/* 0xbf8: */ 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x3f, 0x3f, -/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, -/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, -/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xdf8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x1f, 0x1f, -/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x83, 0x83, -/* 0xe80: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xe88: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xe90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xe98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xea0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xea8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xeb0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xeb8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xec0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xec8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xed0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xed8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xee0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xee8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xef0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* 0xef8: */ 0x80, 0x80, 0x80, 0x80, 0x87, 0x87, 0x87, 0x8f, -/* 0xf00: */ 0xc0, 0xe0, 0xe0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, -/* 0xf08: */ 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xf10: */ 0xc0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xf18: */ 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, -/* 0xf20: */ 0xc0, 0xe0, 0xe0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, -/* 0xf28: */ 0xe0, 0xe0, 0xe0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, -/* 0xf30: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xf38: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xf40: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xf48: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xf50: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xf58: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xf60: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xf68: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xf70: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, -/* 0xf78: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe3, 0xe3, -/* 0xf80: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0xf88: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0xf90: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0xf98: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0xfa0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0xfa8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0xfb0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -/* 0xfb8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, -/* 0xfc0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, -/* 0xfc8: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, -/* 0xfd0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, -/* 0xfd8: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, -/* 0xfe0: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, -/* 0xfe8: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, -/* 0xff0: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, -/* 0xff8: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -}; diff --git a/plugins/stereo_enhancer/stereo_enhancer.cpp b/plugins/stereo_enhancer/stereo_enhancer.cpp index 2faa5846d2f..3f5a9a38c29 100644 --- a/plugins/stereo_enhancer/stereo_enhancer.cpp +++ b/plugins/stereo_enhancer/stereo_enhancer.cpp @@ -35,7 +35,7 @@ Plugin::Descriptor PLUGIN_EXPORT stereoenhancer_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "StereoEnhancer Effect", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "Plugin for enhancing stereo separation of a stereo input file" ), "Lou Herard ", 0x0100, diff --git a/plugins/stereo_matrix/CMakeLists.txt b/plugins/stereo_matrix/CMakeLists.txt index 088107f5c9c..edc8475f6c4 100644 --- a/plugins/stereo_matrix/CMakeLists.txt +++ b/plugins/stereo_matrix/CMakeLists.txt @@ -1,4 +1,4 @@ INCLUDE(BuildPlugin) -BUILD_PLUGIN(stereomatrix stereo_matrix.cpp stereomatrix_controls.cpp stereomatrix_control_dialog.cpp stereo_matrix.h stereomatrix_controls.h stereomatrix_control_dialog.h MOCFILES stereomatrix_controls.h stereomatrix_control_dialog.h EMBEDDED_RESOURCES artwork.png) +BUILD_PLUGIN(stereomatrix stereo_matrix.cpp stereomatrix_controls.cpp stereomatrix_control_dialog.cpp stereo_matrix.h stereomatrix_controls.h stereomatrix_control_dialog.h MOCFILES stereomatrix_controls.h stereomatrix_control_dialog.h EMBEDDED_RESOURCES artwork.png logo.png) diff --git a/plugins/stereo_matrix/stereo_matrix.cpp b/plugins/stereo_matrix/stereo_matrix.cpp index a03a615ba37..2ec9b49509e 100644 --- a/plugins/stereo_matrix/stereo_matrix.cpp +++ b/plugins/stereo_matrix/stereo_matrix.cpp @@ -35,7 +35,7 @@ Plugin::Descriptor PLUGIN_EXPORT stereomatrix_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Stereo Matrix", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "Plugin for freely manipulating stereo output" ), "Paul Giblock ", 0x0100, diff --git a/plugins/stk/mallets/mallets.cpp b/plugins/stk/mallets/mallets.cpp index f9e2e7ede56..6f968985ced 100644 --- a/plugins/stk/mallets/mallets.cpp +++ b/plugins/stk/mallets/mallets.cpp @@ -50,7 +50,7 @@ Plugin::Descriptor PLUGIN_EXPORT malletsstk_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Mallets", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "Tuneful things to bang on" ), "Danny McRae ", 0x0100, @@ -403,7 +403,7 @@ malletsInstrumentView::malletsInstrumentView( malletsInstrument * _instrument, changePreset(); // Show widget m_presetsCombo = new ComboBox( this, tr( "Instrument" ) ); - m_presetsCombo->setGeometry( 140, 50, 99, 22 ); + m_presetsCombo->setGeometry( 140, 50, 99, ComboBox::DEFAULT_HEIGHT ); m_presetsCombo->setFont( pointSize<8>( m_presetsCombo->font() ) ); connect( &_instrument->m_presetsModel, SIGNAL( dataChanged() ), diff --git a/plugins/triple_oscillator/TripleOscillator.cpp b/plugins/triple_oscillator/TripleOscillator.cpp index 2a1eccdd73c..8c05bb9956a 100644 --- a/plugins/triple_oscillator/TripleOscillator.cpp +++ b/plugins/triple_oscillator/TripleOscillator.cpp @@ -49,7 +49,7 @@ Plugin::Descriptor PLUGIN_EXPORT tripleoscillator_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "TripleOscillator", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "Three powerful oscillators you can modulate " "in several ways" ), "Tobias Doerffel ", @@ -98,28 +98,28 @@ OscillatorObject::OscillatorObject( Model * _parent, int _idx ) : { // Connect knobs with Oscillators' inputs connect( &m_volumeModel, SIGNAL( dataChanged() ), - this, SLOT( updateVolume() ) ); + this, SLOT( updateVolume() ), Qt::DirectConnection ); connect( &m_panModel, SIGNAL( dataChanged() ), - this, SLOT( updateVolume() ) ); + this, SLOT( updateVolume() ), Qt::DirectConnection ); updateVolume(); connect( &m_coarseModel, SIGNAL( dataChanged() ), - this, SLOT( updateDetuningLeft() ) ); + this, SLOT( updateDetuningLeft() ), Qt::DirectConnection ); connect( &m_coarseModel, SIGNAL( dataChanged() ), - this, SLOT( updateDetuningRight() ) ); + this, SLOT( updateDetuningRight() ), Qt::DirectConnection ); connect( &m_fineLeftModel, SIGNAL( dataChanged() ), - this, SLOT( updateDetuningLeft() ) ); + this, SLOT( updateDetuningLeft() ), Qt::DirectConnection ); connect( &m_fineRightModel, SIGNAL( dataChanged() ), - this, SLOT( updateDetuningRight() ) ); + this, SLOT( updateDetuningRight() ), Qt::DirectConnection ); updateDetuningLeft(); updateDetuningRight(); connect( &m_phaseOffsetModel, SIGNAL( dataChanged() ), - this, SLOT( updatePhaseOffsetLeft() ) ); + this, SLOT( updatePhaseOffsetLeft() ), Qt::DirectConnection ); connect( &m_phaseOffsetModel, SIGNAL( dataChanged() ), - this, SLOT( updatePhaseOffsetRight() ) ); + this, SLOT( updatePhaseOffsetRight() ), Qt::DirectConnection ); connect( &m_stereoPhaseDetuningModel, SIGNAL( dataChanged() ), - this, SLOT( updatePhaseOffsetLeft() ) ); + this, SLOT( updatePhaseOffsetLeft() ), Qt::DirectConnection ); updatePhaseOffsetLeft(); updatePhaseOffsetRight(); @@ -364,6 +364,7 @@ void TripleOscillator::playNote( NotePlayHandle * _n, osc_l->update( _working_buffer + offset, frames, 0 ); osc_r->update( _working_buffer + offset, frames, 1 ); + applyFadeIn(_working_buffer, _n); applyRelease( _working_buffer, _n ); instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n ); diff --git a/plugins/vestige/vestige.cpp b/plugins/vestige/vestige.cpp index c0d101784d3..77efcb8babd 100644 --- a/plugins/vestige/vestige.cpp +++ b/plugins/vestige/vestige.cpp @@ -38,22 +38,26 @@ #include #include +#include + #include "ConfigManager.h" #include "Engine.h" +#include "FileDialog.h" +#include "GuiApplication.h" #include "gui_templates.h" #include "InstrumentPlayHandle.h" #include "InstrumentTrack.h" #include "LocaleHelper.h" #include "MainWindow.h" #include "Mixer.h" -#include "GuiApplication.h" +#include "PathUtil.h" #include "PixmapButton.h" #include "SampleBuffer.h" #include "Song.h" #include "StringPairDrag.h" #include "TextFloat.h" #include "ToolTip.h" -#include "FileDialog.h" +#include "Clipboard.h" #include "embed.h" @@ -67,7 +71,7 @@ Plugin::Descriptor Q_DECL_EXPORT vestige_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "VeSTige", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "VST-host for using VST(i)-plugins within LMMS" ), "Tobias Doerffel ", 0x0100, @@ -267,7 +271,7 @@ void vestigeInstrument::reloadPlugin() void vestigeInstrument::saveSettings( QDomDocument & _doc, QDomElement & _this ) { - _this.setAttribute( "plugin", m_pluginDLL ); + _this.setAttribute( "plugin", PathUtil::toShortestRelative(m_pluginDLL) ); m_pluginMutex.lock(); if( m_plugin != NULL ) { @@ -334,14 +338,14 @@ void vestigeInstrument::loadFile( const QString & _file ) // if the same is loaded don't load again (for preview) if (instrumentTrack() != NULL && instrumentTrack()->isPreviewMode() && - m_pluginDLL == SampleBuffer::tryToMakeRelative( _file )) + m_pluginDLL == PathUtil::toShortestRelative( _file )) return; if ( m_plugin != NULL ) { closePlugin(); } - m_pluginDLL = SampleBuffer::tryToMakeRelative( _file ); + m_pluginDLL = PathUtil::toShortestRelative( _file ); TextFloat * tf = NULL; if( gui ) { @@ -406,7 +410,7 @@ void vestigeInstrument::play( sampleFrame * _buf ) -bool vestigeInstrument::handleMidiEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset ) +bool vestigeInstrument::handleMidiEvent( const MidiEvent& event, const TimePos& time, f_cnt_t offset ) { m_pluginMutex.lock(); if( m_plugin != NULL ) @@ -682,7 +686,7 @@ void VestigeInstrumentView::openPlugin() if( m_vi->m_pluginDLL != "" ) { - QString f = SampleBuffer::tryToMakeAbsolute( m_vi->m_pluginDLL ); + QString f = PathUtil::toAbsolute( m_vi->m_pluginDLL ); ofd.setDirectory( QFileInfo( f ).absolutePath() ); ofd.selectFile( QFileInfo( f ).fileName() ); } @@ -829,10 +833,13 @@ void VestigeInstrumentView::noteOffAll( void ) void VestigeInstrumentView::dragEnterEvent( QDragEnterEvent * _dee ) { - if( _dee->mimeData()->hasFormat( StringPairDrag::mimeType() ) ) + // For mimeType() and MimeType enum class + using namespace Clipboard; + + if( _dee->mimeData()->hasFormat( mimeType( MimeType::StringPair ) ) ) { QString txt = _dee->mimeData()->data( - StringPairDrag::mimeType() ); + mimeType( MimeType::StringPair ) ); if( txt.section( ':', 0, 0 ) == "vstplugin" ) { _dee->acceptProposedAction(); @@ -963,7 +970,7 @@ manageVestigeInstrumentView::manageVestigeInstrumentView( Instrument * _instrume const QMap & dump = m_vi->m_plugin->parameterDump(); m_vi->paramCount = dump.size(); - vstKnobs = new Knob *[ m_vi->paramCount ]; + vstKnobs = new CustomTextKnob *[ m_vi->paramCount ]; bool hasKnobModel = true; if (m_vi->knobFModel == NULL) { @@ -979,15 +986,15 @@ manageVestigeInstrumentView::manageVestigeInstrumentView( Instrument * _instrume sprintf( paramStr, "param%d", i); s_dumpValues = dump[ paramStr ].split( ":" ); - vstKnobs[ i ] = new Knob( knobBright_26, this, s_dumpValues.at( 1 ) ); - vstKnobs[ i ]->setHintText( s_dumpValues.at( 1 ) + ":", "" ); + vstKnobs[ i ] = new CustomTextKnob( knobBright_26, this, s_dumpValues.at( 1 ) ); + vstKnobs[ i ]->setDescription( s_dumpValues.at( 1 ) + ":" ); vstKnobs[ i ]->setLabel( s_dumpValues.at( 1 ).left( 15 ) ); if( !hasKnobModel ) { sprintf( paramStr, "%d", i); m_vi->knobFModel[ i ] = new FloatModel( LocaleHelper::toFloat(s_dumpValues.at(2)), - 0.0f, 1.0f, 0.01f, castModel(), tr( paramStr ) ); + 0.0f, 1.0f, 0.01f, castModel(), paramStr ); } FloatModel * model = m_vi->knobFModel[i]; @@ -995,6 +1002,7 @@ manageVestigeInstrumentView::manageVestigeInstrumentView( Instrument * _instrume [this, model]() { setParameter( model ); }, Qt::DirectConnection); vstKnobs[i] ->setModel( model ); } + syncParameterText(); int i = 0; for( int lrow = 1; lrow < ( int( m_vi->paramCount / 10 ) + 1 ) + 1; lrow++ ) @@ -1055,6 +1063,7 @@ void manageVestigeInstrumentView::syncPlugin( void ) m_vi->knobFModel[ i ]->setInitValue( f_value ); } } + syncParameterText(); } @@ -1130,6 +1139,38 @@ void manageVestigeInstrumentView::setParameter( Model * action ) if ( m_vi->m_plugin != NULL ) { m_vi->m_plugin->setParam( knobUNID, m_vi->knobFModel[knobUNID]->value() ); + syncParameterText(); + } +} + +void manageVestigeInstrumentView::syncParameterText() +{ + m_vi->m_plugin->loadParameterLabels(); + m_vi->m_plugin->loadParameterDisplays(); + + QString paramLabelStr = m_vi->m_plugin->allParameterLabels(); + QString paramDisplayStr = m_vi->m_plugin->allParameterDisplays(); + + QStringList paramLabelList; + QStringList paramDisplayList; + + for( int i = 0; i < paramLabelStr.size(); ) + { + const int length = paramLabelStr[i].digitValue(); + paramLabelList.append(paramLabelStr.mid(i + 1, length)); + i += length + 1; + } + + for( int i = 0; i < paramDisplayStr.size(); ) + { + const int length = paramDisplayStr[i].digitValue(); + paramDisplayList.append(paramDisplayStr.mid(i + 1, length)); + i += length + 1; + } + + for( int i = 0; i < paramLabelList.size(); ++i ) + { + vstKnobs[i]->setValueText(paramDisplayList[i] + ' ' + paramLabelList[i]); } } @@ -1137,10 +1178,13 @@ void manageVestigeInstrumentView::setParameter( Model * action ) void manageVestigeInstrumentView::dragEnterEvent( QDragEnterEvent * _dee ) { - if( _dee->mimeData()->hasFormat( StringPairDrag::mimeType() ) ) + // For mimeType() and MimeType enum class + using namespace Clipboard; + + if( _dee->mimeData()->hasFormat( mimeType( MimeType::StringPair ) ) ) { QString txt = _dee->mimeData()->data( - StringPairDrag::mimeType() ); + mimeType( MimeType::StringPair ) ); if( txt.section( ':', 0, 0 ) == "vstplugin" ) { _dee->acceptProposedAction(); @@ -1195,7 +1239,3 @@ Q_DECL_EXPORT Plugin * lmms_plugin_main( Model *m, void * ) } - - - - diff --git a/plugins/vestige/vestige.h b/plugins/vestige/vestige.h index 7090fee1e29..48c89f14d4c 100644 --- a/plugins/vestige/vestige.h +++ b/plugins/vestige/vestige.h @@ -34,7 +34,7 @@ #include "Instrument.h" #include "InstrumentView.h" #include "Note.h" -#include "Knob.h" +#include "CustomTextKnob.h" #include "SubWindow.h" #include "AutomatableModel.h" @@ -67,7 +67,7 @@ class vestigeInstrument : public Instrument return IsSingleStreamed | IsMidiBased; } - virtual bool handleMidiEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset = 0 ); + virtual bool handleMidiEvent( const MidiEvent& event, const TimePos& time, f_cnt_t offset = 0 ); virtual PluginView * instantiateView( QWidget * _parent ); @@ -109,6 +109,7 @@ protected slots: void syncPlugin( void ); void displayAutomatedOnly( void ); void setParameter( Model * action ); + void syncParameterText(); void closeWindow(); @@ -128,7 +129,7 @@ protected slots: QPushButton * m_syncButton; QPushButton * m_displayAutomatedOnly; QPushButton * m_closeButton; - Knob ** vstKnobs; + CustomTextKnob ** vstKnobs; } ; diff --git a/plugins/vibed/vibed.cpp b/plugins/vibed/vibed.cpp index c663660826e..6610bab0e43 100644 --- a/plugins/vibed/vibed.cpp +++ b/plugins/vibed/vibed.cpp @@ -48,7 +48,7 @@ Plugin::Descriptor PLUGIN_EXPORT vibedstrings_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Vibed", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "Vibrating string modeler" ), "Danny McRae ", 0x0100, diff --git a/plugins/vst_base/RemoteVstPlugin.cpp b/plugins/vst_base/RemoteVstPlugin.cpp index a103c065282..942c9e960c2 100644 --- a/plugins/vst_base/RemoteVstPlugin.cpp +++ b/plugins/vst_base/RemoteVstPlugin.cpp @@ -70,6 +70,8 @@ #include #include #include +#include +#include #include @@ -223,6 +225,10 @@ class RemoteVstPlugin : public RemotePluginClient // determine name of current program const char * programName(); + void getParameterDisplays(); + + void getParameterLabels(); + // send name of current program back to host void sendCurrentProgramName(); @@ -660,6 +666,14 @@ bool RemoteVstPlugin::processMessage( const message & _m ) //sendMessage( IdVstSetParameter ); break; + case IdVstParameterDisplays: + getParameterDisplays(); + break; + + case IdVstParameterLabels: + getParameterLabels(); + break; + case IdVstIdleUpdate: { @@ -1068,6 +1082,49 @@ const char * RemoteVstPlugin::programName() +// join the ParameterDisplays (stringified values without units) and send them to host +void RemoteVstPlugin::getParameterDisplays() +{ + std::string paramDisplays; + static char buf[9]; // buffer for getting string + for (int i=0; i< m_plugin->numParams; ++i) + { + memset( buf, 0, sizeof( buf ) ); // fill with '\0' because got string may not to be ended with '\0' + pluginDispatch( effGetParamDisplay, i, 0, buf ); + buf[8] = 0; + + // each field shaped like: [length:number][content:string] + paramDisplays += '0' + strlen(buf); // add length descriptor (length is up to 8) + paramDisplays += buf; + } + + sendMessage( message( IdVstParameterDisplays ).addString( paramDisplays.c_str() ) ); +} + + + +// join the ParameterLabels (units) and send them to host +void RemoteVstPlugin::getParameterLabels() +{ + std::string paramLabels; + static char buf[9]; // buffer for getting string + for (int i=0; i< m_plugin->numParams; ++i) + { + memset( buf, 0, sizeof( buf ) ); // fill with '\0' because got string may not to be ended with '\0' + pluginDispatch( effGetParamLabel, i, 0, buf ); + buf[8] = 0; + + // each field shaped like: [length:number][content:string] + paramLabels += '0' + strlen(buf); // add length descriptor (length is up to 8) + paramLabels += buf; + } + + sendMessage( message( IdVstParameterLabels ).addString( paramLabels.c_str() ) ); +} + + + + void RemoteVstPlugin::sendCurrentProgramName() { char presName[64]; diff --git a/plugins/vst_base/RemoteVstPlugin/CMakeLists.txt b/plugins/vst_base/RemoteVstPlugin/CMakeLists.txt index f4023fd426c..aa77459b68a 100644 --- a/plugins/vst_base/RemoteVstPlugin/CMakeLists.txt +++ b/plugins/vst_base/RemoteVstPlugin/CMakeLists.txt @@ -55,7 +55,7 @@ if(WIN32) endif() if(IS_MINGW) - SET(CMAKE_REQUIRED_FLAGS "-std=c++11") + SET(CMAKE_REQUIRED_FLAGS "-std=c++14") CHECK_CXX_SOURCE_COMPILES(" #include diff --git a/plugins/vst_base/RemoteVstPlugin32.cmake b/plugins/vst_base/RemoteVstPlugin32.cmake index cba9a26c8ab..466752aa5da 100644 --- a/plugins/vst_base/RemoteVstPlugin32.cmake +++ b/plugins/vst_base/RemoteVstPlugin32.cmake @@ -20,7 +20,7 @@ ELSEIF(LMMS_BUILD_WIN64 AND MSVC) IF(NOT QT_32_PREFIX) SET(LMMS_MSVC_YEAR_FOR_QT ${LMMS_MSVC_YEAR}) - if(LMMS_MSVC_YEAR_FOR_QT EQUAL 2019) + if(LMMS_MSVC_YEAR_FOR_QT EQUAL 2019 AND Qt5_VERSION VERSION_LESS "5.15") SET(LMMS_MSVC_YEAR_FOR_QT 2017) # Qt only provides binaries for MSVC 2017, but 2019 is binary compatible endif() diff --git a/plugins/vst_base/VstPlugin.cpp b/plugins/vst_base/VstPlugin.cpp index 8d86f576f33..a08ef072d5e 100644 --- a/plugins/vst_base/VstPlugin.cpp +++ b/plugins/vst_base/VstPlugin.cpp @@ -46,10 +46,6 @@ #include #ifdef LMMS_BUILD_WIN32 -# ifndef NOMINMAX -# define NOMINMAX -# endif - # include # include #endif @@ -59,6 +55,7 @@ #include "LocaleHelper.h" #include "MainWindow.h" #include "Mixer.h" +#include "PathUtil.h" #include "Song.h" #include "FileDialog.h" @@ -121,7 +118,7 @@ class FileInfo VstPlugin::VstPlugin( const QString & _plugin ) : - m_plugin( _plugin ), + m_plugin( PathUtil::toAbsolute(_plugin) ), m_pluginWindowID( 0 ), m_embedMethod( gui ? ConfigManager::inst()->vstEmbedMethod() @@ -129,11 +126,6 @@ VstPlugin::VstPlugin( const QString & _plugin ) : m_version( 0 ), m_currentProgram() { - if( QDir::isRelativePath( m_plugin ) ) - { - m_plugin = ConfigManager::inst()->vstDir() + m_plugin; - } - setSplittedChannels( true ); PE::MachineType machineType; @@ -438,6 +430,14 @@ bool VstPlugin::processMessage( const message & _m ) m_allProgramNames = _m.getQString(); break; + case IdVstParameterLabels: + m_allParameterLabels = _m.getQString(); + break; + + case IdVstParameterDisplays: + m_allParameterDisplays = _m.getQString(); + break; + case IdVstPluginUniqueID: // TODO: display graphically in case of failure printf("unique ID: %s\n", _m.getString().c_str() ); @@ -531,10 +531,32 @@ void VstPlugin::loadProgramNames() +void VstPlugin::loadParameterLabels() +{ + lock(); + sendMessage( message( IdVstParameterLabels ) ); + waitForMessage( IdVstParameterLabels, true ); + unlock(); +} + + + + +void VstPlugin::loadParameterDisplays() +{ + lock(); + sendMessage( message( IdVstParameterDisplays ) ); + waitForMessage( IdVstParameterDisplays, true ); + unlock(); +} + + + + void VstPlugin::savePreset( ) { QString presName = currentProgramName().isEmpty() ? tr(": default") : currentProgramName(); - presName.replace(tr("\""), tr("'")); // QFileDialog unable to handle double quotes properly + presName.replace("\"", "'"); // QFileDialog unable to handle double quotes properly FileDialog sfd( NULL, tr( "Save Preset" ), presName.section(": ", 1, 1) + tr(".fxp"), tr( "Vst Plugin Preset (*.fxp *.fxb)" ) ); @@ -774,7 +796,3 @@ QString VstPlugin::embedMethod() const { return m_embedMethod; } - - - - diff --git a/plugins/vst_base/VstPlugin.h b/plugins/vst_base/VstPlugin.h index 26e7fec369a..e05031256eb 100644 --- a/plugins/vst_base/VstPlugin.h +++ b/plugins/vst_base/VstPlugin.h @@ -91,6 +91,16 @@ class VSTBASE_EXPORT VstPlugin : public RemotePlugin, public JournallingObject return m_allProgramNames; } + inline const QString& allParameterLabels() const + { + return m_allParameterLabels; + } + + inline const QString& allParameterDisplays() const + { + return m_allParameterDisplays; + } + int currentProgram(); const QMap & parameterDump(); @@ -120,6 +130,8 @@ public slots: void setProgram( int index ); void rotateProgram( int offset ); void loadProgramNames(); + void loadParameterLabels(); + void loadParameterDisplays(); void savePreset( void ); void setParam( int i, float f ); void idleUpdate(); @@ -148,6 +160,8 @@ public slots: QString m_productString; QString m_currentProgramName; QString m_allProgramNames; + QString m_allParameterLabels; + QString m_allParameterDisplays; QString p_name; diff --git a/plugins/vst_base/communication.h b/plugins/vst_base/communication.h index 756fd75573e..c25b213d18d 100644 --- a/plugins/vst_base/communication.h +++ b/plugins/vst_base/communication.h @@ -67,6 +67,8 @@ enum VstRemoteMessageIDs IdVstSetProgram, IdVstRotateProgram, IdVstIdleUpdate, + IdVstParameterDisplays, + IdVstParameterLabels, // remoteVstPlugin -> vstPlugin IdVstFailedLoadingPlugin, diff --git a/plugins/watsyn/Watsyn.cpp b/plugins/watsyn/Watsyn.cpp index a5af401ccf7..b60dd5a99c2 100644 --- a/plugins/watsyn/Watsyn.cpp +++ b/plugins/watsyn/Watsyn.cpp @@ -44,7 +44,7 @@ Plugin::Descriptor PLUGIN_EXPORT watsyn_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Watsyn", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "4-oscillator modulatable wavetable synth" ), "Vesa Kivimäki ", 0x0100, diff --git a/plugins/waveshaper/waveshaper.cpp b/plugins/waveshaper/waveshaper.cpp index a3bf2ddfb12..5327d931d9c 100644 --- a/plugins/waveshaper/waveshaper.cpp +++ b/plugins/waveshaper/waveshaper.cpp @@ -38,7 +38,7 @@ Plugin::Descriptor PLUGIN_EXPORT waveshaper_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "Waveshaper Effect", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "plugin for waveshaping" ), "Vesa Kivimäki ", 0x0100, diff --git a/plugins/zynaddsubfx/ZynAddSubFx.cpp b/plugins/zynaddsubfx/ZynAddSubFx.cpp index 429948e7508..94f480ce0c5 100644 --- a/plugins/zynaddsubfx/ZynAddSubFx.cpp +++ b/plugins/zynaddsubfx/ZynAddSubFx.cpp @@ -47,6 +47,7 @@ #include "LocalZynAddSubFx.h" #include "Mixer.h" #include "ControllerConnection.h" +#include "Clipboard.h" #include "embed.h" #include "plugin_export.h" @@ -58,7 +59,7 @@ Plugin::Descriptor PLUGIN_EXPORT zynaddsubfx_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "ZynAddSubFX", - QT_TRANSLATE_NOOP( "pluginBrowser", + QT_TRANSLATE_NOOP( "PluginBrowser", "Embedded ZynAddSubFX" ), "Tobias Doerffel ", 0x0100, @@ -350,7 +351,7 @@ void ZynAddSubFxInstrument::play( sampleFrame * _buf ) -bool ZynAddSubFxInstrument::handleMidiEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset ) +bool ZynAddSubFxInstrument::handleMidiEvent( const MidiEvent& event, const TimePos& time, f_cnt_t offset ) { // do not forward external MIDI Control Change events if the according // LED is not checked @@ -578,10 +579,13 @@ ZynAddSubFxView::~ZynAddSubFxView() void ZynAddSubFxView::dragEnterEvent( QDragEnterEvent * _dee ) { - if( _dee->mimeData()->hasFormat( StringPairDrag::mimeType() ) ) + // For mimeType() and MimeType enum class + using namespace Clipboard; + + if( _dee->mimeData()->hasFormat( mimeType( MimeType::StringPair ) ) ) { QString txt = _dee->mimeData()->data( - StringPairDrag::mimeType() ); + mimeType( MimeType::StringPair ) ); if( txt.section( ':', 0, 0 ) == "pluginpresetfile" ) { _dee->acceptProposedAction(); diff --git a/plugins/zynaddsubfx/ZynAddSubFx.h b/plugins/zynaddsubfx/ZynAddSubFx.h index 6f5bc754d1c..10243e3731e 100644 --- a/plugins/zynaddsubfx/ZynAddSubFx.h +++ b/plugins/zynaddsubfx/ZynAddSubFx.h @@ -70,7 +70,7 @@ class ZynAddSubFxInstrument : public Instrument virtual void play( sampleFrame * _working_buffer ); - virtual bool handleMidiEvent( const MidiEvent& event, const MidiTime& time = MidiTime(), f_cnt_t offset = 0 ); + virtual bool handleMidiEvent( const MidiEvent& event, const TimePos& time = TimePos(), f_cnt_t offset = 0 ); virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); virtual void loadSettings( const QDomElement & _this ); diff --git a/src/3rdparty/CMakeLists.txt b/src/3rdparty/CMakeLists.txt index a5ba31c3a29..0f742b00c58 100644 --- a/src/3rdparty/CMakeLists.txt +++ b/src/3rdparty/CMakeLists.txt @@ -67,7 +67,7 @@ FILE(WRITE ${CMAKE_BINARY_DIR}/src/ringbuffer_export.h # Enable MLOCK support for ringbuffer if available INCLUDE(CheckIncludeFiles) CHECK_INCLUDE_FILES(sys/mman.h HAVE_SYS_MMAN) -IF(HAVE_SYS_MMAN) +IF(HAVE_SYS_MMAN AND NOT CMAKE_SYSTEM_NAME MATCHES "Haiku") SET(USE_MLOCK ON) ELSE() SET(USE_MLOCK OFF) diff --git a/src/3rdparty/jack2 b/src/3rdparty/jack2 new file mode 160000 index 00000000000..db76dd6bb87 --- /dev/null +++ b/src/3rdparty/jack2 @@ -0,0 +1 @@ +Subproject commit db76dd6bb879a0a24d73ec41cc2e6a21bca8ee08 diff --git a/src/3rdparty/ringbuffer b/src/3rdparty/ringbuffer index 82ed7cfb9ad..ea00e1fc2b8 160000 --- a/src/3rdparty/ringbuffer +++ b/src/3rdparty/ringbuffer @@ -1 +1 @@ -Subproject commit 82ed7cfb9ad40467421d8b14ca1af0350e92613c +Subproject commit ea00e1fc2b821a0e06d78e8cc13ac06e6b4f72f5 diff --git a/src/3rdparty/rpmalloc/CMakeLists.txt b/src/3rdparty/rpmalloc/CMakeLists.txt index 80d2302b0bc..96018fa8fbd 100644 --- a/src/3rdparty/rpmalloc/CMakeLists.txt +++ b/src/3rdparty/rpmalloc/CMakeLists.txt @@ -24,6 +24,12 @@ if (NOT LMMS_BUILD_WIN32) ) endif() +if(MINGW) + target_compile_definitions(rpmalloc + PRIVATE -D_WIN32_WINNT=0x600 + ) +endif() + if (CMAKE_BUILD_TYPE STREQUAL "Debug") # rpmalloc uses GCC builtin "__builtin_umull_overflow" with ENABLE_VALIDATE_ARGS, # which is only available starting with GCC 5 diff --git a/src/3rdparty/rpmalloc/rpmalloc b/src/3rdparty/rpmalloc/rpmalloc index b5bdc18051b..8d790d2b45e 160000 --- a/src/3rdparty/rpmalloc/rpmalloc +++ b/src/3rdparty/rpmalloc/rpmalloc @@ -1 +1 @@ -Subproject commit b5bdc18051bb74a22f0bde4bcc90b01cf590b496 +Subproject commit 8d790d2b45e1818e531c61bf649c5225556dd07a diff --git a/src/3rdparty/weakjack/weakjack b/src/3rdparty/weakjack/weakjack index cbb05c52561..fd11655be3b 160000 --- a/src/3rdparty/weakjack/weakjack +++ b/src/3rdparty/weakjack/weakjack @@ -1 +1 @@ -Subproject commit cbb05c52561d921885ad6651af6c8dd9f514dc9a +Subproject commit fd11655be3b2efd6082968ecfe53f9cfe88bda2b diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 907647477fa..b6e0376c195 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,8 +9,8 @@ SET(LMMS_UIS "") SET(CMAKE_AUTOMOC ON) SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -# Enable C++11 -SET(CMAKE_CXX_STANDARD 11) +# Enable C++14 +SET(CMAKE_CXX_STANDARD 14) IF(LMMS_BUILD_APPLE) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") @@ -87,6 +87,9 @@ TARGET_INCLUDE_DIRECTORIES(lmmslib PUBLIC ${PULSEAUDIO_INCLUDE_DIR} ${OGGVORBIS_INCLUDE_DIR} ${LAME_INCLUDE_DIRS} + ${LV2_INCLUDE_DIRS} + ${LILV_INCLUDE_DIRS} + ${SUIL_INCLUDE_DIRS} ${WEAKJACK_INCLUDE_DIR} ) @@ -141,6 +144,9 @@ TARGET_LINK_LIBRARIES(lmmslib ${JACK_LIBRARIES} ${OGGVORBIS_LIBRARIES} ${LAME_LIBRARIES} + ${LV2_LIBRARIES} + ${SUIL_LIBRARIES} + ${LILV_LIBRARIES} ${SAMPLERATE_LIBRARIES} ${SNDFILE_LIBRARIES} ${EXTRA_LIBRARIES} diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index 8328e5cb9ea..f66706a3b94 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -708,7 +708,7 @@ void AutomatableModel::reset() -float AutomatableModel::globalAutomationValueAt( const MidiTime& time ) +float AutomatableModel::globalAutomationValueAt( const TimePos& time ) { // get patterns that connect to this model QVector patterns = AutomationPattern::patternsForModel( this ); @@ -720,7 +720,7 @@ float AutomatableModel::globalAutomationValueAt( const MidiTime& time ) else { // of those patterns: - // find the patterns which overlap with the miditime position + // find the patterns which overlap with the time position QVector patternsInRange; for( QVector::ConstIterator it = patterns.begin(); it != patterns.end(); it++ ) { @@ -738,7 +738,7 @@ float AutomatableModel::globalAutomationValueAt( const MidiTime& time ) latestPattern = patternsInRange[0]; } else - // if we find no patterns at the exact miditime, we need to search for the last pattern before time and use that + // if we find no patterns at the exact time, we need to search for the last pattern before time and use that { int latestPosition = 0; diff --git a/src/core/AutomationPattern.cpp b/src/core/AutomationPattern.cpp index 2fd1cea125f..3c6aa3e9c01 100644 --- a/src/core/AutomationPattern.cpp +++ b/src/core/AutomationPattern.cpp @@ -51,7 +51,7 @@ AutomationPattern::AutomationPattern( AutomationTrack * _auto_track ) : m_isRecording( false ), m_lastRecordedValue( 0 ) { - changeLength( MidiTime( 1, 0 ) ); + changeLength( TimePos( 1, 0 ) ); if( getTrack() ) { switch( getTrack()->trackContainer()->type() ) @@ -110,7 +110,7 @@ bool AutomationPattern::addObject( AutomatableModel * _obj, bool _search_dup ) if( m_objects.isEmpty() && hasAutomation() == false ) { // then initialize first value - putValue( MidiTime(0), _obj->inverseScaledValue( _obj->value() ), false ); + putValue( TimePos(0), _obj->inverseScaledValue( _obj->value() ), false ); } m_objects += _obj; @@ -176,9 +176,9 @@ const AutomationPattern::objectVector& AutomationPattern::objects() const -MidiTime AutomationPattern::timeMapLength() const +TimePos AutomationPattern::timeMapLength() const { - MidiTime one_bar = MidiTime(1, 0); + TimePos one_bar = TimePos(1, 0); if (m_timeMap.isEmpty()) { return one_bar; } timeMap::const_iterator it = m_timeMap.end(); @@ -187,7 +187,7 @@ MidiTime AutomationPattern::timeMapLength() const // return length as a whole bar to prevent disappearing TCO if (last_tick == 0) { return one_bar; } - return MidiTime(last_tick); + return TimePos(last_tick); } @@ -202,14 +202,14 @@ void AutomationPattern::updateLength() -MidiTime AutomationPattern::putValue( const MidiTime & time, +TimePos AutomationPattern::putValue( const TimePos & time, const float value, const bool quantPos, const bool ignoreSurroundingPoints ) { cleanObjects(); - MidiTime newTime = quantPos ? + TimePos newTime = quantPos ? Note::quantized( time, quantization() ) : time; @@ -241,7 +241,7 @@ MidiTime AutomationPattern::putValue( const MidiTime & time, -void AutomationPattern::removeValue( const MidiTime & time ) +void AutomationPattern::removeValue( const TimePos & time ) { cleanObjects(); @@ -261,7 +261,7 @@ void AutomationPattern::removeValue( const MidiTime & time ) -void AutomationPattern::recordValue(MidiTime time, float value) +void AutomationPattern::recordValue(TimePos time, float value) { if( value != m_lastRecordedValue ) { @@ -286,14 +286,14 @@ void AutomationPattern::recordValue(MidiTime time, float value) * @param true to snip x position * @return */ -MidiTime AutomationPattern::setDragValue( const MidiTime & time, +TimePos AutomationPattern::setDragValue( const TimePos & time, const float value, const bool quantPos, const bool controlKey ) { if( m_dragging == false ) { - MidiTime newTime = quantPos ? + TimePos newTime = quantPos ? Note::quantized( time, quantization() ) : time; this->removeValue( newTime ); @@ -327,7 +327,7 @@ void AutomationPattern::applyDragValue() -float AutomationPattern::valueAt( const MidiTime & _time ) const +float AutomationPattern::valueAt( const TimePos & _time ) const { if( m_timeMap.isEmpty() ) { @@ -395,7 +395,7 @@ float AutomationPattern::valueAt( timeMap::const_iterator v, int offset ) const -float *AutomationPattern::valuesAfter( const MidiTime & _time ) const +float *AutomationPattern::valuesAfter( const TimePos & _time ) const { timeMap::ConstIterator v = m_timeMap.lowerBound( _time ); if( v == m_timeMap.end() || (v+1) == m_timeMap.end() ) @@ -436,12 +436,12 @@ void AutomationPattern::flipY( int min, int max ) if ( min < 0 ) { tempValue = valueAt( ( iterate + i ).key() ) * -1; - putValue( MidiTime( (iterate + i).key() ) , tempValue, false); + putValue( TimePos( (iterate + i).key() ) , tempValue, false); } else { tempValue = max - valueAt( ( iterate + i ).key() ); - putValue( MidiTime( (iterate + i).key() ) , tempValue, false); + putValue( TimePos( (iterate + i).key() ) , tempValue, false); } } @@ -480,12 +480,12 @@ void AutomationPattern::flipX( int length ) if ( realLength < length ) { tempValue = valueAt( ( iterate + numPoints ).key() ); - putValue( MidiTime( length ) , tempValue, false); + putValue( TimePos( length ) , tempValue, false); numPoints++; for( int i = 0; i <= numPoints; i++ ) { tempValue = valueAt( ( iterate + i ).key() ); - MidiTime newTime = MidiTime( length - ( iterate + i ).key() ); + TimePos newTime = TimePos( length - ( iterate + i ).key() ); tempMap[newTime] = tempValue; } } @@ -494,15 +494,15 @@ void AutomationPattern::flipX( int length ) for( int i = 0; i <= numPoints; i++ ) { tempValue = valueAt( ( iterate + i ).key() ); - MidiTime newTime; + TimePos newTime; if ( ( iterate + i ).key() <= length ) { - newTime = MidiTime( length - ( iterate + i ).key() ); + newTime = TimePos( length - ( iterate + i ).key() ); } else { - newTime = MidiTime( ( iterate + i ).key() ); + newTime = TimePos( ( iterate + i ).key() ); } tempMap[newTime] = tempValue; } @@ -514,7 +514,7 @@ void AutomationPattern::flipX( int length ) { tempValue = valueAt( ( iterate + i ).key() ); cleanObjects(); - MidiTime newTime = MidiTime( realLength - ( iterate + i ).key() ); + TimePos newTime = TimePos( realLength - ( iterate + i ).key() ); tempMap[newTime] = tempValue; } } @@ -538,6 +538,11 @@ void AutomationPattern::saveSettings( QDomDocument & _doc, QDomElement & _this ) _this.setAttribute( "prog", QString::number( progressionType() ) ); _this.setAttribute( "tens", QString::number( getTension() ) ); _this.setAttribute( "mute", QString::number( isMuted() ) ); + + if( usesCustomClipColor() ) + { + _this.setAttribute( "color", color().name() ); + } for( timeMap::const_iterator it = m_timeMap.begin(); it != m_timeMap.end(); ++it ) @@ -593,6 +598,12 @@ void AutomationPattern::loadSettings( const QDomElement & _this ) m_idsToResolve << element.attribute( "id" ).toInt(); } } + + if( _this.hasAttribute( "color" ) ) + { + useCustomClipColor( true ); + setColor( _this.attribute( "color" ) ); + } int len = _this.attribute( "len" ).toInt(); if( len <= 0 ) diff --git a/src/core/BBTrackContainer.cpp b/src/core/BBTrackContainer.cpp index ac4b6cb1a2f..f818684ec4e 100644 --- a/src/core/BBTrackContainer.cpp +++ b/src/core/BBTrackContainer.cpp @@ -32,15 +32,15 @@ BBTrackContainer::BBTrackContainer() : TrackContainer(), - m_bbComboBoxModel( this ) + m_bbComboBoxModel(this) { - connect( &m_bbComboBoxModel, SIGNAL( dataChanged() ), - this, SLOT( currentBBChanged() ) ); + connect(&m_bbComboBoxModel, SIGNAL(dataChanged()), + this, SLOT(currentBBChanged())); // we *always* want to receive updates even in case BB actually did // not change upon setCurrentBB()-call - connect( &m_bbComboBoxModel, SIGNAL( dataUnchanged() ), - this, SLOT( currentBBChanged() ) ); - setType( BBContainer ); + connect(&m_bbComboBoxModel, SIGNAL(dataUnchanged()), + this, SLOT(currentBBChanged())); + setType(BBContainer); } @@ -53,27 +53,27 @@ BBTrackContainer::~BBTrackContainer() -bool BBTrackContainer::play( MidiTime _start, fpp_t _frames, - f_cnt_t _offset, int _tco_num ) +bool BBTrackContainer::play(TimePos start, fpp_t frames, f_cnt_t offset, int tcoNum) { - bool played_a_note = false; - if( lengthOfBB( _tco_num ) <= 0 ) + bool notePlayed = false; + + if (lengthOfBB(tcoNum) <= 0) { return false; } - _start = _start % ( lengthOfBB( _tco_num ) * MidiTime::ticksPerBar() ); + start = start % (lengthOfBB(tcoNum) * TimePos::ticksPerBar()); TrackList tl = tracks(); - for( TrackList::iterator it = tl.begin(); it != tl.end(); ++it ) + for (Track * t : tl) { - if( ( *it )->play( _start, _frames, _offset, _tco_num ) ) + if (t->play(start, frames, offset, tcoNum)) { - played_a_note = true; + notePlayed = true; } } - return played_a_note; + return notePlayed; } @@ -81,7 +81,7 @@ bool BBTrackContainer::play( MidiTime _start, fpp_t _frames, void BBTrackContainer::updateAfterTrackAdd() { - if( numOfBBs() == 0 && !Engine::getSong()->isLoadingProject() ) + if (numOfBBs() == 0 && !Engine::getSong()->isLoadingProject()) { Engine::getSong()->addBBTrack(); } @@ -90,21 +90,21 @@ void BBTrackContainer::updateAfterTrackAdd() -bar_t BBTrackContainer::lengthOfBB( int _bb ) const +bar_t BBTrackContainer::lengthOfBB(int bb) const { - MidiTime max_length = MidiTime::ticksPerBar(); + TimePos maxLength = TimePos::ticksPerBar(); const TrackList & tl = tracks(); - for (Track* t : tl) + for (Track * t : tl) { - // Don't create TCOs here if not exist - if (_bb < t->numOfTCOs()) + // Don't create TCOs here if they don't exist + if (bb < t->numOfTCOs()) { - max_length = qMax(max_length, t->getTCO( _bb )->length()); + maxLength = qMax(maxLength, t->getTCO(bb)->length()); } } - return max_length.nextFullBar(); + return maxLength.nextFullBar(); } @@ -112,35 +112,35 @@ bar_t BBTrackContainer::lengthOfBB( int _bb ) const int BBTrackContainer::numOfBBs() const { - return Engine::getSong()->countTracks( Track::BBTrack ); + return Engine::getSong()->countTracks(Track::BBTrack); } -void BBTrackContainer::removeBB( int _bb ) +void BBTrackContainer::removeBB(int bb) { TrackList tl = tracks(); - for( TrackList::iterator it = tl.begin(); it != tl.end(); ++it ) + for (Track * t : tl) { - delete ( *it )->getTCO( _bb ); - ( *it )->removeBar( _bb * DefaultTicksPerBar ); + delete t->getTCO(bb); + t->removeBar(bb * DefaultTicksPerBar); } - if( _bb <= currentBB() ) + if (bb <= currentBB()) { - setCurrentBB( qMax( currentBB() - 1, 0 ) ); + setCurrentBB(qMax(currentBB() - 1, 0)); } } -void BBTrackContainer::swapBB( int _bb1, int _bb2 ) +void BBTrackContainer::swapBB(int bb1, int bb2) { TrackList tl = tracks(); - for( TrackList::iterator it = tl.begin(); it != tl.end(); ++it ) + for (Track * t : tl) { - ( *it )->swapPositionOfTCOs( _bb1, _bb2 ); + t->swapPositionOfTCOs(bb1, bb2); } updateComboBox(); } @@ -148,11 +148,10 @@ void BBTrackContainer::swapBB( int _bb1, int _bb2 ) -void BBTrackContainer::updateBBTrack( TrackContentObject * _tco ) +void BBTrackContainer::updateBBTrack(TrackContentObject * tco) { - BBTrack * t = BBTrack::findBBTrack( _tco->startPosition() / - DefaultTicksPerBar ); - if( t != NULL ) + BBTrack * t = BBTrack::findBBTrack(tco->startPosition() / DefaultTicksPerBar); + if (t != NULL) { t->dataChanged(); } @@ -164,11 +163,11 @@ void BBTrackContainer::updateBBTrack( TrackContentObject * _tco ) void BBTrackContainer::fixIncorrectPositions() { TrackList tl = tracks(); - for( TrackList::iterator it = tl.begin(); it != tl.end(); ++it ) + for (Track * t : tl) { - for( int i = 0; i < numOfBBs(); ++i ) + for (int i = 0; i < numOfBBs(); ++i) { - ( *it )->getTCO( i )->movePosition( MidiTime( i, 0 ) ); + t->getTCO(i)->movePosition(TimePos(i, 0)); } } } @@ -178,7 +177,7 @@ void BBTrackContainer::fixIncorrectPositions() void BBTrackContainer::play() { - if( Engine::getSong()->playMode() != Song::Mode_PlayBB ) + if (Engine::getSong()->playMode() != Song::Mode_PlayBB) { Engine::getSong()->playBB(); } @@ -201,16 +200,16 @@ void BBTrackContainer::stop() void BBTrackContainer::updateComboBox() { - const int cur_bb = currentBB(); + const int curBB = currentBB(); m_bbComboBoxModel.clear(); - for( int i = 0; i < numOfBBs(); ++i ) + for (int i = 0; i < numOfBBs(); ++i) { - BBTrack * bbt = BBTrack::findBBTrack( i ); - m_bbComboBoxModel.addItem( bbt->name() ); + BBTrack * bbt = BBTrack::findBBTrack(i); + m_bbComboBoxModel.addItem(bbt->name()); } - setCurrentBB( cur_bb ); + setCurrentBB(curBB); } @@ -218,14 +217,13 @@ void BBTrackContainer::updateComboBox() void BBTrackContainer::currentBBChanged() { - // now update all track-labels (the current one has to become white, - // the others gray) + // now update all track-labels (the current one has to become white, the others gray) TrackList tl = Engine::getSong()->tracks(); - for( TrackList::iterator it = tl.begin(); it != tl.end(); ++it ) + for (Track * t : tl) { - if( ( *it )->type() == Track::BBTrack ) + if (t->type() == Track::BBTrack) { - ( *it )->dataChanged(); + t->dataChanged(); } } } @@ -233,27 +231,27 @@ void BBTrackContainer::currentBBChanged() -void BBTrackContainer::createTCOsForBB( int _bb ) +void BBTrackContainer::createTCOsForBB(int bb) { TrackList tl = tracks(); - for( int i = 0; i < tl.size(); ++i ) + for (Track * t : tl) { - tl[i]->createTCOsForBB( _bb ); + t->createTCOsForBB(bb); } } -AutomatedValueMap BBTrackContainer::automatedValuesAt(MidiTime time, int tcoNum) const +AutomatedValueMap BBTrackContainer::automatedValuesAt(TimePos time, int tcoNum) const { Q_ASSERT(tcoNum >= 0); Q_ASSERT(time.getTicks() >= 0); - auto length_bars = lengthOfBB(tcoNum); - auto length_ticks = length_bars * MidiTime::ticksPerBar(); - if (time > length_ticks) + auto lengthBars = lengthOfBB(tcoNum); + auto lengthTicks = lengthBars * TimePos::ticksPerBar(); + if (time > lengthTicks) { - time = length_ticks; + time = lengthTicks; } - return TrackContainer::automatedValuesAt(time + (MidiTime::ticksPerBar() * tcoNum), tcoNum); + return TrackContainer::automatedValuesAt(time + (TimePos::ticksPerBar() * tcoNum), tcoNum); } diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 164ecf410df..6c043b5396c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -45,6 +45,7 @@ set(LMMS_SRCS core/Note.cpp core/NotePlayHandle.cpp core/Oscillator.cpp + core/PathUtil.cpp core/PeakController.cpp core/PerfLog.cpp core/Piano.cpp @@ -65,9 +66,11 @@ set(LMMS_SRCS core/SerializingObject.cpp core/Song.cpp core/TempoSyncKnobModel.cpp + core/TimePos.cpp core/ToolPlugin.cpp core/Track.cpp core/TrackContainer.cpp + core/TrackContentObject.cpp core/ValueBuffer.cpp core/VstSyncController.cpp core/StepRecorder.cpp @@ -89,16 +92,28 @@ set(LMMS_SRCS core/audio/AudioSampleRecorder.cpp core/audio/AudioSdl.cpp + core/lv2/Lv2Basics.cpp + core/lv2/Lv2ControlBase.cpp + core/lv2/Lv2Evbuf.cpp + core/lv2/Lv2Features.cpp + core/lv2/Lv2Ports.cpp + core/lv2/Lv2Proc.cpp + core/lv2/Lv2Manager.cpp + core/lv2/Lv2Options.cpp + core/lv2/Lv2SubPluginFeatures.cpp + core/lv2/Lv2UridCache.cpp + core/lv2/Lv2UridMap.cpp + core/midi/MidiAlsaRaw.cpp core/midi/MidiAlsaSeq.cpp core/midi/MidiClient.cpp core/midi/MidiController.cpp + core/midi/MidiEventToByteSeq.cpp core/midi/MidiJack.cpp core/midi/MidiOss.cpp core/midi/MidiSndio.cpp core/midi/MidiApple.cpp core/midi/MidiPort.cpp - core/midi/MidiTime.cpp core/midi/MidiWinMM.cpp core/libcds.cpp diff --git a/src/core/Clipboard.cpp b/src/core/Clipboard.cpp index 0c4b972865b..9b7cf2e775c 100644 --- a/src/core/Clipboard.cpp +++ b/src/core/Clipboard.cpp @@ -22,32 +22,73 @@ * */ +#include +#include +#include + #include "Clipboard.h" #include "JournallingObject.h" -Clipboard::Map Clipboard::content; +namespace Clipboard +{ + const QMimeData * getMimeData() + { + return QApplication::clipboard()->mimeData( QClipboard::Clipboard ); + } -void Clipboard::copy( JournallingObject * _obj ) -{ - QDomDocument doc; - QDomElement parent = doc.createElement( "Clipboard" ); - _obj->saveState( doc, parent ); - content[_obj->nodeName()] = parent.firstChild().toElement(); -} + bool hasFormat( MimeType mT ) + { + return getMimeData()->hasFormat( mimeType( mT ) ); + } -const QDomElement * Clipboard::getContent( const QString & _node_name ) -{ - if( content.find( _node_name ) != content.end() ) + + + void copyString( const QString & str, MimeType mT ) { - return &content[_node_name]; + QMimeData *content = new QMimeData; + + content->setData( mimeType( mT ), str.toUtf8() ); + QApplication::clipboard()->setMimeData( content, QClipboard::Clipboard ); } - return NULL; -} + + QString getString( MimeType mT ) + { + return QString( getMimeData()->data( mimeType( mT ) ) ); + } + + + + + void copyStringPair( const QString & key, const QString & value ) + { + QString finalString = key + ":" + value; + + QMimeData *content = new QMimeData; + content->setData( mimeType( MimeType::StringPair ), finalString.toUtf8() ); + QApplication::clipboard()->setMimeData( content, QClipboard::Clipboard ); + } + + + + + QString decodeKey( const QMimeData * mimeData ) + { + return( QString::fromUtf8( mimeData->data( mimeType( MimeType::StringPair ) ) ).section( ':', 0, 0 ) ); + } + + + + + QString decodeValue( const QMimeData * mimeData ) + { + return( QString::fromUtf8( mimeData->data( mimeType( MimeType::StringPair ) ) ).section( ':', 1, -1 ) ); + } +} diff --git a/src/core/ConfigManager.cpp b/src/core/ConfigManager.cpp index b8e8cd4ae77..a41f8a8c010 100644 --- a/src/core/ConfigManager.cpp +++ b/src/core/ConfigManager.cpp @@ -38,6 +38,11 @@ #include "lmmsversion.h" +// Vector with all the upgrade methods +const std::vector ConfigManager::UPGRADE_METHODS = { + &ConfigManager::upgrade_1_1_90 , &ConfigManager::upgrade_1_1_91 +}; + static inline QString ensureTrailingSlash(const QString & s ) { if(! s.isEmpty() && !s.endsWith('/') && !s.endsWith('\\')) @@ -52,59 +57,27 @@ ConfigManager * ConfigManager::s_instanceOfMe = NULL; ConfigManager::ConfigManager() : - 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()) + m_version(defaultVersion()), + m_configVersion( UPGRADE_METHODS.size() ) { - // Detect < 1.2.0 working directory as a courtesy - if ( QFileInfo( QDir::home().absolutePath() + "/lmms/projects/" ).exists() ) - m_workingDir = QDir::home().absolutePath() + "/lmms/"; - - if (! qgetenv("LMMS_DATA_DIR").isEmpty()) - QDir::addSearchPath("data", QString::fromLocal8Bit(qgetenv("LMMS_DATA_DIR"))); - - // If we're in development (lmms is not installed) let's get the source and - // binary directories by reading the CMake Cache - QDir appPath = qApp->applicationDirPath(); - // If in tests, get parent directory - if (appPath.dirName() == "tests") { - appPath.cdUp(); + if (QFileInfo::exists(qApp->applicationDirPath() + PORTABLE_MODE_FILE)) + { + initPortableWorkingDir(); } - QFile cmakeCache(appPath.absoluteFilePath("CMakeCache.txt")); - if (cmakeCache.exists()) { - cmakeCache.open(QFile::ReadOnly); - QTextStream stream(&cmakeCache); - - // Find the lines containing something like lmms_SOURCE_DIR:static= - // and lmms_BINARY_DIR:static= - int done = 0; - while(! stream.atEnd()) - { - QString line = stream.readLine(); - - if (line.startsWith("lmms_SOURCE_DIR:")) { - QString srcDir = line.section('=', -1).trimmed(); - QDir::addSearchPath("data", srcDir + "/data/"); - done++; - } - if (line.startsWith("lmms_BINARY_DIR:")) { - m_lmmsRcFile = line.section('=', -1).trimmed() + QDir::separator() + - ".lmmsrc.xml"; - done++; - } - if (done == 2) - { - break; - } - } - - cmakeCache.close(); + else + { + initInstalledWorkingDir(); } + m_dataDir = "data:/"; + m_vstDir = m_workingDir + "vst/"; + m_sf2Dir = m_workingDir + SF2_PATH; + m_gigDir = m_workingDir + GIG_PATH; + m_themeDir = defaultThemeDir(); + if (!qgetenv("LMMS_DATA_DIR").isEmpty()) + { + QDir::addSearchPath("data", QString::fromLocal8Bit(qgetenv("LMMS_DATA_DIR"))); + } + initDevelopmentWorkingDir(); #ifdef LMMS_BUILD_WIN32 QDir::addSearchPath("data", qApp->applicationDirPath() + "/data/"); @@ -112,7 +85,6 @@ ConfigManager::ConfigManager() : QDir::addSearchPath("data", qApp->applicationDirPath().section('/', 0, -2) + "/share/lmms/"); #endif - } @@ -149,7 +121,7 @@ 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")); @@ -166,17 +138,15 @@ void ConfigManager::upgrade() return; } - ProjectVersion createdWith = m_version; - - if (createdWith.setCompareType(ProjectVersion::Build) < "1.1.90") - { - upgrade_1_1_90(); - } + // Runs all necessary upgrade methods + std::for_each( UPGRADE_METHODS.begin() + m_configVersion, UPGRADE_METHODS.end(), + [this](UpgradeMethod um) + { + (this->*um)(); + } + ); - if (createdWith.setCompareType(ProjectVersion::Build) < "1.1.91") - { - upgrade_1_1_91(); - } + ProjectVersion createdWith = m_version; // Don't use old themes as they break the UI (i.e. 0.4 != 1.0, etc) if (createdWith.setCompareType(ProjectVersion::Minor) != LMMS_VERSION) @@ -186,6 +156,7 @@ void ConfigManager::upgrade() // Bump the version, now that we are upgraded m_version = LMMS_VERSION; + m_configVersion = UPGRADE_METHODS.size(); } QString ConfigManager::defaultVersion() const @@ -193,7 +164,7 @@ QString ConfigManager::defaultVersion() const return LMMS_VERSION; } -QStringList ConfigManager::availabeVstEmbedMethods() +QStringList ConfigManager::availableVstEmbedMethods() { QStringList methods; methods.append("none"); @@ -215,7 +186,7 @@ QStringList ConfigManager::availabeVstEmbedMethods() QString ConfigManager::vstEmbedMethod() const { - QStringList methods = availabeVstEmbedMethods(); + QStringList methods = availableVstEmbedMethods(); QString defaultMethod = *(methods.end() - 1); QString currentMethod = value( "ui", "vstembedmethod", defaultMethod ); return methods.contains(currentMethod) ? currentMethod : defaultMethod; @@ -435,11 +406,23 @@ void ConfigManager::loadConfigFile(const QString & configFile) QDomNode node = root.firstChild(); - // Cache the config version for upgrade() + // Cache LMMS version if (!root.attribute("version").isNull()) { m_version = root.attribute("version"); } + // Get the version of the configuration file (for upgrade purposes) + if( root.attribute("configversion").isNull() ) + { + m_configVersion = legacyConfigVersion(); // No configversion attribute found + } + else + { + bool success; + m_configVersion = root.attribute("configversion").toUInt(&success); + if( !success ) qWarning("Config Version conversion failure."); + } + // create the settings-map out of the DOM while(!node.isNull()) { @@ -545,17 +528,16 @@ void ConfigManager::loadConfigFile(const QString & configFile) { #if defined(LMMS_BUILD_WIN32) m_stkDir = m_dataDir + "stk/rawwaves/"; -#elif defined(LMMS_BUILD_APPLE) - m_stkDir = qApp->applicationDirPath() + "/../share/stk/rawwaves/"; #else - if ( qApp->applicationDirPath().startsWith("/tmp/") ) + // Look for bundled raw waves first + m_stkDir = qApp->applicationDirPath() + "/../share/stk/rawwaves/"; + // Try system installations if not exists + if (!QDir(m_stkDir).exists()) { - // Assume AppImage bundle - m_stkDir = qApp->applicationDirPath() + "/../share/stk/rawwaves/"; + m_stkDir = "/usr/local/share/stk/rawwaves/"; } - else + if (!QDir(m_stkDir).exists()) { - // Fallback to system provided location m_stkDir = "/usr/share/stk/rawwaves/"; } #endif @@ -600,6 +582,7 @@ void ConfigManager::saveConfigFile() QDomElement lmms_config = doc.createElement("lmms"); lmms_config.setAttribute("version", m_version); + lmms_config.setAttribute("configversion", m_configVersion); doc.appendChild(lmms_config); for(settingsMap::iterator it = m_settings.begin(); @@ -651,3 +634,82 @@ void ConfigManager::saveConfigFile() outfile.write(xml.toUtf8()); outfile.close(); } + +void ConfigManager::initPortableWorkingDir() +{ + QString applicationPath = qApp->applicationDirPath(); + m_workingDir = applicationPath + "/lmms-workspace/"; + m_lmmsRcFile = applicationPath + "/.lmmsrc.xml"; +} + +void ConfigManager::initInstalledWorkingDir() +{ + m_workingDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/lmms/"; + m_lmmsRcFile = QDir::home().absolutePath() +"/.lmmsrc.xml"; + // Detect < 1.2.0 working directory as a courtesy + if ( QFileInfo( QDir::home().absolutePath() + "/lmms/projects/" ).exists() ) + m_workingDir = QDir::home().absolutePath() + "/lmms/"; +} + +void ConfigManager::initDevelopmentWorkingDir() +{ + // If we're in development (lmms is not installed) let's get the source and + // binary directories by reading the CMake Cache + QDir appPath = qApp->applicationDirPath(); + // If in tests, get parent directory + if (appPath.dirName() == "tests") { + appPath.cdUp(); + } + QFile cmakeCache(appPath.absoluteFilePath("CMakeCache.txt")); + if (cmakeCache.exists()) { + cmakeCache.open(QFile::ReadOnly); + QTextStream stream(&cmakeCache); + + // Find the lines containing something like lmms_SOURCE_DIR:static= + // and lmms_BINARY_DIR:static= + int done = 0; + while(! stream.atEnd()) + { + QString line = stream.readLine(); + + if (line.startsWith("lmms_SOURCE_DIR:")) { + QString srcDir = line.section('=', -1).trimmed(); + QDir::addSearchPath("data", srcDir + "/data/"); + done++; + } + if (line.startsWith("lmms_BINARY_DIR:")) { + m_lmmsRcFile = line.section('=', -1).trimmed() + QDir::separator() + + ".lmmsrc.xml"; + done++; + } + if (done == 2) + { + break; + } + } + + cmakeCache.close(); + } +} + +// If configversion is not present, we will convert the LMMS version to the appropriate +// configuration file version for backwards compatibility. +unsigned int ConfigManager::legacyConfigVersion() +{ + ProjectVersion createdWith = m_version; + + createdWith.setCompareType(ProjectVersion::Build); + + if( createdWith < "1.1.90" ) + { + return 0; + } + else if( createdWith < "1.1.91" ) + { + return 1; + } + else + { + return 2; + } +} diff --git a/src/core/DataFile.cpp b/src/core/DataFile.cpp index 129c9738b3e..9dc413566d7 100644 --- a/src/core/DataFile.cpp +++ b/src/core/DataFile.cpp @@ -49,7 +49,28 @@ static void findIds(const QDomElement& elem, QList& idList); - +// Vector with all the upgrade methods +const std::vector DataFile::UPGRADE_METHODS = { + &DataFile::upgrade_0_2_1_20070501 , &DataFile::upgrade_0_2_1_20070508, + &DataFile::upgrade_0_3_0_rc2 , &DataFile::upgrade_0_3_0, + &DataFile::upgrade_0_4_0_20080104 , &DataFile::upgrade_0_4_0_20080118, + &DataFile::upgrade_0_4_0_20080129 , &DataFile::upgrade_0_4_0_20080409, + &DataFile::upgrade_0_4_0_20080607 , &DataFile::upgrade_0_4_0_20080622, + &DataFile::upgrade_0_4_0_beta1 , &DataFile::upgrade_0_4_0_rc2, + &DataFile::upgrade_1_0_99 , &DataFile::upgrade_1_1_0, + &DataFile::upgrade_1_1_91 , &DataFile::upgrade_1_2_0_rc3, + &DataFile::upgrade_1_3_0 , &DataFile::upgrade_noHiddenClipNames +}; + +// Vector of all versions that have upgrade routines. +const std::vector DataFile::UPGRADE_VERSIONS = { + "0.2.1-20070501" , "0.2.1-20070508" , "0.3.0-rc2", + "0.3.0" , "0.4.0-20080104" , "0.4.0-20080118", + "0.4.0-20080129" , "0.4.0-20080409" , "0.4.0-20080607", + "0.4.0-20080622" , "0.4.0-beta1" , "0.4.0-rc2", + "1.0.99-0" , "1.1.0-0" , "1.1.91-0", + "1.2.0-rc3" , "1.3.0" +}; DataFile::typeDescStruct DataFile::s_types[DataFile::TypeCount] = @@ -71,11 +92,12 @@ DataFile::DataFile( Type type ) : QDomDocument( "lmms-project" ), m_content(), m_head(), - m_type( type ) + m_type( type ), + m_fileVersion( UPGRADE_METHODS.size() ) { appendChild( createProcessingInstruction("xml", "version=\"1.0\"")); QDomElement root = createElement( "lmms-project" ); - root.setAttribute( "version", LDF_VERSION_STRING ); + root.setAttribute( "version", m_fileVersion ); root.setAttribute( "type", typeName( type ) ); root.setAttribute( "creator", "LMMS" ); root.setAttribute( "creatorversion", LMMS_VERSION ); @@ -95,7 +117,8 @@ DataFile::DataFile( Type type ) : DataFile::DataFile( const QString & _fileName ) : QDomDocument(), m_content(), - m_head() + m_head(), + m_fileVersion( UPGRADE_METHODS.size() ) { QFile inFile( _fileName ); if( !inFile.open( QIODevice::ReadOnly ) ) @@ -123,7 +146,8 @@ DataFile::DataFile( const QString & _fileName ) : DataFile::DataFile( const QByteArray & _data ) : QDomDocument(), m_content(), - m_head() + m_head(), + m_fileVersion( UPGRADE_METHODS.size() ) { loadData( _data, "" ); } @@ -166,6 +190,9 @@ bool DataFile::validate( QString extension ) ( extension == "xiz" && ! pluginFactory->pluginSupportingExtension(extension).isNull()) || extension == "sf2" || extension == "sf3" || extension == "pat" || extension == "mid" || extension == "dll" +#ifdef LMMS_HAVE_LV2 + || extension == "lv2" +#endif ) ) { return true; @@ -769,10 +796,10 @@ void DataFile::upgrade_0_4_0_rc2() void DataFile::upgrade_1_0_99() { jo_id_t last_assigned_id = 0; - + QList idList; findIds(documentElement(), idList); - + QDomNodeList list = elementsByTagName("ladspacontrols"); for(int i = 0; !list.item(i).isNull(); ++i) { @@ -788,22 +815,22 @@ void DataFile::upgrade_1_0_99() QDomElement me = createElement("data"); me.setAttribute("value", el.attribute("data")); me.setAttribute("scale_type", "log"); - + jo_id_t id; for(id = last_assigned_id + 1; idList.contains(id); id++) { } - + last_assigned_id = id; idList.append(id); me.setAttribute("id", id); el.appendChild(me); - + } } } - } + } } @@ -870,31 +897,6 @@ void DataFile::upgrade_1_1_91() } -void DataFile::upgrade_1_2_0_rc3() -{ - // Upgrade from earlier bbtrack beat note behaviour of adding - // steps if a note is placed after the last step. - QDomNodeList bbtracks = elementsByTagName( "bbtrack" ); - for( int i = 0; !bbtracks.item( i ).isNull(); ++i ) - { - QDomNodeList patterns = bbtracks.item( i - ).toElement().elementsByTagName( - "pattern" ); - for( int j = 0; !patterns.item( j ).isNull(); ++j ) - { - int patternLength, steps; - QDomElement el = patterns.item( j ).toElement(); - if( el.attribute( "len" ) != "" ) - { - patternLength = el.attribute( "len" ).toInt(); - steps = patternLength / 12; - el.setAttribute( "steps", steps ); - } - } - } -} - - static void upgradeElement_1_2_0_rc2_42( QDomElement & el ) { if( el.hasAttribute( "syncmode" ) ) @@ -927,8 +929,30 @@ static void upgradeElement_1_2_0_rc2_42( QDomElement & el ) } -void DataFile::upgrade_1_2_0_rc2_42() +void DataFile::upgrade_1_2_0_rc3() { + // Upgrade from earlier bbtrack beat note behaviour of adding + // steps if a note is placed after the last step. + QDomNodeList bbtracks = elementsByTagName( "bbtrack" ); + for( int i = 0; !bbtracks.item( i ).isNull(); ++i ) + { + QDomNodeList patterns = bbtracks.item( i + ).toElement().elementsByTagName( + "pattern" ); + for( int j = 0; !patterns.item( j ).isNull(); ++j ) + { + int patternLength, steps; + QDomElement el = patterns.item( j ).toElement(); + if( el.attribute( "len" ) != "" ) + { + patternLength = el.attribute( "len" ).toInt(); + steps = patternLength / 12; + el.setAttribute( "steps", steps ); + } + } + } + + // DataFile::upgrade_1_2_0_rc2_42 QDomElement el = firstChildElement(); while ( !el.isNull() ) { @@ -1044,7 +1068,7 @@ void DataFile::upgrade_1_3_0() QDomElement attribute = attributes.item( k ).toElement(); if( attribute.attribute( "name" ) == "file" && - ( attribute.attribute( "value" ) == "calf" || + ( attribute.attribute( "value" ) == "calf" || attribute.attribute( "value" ) == "calf.so" ) ) { attribute.setAttribute( "value", "veal" ); @@ -1308,7 +1332,7 @@ void DataFile::upgrade_1_3_0() }; iterate_ladspa_ports(effect, fn); } - + if( attribute.attribute( "name" ) == "plugin" && attribute.attribute( "value" ) == "StereoTools" ) { @@ -1332,95 +1356,51 @@ void DataFile::upgrade_1_3_0() } } - -void DataFile::upgrade() +void DataFile::upgrade_noHiddenClipNames() { - ProjectVersion version = - documentElement().attribute( "creatorversion" ). - replace( "svn", "" ); + QDomNodeList tracks = elementsByTagName("track"); - if( version < "0.2.1-20070501" ) + auto clearDefaultNames = [](QDomNodeList clips, QString trackName) { - upgrade_0_2_1_20070501(); - } - - if( version < "0.2.1-20070508" ) - { - upgrade_0_2_1_20070508(); - } - - if( version < "0.3.0-rc2" ) - { - upgrade_0_3_0_rc2(); - } - - if( version < "0.3.0" ) - { - upgrade_0_3_0(); - } - - if( version < "0.4.0-20080104" ) - { - upgrade_0_4_0_20080104(); - } + for (int j = 0; j < clips.size(); ++j) + { + QDomElement clip = clips.item(j).toElement(); + QString clipName = clip.attribute("name", ""); + if (clipName == trackName) { clip.setAttribute("name", ""); } + } + }; - if( version < "0.4.0-20080118" ) + for (int i = 0; i < tracks.size(); ++i) { - upgrade_0_4_0_20080118(); - } + QDomElement track = tracks.item(i).toElement(); + QString trackName = track.attribute("name", ""); - if( version < "0.4.0-20080129" ) - { - upgrade_0_4_0_20080129(); - } + QDomNodeList instClips = track.elementsByTagName("pattern"); + QDomNodeList autoClips = track.elementsByTagName("automationpattern"); + QDomNodeList bbClips = track.elementsByTagName("bbtco"); - if( version < "0.4.0-20080409" ) - { - upgrade_0_4_0_20080409(); + clearDefaultNames(instClips, trackName); + clearDefaultNames(autoClips, trackName); + clearDefaultNames(bbClips, trackName); } +} - if( version < "0.4.0-20080607" ) - { - upgrade_0_4_0_20080607(); - } - if( version < "0.4.0-20080622" ) - { - upgrade_0_4_0_20080622(); - } +void DataFile::upgrade() +{ + // Runs all necessary upgrade methods + std::for_each( UPGRADE_METHODS.begin() + m_fileVersion, UPGRADE_METHODS.end(), + [this](UpgradeMethod um) + { + (this->*um)(); + } + ); - if( version < "0.4.0-beta1" ) - { - upgrade_0_4_0_beta1(); - } - if( version < "0.4.0-rc2" ) - { - upgrade_0_4_0_rc2(); - } - if( version < "1.0.99-0" ) - { - upgrade_1_0_99(); - } - if( version < "1.1.0-0" ) - { - upgrade_1_1_0(); - } - if( version < "1.1.91-0" ) - { - upgrade_1_1_91(); - } - if( version < "1.2.0-rc3" ) - { - upgrade_1_2_0_rc3(); - upgrade_1_2_0_rc2_42(); - } - if( version < "1.3.0" ) - { - upgrade_1_3_0(); - } + // Bump the file version (which should be the size of the upgrade methods vector) + m_fileVersion = UPGRADE_METHODS.size(); // update document meta data - documentElement().setAttribute( "version", LDF_VERSION_STRING ); + documentElement().setAttribute( "version", m_fileVersion ); documentElement().setAttribute( "type", typeName( type() ) ); documentElement().setAttribute( "creator", "LMMS" ); documentElement().setAttribute( "creatorversion", LMMS_VERSION ); @@ -1480,49 +1460,45 @@ void DataFile::loadData( const QByteArray & _data, const QString & _sourceFile ) m_type = type( root.attribute( "type" ) ); m_head = root.elementsByTagName( "head" ).item( 0 ).toElement(); + if (!root.hasAttribute("version") || root.attribute("version")=="1.0") + { + // The file versioning is now a unsigned int, not maj.min, so we use + // legacyFileVersion() to retrieve the appropriate version + m_fileVersion = legacyFileVersion(); + } + else + { + bool success; + m_fileVersion = root.attribute( "version" ).toUInt( &success ); + if( !success ) qWarning("File Version conversion failure."); + } - if( root.hasAttribute( "creatorversion" ) ) + if (root.hasAttribute("creatorversion")) { - // compareType defaults to Build,so it doesn't have to be set here - ProjectVersion createdWith = root.attribute( "creatorversion" ); + // compareType defaults to All, so it doesn't have to be set here + ProjectVersion createdWith = root.attribute("creatorversion"); ProjectVersion openedWith = LMMS_VERSION; - if ( createdWith != openedWith ) - { - // only one compareType needs to be set, and we can compare on one line because setCompareType returns ProjectVersion - if( createdWith.setCompareType( ProjectVersion::Minor ) - != openedWith ) - { - if( gui != nullptr && root.attribute( "type" ) == "song" ) - { - TextFloat::displayMessage( - SongEditor::tr( "Version difference" ), - SongEditor::tr( - "This %1 was created with " - "LMMS %2." - ).arg( - _sourceFile.endsWith( ".mpt" ) ? - SongEditor::tr( "template" ) : - SongEditor::tr( "project" ) - ) - .arg( root.attribute( "creatorversion" ) ), - embed::getIconPixmap( "whatsthis", 24, 24 ), - 2500 - ); - } - } - - // the upgrade needs to happen after the warning as it updates the project version. - if( createdWith.setCompareType( ProjectVersion::Build ) - < openedWith ) - { - upgrade(); - } + if (createdWith < openedWith) { upgrade(); } + + if (createdWith.setCompareType(ProjectVersion::Minor) + != openedWith.setCompareType(ProjectVersion::Minor) + && gui != nullptr && root.attribute("type") == "song" + ){ + auto projectType = _sourceFile.endsWith(".mpt") ? + SongEditor::tr("template") : SongEditor::tr("project"); + + TextFloat::displayMessage( + SongEditor::tr("Version difference"), + SongEditor::tr("This %1 was created with LMMS %2") + .arg(projectType).arg(createdWith.getVersion()), + embed::getIconPixmap("whatsthis", 24, 24), + 2500 + ); } } - m_content = root.elementsByTagName( typeName( m_type ) ). - item( 0 ).toElement(); + m_content = root.elementsByTagName(typeName(m_type)).item(0).toElement(); } @@ -1533,9 +1509,23 @@ void findIds(const QDomElement& elem, QList& idList) idList.append(elem.attribute("id").toInt()); } QDomElement child = elem.firstChildElement(); - while(!child.isNull()) + while(!child.isNull()) { findIds(child, idList); child = child.nextSiblingElement(); } } + +unsigned int DataFile::legacyFileVersion() +{ + // Version of LMMs that created this project + ProjectVersion creator = + documentElement().attribute( "creatorversion" ). + replace( "svn", "" ); + + // Get an iterator pointing at the first upgrade we need to run (or at the end if there is no such upgrade) + auto firstRequiredUpgrade = std::upper_bound( UPGRADE_VERSIONS.begin(), UPGRADE_VERSIONS.end(), creator ); + + // Convert the iterator to an index, which is our file version (starting at 0) + return std::distance( UPGRADE_VERSIONS.begin(), firstRequiredUpgrade ); +} diff --git a/src/core/Effect.cpp b/src/core/Effect.cpp index c842977532f..f1e32669e4f 100644 --- a/src/core/Effect.cpp +++ b/src/core/Effect.cpp @@ -203,8 +203,8 @@ void Effect::resample( int _i, const sampleFrame * _src_buf, } m_srcData[_i].input_frames = _frames; m_srcData[_i].output_frames = Engine::mixer()->framesPerPeriod(); - m_srcData[_i].data_in = (float *) _src_buf[0]; - m_srcData[_i].data_out = _dst_buf[0]; + m_srcData[_i].data_in = const_cast(_src_buf[0].data()); + m_srcData[_i].data_out = _dst_buf[0].data (); m_srcData[_i].src_ratio = (double) _dst_sr / _src_sr; m_srcData[_i].end_of_input = 0; int error; diff --git a/src/core/Engine.cpp b/src/core/Engine.cpp index ce82310fa4c..214e7b59e2e 100644 --- a/src/core/Engine.cpp +++ b/src/core/Engine.cpp @@ -28,6 +28,7 @@ #include "ConfigManager.h" #include "FxMixer.h" #include "Ladspa2LMMS.h" +#include "Lv2Manager.h" #include "Mixer.h" #include "Plugin.h" #include "PresetPreviewPlayHandle.h" @@ -41,9 +42,11 @@ FxMixer * LmmsCore::s_fxMixer = NULL; BBTrackContainer * LmmsCore::s_bbTrackContainer = NULL; Song * LmmsCore::s_song = NULL; ProjectJournal * LmmsCore::s_projectJournal = NULL; +#ifdef LMMS_HAVE_LV2 +Lv2Manager * LmmsCore::s_lv2Manager = nullptr; +#endif Ladspa2LMMS * LmmsCore::s_ladspaManager = NULL; void* LmmsCore::s_dndPluginKey = nullptr; -DummyTrackContainer * LmmsCore::s_dummyTC = NULL; @@ -63,6 +66,10 @@ void LmmsCore::init( bool renderOnly ) s_fxMixer = new FxMixer; s_bbTrackContainer = new BBTrackContainer; +#ifdef LMMS_HAVE_LV2 + s_lv2Manager = new Lv2Manager; + s_lv2Manager->initPlugins(); +#endif s_ladspaManager = new Ladspa2LMMS; s_projectJournal->setJournalling( true ); @@ -71,7 +78,6 @@ void LmmsCore::init( bool renderOnly ) s_mixer->initDevices(); PresetPreviewPlayHandle::init(); - s_dummyTC = new DummyTrackContainer; emit engine->initProgress(tr("Launching mixer threads")); s_mixer->startProcessing(); @@ -90,11 +96,13 @@ void LmmsCore::destroy() s_song->clearProject(); deleteHelper( &s_bbTrackContainer ); - deleteHelper( &s_dummyTC ); deleteHelper( &s_fxMixer ); deleteHelper( &s_mixer ); +#ifdef LMMS_HAVE_LV2 + deleteHelper( &s_lv2Manager ); +#endif deleteHelper( &s_ladspaManager ); //delete ConfigManager::inst(); @@ -105,6 +113,18 @@ void LmmsCore::destroy() delete ConfigManager::inst(); } + + + +bool LmmsCore::ignorePluginBlacklist() +{ + const char* envVar = getenv("LMMS_IGNORE_BLACKLIST"); + return (envVar && *envVar); +} + + + + float LmmsCore::framesPerTick(sample_rate_t sampleRate) { return sampleRate * 60.0f * 4 / diff --git a/src/core/FxMixer.cpp b/src/core/FxMixer.cpp index 94ba4c3cfbf..1aab1fcb8a1 100644 --- a/src/core/FxMixer.cpp +++ b/src/core/FxMixer.cpp @@ -34,6 +34,7 @@ #include "InstrumentTrack.h" #include "SampleTrack.h" #include "BBTrackContainer.h" +#include "TrackContainer.h" // For TrackContainer::TrackList typedef FxRoute::FxRoute( FxChannel * from, FxChannel * to, float amount ) : m_from( from ), @@ -72,6 +73,7 @@ FxChannel::FxChannel( int idx, Model * _parent ) : m_lock(), m_channelIndex( idx ), m_queued( false ), + m_hasColor( false ), m_dependenciesMet(0) { MixHelpers::clear( m_buffer, Engine::mixer()->framesPerPeriod() ); @@ -383,13 +385,13 @@ void FxMixer::moveChannelLeft( int index ) 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(); + TrackContainer::TrackList songTrackList = Engine::getSong()->tracks(); + TrackContainer::TrackList bbTrackList = Engine::getBBTrackContainer()->tracks(); - QVector trackLists[] = {songTrackList, bbTrackList}; + TrackContainer::TrackList trackLists[] = {songTrackList, bbTrackList}; for(int tl=0; tl<2; ++tl) { - QVector trackList = trackLists[tl]; + TrackContainer::TrackList trackList = trackLists[tl]; for(int i=0; itype() == Track::InstrumentTrack ) @@ -740,6 +742,7 @@ void FxMixer::saveSettings( QDomDocument & _doc, QDomElement & _this ) ch->m_soloModel.saveSettings( _doc, fxch, "soloed" ); fxch.setAttribute( "num", i ); fxch.setAttribute( "name", ch->m_name ); + if( ch->m_hasColor ) fxch.setAttribute( "color", ch->m_color.name() ); // add the channel sends for( int si = 0; si < ch->m_sends.size(); ++si ) @@ -785,6 +788,11 @@ void FxMixer::loadSettings( const QDomElement & _this ) m_fxChannels[num]->m_muteModel.loadSettings( fxch, "muted" ); m_fxChannels[num]->m_soloModel.loadSettings( fxch, "soloed" ); m_fxChannels[num]->m_name = fxch.attribute( "name" ); + if( fxch.hasAttribute( "color" ) ) + { + m_fxChannels[num]->m_hasColor = true; + m_fxChannels[num]->m_color.setNamedColor( fxch.attribute( "color" ) ); + } m_fxChannels[num]->m_fxChain.restoreState( fxch.firstChildElement( m_fxChannels[num]->m_fxChain.nodeName() ) ); diff --git a/src/core/Instrument.cpp b/src/core/Instrument.cpp index ba608da14a2..3e8dc80742e 100644 --- a/src/core/Instrument.cpp +++ b/src/core/Instrument.cpp @@ -23,8 +23,12 @@ */ #include "Instrument.h" -#include "InstrumentTrack.h" + +#include + #include "DummyInstrument.h" +#include "InstrumentTrack.h" +#include "lmms_constants.h" Instrument::Instrument(InstrumentTrack * _instrument_track, @@ -78,8 +82,96 @@ bool Instrument::isFromTrack( const Track * _track ) const return( m_instrumentTrack == _track ); } +// helper function for Instrument::applyFadeIn +static int countZeroCrossings(sampleFrame *buf, fpp_t start, fpp_t frames) +{ + // zero point crossing counts of all channels + int zeroCrossings[DEFAULT_CHANNELS] = {0}; + // maximum zero point crossing of all channels + int maxZeroCrossings = 0; + + // determine the zero point crossing counts + for (fpp_t f = start; f < frames; ++f) + { + for (ch_cnt_t ch = 0; ch < DEFAULT_CHANNELS; ++ch) + { + // we don't want to count [-1, 0, 1] as two crossings + if ((buf[f - 1][ch] <= 0.0 && buf[f][ch] > 0.0) || + (buf[f - 1][ch] >= 0.0 && buf[f][ch] < 0.0)) + { + ++zeroCrossings[ch]; + if (zeroCrossings[ch] > maxZeroCrossings) + { + maxZeroCrossings = zeroCrossings[ch]; + } + } + } + } + + return maxZeroCrossings; +} + +// helper function for Instrument::applyFadeIn +fpp_t getFadeInLength(float maxLength, fpp_t frames, int zeroCrossings) +{ + // calculate the length of the fade in + // Length is inversely proportional to the max of zeroCrossings, + // because for low frequencies, we need a longer fade in to + // prevent clicking. + return (fpp_t) (maxLength / ((float) zeroCrossings / ((float) frames / 128.0f) + 1.0f)); +} + +void Instrument::applyFadeIn(sampleFrame * buf, NotePlayHandle * n) +{ + const static float MAX_FADE_IN_LENGTH = 85.0; + f_cnt_t total = n->totalFramesPlayed(); + if (total == 0) + { + const fpp_t frames = n->framesLeftForCurrentPeriod(); + const f_cnt_t offset = n->offset(); + // We need to skip the first sample because it almost always + // produces a zero crossing; it's not helpful while + // determining the fade in length. Hence 1 + int maxZeroCrossings = countZeroCrossings(buf, offset + 1, offset + frames); + + fpp_t length = getFadeInLength(MAX_FADE_IN_LENGTH, frames, maxZeroCrossings); + n->m_fadeInLength = length; + + // apply fade in + length = length < frames ? length : frames; + for (fpp_t f = 0; f < length; ++f) + { + for (ch_cnt_t ch = 0; ch < DEFAULT_CHANNELS; ++ch) + { + buf[offset + f][ch] *= 0.5 - 0.5 * cosf(F_PI * (float) f / (float) n->m_fadeInLength); + } + } + } + else if (total < n->m_fadeInLength) + { + const fpp_t frames = n->framesLeftForCurrentPeriod(); + + int new_zc = countZeroCrossings(buf, 1, frames); + fpp_t new_length = getFadeInLength(MAX_FADE_IN_LENGTH, frames, new_zc); + + for (fpp_t f = 0; f < frames; ++f) + { + for (ch_cnt_t ch = 0; ch < DEFAULT_CHANNELS; ++ch) + { + float currentLength = n->m_fadeInLength * (1.0f - (float) f / frames) + new_length * ((float) f / frames); + buf[f][ch] *= 0.5 - 0.5 * cosf(F_PI * (float) (total + f) / currentLength); + if (total + f >= currentLength) + { + n->m_fadeInLength = currentLength; + return; + } + } + } + n->m_fadeInLength = new_length; + } +} void Instrument::applyRelease( sampleFrame * buf, const NotePlayHandle * _n ) { @@ -109,6 +201,3 @@ QString Instrument::fullDisplayName() const { return instrumentTrack()->displayName(); } - - - diff --git a/src/core/InstrumentFunctions.cpp b/src/core/InstrumentFunctions.cpp index a710262b055..c5b4daa5296 100644 --- a/src/core/InstrumentFunctions.cpp +++ b/src/core/InstrumentFunctions.cpp @@ -30,7 +30,6 @@ #include "InstrumentTrack.h" #include "Mixer.h" #include "PresetPreviewPlayHandle.h" -#include "stdshims.h" InstrumentFunctionNoteStacking::ChordTable::Init InstrumentFunctionNoteStacking::ChordTable::s_initTable[] = { @@ -315,16 +314,16 @@ InstrumentFunctionArpeggio::InstrumentFunctionArpeggio( Model * _parent ) : m_arpModel.addItem( chord_table[i].getName() ); } - m_arpDirectionModel.addItem( tr( "Up" ), make_unique( "arp_up" ) ); - m_arpDirectionModel.addItem( tr( "Down" ), make_unique( "arp_down" ) ); - m_arpDirectionModel.addItem( tr( "Up and down" ), make_unique( "arp_up_and_down" ) ); - m_arpDirectionModel.addItem( tr( "Down and up" ), make_unique( "arp_up_and_down" ) ); - m_arpDirectionModel.addItem( tr( "Random" ), make_unique( "arp_random" ) ); + m_arpDirectionModel.addItem( tr( "Up" ), std::make_unique( "arp_up" ) ); + m_arpDirectionModel.addItem( tr( "Down" ), std::make_unique( "arp_down" ) ); + m_arpDirectionModel.addItem( tr( "Up and down" ), std::make_unique( "arp_up_and_down" ) ); + m_arpDirectionModel.addItem( tr( "Down and up" ), std::make_unique( "arp_up_and_down" ) ); + m_arpDirectionModel.addItem( tr( "Random" ), std::make_unique( "arp_random" ) ); m_arpDirectionModel.setInitValue( ArpDirUp ); - m_arpModeModel.addItem( tr( "Free" ), make_unique( "arp_free" ) ); - m_arpModeModel.addItem( tr( "Sort" ), make_unique( "arp_sort" ) ); - m_arpModeModel.addItem( tr( "Sync" ), make_unique( "arp_sync" ) ); + m_arpModeModel.addItem( tr( "Free" ), std::make_unique( "arp_free" ) ); + m_arpModeModel.addItem( tr( "Sort" ), std::make_unique( "arp_sort" ) ); + m_arpModeModel.addItem( tr( "Sync" ), std::make_unique( "arp_sync" ) ); } @@ -388,8 +387,10 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n ) while( frames_processed < Engine::mixer()->framesPerPeriod() ) { const f_cnt_t remaining_frames_for_cur_arp = arp_frames - ( cur_frame % arp_frames ); - // does current arp-note fill whole audio-buffer? - if( remaining_frames_for_cur_arp > Engine::mixer()->framesPerPeriod() ) + // does current arp-note fill whole audio-buffer or is the remaining time just + // a short bit that we can discard? + if( remaining_frames_for_cur_arp > Engine::mixer()->framesPerPeriod() || + _n->frames() - _n->totalFramesPlayed() < arp_frames / 5 ) { // then we don't have to do something! break; @@ -504,7 +505,7 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n ) NotePlayHandlePool.construct( _n->instrumentTrack(), frames_processed, gated_frames, - Note( MidiTime( 0 ), MidiTime( 0 ), sub_note_key, _n->getVolume(), + Note( TimePos( 0 ), TimePos( 0 ), sub_note_key, _n->getVolume(), _n->getPanning(), _n->detuning() ), _n, -1, NotePlayHandle::OriginArpeggio ) ); diff --git a/src/core/InstrumentSoundShaping.cpp b/src/core/InstrumentSoundShaping.cpp index 46026b96f8c..b9e32427a87 100644 --- a/src/core/InstrumentSoundShaping.cpp +++ b/src/core/InstrumentSoundShaping.cpp @@ -33,7 +33,6 @@ #include "Instrument.h" #include "InstrumentTrack.h" #include "Mixer.h" -#include "stdshims.h" const float CUT_FREQ_MULTIPLIER = 6000.0f; @@ -43,16 +42,14 @@ const float RES_PRECISION = 1000.0f; // names for env- and lfo-targets - first is name being displayed to user // and second one is used internally, e.g. for saving/restoring settings -const QString InstrumentSoundShaping::targetNames[InstrumentSoundShaping::NumTargets][3] = +const char *const InstrumentSoundShaping::targetNames[InstrumentSoundShaping::NumTargets][3] = { - { InstrumentSoundShaping::tr( "VOLUME" ), "vol", - InstrumentSoundShaping::tr( "Volume" ) }, -/* InstrumentSoundShaping::tr( "Pan" ), - InstrumentSoundShaping::tr( "Pitch" ),*/ - { InstrumentSoundShaping::tr( "CUTOFF" ), "cut", - InstrumentSoundShaping::tr( "Cutoff frequency" ) }, - { InstrumentSoundShaping::tr( "RESO" ), "res", - InstrumentSoundShaping::tr( "Resonance" ) } + { QT_TRANSLATE_NOOP("InstrumentSoundShaping", "VOLUME"), "vol", + QT_TRANSLATE_NOOP("InstrumentSoundShaping", "Volume") }, + { QT_TRANSLATE_NOOP("InstrumentSoundShaping", "CUTOFF"), "cut", + QT_TRANSLATE_NOOP("InstrumentSoundShaping", "Cutoff frequency") }, + { QT_TRANSLATE_NOOP("InstrumentSoundShaping", "RESO"), "res", + QT_TRANSLATE_NOOP("InstrumentSoundShaping", "Resonance") } } ; @@ -77,31 +74,31 @@ InstrumentSoundShaping::InstrumentSoundShaping( value_for_zero_amount, this ); m_envLfoParameters[i]->setDisplayName( - tr( targetNames[i][2].toUtf8().constData() ) ); + tr( targetNames[i][2] ) ); } - m_filterModel.addItem( tr( "Low-pass" ), make_unique( "filter_lp" ) ); - m_filterModel.addItem( tr( "Hi-pass" ), make_unique( "filter_hp" ) ); - m_filterModel.addItem( tr( "Band-pass csg" ), make_unique( "filter_bp" ) ); - m_filterModel.addItem( tr( "Band-pass czpg" ), make_unique( "filter_bp" ) ); - m_filterModel.addItem( tr( "Notch" ), make_unique( "filter_notch" ) ); - m_filterModel.addItem( tr( "All-pass" ), make_unique( "filter_ap" ) ); - m_filterModel.addItem( tr( "Moog" ), make_unique( "filter_lp" ) ); - m_filterModel.addItem( tr( "2x Low-pass" ), make_unique( "filter_2lp" ) ); - m_filterModel.addItem( tr( "RC Low-pass 12 dB/oct" ), make_unique( "filter_lp" ) ); - m_filterModel.addItem( tr( "RC Band-pass 12 dB/oct" ), make_unique( "filter_bp" ) ); - m_filterModel.addItem( tr( "RC High-pass 12 dB/oct" ), make_unique( "filter_hp" ) ); - m_filterModel.addItem( tr( "RC Low-pass 24 dB/oct" ), make_unique( "filter_lp" ) ); - m_filterModel.addItem( tr( "RC Band-pass 24 dB/oct" ), make_unique( "filter_bp" ) ); - m_filterModel.addItem( tr( "RC High-pass 24 dB/oct" ), make_unique( "filter_hp" ) ); - m_filterModel.addItem( tr( "Vocal Formant" ), make_unique( "filter_hp" ) ); - m_filterModel.addItem( tr( "2x Moog" ), make_unique( "filter_2lp" ) ); - m_filterModel.addItem( tr( "SV Low-pass" ), make_unique( "filter_lp" ) ); - m_filterModel.addItem( tr( "SV Band-pass" ), make_unique( "filter_bp" ) ); - m_filterModel.addItem( tr( "SV High-pass" ), make_unique( "filter_hp" ) ); - m_filterModel.addItem( tr( "SV Notch" ), make_unique( "filter_notch" ) ); - m_filterModel.addItem( tr( "Fast Formant" ), make_unique( "filter_hp" ) ); - m_filterModel.addItem( tr( "Tripole" ), make_unique( "filter_lp" ) ); + m_filterModel.addItem( tr( "Low-pass" ), std::make_unique( "filter_lp" ) ); + m_filterModel.addItem( tr( "Hi-pass" ), std::make_unique( "filter_hp" ) ); + m_filterModel.addItem( tr( "Band-pass csg" ), std::make_unique( "filter_bp" ) ); + m_filterModel.addItem( tr( "Band-pass czpg" ), std::make_unique( "filter_bp" ) ); + m_filterModel.addItem( tr( "Notch" ), std::make_unique( "filter_notch" ) ); + m_filterModel.addItem( tr( "All-pass" ), std::make_unique( "filter_ap" ) ); + m_filterModel.addItem( tr( "Moog" ), std::make_unique( "filter_lp" ) ); + m_filterModel.addItem( tr( "2x Low-pass" ), std::make_unique( "filter_2lp" ) ); + m_filterModel.addItem( tr( "RC Low-pass 12 dB/oct" ), std::make_unique( "filter_lp" ) ); + m_filterModel.addItem( tr( "RC Band-pass 12 dB/oct" ), std::make_unique( "filter_bp" ) ); + m_filterModel.addItem( tr( "RC High-pass 12 dB/oct" ), std::make_unique( "filter_hp" ) ); + m_filterModel.addItem( tr( "RC Low-pass 24 dB/oct" ), std::make_unique( "filter_lp" ) ); + m_filterModel.addItem( tr( "RC Band-pass 24 dB/oct" ), std::make_unique( "filter_bp" ) ); + m_filterModel.addItem( tr( "RC High-pass 24 dB/oct" ), std::make_unique( "filter_hp" ) ); + m_filterModel.addItem( tr( "Vocal Formant" ), std::make_unique( "filter_hp" ) ); + m_filterModel.addItem( tr( "2x Moog" ), std::make_unique( "filter_2lp" ) ); + m_filterModel.addItem( tr( "SV Low-pass" ), std::make_unique( "filter_lp" ) ); + m_filterModel.addItem( tr( "SV Band-pass" ), std::make_unique( "filter_bp" ) ); + m_filterModel.addItem( tr( "SV High-pass" ), std::make_unique( "filter_hp" ) ); + m_filterModel.addItem( tr( "SV Notch" ), std::make_unique( "filter_notch" ) ); + m_filterModel.addItem( tr( "Fast Formant" ), std::make_unique( "filter_hp" ) ); + m_filterModel.addItem( tr( "Tripole" ), std::make_unique( "filter_lp" ) ); } @@ -163,7 +160,7 @@ void InstrumentSoundShaping::processAudioBuffer( sampleFrame* buffer, if( n->m_filter == nullptr ) { - n->m_filter = make_unique>( Engine::mixer()->processingSampleRate() ); + n->m_filter = std::make_unique>( Engine::mixer()->processingSampleRate() ); } n->m_filter->setFilterType( m_filterModel.value() ); diff --git a/src/core/LadspaControl.cpp b/src/core/LadspaControl.cpp index 731241b8541..68f2ee643b7 100644 --- a/src/core/LadspaControl.cpp +++ b/src/core/LadspaControl.cpp @@ -80,7 +80,7 @@ LadspaControl::LadspaControl( Model * _parent, port_desc_t * _port, ( m_port->max - m_port->min ) / ( m_port->name.toUpper() == "GAIN" && m_port->max == 10.0f ? 4000.0f : - ( m_port->suggests_logscale ? 8000.0f : 800.0f ) ) ); + ( m_port->suggests_logscale ? 8000000.0f : 800000.0f ) ) ); m_knobModel.setInitValue( m_port->def ); connect( &m_knobModel, SIGNAL( dataChanged() ), this, SLOT( knobChanged() ) ); diff --git a/src/core/LadspaManager.cpp b/src/core/LadspaManager.cpp index febbe5a9192..86acb661be5 100644 --- a/src/core/LadspaManager.cpp +++ b/src/core/LadspaManager.cpp @@ -59,6 +59,8 @@ LadspaManager::LadspaManager() for( QStringList::iterator it = ladspaDirectories.begin(); it != ladspaDirectories.end(); ++it ) { + // Skip empty entries as QDir will interpret it as the working directory + if ((*it).isEmpty()) { continue; } QDir directory( ( *it ) ); QFileInfoList list = directory.entryInfoList(); for( QFileInfoList::iterator file = list.begin(); diff --git a/src/core/Mixer.cpp b/src/core/Mixer.cpp index 4621776921b..a3ba9093774 100644 --- a/src/core/Mixer.cpp +++ b/src/core/Mixer.cpp @@ -74,8 +74,8 @@ Mixer::Mixer( bool renderOnly ) : m_framesPerPeriod( DEFAULT_BUFFER_SIZE ), m_inputBufferRead( 0 ), m_inputBufferWrite( 1 ), - m_readBuf( NULL ), - m_writeBuf( NULL ), + m_outputBufferRead(nullptr), + m_outputBufferWrite(nullptr), m_workers(), m_numWorkers( QThread::idealThreadCount()-1 ), m_newPlayHandles( PlayHandle::MaxNumber ), @@ -137,13 +137,11 @@ Mixer::Mixer( bool renderOnly ) : BufferPool::init( m_framesPerPeriod ); AlignedAllocator alloc; - for( int i = 0; i < 3; i++ ) - { - m_readBuf = alloc.allocate( m_framesPerPeriod ); + m_outputBufferRead = alloc.allocate(m_framesPerPeriod); + m_outputBufferWrite = alloc.allocate(m_framesPerPeriod); - MixHelpers::clear( m_readBuf, m_framesPerPeriod ); - m_bufferPool.push_back( m_readBuf ); - } + MixHelpers::clear(m_outputBufferRead, m_framesPerPeriod); + MixHelpers::clear(m_outputBufferWrite, m_framesPerPeriod); for( int i = 0; i < m_numWorkers+1; ++i ) { @@ -154,10 +152,6 @@ Mixer::Mixer( bool renderOnly ) : } m_workers.push_back( wt ); } - - m_poolDepth = 2; - m_readBuffer = 0; - m_writeBuffer = 1; } @@ -189,10 +183,8 @@ Mixer::~Mixer() delete m_audioDev; AlignedAllocator alloc; - for( int i = 0; i < 3; i++ ) - { - alloc.deallocate( m_bufferPool[i], m_framesPerPeriod ); - } + alloc.deallocate(m_outputBufferRead, m_framesPerPeriod); + alloc.deallocate(m_outputBufferWrite, m_framesPerPeriod); for( int i = 0; i < 2; ++i ) { @@ -220,9 +212,9 @@ void Mixer::initDevices() -void Mixer::startProcessing( bool _needs_fifo ) +void Mixer::startProcessing(bool needsFifo) { - if( _needs_fifo ) + if (needsFifo) { m_fifoWriter = new fifoWriter( this, m_fifo ); m_fifoWriter->start( QThread::HighPriority ); @@ -345,42 +337,6 @@ const surroundSampleFrame * Mixer::renderNextBuffer() s_renderingThread = true; - static Song::PlayPos last_metro_pos = -1; - - Song *song = Engine::getSong(); - - Song::PlayModes currentPlayMode = song->playMode(); - Song::PlayPos p = song->getPlayPos( currentPlayMode ); - - bool playModeSupportsMetronome = currentPlayMode == Song::Mode_PlayPattern || - currentPlayMode == Song::Mode_PlaySong || - currentPlayMode == Song::Mode_PlayBB; - - if( playModeSupportsMetronome && m_metronomeActive && !song->isExporting() && - p != last_metro_pos && - // Stop crash with metronome if empty project - Engine::getSong()->countTracks() ) - { - tick_t ticksPerBar = MidiTime::ticksPerBar(); - if ( p.getTicks() % ( ticksPerBar / 1 ) == 0 ) - { - addPlayHandle( new SamplePlayHandle( "misc/metronome02.ogg" ) ); - } - else if ( p.getTicks() % ( ticksPerBar / - song->getTimeSigModel().getNumerator() ) == 0 ) - { - addPlayHandle( new SamplePlayHandle( "misc/metronome01.ogg" ) ); - } - last_metro_pos = p; - } - - // swap buffer - m_inputBufferWrite = ( m_inputBufferWrite + 1 ) % 2; - m_inputBufferRead = ( m_inputBufferRead + 1 ) % 2; - - // clear new write buffer - m_inputBufferFrames[ m_inputBufferWrite ] = 0; - if( m_clearSignal ) { m_clearSignal = false; @@ -409,22 +365,16 @@ const surroundSampleFrame * Mixer::renderNextBuffer() it_rem = m_playHandlesToRemove.erase( it_rem ); } - // rotate buffers - m_writeBuffer = ( m_writeBuffer + 1 ) % m_poolDepth; - m_readBuffer = ( m_readBuffer + 1 ) % m_poolDepth; - - m_writeBuf = m_bufferPool[m_writeBuffer]; - m_readBuf = m_bufferPool[m_readBuffer]; - - // clear last audio-buffer - MixHelpers::clear( m_writeBuf, m_framesPerPeriod ); + swapBuffers(); // prepare master mix (clear internal buffers etc.) FxMixer * fxMixer = Engine::fxMixer(); fxMixer->prepareMasterMix(); + handleMetronome(); + // create play-handles for new notes, samples etc. - song->processNextBuffer(); + Engine::getSong()->processNextBuffer(); // add all play-handles that have to be added for( LocklessListElement * e = m_newPlayHandles.popList(); e; ) @@ -471,10 +421,10 @@ const surroundSampleFrame * Mixer::renderNextBuffer() // STAGE 3: do master mix in FX mixer - fxMixer->masterMix( m_writeBuf ); + fxMixer->masterMix(m_outputBufferWrite); - emit nextAudioBuffer( m_readBuf ); + emit nextAudioBuffer(m_outputBufferRead); runChangesInModel(); @@ -487,12 +437,71 @@ const surroundSampleFrame * Mixer::renderNextBuffer() m_profiler.finishPeriod( processingSampleRate(), m_framesPerPeriod ); - return m_readBuf; + return m_outputBufferRead; +} + + + + +void Mixer::swapBuffers() +{ + m_inputBufferWrite = (m_inputBufferWrite + 1) % 2; + m_inputBufferRead = (m_inputBufferRead + 1) % 2; + m_inputBufferFrames[m_inputBufferWrite] = 0; + + std::swap(m_outputBufferRead, m_outputBufferWrite); + MixHelpers::clear(m_outputBufferWrite, m_framesPerPeriod); } +void Mixer::handleMetronome() +{ + static tick_t lastMetroTicks = -1; + + Song * song = Engine::getSong(); + Song::PlayModes currentPlayMode = song->playMode(); + + bool metronomeSupported = + currentPlayMode == Song::Mode_PlayPattern + || currentPlayMode == Song::Mode_PlaySong + || currentPlayMode == Song::Mode_PlayBB; + + if (!metronomeSupported || !m_metronomeActive || song->isExporting()) + { + return; + } + + // stop crash with metronome if empty project + if (song->countTracks() == 0) + { + return; + } + + tick_t ticks = song->getPlayPos(currentPlayMode).getTicks(); + tick_t ticksPerBar = TimePos::ticksPerBar(); + int numerator = song->getTimeSigModel().getNumerator(); + + if (ticks == lastMetroTicks) + { + return; + } + + if (ticks % (ticksPerBar / 1) == 0) + { + addPlayHandle(new SamplePlayHandle("misc/metronome02.ogg")); + } + else if (ticks % (ticksPerBar / numerator) == 0) + { + addPlayHandle(new SamplePlayHandle("misc/metronome01.ogg")); + } + + lastMetroTicks = ticks; +} + + + void Mixer::clear() { m_clearSignal = true; @@ -520,29 +529,28 @@ void Mixer::clearNewPlayHandles() void Mixer::clearInternal() { // TODO: m_midiClient->noteOffAll(); - for( PlayHandleList::Iterator it = m_playHandles.begin(); it != m_playHandles.end(); ++it ) + for (auto ph : m_playHandles) { - // we must not delete instrument-play-handles as they exist - // during the whole lifetime of an instrument - if( ( *it )->type() != PlayHandle::TypeInstrumentPlayHandle ) + if (ph->type() != PlayHandle::TypeInstrumentPlayHandle) { - m_playHandlesToRemove.push_back( *it ); + m_playHandlesToRemove.push_back(ph); } + } } -Mixer::StereoSample Mixer::getPeakValues(sampleFrame * _ab, const f_cnt_t _frames) const +Mixer::StereoSample Mixer::getPeakValues(sampleFrame * ab, const f_cnt_t frames) const { sample_t peakLeft = 0.0f; sample_t peakRight = 0.0f; - for( f_cnt_t f = 0; f < _frames; ++f ) + for (f_cnt_t f = 0; f < frames; ++f) { - float const absLeft = qAbs( _ab[f][0] ); - float const absRight = qAbs( _ab[f][1] ); + float const absLeft = qAbs(ab[f][0]); + float const absRight = qAbs(ab[f][1]); if (absLeft > peakLeft) { peakLeft = absLeft; @@ -560,12 +568,12 @@ Mixer::StereoSample Mixer::getPeakValues(sampleFrame * _ab, const f_cnt_t _frame -void Mixer::changeQuality( const struct qualitySettings & _qs ) +void Mixer::changeQuality(const struct qualitySettings & qs) { // don't delete the audio-device stopProcessing(); - m_qualitySettings = _qs; + m_qualitySettings = qs; m_audioDev->applyQualitySettings(); emit sampleRateChanged(); @@ -600,21 +608,6 @@ void Mixer::doSetAudioDevice( AudioDevice * _dev ) -void Mixer::setAudioDevice( AudioDevice * _dev, - bool startNow ) -{ - stopProcessing(); - - doSetAudioDevice( _dev ); - - emit sampleRateChanged(); - - if (startNow) {startProcessing();} -} - - - - void Mixer::setAudioDevice(AudioDevice * _dev, const struct qualitySettings & _qs, bool _needs_fifo, @@ -664,15 +657,14 @@ void Mixer::restoreAudioDevice() -void Mixer::removeAudioPort( AudioPort * _port ) +void Mixer::removeAudioPort(AudioPort * port) { requestChangeInModel(); - QVector::Iterator it = std::find( m_audioPorts.begin(), - m_audioPorts.end(), - _port ); - if( it != m_audioPorts.end() ) + + QVector::Iterator it = std::find(m_audioPorts.begin(), m_audioPorts.end(), port); + if (it != m_audioPorts.end()) { - m_audioPorts.erase( it ); + m_audioPorts.erase(it); } doneChangeInModel(); } @@ -697,22 +689,21 @@ bool Mixer::addPlayHandle( PlayHandle* handle ) } -void Mixer::removePlayHandle( PlayHandle * _ph ) +void Mixer::removePlayHandle(PlayHandle * ph) { requestChangeInModel(); // check thread affinity as we must not delete play-handles // which were created in a thread different than mixer thread - if( _ph->affinityMatters() && - _ph->affinity() == QThread::currentThread() ) + if (ph->affinityMatters() && ph->affinity() == QThread::currentThread()) { - _ph->audioPort()->removePlayHandle( _ph ); + ph->audioPort()->removePlayHandle(ph); bool removedFromList = false; // Check m_newPlayHandles first because doing it the other way around // creates a race condition for( LocklessListElement * e = m_newPlayHandles.first(), * ePrev = NULL; e; ePrev = e, e = e->next ) { - if( e->value == _ph ) + if (e->value == ph) { if( ePrev ) { @@ -728,11 +719,10 @@ void Mixer::removePlayHandle( PlayHandle * _ph ) } } // Now check m_playHandles - PlayHandleList::Iterator it = std::find( m_playHandles.begin(), - m_playHandles.end(), _ph ); - if( it != m_playHandles.end() ) + PlayHandleList::Iterator it = std::find(m_playHandles.begin(), m_playHandles.end(), ph); + if (it != m_playHandles.end()) { - m_playHandles.erase( it ); + m_playHandles.erase(it); removedFromList = true; } // Only deleting PlayHandles that were actually found in the list @@ -740,16 +730,16 @@ void Mixer::removePlayHandle( PlayHandle * _ph ) // (See tobydox's 2008 commit 4583e48) if ( removedFromList ) { - if( _ph->type() == PlayHandle::TypeNotePlayHandle ) + if (ph->type() == PlayHandle::TypeNotePlayHandle) { - NotePlayHandlePool.destroy( (NotePlayHandle*) _ph ); + NotePlayHandlePool.destroy(dynamic_cast(ph)); } - else delete _ph; + else { delete ph; } } } else { - m_playHandlesToRemove.push_back( _ph ); + m_playHandlesToRemove.push_back(ph); } doneChangeInModel(); } @@ -757,13 +747,13 @@ void Mixer::removePlayHandle( PlayHandle * _ph ) -void Mixer::removePlayHandlesOfTypes( Track * _track, const quint8 types ) +void Mixer::removePlayHandlesOfTypes(Track * track, const quint8 types) { requestChangeInModel(); PlayHandleList::Iterator it = m_playHandles.begin(); while( it != m_playHandles.end() ) { - if( ( *it )->isFromTrack( _track ) && ( ( *it )->type() & types ) ) + if ((*it)->isFromTrack(track) && ((*it)->type() & types)) { ( *it )->audioPort()->removePlayHandle( ( *it ) ); if( ( *it )->type() == PlayHandle::TypeNotePlayHandle ) @@ -795,7 +785,7 @@ void Mixer::requestChangeInModel() m_doChangesMutex.lock(); m_waitChangesMutex.lock(); - if ( m_isProcessing && !m_waitingForWrite && !m_changesSignal ) + if (m_isProcessing && !m_waitingForWrite && !m_changesSignal) { m_changesSignal = true; m_changesRequestCondition.wait( &m_waitChangesMutex ); @@ -1207,8 +1197,18 @@ MidiClient * Mixer::tryMidiClients() printf( "midi apple didn't work: client_name=%s\n", client_name.toUtf8().constData()); #endif - printf( "Couldn't create MIDI-client, neither with ALSA nor with " - "OSS. Will use dummy-MIDI-client.\n" ); + if(client_name != MidiDummy::name()) + { + if (client_name.isEmpty()) + { + printf("Unknown MIDI-client. "); + } + else + { + printf("Couldn't create %s MIDI-client. ", client_name.toUtf8().constData()); + } + printf("Will use dummy-MIDI-client.\n"); + } m_midiClientName = MidiDummy::name(); @@ -1287,4 +1287,3 @@ void Mixer::fifoWriter::write( surroundSampleFrame * buffer ) m_mixer->m_waitingForWrite = false; m_mixer->m_doChangesMutex.unlock(); } - diff --git a/src/core/Note.cpp b/src/core/Note.cpp index 389526bb9e0..080a555b5d0 100644 --- a/src/core/Note.cpp +++ b/src/core/Note.cpp @@ -31,7 +31,7 @@ #include "DetuningHelper.h" -Note::Note( const MidiTime & length, const MidiTime & pos, +Note::Note( const TimePos & length, const TimePos & pos, int key, volume_t volume, panning_t panning, DetuningHelper * detuning ) : m_selected( false ), @@ -93,7 +93,7 @@ Note::~Note() -void Note::setLength( const MidiTime & length ) +void Note::setLength( const TimePos & length ) { m_length = length; } @@ -101,7 +101,7 @@ void Note::setLength( const MidiTime & length ) -void Note::setPos( const MidiTime & pos ) +void Note::setPos( const TimePos & pos ) { m_pos = pos; } @@ -136,7 +136,7 @@ void Note::setPanning( panning_t panning ) -MidiTime Note::quantized( const MidiTime & m, const int qGrid ) +TimePos Note::quantized( const TimePos & m, const int qGrid ) { float p = ( (float) m / qGrid ); if( p - floorf( p ) < 0.5f ) diff --git a/src/core/NotePlayHandle.cpp b/src/core/NotePlayHandle.cpp index 523c4d95639..0912f2926fb 100644 --- a/src/core/NotePlayHandle.cpp +++ b/src/core/NotePlayHandle.cpp @@ -210,7 +210,7 @@ void NotePlayHandle::play( sampleFrame * _working_buffer ) // send MidiNoteOn event m_instrumentTrack->processOutEvent( MidiEvent( MidiNoteOn, midiChannel(), midiKey(), midiVelocity( baseVelocity ) ), - MidiTime::fromFrames( offset(), Engine::framesPerTick() ), + TimePos::fromFrames( offset(), Engine::framesPerTick() ), offset() ); } @@ -373,7 +373,7 @@ void NotePlayHandle::noteOff( const f_cnt_t _s ) // send MidiNoteOff event m_instrumentTrack->processOutEvent( MidiEvent( MidiNoteOff, midiChannel(), midiKey(), 0 ), - MidiTime::fromFrames( _s, Engine::framesPerTick() ), + TimePos::fromFrames( _s, Engine::framesPerTick() ), _s ); } @@ -382,7 +382,7 @@ void NotePlayHandle::noteOff( const f_cnt_t _s ) { if( m_origin == OriginMidiInput ) { - setLength( MidiTime( static_cast( totalFramesPlayed() / Engine::framesPerTick() ) ) ); + setLength( TimePos( static_cast( totalFramesPlayed() / Engine::framesPerTick() ) ) ); m_instrumentTrack->midiNoteOff( *this ); } } @@ -518,7 +518,7 @@ void NotePlayHandle::updateFrequency() -void NotePlayHandle::processMidiTime( const MidiTime& time ) +void NotePlayHandle::processTimePos( const TimePos& time ) { if( detuning() && time >= songGlobalParentOffset()+pos() ) { diff --git a/src/core/Oscillator.cpp b/src/core/Oscillator.cpp index 1437c789c6a..1909a9c6e4e 100644 --- a/src/core/Oscillator.cpp +++ b/src/core/Oscillator.cpp @@ -316,8 +316,7 @@ inline void Oscillator::recalcPhase() m_phaseOffset = m_ext_phaseOffset; m_phase += m_phaseOffset; } - m_phase = absFraction( m_phase )+2; // make sure we're not running - // negative when doing PM + m_phase = absFraction( m_phase ); } diff --git a/src/core/PathUtil.cpp b/src/core/PathUtil.cpp new file mode 100644 index 00000000000..5881db9f40f --- /dev/null +++ b/src/core/PathUtil.cpp @@ -0,0 +1,153 @@ +#include "PathUtil.h" + +#include +#include +#include + +#include "ConfigManager.h" + +namespace PathUtil +{ + Base relativeBases[] = { Base::ProjectDir, Base::FactorySample, Base::UserSample, Base::UserVST, Base::Preset, + Base::UserLADSPA, Base::DefaultLADSPA, Base::UserSoundfont, Base::DefaultSoundfont, Base::UserGIG, Base::DefaultGIG }; + + QString baseLocation(const Base base) + { + QString loc = ""; + switch (base) + { + case Base::ProjectDir : loc = ConfigManager::inst()->userProjectsDir(); break; + case Base::FactorySample : + { + QDir fsd = QDir(ConfigManager::inst()->factorySamplesDir()); + loc = fsd.absolutePath(); break; + } + case Base::UserSample : loc = ConfigManager::inst()->userSamplesDir(); break; + case Base::UserVST : loc = ConfigManager::inst()->userVstDir(); break; + case Base::Preset : loc = ConfigManager::inst()->userPresetsDir(); break; + case Base::UserLADSPA : loc = ConfigManager::inst()->ladspaDir(); break; + case Base::DefaultLADSPA : loc = ConfigManager::inst()->userLadspaDir(); break; + case Base::UserSoundfont : loc = ConfigManager::inst()->sf2Dir(); break; + case Base::DefaultSoundfont : loc = ConfigManager::inst()->userSf2Dir(); break; + case Base::UserGIG : loc = ConfigManager::inst()->gigDir(); break; + case Base::DefaultGIG : loc = ConfigManager::inst()->userGigDir(); break; + default : return QString(""); + } + return QDir::cleanPath(loc) + "/"; + } + + QDir baseQDir (const Base base) + { + if (base == Base::Absolute) { return QDir::root(); } + return QDir(baseLocation(base)); + } + + QString basePrefix(const Base base) + { + switch (base) + { + case Base::ProjectDir : return QStringLiteral("userprojects:"); + case Base::FactorySample : return QStringLiteral("factorysample:"); + case Base::UserSample : return QStringLiteral("usersample:"); + case Base::UserVST : return QStringLiteral("uservst:"); + case Base::Preset : return QStringLiteral("preset:"); + case Base::UserLADSPA : return QStringLiteral("userladspa:"); + case Base::DefaultLADSPA : return QStringLiteral("defaultladspa:"); + case Base::UserSoundfont : return QStringLiteral("usersoundfont:"); + case Base::DefaultSoundfont : return QStringLiteral("defaultsoundfont:"); + case Base::UserGIG : return QStringLiteral("usergig:"); + case Base::DefaultGIG : return QStringLiteral("defaultgig:"); + default : return QStringLiteral(""); + } + } + + Base baseLookup(const QString & path) + { + for (auto base: relativeBases) + { + QString prefix = basePrefix(base); + if ( path.startsWith(prefix) ) { return base; } + } + return Base::Absolute; + } + + + + + QString stripPrefix(const QString & path) + { + return path.mid( basePrefix(baseLookup(path)).length() ); + } + + QString cleanName(const QString & path) + { + return stripPrefix(QFileInfo(path).baseName()); + } + + + + + QString oldRelativeUpgrade(const QString & input) + { + if (input.isEmpty()) { return input; } + + //Start by assuming that the file is a user sample + Base assumedBase = Base::UserSample; + + //Check if it's a factory sample + QString factoryPath = baseLocation(Base::FactorySample) + input; + QFileInfo factoryInfo(factoryPath); + if (factoryInfo.exists()) { assumedBase = Base::FactorySample; } + + //Check if it's a VST + QString vstPath = baseLocation(Base::UserVST) + input; + QFileInfo vstInfo(vstPath); + if (vstInfo.exists()) { assumedBase = Base::UserVST; } + + //Assume we've found the correct base location, return the full path + return basePrefix(assumedBase) + input; + } + + + + + QString toAbsolute(const QString & input) + { + //First, do no harm to absolute paths + QFileInfo inputFileInfo = QFileInfo(input); + if (inputFileInfo.isAbsolute()) { return input; } + //Next, handle old relative paths with no prefix + QString upgraded = input.contains(":") ? input : oldRelativeUpgrade(input); + + Base base = baseLookup(upgraded); + return baseLocation(base) + upgraded.remove(0, basePrefix(base).length()); + } + + QString relativeOrAbsolute(const QString & input, const Base base) + { + if (input.isEmpty()) { return input; } + QString absolutePath = toAbsolute(input); + if (base == Base::Absolute) { return absolutePath; } + QString relativePath = baseQDir(base).relativeFilePath(absolutePath); + return relativePath.startsWith("..") ? absolutePath : relativePath; + } + + QString toShortestRelative(const QString & input) + { + QFileInfo inputFileInfo = QFileInfo(input); + QString absolutePath = inputFileInfo.isAbsolute() ? input : toAbsolute(input); + + Base shortestBase = Base::Absolute; + QString shortestPath = relativeOrAbsolute(absolutePath, shortestBase); + for (auto base: relativeBases) + { + QString otherPath = relativeOrAbsolute(absolutePath, base); + if (otherPath.length() < shortestPath.length()) + { + shortestBase = base; + shortestPath = otherPath; + } + } + return basePrefix(shortestBase) + relativeOrAbsolute(absolutePath, shortestBase); + } +} diff --git a/src/core/Plugin.cpp b/src/core/Plugin.cpp index 411f6fe5899..f1256654970 100644 --- a/src/core/Plugin.cpp +++ b/src/core/Plugin.cpp @@ -44,7 +44,7 @@ static Plugin::Descriptor dummyPluginDescriptor = { "dummy", "dummy", - QT_TRANSLATE_NOOP( "pluginBrowser", "no description" ), + QT_TRANSLATE_NOOP( "PluginBrowser", "no description" ), "Tobias Doerffel ", 0x0100, Plugin::Undefined, diff --git a/src/core/PluginFactory.cpp b/src/core/PluginFactory.cpp index abf6421229e..16f86a17a4e 100644 --- a/src/core/PluginFactory.cpp +++ b/src/core/PluginFactory.cpp @@ -144,7 +144,12 @@ void PluginFactory::discoverPlugins() QSet files; for (const QString& searchPath : QDir::searchPaths("plugins")) { +#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0)) + auto discoveredPluginList = QDir(searchPath).entryInfoList(nameFilters); + files.unite(QSet(discoveredPluginList.begin(), discoveredPluginList.end())); +#else files.unite(QDir(searchPath).entryInfoList(nameFilters).toSet()); +#endif } // Cheap dependency handling: zynaddsubfx needs ZynAddSubFxCore. By loading diff --git a/src/core/PluginIssue.cpp b/src/core/PluginIssue.cpp index 4a8b2ee5b4e..7d43586f5b6 100644 --- a/src/core/PluginIssue.cpp +++ b/src/core/PluginIssue.cpp @@ -38,6 +38,10 @@ const char *PluginIssue::msgFor(const PluginIssueType &it) return "too many audio input channels"; case tooManyOutputChannels: return "too many audio output channels"; + case tooManyMidiInputChannels: + return "too many MIDI input channels"; + case tooManyMidiOutputChannels: + return "too many MIDI output channels"; case noOutputChannel: return "no audio output channel"; case portHasNoDef: @@ -46,10 +50,22 @@ const char *PluginIssue::msgFor(const PluginIssueType &it) return "port is missing min value"; case portHasNoMax: return "port is missing max value"; + case minGreaterMax: + return "port minimum is greater than maximum"; + case defaultValueNotInRange: + return "default value is not in range [min, max]"; + case logScaleMinMissing: + return "logscale requires minimum value"; + case logScaleMaxMissing: + return "logscale requires maximum value"; + case logScaleMinMaxDifferentSigns: + return "logscale with min < 0 < max"; case featureNotSupported: return "required feature not supported"; case badPortType: return "unsupported port type"; + case blacklisted: + return "blacklisted plugin"; case noIssue: return nullptr; } @@ -59,6 +75,24 @@ const char *PluginIssue::msgFor(const PluginIssueType &it) +bool PluginIssue::operator==(const PluginIssue &other) const +{ + return (m_issueType == other.m_issueType) && (m_info == other.m_info); +} + + + + +bool PluginIssue::operator<(const PluginIssue &other) const +{ + return (m_issueType != other.m_issueType) + ? m_issueType < other.m_issueType + : m_info < other.m_info; +} + + + + QDebug operator<<(QDebug stream, const PluginIssue &iss) { stream << PluginIssue::msgFor(iss.m_issueType); diff --git a/src/core/ProjectRenderer.cpp b/src/core/ProjectRenderer.cpp index 19bdf4be806..0616a925278 100644 --- a/src/core/ProjectRenderer.cpp +++ b/src/core/ProjectRenderer.cpp @@ -181,7 +181,6 @@ void ProjectRenderer::run() PerfLogTimer perfLog("Project Render"); Engine::getSong()->startExport(); - Engine::getSong()->updateLength(); // Skip first empty buffer. Engine::mixer()->nextBuffer(); diff --git a/src/core/ProjectVersion.cpp b/src/core/ProjectVersion.cpp index ea97a6fec7d..6f3dcddbeb1 100644 --- a/src/core/ProjectVersion.cpp +++ b/src/core/ProjectVersion.cpp @@ -27,123 +27,105 @@ #include "ProjectVersion.h" -int parseMajor(QString & version) { - return version.section( '.', 0, 0 ).toInt(); -} - - - - -int parseMinor(QString & version) { - return version.section( '.', 1, 1 ).toInt(); -} - - - - -int parseRelease(QString & version) { - return version.section( '.', 2, 2 ).section( '-', 0, 0 ).toInt(); -} - - - - -QString parseStage(QString & version) { - return version.section( '.', 2, 2 ).section( '-', 1 ); -} - - - - -int parseBuild(QString & version) { - return version.section( '.', 3 ).toInt(); -} - ProjectVersion::ProjectVersion(QString version, CompareType c) : m_version(version), - m_major(parseMajor(m_version)), - m_minor(parseMinor(m_version)), - m_release(parseRelease(m_version)), - m_stage(parseStage(m_version)), - m_build(parseBuild(m_version)), m_compareType(c) { + // Version numbers may have build data, prefixed with a '+', + // but this mustn't affect version precedence in comparisons + QString metadataStripped = version.split("+").first(); + // They must have an obligatory initial segement, and may have + // optional identifiers prefaced by a '-'. Both parts affect precedence + QString obligatorySegment = metadataStripped.section('-', 0, 0); + QString prereleaseSegment = metadataStripped.section('-', 1); + + // The obligatory segment consists of three identifiers: MAJOR.MINOR.PATCH + QStringList mainVersion = obligatorySegment.split("."); + // HACK: Pad invalid versions in order to prevent crashes + while (mainVersion.size() < 3){ mainVersion.append("0"); } + m_major = mainVersion.at(0).toInt(); + m_minor = mainVersion.at(1).toInt(); + m_patch = mainVersion.at(2).toInt(); + + // Any # of optional pre-release identifiers may follow, separated by '.'s + if (!prereleaseSegment.isEmpty()){ m_labels = prereleaseSegment.split("."); } + + // HACK: Handle old (1.2.2 and earlier), non-standard versions of the form + // MAJOR.MINOR.PATCH.COMMITS, used for non-release builds from source. + if (mainVersion.size() >= 4 && m_major <= 1 && m_minor <= 2 && m_patch <= 2){ + // Drop the standard version identifiers. erase(a, b) removes [a,b) + mainVersion.erase(mainVersion.begin(), mainVersion.begin() + 3); + // Prepend the remaining identifiers as prerelease versions + m_labels = mainVersion + m_labels; + // Bump the patch version. x.y.z-a < x.y.z, but we want x.y.z.a > x.y.z + m_patch += 1; + } } -ProjectVersion::ProjectVersion(const char* version, CompareType c) : - m_version(QString(version)), - m_major(parseMajor(m_version)), - m_minor(parseMinor(m_version)), - m_release(parseRelease(m_version)), - m_stage(parseStage(m_version)), - m_build(parseBuild(m_version)), - m_compareType(c) +ProjectVersion::ProjectVersion(const char* version, CompareType c) : ProjectVersion(QString(version), c) { } +//! @param c Determines the number of identifiers to check when comparing int ProjectVersion::compare(const ProjectVersion & a, const ProjectVersion & b, CompareType c) { - if(a.getMajor() != b.getMajor()) - { - return a.getMajor() - b.getMajor(); - } - if(c == Major) - { - return 0; - } - - if(a.getMinor() != b.getMinor()) - { - return a.getMinor() - b.getMinor(); - } - if(c == Minor) - { - return 0; + // How many identifiers to compare before we consider the versions equal + const int limit = static_cast(c); + + // Use the value of limit to zero out identifiers we don't care about + int aMaj = 0, bMaj = 0, aMin = 0, bMin = 0, aPat = 0, bPat = 0; + if (limit >= 1){ aMaj = a.getMajor(); bMaj = b.getMajor(); } + if (limit >= 2){ aMin = a.getMinor(); bMin = b.getMinor(); } + if (limit >= 3){ aPat = a.getPatch(); bPat = b.getPatch(); } + + // Then we can compare as if we care about every identifier + if(aMaj != bMaj){ return aMaj - bMaj; } + if(aMin != bMin){ return aMin - bMin; } + if(aPat != bPat){ return aPat - bPat; } + + // Decide how many optional identifiers we care about + const int maxLabels = qMax(0, limit - 3); + const auto aLabels = a.getLabels().mid(0, maxLabels); + const auto bLabels = b.getLabels().mid(0, maxLabels); + + // We can only compare identifiers if both versions have them + const int commonLabels = qMin(aLabels.size(), bLabels.size()); + // If one version has optional labels and the other doesn't, + // the one without them is bigger + if (commonLabels == 0){ return bLabels.size() - aLabels.size(); } + + // Otherwise, compare as many labels as we can + for (int i = 0; i < commonLabels; i++){ + const QString& labelA = aLabels.at(i); + const QString& labelB = bLabels.at(i); + // If both labels are the same, skip + if (labelA == labelB){ continue; } + // Numeric and non-numeric identifiers compare differently + bool aIsNumeric = false, bIsNumeric = false; + const int numA = labelA.toInt(&aIsNumeric); + const int numB = labelB.toInt(&bIsNumeric); + // toInt reads '-x' as a negative number, semver says it's non-numeric + aIsNumeric &= !labelA.startsWith("-"); + bIsNumeric &= !labelB.startsWith("-"); + // If only one identifier is numeric, that one is smaller + if (aIsNumeric != bIsNumeric){ return aIsNumeric ? -1 : 1; } + // If both are numeric, compare as numbers + if (aIsNumeric && bIsNumeric){ return numA - numB; } + // Otherwise, compare lexically + return labelA.compare(labelB); } - if(a.getRelease() != b.getRelease()) - { - return a.getRelease() - b.getRelease(); - } - if(c == Release) - { - return 0; - } - - if(!(a.getStage().isEmpty() && b.getStage().isEmpty())) - { - // make sure 0.x.y > 0.x.y-alpha - if(a.getStage().isEmpty()) - { - return 1; - } - if(b.getStage().isEmpty()) - { - return -1; - } - - // 0.x.y-beta > 0.x.y-alpha - int cmp = QString::compare(a.getStage(), b.getStage()); - if(cmp) - { - return cmp; - } - } - if(c == Stage) - { - return 0; - } - - return a.getBuild() - b.getBuild(); + // If everything else matches, the version with more labels is bigger + return aLabels.size() - bLabels.size(); } @@ -153,6 +135,3 @@ int ProjectVersion::compare(ProjectVersion v1, ProjectVersion v2) { return compare(v1, v2, std::min(v1.getCompareType(), v2.getCompareType())); } - - - diff --git a/src/core/RenderManager.cpp b/src/core/RenderManager.cpp index 785aa9fb16d..62b2788888c 100644 --- a/src/core/RenderManager.cpp +++ b/src/core/RenderManager.cpp @@ -29,7 +29,6 @@ #include "Song.h" #include "BBTrackContainer.h" #include "BBTrack.h" -#include "stdshims.h" RenderManager::RenderManager( @@ -80,9 +79,9 @@ void RenderManager::renderNextTrack() m_tracksToRender.pop_back(); // mute everything but the track we are about to render - for( auto it = m_unmuted.begin(); it != m_unmuted.end(); ++it ) + for (auto track : m_unmuted) { - (*it)->setMuted( (*it) != renderTrack ); + track->setMuted(track != renderTrack); } // for multi-render, prefix each output file with a different number @@ -140,7 +139,7 @@ void RenderManager::renderProject() void RenderManager::render(QString outputPath) { - m_activeRenderer = make_unique( + m_activeRenderer = std::make_unique( m_qualitySettings, m_outputSettings, m_format, diff --git a/src/core/SampleBuffer.cpp b/src/core/SampleBuffer.cpp index d0c39b13aa8..102b7e1d36d 100644 --- a/src/core/SampleBuffer.cpp +++ b/src/core/SampleBuffer.cpp @@ -24,6 +24,7 @@ #include "SampleBuffer.h" +#include #include #include @@ -55,44 +56,43 @@ #include "Engine.h" #include "GuiApplication.h" #include "Mixer.h" +#include "PathUtil.h" #include "FileDialog.h" - SampleBuffer::SampleBuffer() : - m_audioFile( "" ), - m_origData( NULL ), - m_origFrames( 0 ), - m_data( NULL ), - m_frames( 0 ), - m_startFrame( 0 ), - m_endFrame( 0 ), - m_loopStartFrame( 0 ), - m_loopEndFrame( 0 ), - m_amplification( 1.0f ), - m_reversed( false ), - m_frequency( BaseFreq ), - m_sampleRate( mixerSampleRate () ) + m_audioFile(""), + m_origData(nullptr), + m_origFrames(0), + m_data(nullptr), + m_frames(0), + m_startFrame(0), + m_endFrame(0), + m_loopStartFrame(0), + m_loopEndFrame(0), + m_amplification(1.0f), + m_reversed(false), + m_frequency(BaseFreq), + m_sampleRate(mixerSampleRate()) { - connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) ); + connect(Engine::mixer(), SIGNAL(sampleRateChanged()), this, SLOT(sampleRateChanged())); update(); } -SampleBuffer::SampleBuffer( const QString & _audio_file, - bool _is_base64_data ) +SampleBuffer::SampleBuffer(const QString & audioFile, bool isBase64Data) : SampleBuffer() { - if( _is_base64_data ) + if (isBase64Data) { - loadFromBase64( _audio_file ); + loadFromBase64(audioFile); } else { - m_audioFile = _audio_file; + m_audioFile = audioFile; update(); } } @@ -100,14 +100,14 @@ SampleBuffer::SampleBuffer( const QString & _audio_file, -SampleBuffer::SampleBuffer( const sampleFrame * _data, const f_cnt_t _frames ) +SampleBuffer::SampleBuffer(const sampleFrame * data, const f_cnt_t frames) : SampleBuffer() { - if( _frames > 0 ) + if (frames > 0) { - m_origData = MM_ALLOC( sampleFrame, _frames ); - memcpy( m_origData, _data, _frames * BYTES_PER_FRAME ); - m_origFrames = _frames; + m_origData = MM_ALLOC(sampleFrame, frames); + memcpy(m_origData, data, frames * BYTES_PER_FRAME); + m_origFrames = frames; update(); } } @@ -115,14 +115,14 @@ SampleBuffer::SampleBuffer( const sampleFrame * _data, const f_cnt_t _frames ) -SampleBuffer::SampleBuffer( const f_cnt_t _frames ) +SampleBuffer::SampleBuffer(const f_cnt_t frames) : SampleBuffer() { - if( _frames > 0 ) + if (frames > 0) { - m_origData = MM_ALLOC( sampleFrame, _frames ); - memset( m_origData, 0, _frames * BYTES_PER_FRAME ); - m_origFrames = _frames; + m_origData = MM_ALLOC(sampleFrame, frames); + memset(m_origData, 0, frames * BYTES_PER_FRAME); + m_origFrames = frames; update(); } } @@ -132,15 +132,15 @@ SampleBuffer::SampleBuffer( const f_cnt_t _frames ) SampleBuffer::~SampleBuffer() { - MM_FREE( m_origData ); - MM_FREE( m_data ); + MM_FREE(m_origData); + MM_FREE(m_data); } void SampleBuffer::sampleRateChanged() { - update( true ); + update(true); } sample_rate_t SampleBuffer::mixerSampleRate() @@ -149,14 +149,14 @@ sample_rate_t SampleBuffer::mixerSampleRate() } -void SampleBuffer::update( bool _keep_settings ) +void SampleBuffer::update(bool keepSettings) { - const bool lock = ( m_data != NULL ); - if( lock ) + const bool lock = (m_data != nullptr); + if (lock) { Engine::mixer()->requestChangeInModel(); m_varLock.lockForWrite(); - MM_FREE( m_data ); + MM_FREE(m_data); } // File size and sample length limits @@ -164,30 +164,30 @@ void SampleBuffer::update( bool _keep_settings ) const int sampleLengthMax = 90; // Minutes bool fileLoadError = false; - if( m_audioFile.isEmpty() && m_origData != NULL && m_origFrames > 0 ) + if (m_audioFile.isEmpty() && m_origData != nullptr && m_origFrames > 0) { // TODO: reverse- and amplification-property is not covered // by following code... - m_data = MM_ALLOC( sampleFrame, m_origFrames ); - memcpy( m_data, m_origData, m_origFrames * BYTES_PER_FRAME ); - if( _keep_settings == false ) + m_data = MM_ALLOC(sampleFrame, m_origFrames); + memcpy(m_data, m_origData, m_origFrames * BYTES_PER_FRAME); + if (keepSettings == false) { m_frames = m_origFrames; m_loopStartFrame = m_startFrame = 0; m_loopEndFrame = m_endFrame = m_frames; } } - else if( !m_audioFile.isEmpty() ) + else if (!m_audioFile.isEmpty()) { - QString file = tryToMakeAbsolute( m_audioFile ); - int_sample_t * buf = NULL; - sample_t * fbuf = NULL; + QString file = PathUtil::toAbsolute(m_audioFile); + int_sample_t * buf = nullptr; + sample_t * fbuf = nullptr; ch_cnt_t channels = DEFAULT_CHANNELS; sample_rate_t samplerate = mixerSampleRate(); m_frames = 0; - const QFileInfo fileInfo( file ); - if( fileInfo.size() > fileSizeMax * 1024 * 1024 ) + const QFileInfo fileInfo(file); + if (fileInfo.size() > fileSizeMax * 1024 * 1024) { fileLoadError = true; } @@ -195,80 +195,76 @@ void SampleBuffer::update( bool _keep_settings ) { // Use QFile to handle unicode file names on Windows QFile f(file); - f.open(QIODevice::ReadOnly); - SNDFILE * snd_file; - SF_INFO sf_info; - sf_info.format = 0; - if( ( snd_file = sf_open_fd( f.handle(), SFM_READ, &sf_info, false ) ) != NULL ) + SNDFILE * sndFile; + SF_INFO sfInfo; + sfInfo.format = 0; + if (f.open(QIODevice::ReadOnly) && (sndFile = sf_open_fd(f.handle(), SFM_READ, &sfInfo, false))) { - f_cnt_t frames = sf_info.frames; - int rate = sf_info.samplerate; - if( frames / rate > sampleLengthMax * 60 ) + f_cnt_t frames = sfInfo.frames; + int rate = sfInfo.samplerate; + if (frames / rate > sampleLengthMax * 60) { fileLoadError = true; } - sf_close( snd_file ); + sf_close(sndFile); } f.close(); } - if( !fileLoadError ) + if (!fileLoadError) { #ifdef LMMS_HAVE_OGGVORBIS // workaround for a bug in libsndfile or our libsndfile decoder // causing some OGG files to be distorted -> try with OGG Vorbis // decoder first if filename extension matches "ogg" - if( m_frames == 0 && fileInfo.suffix() == "ogg" ) + if (m_frames == 0 && fileInfo.suffix() == "ogg") { - m_frames = decodeSampleOGGVorbis( file, buf, channels, samplerate ); + m_frames = decodeSampleOGGVorbis(file, buf, channels, samplerate); } #endif - if( m_frames == 0 ) + if (m_frames == 0) { - m_frames = decodeSampleSF( file, fbuf, channels, - samplerate ); + m_frames = decodeSampleSF(file, fbuf, channels, samplerate); } #ifdef LMMS_HAVE_OGGVORBIS - if( m_frames == 0 ) + if (m_frames == 0) { - m_frames = decodeSampleOGGVorbis( file, buf, channels, - samplerate ); + m_frames = decodeSampleOGGVorbis(file, buf, channels, samplerate); } #endif - if( m_frames == 0 ) + if (m_frames == 0) { - m_frames = decodeSampleDS( file, buf, channels, - samplerate ); + m_frames = decodeSampleDS(file, buf, channels, samplerate); } } - if ( m_frames == 0 || fileLoadError ) // if still no frames, bail + if (m_frames == 0 || fileLoadError) // if still no frames, bail { // sample couldn't be decoded, create buffer containing // one sample-frame - m_data = MM_ALLOC( sampleFrame, 1 ); - memset( m_data, 0, sizeof( *m_data ) ); + m_data = MM_ALLOC(sampleFrame, 1); + memset(m_data, 0, sizeof(*m_data)); m_frames = 1; m_loopStartFrame = m_startFrame = 0; m_loopEndFrame = m_endFrame = 1; } else // otherwise normalize sample rate { - normalizeSampleRate( samplerate, _keep_settings ); + normalizeSampleRate(samplerate, keepSettings); } } else { // neither an audio-file nor a buffer to copy from, so create // buffer containing one sample-frame - m_data = MM_ALLOC( sampleFrame, 1 ); - memset( m_data, 0, sizeof( *m_data ) ); + m_data = MM_ALLOC(sampleFrame, 1); + memset(m_data, 0, sizeof(*m_data)); m_frames = 1; m_loopStartFrame = m_startFrame = 0; m_loopEndFrame = m_endFrame = 1; } - if( lock ) + if (lock) { m_varLock.unlock(); Engine::mixer()->doneChangeInModel(); @@ -276,130 +272,103 @@ void SampleBuffer::update( bool _keep_settings ) emit sampleUpdated(); - if( fileLoadError ) + if (fileLoadError) { - QString title = tr( "Fail to open file" ); - QString message = tr( "Audio files are limited to %1 MB " + QString title = tr("Fail to open file"); + QString message = tr("Audio files are limited to %1 MB " "in size and %2 minutes of playing time" - ).arg( fileSizeMax ).arg( sampleLengthMax ); - if( gui ) + ).arg(fileSizeMax).arg(sampleLengthMax); + if (gui) { - QMessageBox::information( NULL, - title, message, QMessageBox::Ok ); + QMessageBox::information(nullptr, + title, message, QMessageBox::Ok); } else { - fprintf( stderr, "%s\n", message.toUtf8().constData() ); + fprintf(stderr, "%s\n", message.toUtf8().constData()); } } } -void SampleBuffer::convertIntToFloat ( int_sample_t * & _ibuf, f_cnt_t _frames, int _channels) +void SampleBuffer::convertIntToFloat( + int_sample_t * & ibuf, + f_cnt_t frames, + int channels +) { - // following code transforms int-samples into - // float-samples and does amplifying & reversing + // following code transforms int-samples into float-samples and does amplifying & reversing const float fac = 1 / OUTPUT_SAMPLE_MULTIPLIER; - m_data = MM_ALLOC( sampleFrame, _frames ); - const int ch = ( _channels > 1 ) ? 1 : 0; + m_data = MM_ALLOC(sampleFrame, frames); + const int ch = (channels > 1) ? 1 : 0; - // if reversing is on, we also reverse when - // scaling - if( m_reversed ) + // if reversing is on, we also reverse when scaling + bool isReversed = m_reversed; + int idx = isReversed ? (frames - 1) * channels : 0; + for (f_cnt_t frame = 0; frame < frames; ++frame) { - int idx = ( _frames - 1 ) * _channels; - for( f_cnt_t frame = 0; frame < _frames; - ++frame ) - { - m_data[frame][0] = _ibuf[idx+0] * fac; - m_data[frame][1] = _ibuf[idx+ch] * fac; - idx -= _channels; - } - } - else - { - int idx = 0; - for( f_cnt_t frame = 0; frame < _frames; - ++frame ) - { - m_data[frame][0] = _ibuf[idx+0] * fac; - m_data[frame][1] = _ibuf[idx+ch] * fac; - idx += _channels; - } + m_data[frame][0] = ibuf[idx+0] * fac; + m_data[frame][1] = ibuf[idx+ch] * fac; + idx += isReversed ? -channels : channels; } - delete[] _ibuf; + delete[] ibuf; } -void SampleBuffer::directFloatWrite ( sample_t * & _fbuf, f_cnt_t _frames, int _channels) - +void SampleBuffer::directFloatWrite( + sample_t * & fbuf, + f_cnt_t frames, + int channels +) { - m_data = MM_ALLOC( sampleFrame, _frames ); - const int ch = ( _channels > 1 ) ? 1 : 0; + m_data = MM_ALLOC(sampleFrame, frames); + const int ch = (channels > 1) ? 1 : 0; - // if reversing is on, we also reverse when - // scaling - if( m_reversed ) + // if reversing is on, we also reverse when scaling + bool isReversed = m_reversed; + int idx = isReversed ? (frames - 1) * channels : 0; + for (f_cnt_t frame = 0; frame < frames; ++frame) { - int idx = ( _frames - 1 ) * _channels; - for( f_cnt_t frame = 0; frame < _frames; - ++frame ) - { - m_data[frame][0] = _fbuf[idx+0]; - m_data[frame][1] = _fbuf[idx+ch]; - idx -= _channels; - } - } - else - { - int idx = 0; - for( f_cnt_t frame = 0; frame < _frames; - ++frame ) - { - m_data[frame][0] = _fbuf[idx+0]; - m_data[frame][1] = _fbuf[idx+ch]; - idx += _channels; - } + m_data[frame][0] = fbuf[idx+0]; + m_data[frame][1] = fbuf[idx+ch]; + idx += isReversed ? -channels : channels; } - delete[] _fbuf; + delete[] fbuf; } -void SampleBuffer::normalizeSampleRate( const sample_rate_t _src_sr, - bool _keep_settings ) +void SampleBuffer::normalizeSampleRate(const sample_rate_t srcSR, bool keepSettings) { - const sample_rate_t old_rate = m_sampleRate; + const sample_rate_t oldRate = m_sampleRate; // do samplerate-conversion to our default-samplerate - if( _src_sr != mixerSampleRate() ) + if (srcSR != mixerSampleRate()) { - SampleBuffer * resampled = resample( _src_sr, - mixerSampleRate() ); + SampleBuffer * resampled = resample(srcSR, mixerSampleRate()); m_sampleRate = mixerSampleRate(); - MM_FREE( m_data ); + MM_FREE(m_data); m_frames = resampled->frames(); - m_data = MM_ALLOC( sampleFrame, m_frames ); - memcpy( m_data, resampled->data(), m_frames * - sizeof( sampleFrame ) ); + m_data = MM_ALLOC(sampleFrame, m_frames); + memcpy(m_data, resampled->data(), m_frames * sizeof(sampleFrame)); delete resampled; } - if( _keep_settings == false ) + if (keepSettings == false) { // update frame-variables m_loopStartFrame = m_startFrame = 0; m_loopEndFrame = m_endFrame = m_frames; } - else if( old_rate != mixerSampleRate() ) + else if (oldRate != mixerSampleRate()) { - auto old_rate_to_new_rate_ratio = static_cast(mixerSampleRate()) / old_rate; + auto oldRateToNewRateRatio = static_cast(mixerSampleRate()) / oldRate; - 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_startFrame = qBound(0, f_cnt_t(m_startFrame * oldRateToNewRateRatio), m_frames); + m_endFrame = qBound(m_startFrame, f_cnt_t(m_endFrame * oldRateToNewRateRatio), m_frames); + m_loopStartFrame = qBound(0, f_cnt_t(m_loopStartFrame * oldRateToNewRateRatio), m_frames); + m_loopEndFrame = qBound(m_loopStartFrame, f_cnt_t(m_loopEndFrame * oldRateToNewRateRatio), m_frames); m_sampleRate = mixerSampleRate(); } } @@ -407,54 +376,55 @@ void SampleBuffer::normalizeSampleRate( const sample_rate_t _src_sr, -f_cnt_t SampleBuffer::decodeSampleSF(QString _f, - sample_t * & _buf, - ch_cnt_t & _channels, - sample_rate_t & _samplerate ) +f_cnt_t SampleBuffer::decodeSampleSF( + QString fileName, + sample_t * & buf, + ch_cnt_t & channels, + sample_rate_t & samplerate +) { - SNDFILE * snd_file; - SF_INFO sf_info; - sf_info.format = 0; + SNDFILE * sndFile; + SF_INFO sfInfo; + sfInfo.format = 0; f_cnt_t frames = 0; - bool sf_rr = false; + sf_count_t sfFramesRead; // Use QFile to handle unicode file names on Windows - QFile f(_f); - f.open(QIODevice::ReadOnly); - if( ( snd_file = sf_open_fd( f.handle(), SFM_READ, &sf_info, false ) ) != NULL ) + QFile f(fileName); + if (f.open(QIODevice::ReadOnly) && (sndFile = sf_open_fd(f.handle(), SFM_READ, &sfInfo, false))) { - frames = sf_info.frames; + frames = sfInfo.frames; - _buf = new sample_t[sf_info.channels * frames]; - sf_rr = sf_read_float( snd_file, _buf, sf_info.channels * frames ); + buf = new sample_t[sfInfo.channels * frames]; + sfFramesRead = sf_read_float(sndFile, buf, sfInfo.channels * frames); - if( sf_rr < sf_info.channels * frames ) + if (sfFramesRead < sfInfo.channels * frames) { #ifdef DEBUG_LMMS - qDebug( "SampleBuffer::decodeSampleSF(): could not read" - " sample %s: %s", _f, sf_strerror( NULL ) ); + qDebug("SampleBuffer::decodeSampleSF(): could not read" + " sample %s: %s", fileName, sf_strerror(nullptr)); #endif } - _channels = sf_info.channels; - _samplerate = sf_info.samplerate; + channels = sfInfo.channels; + samplerate = sfInfo.samplerate; - sf_close( snd_file ); + sf_close(sndFile); } else { #ifdef DEBUG_LMMS - qDebug( "SampleBuffer::decodeSampleSF(): could not load " - "sample %s: %s", _f, sf_strerror( NULL ) ); + qDebug("SampleBuffer::decodeSampleSF(): could not load " + "sample %s: %s", fileName, sf_strerror(nullptr)); #endif } f.close(); //write down either directly or convert i->f depending on file type - if ( frames > 0 && _buf != NULL ) + if (frames > 0 && buf != nullptr) { - directFloatWrite ( _buf, frames, _channels); + directFloatWrite(buf, frames, channels); } return frames; @@ -467,30 +437,29 @@ f_cnt_t SampleBuffer::decodeSampleSF(QString _f, // callback-functions for reading ogg-file -size_t qfileReadCallback( void * _ptr, size_t _size, size_t _n, void * _udata ) +size_t qfileReadCallback(void * ptr, size_t size, size_t n, void * udata ) { - return static_cast( _udata )->read( (char*) _ptr, - _size * _n ); + return static_cast(udata)->read((char*) ptr, size * n); } -int qfileSeekCallback( void * _udata, ogg_int64_t _offset, int _whence ) +int qfileSeekCallback(void * udata, ogg_int64_t offset, int whence) { - QFile * f = static_cast( _udata ); + QFile * f = static_cast(udata); - if( _whence == SEEK_CUR ) + if (whence == SEEK_CUR) { - f->seek( f->pos() + _offset ); + f->seek(f->pos() + offset); } - else if( _whence == SEEK_END ) + else if (whence == SEEK_END) { - f->seek( f->size() + _offset ); + f->seek(f->size() + offset); } else { - f->seek( _offset ); + f->seek(offset); } return 0; } @@ -498,27 +467,29 @@ int qfileSeekCallback( void * _udata, ogg_int64_t _offset, int _whence ) -int qfileCloseCallback( void * _udata ) +int qfileCloseCallback(void * udata) { - delete static_cast( _udata ); + delete static_cast(udata); return 0; } -long qfileTellCallback( void * _udata ) +long qfileTellCallback(void * udata) { - return static_cast( _udata )->pos(); + return static_cast(udata)->pos(); } -f_cnt_t SampleBuffer::decodeSampleOGGVorbis( QString _f, - int_sample_t * & _buf, - ch_cnt_t & _channels, - sample_rate_t & _samplerate ) +f_cnt_t SampleBuffer::decodeSampleOGGVorbis( + QString fileName, + int_sample_t * & buf, + ch_cnt_t & channels, + sample_rate_t & samplerate +) { static ov_callbacks callbacks = { @@ -532,76 +503,80 @@ f_cnt_t SampleBuffer::decodeSampleOGGVorbis( QString _f, f_cnt_t frames = 0; - QFile * f = new QFile( _f ); - if( f->open( QFile::ReadOnly ) == false ) + QFile * f = new QFile(fileName); + if (f->open(QFile::ReadOnly) == false) { delete f; return 0; } - int err = ov_open_callbacks( f, &vf, NULL, 0, callbacks ); + int err = ov_open_callbacks(f, &vf, nullptr, 0, callbacks); - if( err < 0 ) + if (err < 0) { - switch( err ) + switch (err) { case OV_EREAD: - printf( "SampleBuffer::decodeSampleOGGVorbis():" - " media read error\n" ); + printf("SampleBuffer::decodeSampleOGGVorbis():" + " media read error\n"); break; case OV_ENOTVORBIS: -/* printf( "SampleBuffer::decodeSampleOGGVorbis():" - " not an Ogg Vorbis file\n" );*/ + printf("SampleBuffer::decodeSampleOGGVorbis():" + " not an Ogg Vorbis file\n"); break; case OV_EVERSION: - printf( "SampleBuffer::decodeSampleOGGVorbis():" - " vorbis version mismatch\n" ); + printf("SampleBuffer::decodeSampleOGGVorbis():" + " vorbis version mismatch\n"); break; case OV_EBADHEADER: - printf( "SampleBuffer::decodeSampleOGGVorbis():" - " invalid Vorbis bitstream header\n" ); + printf("SampleBuffer::decodeSampleOGGVorbis():" + " invalid Vorbis bitstream header\n"); break; case OV_EFAULT: - printf( "SampleBuffer::decodeSampleOgg(): " - "internal logic fault\n" ); + printf("SampleBuffer::decodeSampleOgg(): " + "internal logic fault\n"); break; } delete f; return 0; } - ov_pcm_seek( &vf, 0 ); + ov_pcm_seek(&vf, 0); - _channels = ov_info( &vf, -1 )->channels; - _samplerate = ov_info( &vf, -1 )->rate; + channels = ov_info(&vf, -1)->channels; + samplerate = ov_info(&vf, -1)->rate; - ogg_int64_t total = ov_pcm_total( &vf, -1 ); + ogg_int64_t total = ov_pcm_total(&vf, -1); - _buf = new int_sample_t[total * _channels]; + buf = new int_sample_t[total * channels]; int bitstream = 0; - long bytes_read = 0; + long bytesRead = 0; do { - bytes_read = ov_read( &vf, (char *) &_buf[frames * _channels], - ( total - frames ) * _channels * - BYTES_PER_INT_SAMPLE, - isLittleEndian() ? 0 : 1, - BYTES_PER_INT_SAMPLE, 1, &bitstream ); - if( bytes_read < 0 ) + bytesRead = ov_read(&vf, + (char *) &buf[frames * channels], + (total - frames) * channels * BYTES_PER_INT_SAMPLE, + isLittleEndian() ? 0 : 1, + BYTES_PER_INT_SAMPLE, + 1, + &bitstream + ); + + if (bytesRead < 0) { break; } - frames += bytes_read / ( _channels * BYTES_PER_INT_SAMPLE ); + frames += bytesRead / (channels * BYTES_PER_INT_SAMPLE); } - while( bytes_read != 0 && bitstream == 0 ); + while (bytesRead != 0 && bitstream == 0); - ov_clear( &vf ); - // if buffer isn't empty, convert it to float and write it down + ov_clear(&vf); - if ( frames > 0 && _buf != NULL ) + // if buffer isn't empty, convert it to float and write it down + if (frames > 0 && buf != nullptr) { - convertIntToFloat ( _buf, frames, _channels); + convertIntToFloat(buf, frames, channels); } return frames; @@ -611,17 +586,19 @@ f_cnt_t SampleBuffer::decodeSampleOGGVorbis( QString _f, -f_cnt_t SampleBuffer::decodeSampleDS( QString _f, - int_sample_t * & _buf, - ch_cnt_t & _channels, - sample_rate_t & _samplerate ) +f_cnt_t SampleBuffer::decodeSampleDS( + QString fileName, + int_sample_t * & buf, + ch_cnt_t & channels, + sample_rate_t & samplerate +) { DrumSynth ds; - f_cnt_t frames = ds.GetDSFileSamples( _f, _buf, _channels, _samplerate ); + f_cnt_t frames = ds.GetDSFileSamples(fileName, buf, channels, samplerate); - if ( frames > 0 && _buf != NULL ) + if (frames > 0 && buf != nullptr) { - convertIntToFloat ( _buf, frames, _channels); + convertIntToFloat(buf, frames, channels); } return frames; @@ -631,112 +608,114 @@ f_cnt_t SampleBuffer::decodeSampleDS( QString _f, -bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, - const fpp_t _frames, - const float _freq, - const LoopMode _loopmode ) +bool SampleBuffer::play( + sampleFrame * ab, + handleState * state, + const fpp_t frames, + const float freq, + const LoopMode loopMode +) { f_cnt_t startFrame = m_startFrame; f_cnt_t endFrame = m_endFrame; f_cnt_t loopStartFrame = m_loopStartFrame; f_cnt_t loopEndFrame = m_loopEndFrame; - if( endFrame == 0 || _frames == 0 ) + if (endFrame == 0 || frames == 0) { return false; } // variable for determining if we should currently be playing backwards in a ping-pong loop - bool is_backwards = _state->isBackwards(); + bool isBackwards = state->isBackwards(); - const double freq_factor = (double) _freq / (double) m_frequency * + const double freqFactor = (double) freq / (double) m_frequency * m_sampleRate / Engine::mixer()->processingSampleRate(); // calculate how many frames we have in requested pitch - const f_cnt_t total_frames_for_current_pitch = static_cast( ( - endFrame - startFrame ) / - freq_factor ); + const f_cnt_t totalFramesForCurrentPitch = static_cast( + (endFrame - startFrame) / freqFactor + ); - if( total_frames_for_current_pitch == 0 ) + if (totalFramesForCurrentPitch == 0) { return false; } // this holds the index of the first frame to play - f_cnt_t play_frame = qMax(_state->m_frameIndex, startFrame); + f_cnt_t playFrame = qMax(state->m_frameIndex, startFrame); - if( _loopmode == LoopOff ) + if (loopMode == LoopOff) { - if( play_frame >= endFrame || ( endFrame - play_frame ) / freq_factor == 0 ) + if (playFrame >= endFrame || (endFrame - playFrame) / freqFactor == 0) { // the sample is done being played return false; } } - else if( _loopmode == LoopOn ) + else if (loopMode == LoopOn) { - play_frame = getLoopedIndex( play_frame, loopStartFrame, loopEndFrame ); + playFrame = getLoopedIndex(playFrame, loopStartFrame, loopEndFrame); } else { - play_frame = getPingPongIndex( play_frame, loopStartFrame, loopEndFrame ); + playFrame = getPingPongIndex(playFrame, loopStartFrame, loopEndFrame); } - f_cnt_t fragment_size = (f_cnt_t)( _frames * freq_factor ) + MARGIN[ _state->interpolationMode() ]; + f_cnt_t fragmentSize = (f_cnt_t)(frames * freqFactor) + MARGIN[state->interpolationMode()]; - sampleFrame * tmp = NULL; + sampleFrame * tmp = nullptr; // check whether we have to change pitch... - if( freq_factor != 1.0 || _state->m_varyingPitch ) + if (freqFactor != 1.0 || state->m_varyingPitch) { - SRC_DATA src_data; + SRC_DATA srcData; // Generate output - src_data.data_in = - getSampleFragment( play_frame, fragment_size, _loopmode, &tmp, &is_backwards, - loopStartFrame, loopEndFrame, endFrame )[0]; - src_data.data_out = _ab[0]; - src_data.input_frames = fragment_size; - src_data.output_frames = _frames; - src_data.src_ratio = 1.0 / freq_factor; - src_data.end_of_input = 0; - int error = src_process( _state->m_resamplingData, - &src_data ); - if( error ) + srcData.data_in = + getSampleFragment(playFrame, fragmentSize, loopMode, &tmp, &isBackwards, + loopStartFrame, loopEndFrame, endFrame )->data(); + srcData.data_out = ab->data(); + srcData.input_frames = fragmentSize; + srcData.output_frames = frames; + srcData.src_ratio = 1.0 / freqFactor; + srcData.end_of_input = 0; + int error = src_process(state->m_resamplingData, &srcData); + if (error) { - printf( "SampleBuffer: error while resampling: %s\n", - src_strerror( error ) ); + printf("SampleBuffer: error while resampling: %s\n", + src_strerror(error)); } - if( src_data.output_frames_gen > _frames ) + if (srcData.output_frames_gen > frames) { - printf( "SampleBuffer: not enough frames: %ld / %d\n", - src_data.output_frames_gen, _frames ); + printf("SampleBuffer: not enough frames: %ld / %d\n", + srcData.output_frames_gen, frames); } // Advance - switch( _loopmode ) + switch (loopMode) { case LoopOff: - play_frame += src_data.input_frames_used; + playFrame += srcData.input_frames_used; break; case LoopOn: - play_frame += src_data.input_frames_used; - play_frame = getLoopedIndex( play_frame, loopStartFrame, loopEndFrame ); + playFrame += srcData.input_frames_used; + playFrame = getLoopedIndex(playFrame, loopStartFrame, loopEndFrame); break; case LoopPingPong: { - f_cnt_t left = src_data.input_frames_used; - if( _state->isBackwards() ) + f_cnt_t left = srcData.input_frames_used; + if (state->isBackwards()) { - play_frame -= src_data.input_frames_used; - if( play_frame < loopStartFrame ) + playFrame -= srcData.input_frames_used; + if (playFrame < loopStartFrame) { - left -= ( loopStartFrame - play_frame ); - play_frame = loopStartFrame; + left -= (loopStartFrame - playFrame); + playFrame = loopStartFrame; } else left = 0; } - play_frame += left; - play_frame = getPingPongIndex( play_frame, loopStartFrame, loopEndFrame ); + playFrame += left; + playFrame = getPingPongIndex(playFrame, loopStartFrame, loopEndFrame); break; } } @@ -747,52 +726,52 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, // as is into pitched-copy-buffer // Generate output - memcpy( _ab, - getSampleFragment( play_frame, _frames, _loopmode, &tmp, &is_backwards, - loopStartFrame, loopEndFrame, endFrame ), - _frames * BYTES_PER_FRAME ); + memcpy(ab, + getSampleFragment(playFrame, frames, loopMode, &tmp, &isBackwards, + loopStartFrame, loopEndFrame, endFrame), + frames * BYTES_PER_FRAME); // Advance - switch( _loopmode ) + switch (loopMode) { case LoopOff: - play_frame += _frames; + playFrame += frames; break; case LoopOn: - play_frame += _frames; - play_frame = getLoopedIndex( play_frame, loopStartFrame, loopEndFrame ); + playFrame += frames; + playFrame = getLoopedIndex(playFrame, loopStartFrame, loopEndFrame); break; case LoopPingPong: { - f_cnt_t left = _frames; - if( _state->isBackwards() ) + f_cnt_t left = frames; + if (state->isBackwards()) { - play_frame -= _frames; - if( play_frame < loopStartFrame ) + playFrame -= frames; + if (playFrame < loopStartFrame) { - left -= ( loopStartFrame - play_frame ); - play_frame = loopStartFrame; + left -= (loopStartFrame - playFrame); + playFrame = loopStartFrame; } else left = 0; } - play_frame += left; - play_frame = getPingPongIndex( play_frame, loopStartFrame, loopEndFrame ); + playFrame += left; + playFrame = getPingPongIndex(playFrame, loopStartFrame, loopEndFrame); break; } } } - if( tmp != NULL ) + if (tmp != nullptr) { - MM_FREE( tmp ); + MM_FREE(tmp); } - _state->setBackwards( is_backwards ); - _state->setFrameIndex( play_frame ); + state->setBackwards(isBackwards); + state->setFrameIndex(playFrame); - for( fpp_t i = 0; i < _frames; ++i ) + for (fpp_t i = 0; i < frames; ++i) { - _ab[i][0] *= m_amplification; - _ab[i][1] *= m_amplification; + ab[i][0] *= m_amplification; + ab[i][1] *= m_amplification; } return true; @@ -801,172 +780,185 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, -sampleFrame * SampleBuffer::getSampleFragment( f_cnt_t _index, - f_cnt_t _frames, LoopMode _loopmode, sampleFrame * * _tmp, bool * _backwards, - f_cnt_t _loopstart, f_cnt_t _loopend, f_cnt_t _end ) const +sampleFrame * SampleBuffer::getSampleFragment( + f_cnt_t index, + f_cnt_t frames, + LoopMode loopMode, + sampleFrame * * tmp, + bool * backwards, + f_cnt_t loopStart, + f_cnt_t loopEnd, + f_cnt_t end +) const { - if( _loopmode == LoopOff ) + if (loopMode == LoopOff) { - if( _index + _frames <= _end ) + if (index + frames <= end) { - return m_data + _index; + return m_data + index; } } - else if( _loopmode == LoopOn ) + else if (loopMode == LoopOn) { - if( _index + _frames <= _loopend ) + if (index + frames <= loopEnd) { - return m_data + _index; + return m_data + index; } } else { - if( ! *_backwards && _index + _frames < _loopend ) + if (!*backwards && index + frames < loopEnd) { - return m_data + _index; + return m_data + index; } } - *_tmp = MM_ALLOC( sampleFrame, _frames ); + *tmp = MM_ALLOC(sampleFrame, frames); - if( _loopmode == LoopOff ) + if (loopMode == LoopOff) { - f_cnt_t available = _end - _index; - memcpy( *_tmp, m_data + _index, available * BYTES_PER_FRAME ); - memset( *_tmp + available, 0, ( _frames - available ) * - BYTES_PER_FRAME ); + f_cnt_t available = end - index; + memcpy(*tmp, m_data + index, available * BYTES_PER_FRAME); + memset(*tmp + available, 0, (frames - available) * BYTES_PER_FRAME); } - else if( _loopmode == LoopOn ) + else if (loopMode == LoopOn) { - f_cnt_t copied = qMin( _frames, _loopend - _index ); - memcpy( *_tmp, m_data + _index, copied * BYTES_PER_FRAME ); - f_cnt_t loop_frames = _loopend - _loopstart; - while( copied < _frames ) + f_cnt_t copied = qMin(frames, loopEnd - index); + memcpy(*tmp, m_data + index, copied * BYTES_PER_FRAME); + f_cnt_t loopFrames = loopEnd - loopStart; + while (copied < frames) { - f_cnt_t todo = qMin( _frames - copied, loop_frames ); - memcpy( *_tmp + copied, m_data + _loopstart, todo * BYTES_PER_FRAME ); + f_cnt_t todo = qMin(frames - copied, loopFrames); + memcpy(*tmp + copied, m_data + loopStart, todo * BYTES_PER_FRAME); copied += todo; } } else { - f_cnt_t pos = _index; - bool backwards = pos < _loopstart + f_cnt_t pos = index; + bool currentBackwards = pos < loopStart ? false - : *_backwards; + : *backwards; f_cnt_t copied = 0; - if( backwards ) + if (currentBackwards) { - copied = qMin( _frames, pos - _loopstart ); - for( int i=0; i < copied; i++ ) + copied = qMin(frames, pos - loopStart); + for (int i = 0; i < copied; i++) { - (*_tmp)[i][0] = m_data[ pos - i ][0]; - (*_tmp)[i][1] = m_data[ pos - i ][1]; + (*tmp)[i][0] = m_data[pos - i][0]; + (*tmp)[i][1] = m_data[pos - i][1]; } pos -= copied; - if( pos == _loopstart ) backwards = false; + if (pos == loopStart) { currentBackwards = false; } } else { - copied = qMin( _frames, _loopend - pos ); - memcpy( *_tmp, m_data + pos, copied * BYTES_PER_FRAME ); + copied = qMin(frames, loopEnd - pos); + memcpy(*tmp, m_data + pos, copied * BYTES_PER_FRAME); pos += copied; - if( pos == _loopend ) backwards = true; + if (pos == loopEnd) { currentBackwards = true; } } - while( copied < _frames ) + while (copied < frames) { - if( backwards ) + if (currentBackwards) { - f_cnt_t todo = qMin( _frames - copied, pos - _loopstart ); - for ( int i=0; i < todo; i++ ) + f_cnt_t todo = qMin(frames - copied, pos - loopStart); + for (int i = 0; i < todo; i++) { - (*_tmp)[ copied + i ][0] = m_data[ pos - i ][0]; - (*_tmp)[ copied + i ][1] = m_data[ pos - i ][1]; + (*tmp)[copied + i][0] = m_data[pos - i][0]; + (*tmp)[copied + i][1] = m_data[pos - i][1]; } pos -= todo; copied += todo; - if( pos <= _loopstart ) backwards = false; + if (pos <= loopStart) { currentBackwards = false; } } else { - f_cnt_t todo = qMin( _frames - copied, _loopend - pos ); - memcpy( *_tmp + copied, m_data + pos, todo * BYTES_PER_FRAME ); + f_cnt_t todo = qMin(frames - copied, loopEnd - pos); + memcpy(*tmp + copied, m_data + pos, todo * BYTES_PER_FRAME); pos += todo; copied += todo; - if( pos >= _loopend ) backwards = true; + if (pos >= loopEnd) { currentBackwards = true; } } } - *_backwards = backwards; + *backwards = currentBackwards; } - return *_tmp; + return *tmp; } -f_cnt_t SampleBuffer::getLoopedIndex( f_cnt_t _index, f_cnt_t _startf, f_cnt_t _endf ) const +f_cnt_t SampleBuffer::getLoopedIndex(f_cnt_t index, f_cnt_t startf, f_cnt_t endf) const { - if( _index < _endf ) + if (index < endf) { - return _index; + return index; } - return _startf + ( _index - _startf ) - % ( _endf - _startf ); + return startf + (index - startf) % (endf - startf); } -f_cnt_t SampleBuffer::getPingPongIndex( f_cnt_t _index, f_cnt_t _startf, f_cnt_t _endf ) const +f_cnt_t SampleBuffer::getPingPongIndex(f_cnt_t index, f_cnt_t startf, f_cnt_t endf) const { - if( _index < _endf ) + if (index < endf) { - return _index; + return index; } - const f_cnt_t looplen = _endf - _startf; - const f_cnt_t looppos = ( _index - _endf ) % ( looplen*2 ); + const f_cnt_t loopLen = endf - startf; + const f_cnt_t loopPos = (index - endf) % (loopLen * 2); - return ( looppos < looplen ) - ? _endf - looppos - : _startf + ( looppos - looplen ); + return (loopPos < loopLen) + ? endf - loopPos + : startf + (loopPos - loopLen); } -void SampleBuffer::visualize( QPainter & _p, const QRect & _dr, - const QRect & _clip, f_cnt_t _from_frame, f_cnt_t _to_frame ) +void SampleBuffer::visualize( + QPainter & p, + const QRect & dr, + const QRect & clip, + f_cnt_t fromFrame, + f_cnt_t toFrame +) { - if( m_frames == 0 ) return; + if (m_frames == 0) { return; } - const bool focus_on_range = _to_frame <= m_frames - && 0 <= _from_frame && _from_frame < _to_frame; - //_p.setClipRect( _clip ); - const int w = _dr.width(); - const int h = _dr.height(); + const bool focusOnRange = toFrame <= m_frames && 0 <= fromFrame && fromFrame < toFrame; + //p.setClipRect(clip); + const int w = dr.width(); + const int h = dr.height(); - const int yb = h / 2 + _dr.y(); - const float y_space = h*0.5f; - const int nb_frames = focus_on_range ? _to_frame - _from_frame : m_frames; + const int yb = h / 2 + dr.y(); + const float ySpace = h * 0.5f; + const int nbFrames = focusOnRange ? toFrame - fromFrame : m_frames; - const int fpp = qBound( 1, nb_frames / w, 20 ); - QPointF * l = new QPointF[nb_frames / fpp + 1]; - QPointF * r = new QPointF[nb_frames / fpp + 1]; + const int fpp = qBound(1, nbFrames / w, 20); + QPointF * l = new QPointF[nbFrames / fpp + 1]; + QPointF * r = new QPointF[nbFrames / fpp + 1]; int n = 0; - const int xb = _dr.x(); - const int first = focus_on_range ? _from_frame : 0; - const int last = focus_on_range ? _to_frame : m_frames; - for( int frame = first; frame < last; frame += fpp ) + const int xb = dr.x(); + const int first = focusOnRange ? fromFrame : 0; + const int last = focusOnRange ? toFrame - 1 : m_frames - 1; + + for (int frame = first; frame <= last; frame += fpp) { - l[n] = QPointF( xb + ( (frame - first) * double( w ) / nb_frames ), - ( yb - ( m_data[frame][0] * y_space * m_amplification ) ) ); - r[n] = QPointF( xb + ( (frame - first) * double( w ) / nb_frames ), - ( yb - ( m_data[frame][1] * y_space * m_amplification ) ) ); + auto x = xb + ((frame - first) * double(w) / nbFrames); + // Partial Y calculation + auto py = ySpace * m_amplification; + l[n] = QPointF(x, (yb - (m_data[frame][0] * py))); + r[n] = QPointF(x, (yb - (m_data[frame][1] * py))); ++n; } - _p.setRenderHint( QPainter::Antialiasing ); - _p.drawPolyline( l, nb_frames / fpp ); - _p.drawPolyline( r, nb_frames / fpp ); + + p.setRenderHint(QPainter::Antialiasing); + p.drawPolyline(l, nbFrames / fpp); + p.drawPolyline(r, nbFrames / fpp); + delete[] l; delete[] r; } @@ -976,62 +968,62 @@ void SampleBuffer::visualize( QPainter & _p, const QRect & _dr, QString SampleBuffer::openAudioFile() const { - FileDialog ofd( NULL, tr( "Open audio file" ) ); + FileDialog ofd(nullptr, tr("Open audio file")); QString dir; - if( !m_audioFile.isEmpty() ) + if (!m_audioFile.isEmpty()) { QString f = m_audioFile; - if( QFileInfo( f ).isRelative() ) + if (QFileInfo(f).isRelative()) { f = ConfigManager::inst()->userSamplesDir() + f; - if( QFileInfo( f ).exists() == false ) + if (QFileInfo(f).exists() == false) { f = ConfigManager::inst()->factorySamplesDir() + m_audioFile; } } - dir = QFileInfo( f ).absolutePath(); + dir = QFileInfo(f).absolutePath(); } else { dir = ConfigManager::inst()->userSamplesDir(); } // change dir to position of previously opened file - ofd.setDirectory( dir ); - ofd.setFileMode( FileDialog::ExistingFiles ); + ofd.setDirectory(dir); + ofd.setFileMode(FileDialog::ExistingFiles); // set filters QStringList types; - types << tr( "All Audio-Files (*.wav *.ogg *.ds *.flac *.spx *.voc " - "*.aif *.aiff *.au *.raw)" ) - << tr( "Wave-Files (*.wav)" ) - << tr( "OGG-Files (*.ogg)" ) - << tr( "DrumSynth-Files (*.ds)" ) - << tr( "FLAC-Files (*.flac)" ) - << tr( "SPEEX-Files (*.spx)" ) - //<< tr( "MP3-Files (*.mp3)" ) - //<< tr( "MIDI-Files (*.mid)" ) - << tr( "VOC-Files (*.voc)" ) - << tr( "AIFF-Files (*.aif *.aiff)" ) - << tr( "AU-Files (*.au)" ) - << tr( "RAW-Files (*.raw)" ) - //<< tr( "MOD-Files (*.mod)" ) + types << tr("All Audio-Files (*.wav *.ogg *.ds *.flac *.spx *.voc " + "*.aif *.aiff *.au *.raw)") + << tr("Wave-Files (*.wav)") + << tr("OGG-Files (*.ogg)") + << tr("DrumSynth-Files (*.ds)") + << tr("FLAC-Files (*.flac)") + << tr("SPEEX-Files (*.spx)") + //<< tr("MP3-Files (*.mp3)") + //<< tr("MIDI-Files (*.mid)") + << tr("VOC-Files (*.voc)") + << tr("AIFF-Files (*.aif *.aiff)") + << tr("AU-Files (*.au)") + << tr("RAW-Files (*.raw)") + //<< tr("MOD-Files (*.mod)") ; - ofd.setNameFilters( types ); - if( !m_audioFile.isEmpty() ) + ofd.setNameFilters(types); + if (!m_audioFile.isEmpty()) { // select previously opened file - ofd.selectFile( QFileInfo( m_audioFile ).fileName() ); + ofd.selectFile(QFileInfo(m_audioFile).fileName()); } - if( ofd.exec () == QDialog::Accepted ) + if (ofd.exec () == QDialog::Accepted) { - if( ofd.selectedFiles().isEmpty() ) + if (ofd.selectedFiles().isEmpty()) { return QString(); } - return tryToMakeRelative( ofd.selectedFiles()[0] ); + return PathUtil::toShortestRelative(ofd.selectedFiles()[0]); } return QString(); @@ -1046,7 +1038,7 @@ QString SampleBuffer::openAndSetAudioFile() if(!fileName.isEmpty()) { - this->setAudioFile( fileName ); + this->setAudioFile(fileName); } return fileName; @@ -1055,16 +1047,16 @@ QString SampleBuffer::openAndSetAudioFile() QString SampleBuffer::openAndSetWaveformFile() { - if( m_audioFile.isEmpty() ) + if (m_audioFile.isEmpty()) { m_audioFile = ConfigManager::inst()->factorySamplesDir() + "waveforms/10saw.flac"; } QString fileName = this->openAudioFile(); - if(!fileName.isEmpty()) + if (!fileName.isEmpty()) { - this->setAudioFile( fileName ); + this->setAudioFile(fileName); } else { @@ -1081,148 +1073,145 @@ QString SampleBuffer::openAndSetWaveformFile() #ifdef LMMS_HAVE_FLAC_STREAM_ENCODER_H FLAC__StreamEncoderWriteStatus flacStreamEncoderWriteCallback( - const FLAC__StreamEncoder * - /*_encoder*/, - const FLAC__byte _buffer[], - unsigned int/* _samples*/, - unsigned int _bytes, - unsigned int/* _current_frame*/, - void * _client_data ) + const FLAC__StreamEncoder * /*encoder*/, + const FLAC__byte buffer[], + unsigned int /*samples*/, + unsigned int bytes, + unsigned int /*currentFrame*/, + void * clientData +) { -/* if( _bytes == 0 ) +/* if (bytes == 0) { return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; }*/ - return ( static_cast( _client_data )->write( - (const char *) _buffer, _bytes ) == - (int) _bytes ) ? - FLAC__STREAM_ENCODER_WRITE_STATUS_OK : - FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + return (static_cast(clientData)->write( + (const char *) buffer, bytes) == (int) bytes) + ? FLAC__STREAM_ENCODER_WRITE_STATUS_OK + : FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; } -void flacStreamEncoderMetadataCallback( const FLAC__StreamEncoder *, - const FLAC__StreamMetadata * _metadata, - void * _client_data ) +void flacStreamEncoderMetadataCallback( + const FLAC__StreamEncoder *, + const FLAC__StreamMetadata * metadata, + void * clientData +) { - QBuffer * b = static_cast( _client_data ); - b->seek( 0 ); - b->write( (const char *) _metadata, sizeof( *_metadata ) ); + QBuffer * b = static_cast(clientData); + b->seek(0); + b->write((const char *) metadata, sizeof(*metadata)); } #endif -QString & SampleBuffer::toBase64( QString & _dst ) const +QString & SampleBuffer::toBase64(QString & dst) const { #ifdef LMMS_HAVE_FLAC_STREAM_ENCODER_H const f_cnt_t FRAMES_PER_BUF = 1152; - FLAC__StreamEncoder * flac_enc = FLAC__stream_encoder_new(); - FLAC__stream_encoder_set_channels( flac_enc, DEFAULT_CHANNELS ); - FLAC__stream_encoder_set_blocksize( flac_enc, FRAMES_PER_BUF ); -/* FLAC__stream_encoder_set_do_exhaustive_model_search( flac_enc, true ); - FLAC__stream_encoder_set_do_mid_side_stereo( flac_enc, true );*/ - FLAC__stream_encoder_set_sample_rate( flac_enc, - Engine::mixer()->sampleRate() ); - QBuffer ba_writer; - ba_writer.open( QBuffer::WriteOnly ); - - FLAC__stream_encoder_set_write_callback( flac_enc, - flacStreamEncoderWriteCallback ); - FLAC__stream_encoder_set_metadata_callback( flac_enc, - flacStreamEncoderMetadataCallback ); - FLAC__stream_encoder_set_client_data( flac_enc, &ba_writer ); - if( FLAC__stream_encoder_init( flac_enc ) != FLAC__STREAM_ENCODER_OK ) + FLAC__StreamEncoder * flacEnc = FLAC__stream_encoder_new(); + FLAC__stream_encoder_set_channels(flacEnc, DEFAULT_CHANNELS); + FLAC__stream_encoder_set_blocksize(flacEnc, FRAMES_PER_BUF); +/* FLAC__stream_encoder_set_do_exhaustive_model_search(flacEnc, true); + FLAC__stream_encoder_set_do_mid_side_stereo(flacEnc, true);*/ + FLAC__stream_encoder_set_sample_rate(flacEnc, + Engine::mixer()->sampleRate()); + + QBuffer baWriter; + baWriter.open(QBuffer::WriteOnly); + + FLAC__stream_encoder_set_write_callback(flacEnc, + flacStreamEncoderWriteCallback); + FLAC__stream_encoder_set_metadata_callback(flacEnc, + flacStreamEncoderMetadataCallback); + FLAC__stream_encoder_set_client_data(flacEnc, &baWriter); + + if (FLAC__stream_encoder_init(flacEnc) != FLAC__STREAM_ENCODER_OK) { - printf( "error within FLAC__stream_encoder_init()!\n" ); + printf("Error within FLAC__stream_encoder_init()!\n"); } - f_cnt_t frame_cnt = 0; - while( frame_cnt < m_frames ) + + f_cnt_t frameCnt = 0; + + while (frameCnt < m_frames) { - f_cnt_t remaining = qMin( FRAMES_PER_BUF, - m_frames - frame_cnt ); + f_cnt_t remaining = qMin(FRAMES_PER_BUF, m_frames - frameCnt); FLAC__int32 buf[FRAMES_PER_BUF * DEFAULT_CHANNELS]; - for( f_cnt_t f = 0; f < remaining; ++f ) + for (f_cnt_t f = 0; f < remaining; ++f) { - for( ch_cnt_t ch = 0; ch < DEFAULT_CHANNELS; ++ch ) + for (ch_cnt_t ch = 0; ch < DEFAULT_CHANNELS; ++ch) { buf[f*DEFAULT_CHANNELS+ch] = (FLAC__int32)( - Mixer::clip( m_data[f+frame_cnt][ch] ) * - OUTPUT_SAMPLE_MULTIPLIER ); + Mixer::clip(m_data[f+frameCnt][ch]) * + OUTPUT_SAMPLE_MULTIPLIER); } } - FLAC__stream_encoder_process_interleaved( flac_enc, buf, - remaining ); - frame_cnt += remaining; + FLAC__stream_encoder_process_interleaved(flacEnc, buf, remaining); + frameCnt += remaining; } - FLAC__stream_encoder_finish( flac_enc ); - FLAC__stream_encoder_delete( flac_enc ); - printf("%d %d\n", frame_cnt, (int)ba_writer.size() ); - ba_writer.close(); - - base64::encode( ba_writer.buffer().data(), ba_writer.buffer().size(), - _dst ); + FLAC__stream_encoder_finish(flacEnc); + FLAC__stream_encoder_delete(flacEnc); + printf("%d %d\n", frameCnt, (int)baWriter.size()); + baWriter.close(); + base64::encode(baWriter.buffer().data(), baWriter.buffer().size(), dst); #else /* LMMS_HAVE_FLAC_STREAM_ENCODER_H */ - base64::encode( (const char *) m_data, - m_frames * sizeof( sampleFrame ), _dst ); + base64::encode((const char *) m_data, + m_frames * sizeof(sampleFrame), dst); #endif /* LMMS_HAVE_FLAC_STREAM_ENCODER_H */ - return _dst; + return dst; } -SampleBuffer * SampleBuffer::resample( const sample_rate_t _src_sr, - const sample_rate_t _dst_sr ) +SampleBuffer * SampleBuffer::resample(const sample_rate_t srcSR, const sample_rate_t dstSR ) { sampleFrame * data = m_data; const f_cnt_t frames = m_frames; - const f_cnt_t dst_frames = static_cast( frames / - (float) _src_sr * (float) _dst_sr ); - SampleBuffer * dst_sb = new SampleBuffer( dst_frames ); - sampleFrame * dst_buf = dst_sb->m_origData; + const f_cnt_t dstFrames = static_cast((frames / (float) srcSR) * (float) dstSR); + SampleBuffer * dstSB = new SampleBuffer(dstFrames); + sampleFrame * dstBuf = dstSB->m_origData; // yeah, libsamplerate, let's rock with sinc-interpolation! int error; SRC_STATE * state; - if( ( state = src_new( SRC_SINC_MEDIUM_QUALITY, - DEFAULT_CHANNELS, &error ) ) != NULL ) - { - SRC_DATA src_data; - src_data.end_of_input = 1; - src_data.data_in = data[0]; - src_data.data_out = dst_buf[0]; - src_data.input_frames = frames; - src_data.output_frames = dst_frames; - src_data.src_ratio = (double) _dst_sr / _src_sr; - if( ( error = src_process( state, &src_data ) ) ) + if ((state = src_new(SRC_SINC_MEDIUM_QUALITY, DEFAULT_CHANNELS, &error)) != nullptr) + { + SRC_DATA srcData; + srcData.end_of_input = 1; + srcData.data_in = data->data(); + srcData.data_out = dstBuf->data(); + srcData.input_frames = frames; + srcData.output_frames = dstFrames; + srcData.src_ratio = (double) dstSR / srcSR; + if ((error = src_process(state, &srcData))) { - printf( "SampleBuffer: error while resampling: %s\n", - src_strerror( error ) ); + printf("SampleBuffer: error while resampling: %s\n", src_strerror(error)); } - src_delete( state ); + src_delete(state); } else { - printf( "Error: src_new() failed in sample_buffer.cpp!\n" ); + printf("Error: src_new() failed in sample_buffer.cpp!\n"); } - dst_sb->update(); - return dst_sb; + dstSB->update(); + return dstSB; } -void SampleBuffer::setAudioFile( const QString & _audio_file ) +void SampleBuffer::setAudioFile(const QString & audioFile) { - m_audioFile = tryToMakeRelative( _audio_file ); + m_audioFile = PathUtil::toShortestRelative(audioFile); update(); } @@ -1232,30 +1221,29 @@ void SampleBuffer::setAudioFile( const QString & _audio_file ) struct flacStreamDecoderClientData { - QBuffer * read_buffer; - QBuffer * write_buffer; + QBuffer * readBuffer; + QBuffer * writeBuffer; } ; FLAC__StreamDecoderReadStatus flacStreamDecoderReadCallback( - const FLAC__StreamDecoder * - /*_decoder*/, - FLAC__byte * _buffer, - unsigned int * _bytes, - void * _client_data ) + const FLAC__StreamDecoder * /*decoder*/, + FLAC__byte * buffer, + unsigned int * bytes, + void * clientData +) { int res = static_cast( - _client_data )->read_buffer->read( - (char *) _buffer, *_bytes ); + clientData)->readBuffer->read((char *) buffer, *bytes); - if( res > 0 ) + if (res > 0) { - *_bytes = res; + *bytes = res; return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; - } - *_bytes = 0; + + *bytes = 0; return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; } @@ -1263,116 +1251,116 @@ FLAC__StreamDecoderReadStatus flacStreamDecoderReadCallback( FLAC__StreamDecoderWriteStatus flacStreamDecoderWriteCallback( - const FLAC__StreamDecoder * - /*_decoder*/, - const FLAC__Frame * _frame, - const FLAC__int32 * const _buffer[], - void * _client_data ) + const FLAC__StreamDecoder * /*decoder*/, + const FLAC__Frame * frame, + const FLAC__int32 * const buffer[], + void * clientData +) { - if( _frame->header.channels != 2 ) + if (frame->header.channels != 2) { - printf( "channels != 2 in " - "flacStreamDecoderWriteCallback()\n" ); + printf("channels != 2 in flacStreamDecoderWriteCallback()\n"); return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } - if( _frame->header.bits_per_sample != 16 ) + if (frame->header.bits_per_sample != 16) { - printf( "bits_per_sample != 16 in " - "flacStreamDecoderWriteCallback()\n" ); + printf("bits_per_sample != 16 in flacStreamDecoderWriteCallback()\n"); return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } - const f_cnt_t frames = _frame->header.blocksize; - for( f_cnt_t frame = 0; frame < frames; ++frame ) + const f_cnt_t numberOfFrames = frame->header.blocksize; + for (f_cnt_t f = 0; f < numberOfFrames; ++f) { - sampleFrame sframe = { _buffer[0][frame] / - OUTPUT_SAMPLE_MULTIPLIER, - _buffer[1][frame] / - OUTPUT_SAMPLE_MULTIPLIER - } ; + sampleFrame sframe = { buffer[0][f] / OUTPUT_SAMPLE_MULTIPLIER, + buffer[1][f] / OUTPUT_SAMPLE_MULTIPLIER + } ; static_cast( - _client_data )->write_buffer->write( - (const char *) sframe, sizeof( sframe ) ); + clientData )->writeBuffer->write( + (const char *) sframe, sizeof(sframe)); } return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } -void flacStreamDecoderMetadataCallback( const FLAC__StreamDecoder *, - const FLAC__StreamMetadata *, - void * /*_client_data*/ ) +void flacStreamDecoderMetadataCallback( + const FLAC__StreamDecoder *, + const FLAC__StreamMetadata *, + void * /*clientData*/ +) { printf("stream decoder metadata callback\n"); -/* QBuffer * b = static_cast( _client_data ); - b->seek( 0 ); - b->write( (const char *) _metadata, sizeof( *_metadata ) );*/ +/* QBuffer * b = static_cast(clientData); + b->seek(0); + b->write((const char *) metadata, sizeof(*metadata));*/ } -void flacStreamDecoderErrorCallback( const FLAC__StreamDecoder *, - FLAC__StreamDecoderErrorStatus _status, - void * /*_client_data*/ ) +void flacStreamDecoderErrorCallback( + const FLAC__StreamDecoder *, + FLAC__StreamDecoderErrorStatus status, + void * /*clientData*/ +) { - printf("error callback! %d\n", _status); + printf("error callback! %d\n", status); // what to do now?? } #endif -void SampleBuffer::loadFromBase64( const QString & _data ) +void SampleBuffer::loadFromBase64(const QString & data) { - char * dst = NULL; + char * dst = nullptr; int dsize = 0; - base64::decode( _data, &dst, &dsize ); + base64::decode(data, &dst, &dsize); #ifdef LMMS_HAVE_FLAC_STREAM_DECODER_H - QByteArray orig_data = QByteArray::fromRawData( dst, dsize ); - QBuffer ba_reader( &orig_data ); - ba_reader.open( QBuffer::ReadOnly ); + QByteArray origData = QByteArray::fromRawData(dst, dsize); + QBuffer baReader(&origData); + baReader.open(QBuffer::ReadOnly); - QBuffer ba_writer; - ba_writer.open( QBuffer::WriteOnly ); + QBuffer baWriter; + baWriter.open(QBuffer::WriteOnly); - flacStreamDecoderClientData cdata = { &ba_reader, &ba_writer } ; + flacStreamDecoderClientData cdata = { &baReader, &baWriter } ; - FLAC__StreamDecoder * flac_dec = FLAC__stream_decoder_new(); + FLAC__StreamDecoder * flacDec = FLAC__stream_decoder_new(); - FLAC__stream_decoder_set_read_callback( flac_dec, - flacStreamDecoderReadCallback ); - FLAC__stream_decoder_set_write_callback( flac_dec, - flacStreamDecoderWriteCallback ); - FLAC__stream_decoder_set_error_callback( flac_dec, - flacStreamDecoderErrorCallback ); - FLAC__stream_decoder_set_metadata_callback( flac_dec, - flacStreamDecoderMetadataCallback ); - FLAC__stream_decoder_set_client_data( flac_dec, &cdata ); + FLAC__stream_decoder_set_read_callback(flacDec, + flacStreamDecoderReadCallback); + FLAC__stream_decoder_set_write_callback(flacDec, + flacStreamDecoderWriteCallback); + FLAC__stream_decoder_set_error_callback(flacDec, + flacStreamDecoderErrorCallback); + FLAC__stream_decoder_set_metadata_callback(flacDec, + flacStreamDecoderMetadataCallback); + FLAC__stream_decoder_set_client_data(flacDec, &cdata); - FLAC__stream_decoder_init( flac_dec ); + FLAC__stream_decoder_init(flacDec); - FLAC__stream_decoder_process_until_end_of_stream( flac_dec ); + FLAC__stream_decoder_process_until_end_of_stream(flacDec); - FLAC__stream_decoder_finish( flac_dec ); - FLAC__stream_decoder_delete( flac_dec ); + FLAC__stream_decoder_finish(flacDec); + FLAC__stream_decoder_delete(flacDec); - ba_reader.close(); + baReader.close(); - orig_data = ba_writer.buffer(); - printf("%d\n", (int) orig_data.size() ); + origData = baWriter.buffer(); + printf("%d\n", (int) origData.size()); - m_origFrames = orig_data.size() / sizeof( sampleFrame ); - MM_FREE( m_origData ); - m_origData = MM_ALLOC( sampleFrame, m_origFrames ); - memcpy( m_origData, orig_data.data(), orig_data.size() ); + m_origFrames = origData.size() / sizeof(sampleFrame); + MM_FREE(m_origData); + m_origData = MM_ALLOC(sampleFrame, m_origFrames); + memcpy(m_origData, origData.data(), origData.size()); #else /* LMMS_HAVE_FLAC_STREAM_DECODER_H */ - m_origFrames = dsize / sizeof( sampleFrame ); - MM_FREE( m_origData ); - m_origData = MM_ALLOC( sampleFrame, m_origFrames ); - memcpy( m_origData, dst, dsize ); + m_origFrames = dsize / sizeof(sampleFrame); + MM_FREE(m_origData); + m_origData = MM_ALLOC(sampleFrame, m_origFrames); + memcpy(m_origData, dst, dsize); #endif @@ -1385,113 +1373,57 @@ void SampleBuffer::loadFromBase64( const QString & _data ) -void SampleBuffer::setStartFrame( const f_cnt_t _s ) +void SampleBuffer::setStartFrame(const f_cnt_t s) { - m_startFrame = _s; + m_startFrame = s; } -void SampleBuffer::setEndFrame( const f_cnt_t _e ) +void SampleBuffer::setEndFrame(const f_cnt_t e) { - m_endFrame = _e; + m_endFrame = e; } -void SampleBuffer::setAmplification( float _a ) +void SampleBuffer::setAmplification(float a) { - m_amplification = _a; + m_amplification = a; emit sampleUpdated(); } -void SampleBuffer::setReversed( bool _on ) -{ - m_reversed = _on; - update( true ); -} - - - - -QString SampleBuffer::tryToMakeRelative( const QString & file ) -{ - if( QFileInfo( file ).isRelative() == false ) - { - // Normalize the path - QString f( QDir::cleanPath( file ) ); - - // First, look in factory samples - // Isolate "samples/" from "data:/samples/" - QString samplesSuffix = ConfigManager::inst()->factorySamplesDir().mid( ConfigManager::inst()->dataDir().length() ); - - // Iterate over all valid "data:/" searchPaths - for ( const QString & path : QDir::searchPaths( "data" ) ) - { - QString samplesPath = QDir::cleanPath( path + samplesSuffix ) + "/"; - if ( f.startsWith( samplesPath ) ) - { - return QString( f ).mid( samplesPath.length() ); - } - } - - // Next, look in user samples - QString usd = ConfigManager::inst()->userSamplesDir(); - usd.replace( QDir::separator(), '/' ); - if( f.startsWith( usd ) ) - { - return QString( f ).mid( usd.length() ); - } - } - return file; -} - - - - -QString SampleBuffer::tryToMakeAbsolute(const QString& file) +void SampleBuffer::setReversed(bool on) { - QFileInfo f(file); - - if(f.isRelative()) - { - f = QFileInfo(ConfigManager::inst()->userSamplesDir() + file); - - if(! f.exists()) - { - f = QFileInfo(ConfigManager::inst()->factorySamplesDir() + file); - } - } - - if (f.exists()) { - return f.absoluteFilePath(); - } - return file; + Engine::mixer()->requestChangeInModel(); + m_varLock.lockForWrite(); + if (m_reversed != on) { std::reverse(m_data, m_data + m_frames); } + m_reversed = on; + m_varLock.unlock(); + Engine::mixer()->doneChangeInModel(); + emit sampleUpdated(); } - - - -SampleBuffer::handleState::handleState( bool _varying_pitch, int interpolation_mode ) : - m_frameIndex( 0 ), - m_varyingPitch( _varying_pitch ), - m_isBackwards( false ) +SampleBuffer::handleState::handleState(bool varyingPitch, int interpolationMode) : + m_frameIndex(0), + m_varyingPitch(varyingPitch), + m_isBackwards(false) { int error; - m_interpolationMode = interpolation_mode; - - if( ( m_resamplingData = src_new( interpolation_mode, DEFAULT_CHANNELS, &error ) ) == NULL ) + m_interpolationMode = interpolationMode; + + if ((m_resamplingData = src_new(interpolationMode, DEFAULT_CHANNELS, &error)) == nullptr) { - qDebug( "Error: src_new() failed in sample_buffer.cpp!\n" ); + qDebug("Error: src_new() failed in sample_buffer.cpp!\n"); } } @@ -1500,5 +1432,5 @@ SampleBuffer::handleState::handleState( bool _varying_pitch, int interpolation_m SampleBuffer::handleState::~handleState() { - src_delete( m_resamplingData ); + src_delete(m_resamplingData); } diff --git a/src/core/SampleRecordHandle.cpp b/src/core/SampleRecordHandle.cpp index cf9342b9e08..c8f688a969a 100644 --- a/src/core/SampleRecordHandle.cpp +++ b/src/core/SampleRecordHandle.cpp @@ -73,7 +73,7 @@ void SampleRecordHandle::play( sampleFrame * /*_working_buffer*/ ) writeBuffer( recbuf, frames ); m_framesRecorded += frames; - MidiTime len = (tick_t)( m_framesRecorded / Engine::framesPerTick() ); + TimePos len = (tick_t)( m_framesRecorded / Engine::framesPerTick() ); if( len > m_minLength ) { // m_tco->changeLength( len ); diff --git a/src/core/Song.cpp b/src/core/Song.cpp index 60ab3bfbce7..be3d2745ae1 100644 --- a/src/core/Song.cpp +++ b/src/core/Song.cpp @@ -30,6 +30,8 @@ #include #include +#include +#include #include #include "AutomationTrack.h" @@ -46,6 +48,8 @@ #include "FxMixerView.h" #include "GuiApplication.h" #include "ExportFilter.h" +#include "InstrumentTrack.h" +#include "NotePlayHandle.h" #include "Pattern.h" #include "PianoRoll.h" #include "ProjectJournal.h" @@ -55,7 +59,7 @@ #include "PeakController.h" -tick_t MidiTime::s_ticksPerBar = DefaultTicksPerBar; +tick_t TimePos::s_ticksPerBar = DefaultTicksPerBar; @@ -164,7 +168,7 @@ void Song::setTempo() void Song::setTimeSignature() { - MidiTime::setTicksPerBar( ticksPerBar() ); + TimePos::setTicksPerBar( ticksPerBar() ); emit timeSignatureChanged( m_oldTicksPerBar, ticksPerBar() ); emit dataChanged(); m_oldTicksPerBar = ticksPerBar(); @@ -191,231 +195,164 @@ void Song::savePos() void Song::processNextBuffer() { - m_vstSyncController.setPlaybackJumped( false ); + m_vstSyncController.setPlaybackJumped(false); - // if not playing, nothing to do - if( m_playing == false ) + // If nothing is playing, there is nothing to do + if (!m_playing) { return; } + + // At the beginning of the song, we have to reset the LFOs + if (m_playMode == Mode_PlaySong && getPlayPos() == 0) { - return; + EnvelopeAndLfoParameters::instances()->reset(); } TrackList trackList; - int tcoNum = -1; // track content object number + int clipNum = -1; // The number of the clip that will be played - // determine the list of tracks to play and the track content object - // (TCO) number - switch( m_playMode ) + // Determine the list of tracks to play and the clip number + switch (m_playMode) { case Mode_PlaySong: trackList = tracks(); - // at song-start we have to reset the LFOs - if( m_playPos[Mode_PlaySong] == 0 ) - { - EnvelopeAndLfoParameters::instances()->reset(); - } break; case Mode_PlayBB: - if( Engine::getBBTrackContainer()->numOfBBs() > 0 ) + if (Engine::getBBTrackContainer()->numOfBBs() > 0) { - tcoNum = Engine::getBBTrackContainer()-> - currentBB(); - trackList.push_back( BBTrack::findBBTrack( - tcoNum ) ); + clipNum = Engine::getBBTrackContainer()->currentBB(); + trackList.push_back(BBTrack::findBBTrack(clipNum)); } break; case Mode_PlayPattern: - if( m_patternToPlay != NULL ) + if (m_patternToPlay) { - tcoNum = m_patternToPlay->getTrack()-> - getTCONum( m_patternToPlay ); - trackList.push_back( - m_patternToPlay->getTrack() ); + clipNum = m_patternToPlay->getTrack()->getTCONum(m_patternToPlay); + trackList.push_back(m_patternToPlay->getTrack()); } break; default: return; - - } - - // if we have no tracks to play, nothing to do - if( trackList.empty() == true ) - { - return; } - // check for looping-mode and act if necessary - TimeLineWidget * tl = m_playPos[m_playMode].m_timeLine; - bool checkLoop = - tl != NULL && m_exporting == false && tl->loopPointsEnabled(); + // If we have no tracks to play, there is nothing to do + if (trackList.empty()) { return; } - if( checkLoop ) + // If the playback position is outside of the range [begin, end), move it to + // begin and inform interested parties. + // Returns true if the playback position was moved, else false. + const auto enforceLoop = [this](const TimePos& begin, const TimePos& end) { - // if looping-mode is enabled and we are outside of the looping - // range, go to the beginning of the range - if( m_playPos[m_playMode] < tl->loopBegin() || - m_playPos[m_playMode] >= tl->loopEnd() ) + if (getPlayPos() < begin || getPlayPos() >= end) { - setToTime(tl->loopBegin()); - m_playPos[m_playMode].setTicks( - tl->loopBegin().getTicks() ); - - m_vstSyncController.setPlaybackJumped( true ); - + setToTime(begin); + m_vstSyncController.setPlaybackJumped(true); emit updateSampleTracks(); + return true; } - } + return false; + }; + + const auto timeline = getPlayPos().m_timeLine; + const auto loopEnabled = !m_exporting && timeline && timeline->loopPointsEnabled(); - if( m_playPos[m_playMode].jumped() ) + // Ensure playback begins within the loop if it is enabled + if (loopEnabled) { enforceLoop(timeline->loopBegin(), timeline->loopEnd()); } + + // Inform VST plugins if the user moved the play head + if (getPlayPos().jumped()) { - m_vstSyncController.setPlaybackJumped( true ); - m_playPos[m_playMode].setJumped( false ); + m_vstSyncController.setPlaybackJumped(true); + getPlayPos().setJumped(false); } - f_cnt_t framesPlayed = 0; - const float framesPerTick = Engine::framesPerTick(); + const auto framesPerTick = Engine::framesPerTick(); + const auto framesPerPeriod = Engine::mixer()->framesPerPeriod(); + + f_cnt_t frameOffsetInPeriod = 0; - while( framesPlayed < Engine::mixer()->framesPerPeriod() ) + while (frameOffsetInPeriod < framesPerPeriod) { - m_vstSyncController.update(); + auto frameOffsetInTick = getPlayPos().currentFrame(); - float currentFrame = m_playPos[m_playMode].currentFrame(); - // did we play a tick? - if( currentFrame >= framesPerTick ) + // If a whole tick has elapsed, update the frame and tick count, and check any loops + if (frameOffsetInTick >= framesPerTick) { - int ticks = m_playPos[m_playMode].getTicks() + - ( int )( currentFrame / framesPerTick ); - - // did we play a whole bar? - if( ticks >= MidiTime::ticksPerBar() ) + // Transfer any whole ticks from the frame count to the tick count + const auto elapsedTicks = static_cast(frameOffsetInTick / framesPerTick); + getPlayPos().setTicks(getPlayPos().getTicks() + elapsedTicks); + frameOffsetInTick -= elapsedTicks * framesPerTick; + getPlayPos().setCurrentFrame(frameOffsetInTick); + + // If we are playing a BB track, or a pattern with no loop enabled, + // loop back to the beginning when we reach the end + if (m_playMode == Mode_PlayBB) { - // per default we just continue playing even if - // there's no more stuff to play - // (song-play-mode) - int maxBar = m_playPos[m_playMode].getBar() - + 2; - - // then decide whether to go over to next bar - // or to loop back to first bar - if( m_playMode == Mode_PlayBB ) - { - maxBar = Engine::getBBTrackContainer() - ->lengthOfCurrentBB(); - } - else if( m_playMode == Mode_PlayPattern && - m_loopPattern == true && - tl != NULL && - tl->loopPointsEnabled() == false ) - { - maxBar = m_patternToPlay->length() - .getBar(); - } - - // end of played object reached? - if( m_playPos[m_playMode].getBar() + 1 - >= maxBar ) - { - // then start from beginning and keep - // offset - ticks %= ( maxBar * MidiTime::ticksPerBar() ); - - // wrap milli second counter - setToTimeByTicks(ticks); - - m_vstSyncController.setPlaybackJumped( true ); - } + enforceLoop(TimePos{0}, TimePos{Engine::getBBTrackContainer()->lengthOfCurrentBB(), 0}); + } + else if (m_playMode == Mode_PlayPattern && m_loopPattern && !loopEnabled) + { + enforceLoop(TimePos{0}, m_patternToPlay->length()); } - m_playPos[m_playMode].setTicks( ticks ); - if (checkLoop || m_loopRenderRemaining > 1) + // Handle loop points, and inform VST plugins of the loop status + if (loopEnabled || (m_loopRenderRemaining > 1 && getPlayPos() >= timeline->loopBegin())) { m_vstSyncController.startCycle( - tl->loopBegin().getTicks(), tl->loopEnd().getTicks() ); + timeline->loopBegin().getTicks(), timeline->loopEnd().getTicks()); - // if looping-mode is enabled and we have got - // past the looping range, return to the - // beginning of the range - if( m_playPos[m_playMode] >= tl->loopEnd() ) + // Loop if necessary, and decrement the remaining loops if we did + if (enforceLoop(timeline->loopBegin(), timeline->loopEnd()) + && m_loopRenderRemaining > 1) { - if (m_loopRenderRemaining > 1) - m_loopRenderRemaining--; - ticks = tl->loopBegin().getTicks(); - m_playPos[m_playMode].setTicks( ticks ); - setToTime(tl->loopBegin()); - - m_vstSyncController.setPlaybackJumped( true ); - - emit updateSampleTracks(); + m_loopRenderRemaining--; } } else { m_vstSyncController.stopCycle(); } - - currentFrame = fmodf( currentFrame, framesPerTick ); - m_playPos[m_playMode].setCurrentFrame( currentFrame ); } - if( framesPlayed == 0 ) - { - // update VST sync position after we've corrected frame/ - // tick count but before actually playing any frames - m_vstSyncController.setAbsolutePosition( - m_playPos[m_playMode].getTicks() - + m_playPos[m_playMode].currentFrame() - / (double) framesPerTick ); - } + const f_cnt_t framesUntilNextPeriod = framesPerPeriod - frameOffsetInPeriod; + const f_cnt_t framesUntilNextTick = static_cast(std::ceil(framesPerTick - frameOffsetInTick)); - f_cnt_t framesToPlay = - Engine::mixer()->framesPerPeriod() - framesPlayed; + // We want to proceed to the next buffer or tick, whichever is closer + const auto framesToPlay = std::min(framesUntilNextPeriod, framesUntilNextTick); - f_cnt_t framesLeft = ( f_cnt_t )framesPerTick - - ( f_cnt_t )currentFrame; - // skip last frame fraction - if( framesLeft == 0 ) - { - ++framesPlayed; - m_playPos[m_playMode].setCurrentFrame( currentFrame - + 1.0f ); - continue; - } - // do we have samples left in this tick but these are less - // than samples we have to play? - if( framesLeft < framesToPlay ) + if (frameOffsetInPeriod == 0) { - // then set framesToPlay to remaining samples, the - // rest will be played in next loop - framesToPlay = framesLeft; + // First frame of buffer: update VST sync position. + // This must be done after we've corrected the frame/tick count, + // but before actually playing any frames. + m_vstSyncController.setAbsolutePosition(getPlayPos().getTicks() + + getPlayPos().currentFrame() / static_cast(framesPerTick)); + m_vstSyncController.update(); } - if( ( f_cnt_t ) currentFrame == 0 ) + if (static_cast(frameOffsetInTick) == 0) { - processAutomations(trackList, m_playPos[m_playMode], framesToPlay); - - // loop through all tracks and play them - for( int i = 0; i < trackList.size(); ++i ) + // First frame of tick: process automation and play tracks + processAutomations(trackList, getPlayPos(), framesToPlay); + for (const auto track : trackList) { - trackList[i]->play( m_playPos[m_playMode], - framesToPlay, - framesPlayed, tcoNum ); + track->play(getPlayPos(), framesToPlay, frameOffsetInPeriod, clipNum); } } - // update frame-counters - framesPlayed += framesToPlay; - m_playPos[m_playMode].setCurrentFrame( framesToPlay + - currentFrame ); - m_elapsedMilliSeconds[m_playMode] += MidiTime::ticksToMilliseconds(framesToPlay / framesPerTick, getTempo()); + // Update frame counters + frameOffsetInPeriod += framesToPlay; + frameOffsetInTick += framesToPlay; + getPlayPos().setCurrentFrame(frameOffsetInTick); + m_elapsedMilliSeconds[m_playMode] += TimePos::ticksToMilliseconds(framesToPlay / framesPerTick, getTempo()); m_elapsedBars = m_playPos[Mode_PlaySong].getBar(); - m_elapsedTicks = ( m_playPos[Mode_PlaySong].getTicks() % ticksPerBar() ) / 48; + m_elapsedTicks = (m_playPos[Mode_PlaySong].getTicks() % ticksPerBar()) / 48; } } -void Song::processAutomations(const TrackList &tracklist, MidiTime timeStart, fpp_t) +void Song::processAutomations(const TrackList &tracklist, TimePos timeStart, fpp_t) { AutomatedValueMap values; @@ -457,7 +394,7 @@ void Song::processAutomations(const TrackList &tracklist, MidiTime timeStart, fp for (TrackContentObject* tco : tcos) { auto p = dynamic_cast(tco); - MidiTime relTime = timeStart - p->startPosition(); + TimePos relTime = timeStart - p->startPosition(); if (p->isRecording() && relTime >= 0 && relTime < p->length()) { const AutomatableModel* recordedModel = p->firstObject(); @@ -493,7 +430,7 @@ bool Song::isExportDone() const int Song::getExportProgress() const { - MidiTime pos = m_playPos[m_playMode]; + TimePos pos = m_playPos[m_playMode]; if (pos >= m_exportSongEnd) { @@ -612,16 +549,14 @@ void Song::updateLength() { m_length = 0; m_tracksMutex.lockForRead(); - for( TrackList::const_iterator it = tracks().begin(); - it != tracks().end(); ++it ) + for (auto track : tracks()) { - if( Engine::getSong()->isExporting() && - ( *it )->isMuted() ) + if (m_exporting && track->isMuted()) { continue; } - const bar_t cur = ( *it )->length(); + const bar_t cur = track->length(); if( cur > m_length ) { m_length = cur; @@ -639,7 +574,7 @@ void Song::setPlayPos( tick_t ticks, PlayModes playMode ) { tick_t ticksFromPlayMode = m_playPos[playMode].getTicks(); m_elapsedTicks += ticksFromPlayMode - ticks; - m_elapsedMilliSeconds[playMode] += MidiTime::ticksToMilliseconds( ticks - ticksFromPlayMode, getTempo() ); + m_elapsedMilliSeconds[playMode] += TimePos::ticksToMilliseconds( ticks - ticksFromPlayMode, getTempo() ); m_playPos[playMode].setTicks( ticks ); m_playPos[playMode].setCurrentFrame( 0.0f ); m_playPos[playMode].setJumped( true ); @@ -744,6 +679,10 @@ void Song::stop() void Song::startExport() { stop(); + + m_exporting = true; + updateLength(); + if (m_renderBetweenMarkers) { m_exportSongBegin = m_exportLoopBegin = m_playPos[Mode_PlaySong].m_timeLine->loopBegin(); @@ -753,7 +692,7 @@ void Song::startExport() } else { - m_exportSongEnd = MidiTime(m_length, 0); + m_exportSongEnd = TimePos(m_length, 0); // Handle potentially ridiculous loop points gracefully. if (m_loopRenderCount > 1 && m_playPos[Mode_PlaySong].m_timeLine->loopEnd() > m_exportSongEnd) @@ -762,15 +701,19 @@ void Song::startExport() } if (!m_exportLoop) - m_exportSongEnd += MidiTime(1,0); + m_exportSongEnd += TimePos(1,0); - m_exportSongBegin = MidiTime(0,0); - m_exportLoopBegin = m_playPos[Mode_PlaySong].m_timeLine->loopBegin() < m_exportSongEnd && - m_playPos[Mode_PlaySong].m_timeLine->loopEnd() <= m_exportSongEnd ? - m_playPos[Mode_PlaySong].m_timeLine->loopBegin() : MidiTime(0,0); - m_exportLoopEnd = m_playPos[Mode_PlaySong].m_timeLine->loopBegin() < m_exportSongEnd && - m_playPos[Mode_PlaySong].m_timeLine->loopEnd() <= m_exportSongEnd ? - m_playPos[Mode_PlaySong].m_timeLine->loopEnd() : MidiTime(0,0); + m_exportSongBegin = TimePos(0,0); + // FIXME: remove this check once we load timeline in headless mode + if (m_playPos[Mode_PlaySong].m_timeLine) + { + m_exportLoopBegin = m_playPos[Mode_PlaySong].m_timeLine->loopBegin() < m_exportSongEnd && + m_playPos[Mode_PlaySong].m_timeLine->loopEnd() <= m_exportSongEnd ? + m_playPos[Mode_PlaySong].m_timeLine->loopBegin() : TimePos(0,0); + m_exportLoopEnd = m_playPos[Mode_PlaySong].m_timeLine->loopBegin() < m_exportSongEnd && + m_playPos[Mode_PlaySong].m_timeLine->loopEnd() <= m_exportSongEnd ? + m_playPos[Mode_PlaySong].m_timeLine->loopEnd() : TimePos(0,0); + } m_playPos[Mode_PlaySong].setTicks( 0 ); } @@ -781,8 +724,6 @@ void Song::startExport() playSong(); - m_exporting = true; - m_vstSyncController.setPlaybackState( true ); } @@ -793,7 +734,6 @@ void Song::stopExport() { stop(); m_exporting = false; - m_exportLoop = false; m_vstSyncController.setPlaybackState( m_playing ); } @@ -868,7 +808,7 @@ AutomationPattern * Song::tempoAutomationPattern() } -AutomatedValueMap Song::automatedValuesAt(MidiTime time, int tcoNum) const +AutomatedValueMap Song::automatedValuesAt(TimePos time, int tcoNum) const { return TrackContainer::automatedValuesFromTracks(TrackList{m_globalAutomationTrack} << tracks(), time, tcoNum); } @@ -946,8 +886,6 @@ void Song::clearProject() Engine::projectJournal()->clearJournal(); Engine::projectJournal()->setJournalling( true ); - - InstrumentTrackView::cleanupWindowCache(); } @@ -1200,7 +1138,11 @@ void Song::loadProject( const QString & fileName ) } else { +#if (QT_VERSION >= QT_VERSION_CHECK(5,15,0)) + QTextStream(stderr) << Engine::getSong()->errorSummary() << Qt::endl; +#else QTextStream(stderr) << Engine::getSong()->errorSummary() << endl; +#endif } } @@ -1422,21 +1364,34 @@ void Song::clearErrors() void Song::collectError( const QString error ) { - m_errors.append( error ); + if (!m_errors.contains(error)) { m_errors[error] = 1; } + else { m_errors[ error ]++; } } bool Song::hasErrors() { - return ( m_errors.length() > 0 ); + return !(m_errors.isEmpty()); } QString Song::errorSummary() { - QString errors = m_errors.join("\n") + '\n'; + QString errors; + + auto i = m_errors.constBegin(); + while (i != m_errors.constEnd()) + { + errors.append( i.key() ); + if( i.value() > 1 ) + { + errors.append( tr(" (repeated %1 times)").arg( i.value() ) ); + } + errors.append("\n"); + ++i; + } errors.prepend( "\n\n" ); errors.prepend( tr( "The following errors occurred while loading: " ) ); diff --git a/src/core/StepRecorder.cpp b/src/core/StepRecorder.cpp index e107c58181b..1413d505014 100644 --- a/src/core/StepRecorder.cpp +++ b/src/core/StepRecorder.cpp @@ -43,7 +43,7 @@ void StepRecorder::initialize() connect(&m_updateReleasedTimer, SIGNAL(timeout()), this, SLOT(removeNotesReleasedForTooLong())); } -void StepRecorder::start(const MidiTime& currentPosition, const MidiTime& stepLength) +void StepRecorder::start(const TimePos& currentPosition, const TimePos& stepLength) { m_isRecording = true; @@ -53,7 +53,7 @@ void StepRecorder::start(const MidiTime& currentPosition, const MidiTime& stepLe const int q = m_pianoRoll.quantization(); const int curPosTicks = currentPosition.getTicks(); const int QuantizedPosTicks = (curPosTicks / q) * q; - const MidiTime& QuantizedPos = MidiTime(QuantizedPosTicks); + const TimePos& QuantizedPos = TimePos(QuantizedPosTicks); m_curStepStartPos = QuantizedPos; m_curStepLength = 0; @@ -154,7 +154,7 @@ bool StepRecorder::keyPressEvent(QKeyEvent* ke) return event_handled; } -void StepRecorder::setStepsLength(const MidiTime& newLength) +void StepRecorder::setStepsLength(const TimePos& newLength) { if(m_isStepInProgress) { @@ -319,7 +319,7 @@ void StepRecorder::removeNotesReleasedForTooLong() } } -MidiTime StepRecorder::getCurStepEndPos() +TimePos StepRecorder::getCurStepEndPos() { return m_curStepStartPos + m_curStepLength; } diff --git a/src/core/midi/MidiTime.cpp b/src/core/TimePos.cpp similarity index 64% rename from src/core/midi/MidiTime.cpp rename to src/core/TimePos.cpp index 4e718a1d880..9d25b9ce136 100644 --- a/src/core/midi/MidiTime.cpp +++ b/src/core/TimePos.cpp @@ -1,5 +1,5 @@ /* - * MidiTime.cpp - Class that encapsulates the position of a note/event in terms of + * TimePos.cpp - Class that encapsulates the position of a note/event in terms of * its bar, beat and tick. * * Copyright (c) 2004-2014 Tobias Doerffel = 0 ) { @@ -160,53 +160,53 @@ f_cnt_t MidiTime::frames( const float framesPerTick ) const return 0; } -double MidiTime::getTimeInMilliseconds( bpm_t beatsPerMinute ) const +double TimePos::getTimeInMilliseconds( bpm_t beatsPerMinute ) const { return ticksToMilliseconds( getTicks(), beatsPerMinute ); } -MidiTime MidiTime::fromFrames( const f_cnt_t frames, const float framesPerTick ) +TimePos TimePos::fromFrames( const f_cnt_t frames, const float framesPerTick ) { - return MidiTime( static_cast( frames / framesPerTick ) ); + return TimePos( static_cast( frames / framesPerTick ) ); } -tick_t MidiTime::ticksPerBar() +tick_t TimePos::ticksPerBar() { return s_ticksPerBar; } -tick_t MidiTime::ticksPerBar( const TimeSig &sig ) +tick_t TimePos::ticksPerBar( const TimeSig &sig ) { return DefaultTicksPerBar * sig.numerator() / sig.denominator(); } -int MidiTime::stepsPerBar() +int TimePos::stepsPerBar() { int steps = ticksPerBar() / DefaultBeatsPerBar; return qMax( 1, steps ); } -void MidiTime::setTicksPerBar( tick_t tpb ) +void TimePos::setTicksPerBar( tick_t tpb ) { s_ticksPerBar = tpb; } -MidiTime MidiTime::stepPosition( int step ) +TimePos TimePos::stepPosition( int step ) { return step * ticksPerBar() / stepsPerBar(); } -double MidiTime::ticksToMilliseconds( tick_t ticks, bpm_t beatsPerMinute ) +double TimePos::ticksToMilliseconds( tick_t ticks, bpm_t beatsPerMinute ) { - return MidiTime::ticksToMilliseconds( static_cast(ticks), beatsPerMinute ); + return TimePos::ticksToMilliseconds( static_cast(ticks), beatsPerMinute ); } -double MidiTime::ticksToMilliseconds(double ticks, bpm_t beatsPerMinute) +double TimePos::ticksToMilliseconds(double ticks, bpm_t beatsPerMinute) { // 60 * 1000 / 48 = 1250 return ( ticks * 1250 ) / beatsPerMinute; diff --git a/src/core/Track.cpp b/src/core/Track.cpp index f6b10928013..a6111c06e82 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1,6 +1,5 @@ /* - * Track.cpp - implementation of classes concerning tracks -> necessary for - * all track-like objects (beat/bassline, sample-track...) + * Track.cpp - implementation of Track class * * Copyright (c) 2004-2014 Tobias Doerffel * @@ -24,2060 +23,24 @@ */ /** \file Track.cpp - * \brief All classes concerning tracks and track-like objects + * \brief Implementation of Track class */ -/* - * \mainpage Track classes - * - * \section introduction Introduction - * - * \todo fill this out - */ - -#include "Track.h" - -#include - -#include -#include -#include -#include -#include - - -#include "AutomationPattern.h" -#include "AutomationTrack.h" -#include "AutomationEditor.h" -#include "BBEditor.h" -#include "BBTrack.h" -#include "BBTrackContainer.h" -#include "ConfigManager.h" -#include "Clipboard.h" -#include "embed.h" -#include "Engine.h" -#include "GuiApplication.h" -#include "FxMixerView.h" -#include "gui_templates.h" -#include "MainWindow.h" -#include "Mixer.h" -#include "ProjectJournal.h" -#include "SampleTrack.h" -#include "Song.h" -#include "SongEditor.h" -#include "StringPairDrag.h" -#include "TextFloat.h" - - -/*! The width of the resize grip in pixels - */ -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. - * - * In a number of situations, LMMS displays a floating text bubble - * beside the cursor as you move or resize elements of a track about. - * This pointer keeps track of it, as you only ever need one at a time. - */ -TextFloat * TrackContentObjectView::s_textFloat = NULL; - - -// =========================================================================== -// TrackContentObject -// =========================================================================== -/*! \brief Create a new TrackContentObject - * - * Creates a new track content object for the given track. - * - * \param _track The track that will contain the new object - */ -TrackContentObject::TrackContentObject( Track * track ) : - Model( track ), - m_track( track ), - m_startPosition(), - m_length(), - m_mutedModel( false, this, tr( "Mute" ) ), - m_selectViewOnCreate( false ) -{ - if( getTrack() ) - { - getTrack()->addTCO( this ); - } - setJournalling( false ); - movePosition( 0 ); - changeLength( 0 ); - setJournalling( true ); -} - - - - -/*! \brief Destroy a TrackContentObject - * - * Destroys the given track content object. - * - */ -TrackContentObject::~TrackContentObject() -{ - emit destroyedTCO(); - - if( getTrack() ) - { - getTrack()->removeTCO( this ); - } -} - - - - -/*! \brief Move this TrackContentObject's position in time - * - * If the track content object has moved, update its position. We - * also add a journal entry for undo and update the display. - * - * \param _pos The new position of the track content object. - */ -void TrackContentObject::movePosition( const MidiTime & pos ) -{ - if( m_startPosition != pos ) - { - Engine::mixer()->requestChangeInModel(); - m_startPosition = pos; - Engine::mixer()->doneChangeInModel(); - Engine::getSong()->updateLength(); - emit positionChanged(); - } -} - - - - -/*! \brief Change the length of this TrackContentObject - * - * If the track content object's length has changed, update it. We - * also add a journal entry for undo and update the display. - * - * \param _length The new length of the track content object. - */ -void TrackContentObject::changeLength( const MidiTime & length ) -{ - m_length = length; - Engine::getSong()->updateLength(); - emit lengthChanged(); -} - - - - -bool TrackContentObject::comparePosition(const TrackContentObject *a, const TrackContentObject *b) -{ - return a->startPosition() < b->startPosition(); -} - - - - -/*! \brief Copy this TrackContentObject to the clipboard. - * - * Copies this track content object to the clipboard. - */ -void TrackContentObject::copy() -{ - Clipboard::copy( this ); -} - - - - -/*! \brief Pastes this TrackContentObject into a track. - * - * Pastes this track content object into a track. - * - * \param _je The journal entry to undo - */ -void TrackContentObject::paste() -{ - if( Clipboard::getContent( nodeName() ) != NULL ) - { - const MidiTime pos = startPosition(); - restoreState( *( Clipboard::getContent( nodeName() ) ) ); - movePosition( pos ); - } - AutomationPattern::resolveAllIDs(); - GuiApplication::instance()->automationEditor()->m_editor->updateAfterPatternChange(); -} - - - - -/*! \brief Mutes this TrackContentObject - * - * Restore the previous state of this track content object. This will - * restore the position or the length of the track content object - * depending on what was changed. - * - * \param _je The journal entry to undo - */ -void TrackContentObject::toggleMute() -{ - m_mutedModel.setValue( !m_mutedModel.value() ); - emit dataChanged(); -} - - - - -MidiTime TrackContentObject::startTimeOffset() const -{ - return m_startTimeOffset; -} - - - - -void TrackContentObject::setStartTimeOffset( const MidiTime &startTimeOffset ) -{ - m_startTimeOffset = startTimeOffset; -} - - - - - - - -// =========================================================================== -// trackContentObjectView -// =========================================================================== -/*! \brief Create a new trackContentObjectView - * - * Creates a new track content object view for the given - * track content object in the given track view. - * - * \param _tco The track content object to be displayed - * \param _tv The track view that will contain the new object - */ -TrackContentObjectView::TrackContentObjectView( TrackContentObject * tco, - TrackView * tv ) : - selectableObject( tv->getTrackContentWidget() ), - ModelView( NULL, this ), - m_tco( tco ), - m_trackView( tv ), - m_action( NoAction ), - m_initialMousePos( QPoint( 0, 0 ) ), - m_initialMouseGlobalPos( QPoint( 0, 0 ) ), - m_initialTCOPos( MidiTime(0) ), - m_initialTCOEnd( MidiTime(0) ), - m_initialOffsets( QVector() ), - m_hint( NULL ), - m_mutedColor( 0, 0, 0 ), - m_mutedBackgroundColor( 0, 0, 0 ), - m_selectedColor( 0, 0, 0 ), - m_textColor( 0, 0, 0 ), - m_textShadowColor( 0, 0, 0 ), - m_BBPatternBackground( 0, 0, 0 ), - m_gradient( true ), - m_needsUpdate( true ) -{ - if( s_textFloat == NULL ) - { - s_textFloat = new TextFloat; - s_textFloat->setPixmap( embed::getIconPixmap( "clock" ) ); - } - - setAttribute( Qt::WA_OpaquePaintEvent, true ); - setAttribute( Qt::WA_DeleteOnClose, true ); - setFocusPolicy( Qt::StrongFocus ); - setCursor( QCursor( embed::getIconPixmap( "hand" ), 3, 3 ) ); - move( 0, 0 ); - show(); - - setFixedHeight( tv->getTrackContentWidget()->height() - 1); - setAcceptDrops( true ); - setMouseTracking( true ); - - connect( m_tco, SIGNAL( lengthChanged() ), - this, SLOT( updateLength() ) ); - connect( gui->songEditor()->m_editor->zoomingModel(), SIGNAL( dataChanged() ), this, SLOT( updateLength() ) ); - connect( m_tco, SIGNAL( positionChanged() ), - this, SLOT( updatePosition() ) ); - connect( m_tco, SIGNAL( destroyedTCO() ), this, SLOT( close() ) ); - setModel( m_tco ); - - m_trackView->getTrackContentWidget()->addTCOView( this ); - updateLength(); - updatePosition(); -} - - - - -/*! \brief Destroy a trackContentObjectView - * - * Destroys the given track content object view. - * - */ -TrackContentObjectView::~TrackContentObjectView() -{ - delete m_hint; - // we have to give our track-container the focus because otherwise the - // op-buttons of our track-widgets could become focus and when the user - // presses space for playing song, just one of these buttons is pressed - // which results in unwanted effects - m_trackView->trackContainerView()->setFocus(); -} - - -/*! \brief Update a TrackContentObjectView - * - * TCO's get drawn only when needed, - * and when a TCO is updated, - * it needs to be redrawn. - * - */ -void TrackContentObjectView::update() -{ - if( fixedTCOs() ) - { - updateLength(); - } - m_needsUpdate = true; - selectableObject::update(); -} - - - -/*! \brief Does this trackContentObjectView have a fixed TCO? - * - * Returns whether the containing trackView has fixed - * TCOs. - * - * \todo What the hell is a TCO here - track content object? And in - * what circumstance are they fixed? - */ -bool TrackContentObjectView::fixedTCOs() -{ - return m_trackView->trackContainerView()->fixedTCOs(); -} - - - -// qproperty access functions, to be inherited & used by TCOviews -//! \brief CSS theming qproperty access method -QColor TrackContentObjectView::mutedColor() const -{ return m_mutedColor; } - -QColor TrackContentObjectView::mutedBackgroundColor() const -{ return m_mutedBackgroundColor; } - -QColor TrackContentObjectView::selectedColor() const -{ return m_selectedColor; } - -QColor TrackContentObjectView::textColor() const -{ return m_textColor; } - -QColor TrackContentObjectView::textBackgroundColor() const -{ - return m_textBackgroundColor; -} - -QColor TrackContentObjectView::textShadowColor() const -{ return m_textShadowColor; } - -QColor TrackContentObjectView::BBPatternBackground() const -{ return m_BBPatternBackground; } - -bool TrackContentObjectView::gradient() const -{ return m_gradient; } - -//! \brief CSS theming qproperty access method -void TrackContentObjectView::setMutedColor( const QColor & c ) -{ m_mutedColor = QColor( c ); } - -void TrackContentObjectView::setMutedBackgroundColor( const QColor & c ) -{ m_mutedBackgroundColor = QColor( c ); } - -void TrackContentObjectView::setSelectedColor( const QColor & c ) -{ m_selectedColor = QColor( c ); } - -void TrackContentObjectView::setTextColor( const QColor & c ) -{ m_textColor = QColor( c ); } - -void TrackContentObjectView::setTextBackgroundColor( const QColor & c ) -{ - m_textBackgroundColor = c; -} - -void TrackContentObjectView::setTextShadowColor( const QColor & c ) -{ m_textShadowColor = QColor( c ); } - -void TrackContentObjectView::setBBPatternBackground( const QColor & c ) -{ m_BBPatternBackground = QColor( c ); } - -void TrackContentObjectView::setGradient( const bool & b ) -{ m_gradient = b; } - -// access needsUpdate member variable -bool TrackContentObjectView::needsUpdate() -{ return m_needsUpdate; } -void TrackContentObjectView::setNeedsUpdate( bool b ) -{ m_needsUpdate = b; } - -/*! \brief Close a trackContentObjectView - * - * Closes a track content object view by asking the track - * view to remove us and then asking the QWidget to close us. - * - * \return Boolean state of whether the QWidget was able to close. - */ -bool TrackContentObjectView::close() -{ - m_trackView->getTrackContentWidget()->removeTCOView( this ); - return QWidget::close(); -} - - - - -/*! \brief Removes a trackContentObjectView from its track view. - * - * Like the close() method, this asks the track view to remove this - * track content object view. However, the track content object is - * scheduled for later deletion rather than closed immediately. - * - */ -void TrackContentObjectView::remove() -{ - m_trackView->getTrack()->addJournalCheckPoint(); - - // delete ourself - close(); - m_tco->deleteLater(); -} - - - - -/*! \brief Cut this trackContentObjectView from its track to the clipboard. - * - * Perform the 'cut' action of the clipboard - copies the track content - * object to the clipboard and then removes it from the track. - */ -void TrackContentObjectView::cut() -{ - m_tco->copy(); - remove(); -} - - - - -/*! \brief Updates a trackContentObjectView's length - * - * If this track content object view has a fixed TCO, then we must - * keep the width of our parent. Otherwise, calculate our width from - * the track content object's length in pixels adding in the border. - * - */ -void TrackContentObjectView::updateLength() -{ - if( fixedTCOs() ) - { - setFixedWidth( parentWidget()->width() ); - } - else - { - setFixedWidth( - static_cast( m_tco->length() * pixelsPerBar() / - MidiTime::ticksPerBar() ) + 1 /*+ - TCO_BORDER_WIDTH * 2-1*/ ); - } - m_trackView->trackContainerView()->update(); -} - - - - -/*! \brief Updates a trackContentObjectView's position. - * - * Ask our track view to change our position. Then make sure that the - * track view is updated in case this position has changed the track - * view's length. - * - */ -void TrackContentObjectView::updatePosition() -{ - m_trackView->getTrackContentWidget()->changePosition(); - // moving a TCO can result in change of song-length etc., - // therefore we update the track-container - m_trackView->trackContainerView()->update(); -} - - - -/*! \brief Change the trackContentObjectView's display when something - * being dragged enters it. - * - * We need to notify Qt to change our display if something being - * dragged has entered our 'airspace'. - * - * \param dee The QDragEnterEvent to watch. - */ -void TrackContentObjectView::dragEnterEvent( QDragEnterEvent * dee ) -{ - TrackContentWidget * tcw = getTrackView()->getTrackContentWidget(); - MidiTime tcoPos = MidiTime( m_tco->startPosition() ); - - if( tcw->canPasteSelection( tcoPos, dee ) == false ) - { - dee->ignore(); - } - else - { - StringPairDrag::processDragEnterEvent( dee, "tco_" + - QString::number( m_tco->getTrack()->type() ) ); - } -} - - - - -/*! \brief Handle something being dropped on this trackContentObjectView. - * - * When something has been dropped on this trackContentObjectView, and - * it's a track content object, then use an instance of our dataFile reader - * to take the xml of the track content object and turn it into something - * we can write over our current state. - * - * \param de The QDropEvent to handle. - */ -void TrackContentObjectView::dropEvent( QDropEvent * de ) -{ - QString type = StringPairDrag::decodeKey( de ); - QString value = StringPairDrag::decodeValue( de ); - - // Track must be the same type to paste into - if( type != ( "tco_" + QString::number( m_tco->getTrack()->type() ) ) ) - { - return; - } - - // Defer to rubberband paste if we're in that mode - if( m_trackView->trackContainerView()->allowRubberband() == true ) - { - TrackContentWidget * tcw = getTrackView()->getTrackContentWidget(); - MidiTime tcoPos = MidiTime( m_tco->startPosition() ); - - if( tcw->pasteSelection( tcoPos, de ) == true ) - { - de->accept(); - } - return; - } - - // Don't allow pasting a tco into itself. - QObject* qwSource = de->source(); - if( qwSource != NULL && - dynamic_cast( qwSource ) == this ) - { - return; - } - - // Copy state into existing tco - DataFile dataFile( value.toUtf8() ); - MidiTime pos = m_tco->startPosition(); - QDomElement tcos = dataFile.content().firstChildElement( "tcos" ); - m_tco->restoreState( tcos.firstChildElement().firstChildElement() ); - m_tco->movePosition( pos ); - AutomationPattern::resolveAllIDs(); - de->accept(); -} - - - - -/*! \brief Handle a dragged selection leaving our 'airspace'. - * - * \param e The QEvent to watch. - */ -void TrackContentObjectView::leaveEvent( QEvent * e ) -{ - if( cursor().shape() != Qt::BitmapCursor ) - { - setCursor( QCursor( embed::getIconPixmap( "hand" ), 3, 3 ) ); - } - if( e != NULL ) - { - QWidget::leaveEvent( e ); - } -} - -/*! \brief Create a DataFile suitable for copying multiple trackContentObjects. - * - * trackContentObjects in the vector are written to the "tcos" node in the - * DataFile. The trackContentObjectView's initial mouse position is written - * to the "initialMouseX" node in the DataFile. When dropped on a track, - * this is used to create copies of the TCOs. - * - * \param tcos The trackContectObjects to save in a DataFile - */ -DataFile TrackContentObjectView::createTCODataFiles( - const QVector & tcoViews) const -{ - Track * t = m_trackView->getTrack(); - TrackContainer * tc = t->trackContainer(); - DataFile dataFile( DataFile::DragNDropData ); - QDomElement tcoParent = dataFile.createElement( "tcos" ); - - typedef QVector tcoViewVector; - for( tcoViewVector::const_iterator it = tcoViews.begin(); - it != tcoViews.end(); ++it ) - { - // Insert into the dom under the "tcos" element - Track* tcoTrack = ( *it )->m_trackView->getTrack(); - int trackIndex = tc->tracks().indexOf( tcoTrack ); - QDomElement tcoElement = dataFile.createElement( "tco" ); - tcoElement.setAttribute( "trackIndex", trackIndex ); - tcoElement.setAttribute( "trackType", tcoTrack->type() ); - tcoElement.setAttribute( "trackName", tcoTrack->name() ); - ( *it )->m_tco->saveState( dataFile, tcoElement ); - tcoParent.appendChild( tcoElement ); - } - - dataFile.content().appendChild( tcoParent ); - - // Add extra metadata needed for calculations later - int initialTrackIndex = tc->tracks().indexOf( t ); - if( initialTrackIndex < 0 ) - { - printf("Failed to find selected track in the TrackContainer.\n"); - return dataFile; - } - QDomElement metadata = dataFile.createElement( "copyMetadata" ); - // 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 bar containing the TCO we grabbed - metadata.setAttribute( "grabbedTCOPos", m_tco->startPosition() ); - - dataFile.content().appendChild( metadata ); - - return dataFile; -} - -void TrackContentObjectView::paintTextLabel(QString const & text, QPainter & painter) -{ - if (text.trimmed() == "") - { - return; - } - - painter.setRenderHint( QPainter::TextAntialiasing ); - - QFont labelFont = this->font(); - labelFont.setHintingPreference( QFont::PreferFullHinting ); - painter.setFont( labelFont ); - - const int textTop = TCO_BORDER_WIDTH + 1; - const int textLeft = TCO_BORDER_WIDTH + 3; - - QFontMetrics fontMetrics(labelFont); - QString elidedPatternName = fontMetrics.elidedText(text, Qt::ElideMiddle, width() - 2 * textLeft); - - if (elidedPatternName.length() < 2) - { - elidedPatternName = text.trimmed(); - } - - painter.fillRect(QRect(0, 0, width(), fontMetrics.height() + 2 * textTop), textBackgroundColor()); - - int const finalTextTop = textTop + fontMetrics.ascent(); - painter.setPen(textShadowColor()); - painter.drawText( textLeft + 1, finalTextTop + 1, elidedPatternName ); - painter.setPen( textColor() ); - painter.drawText( textLeft, finalTextTop, elidedPatternName ); -} - -/*! \brief Handle a mouse press on this trackContentObjectView. - * - * Handles the various ways in which a trackContentObjectView can be - * used with a click of a mouse button. - * - * * If our container supports rubber band selection then handle - * selection events. - * * or if shift-left button, add this object to the selection - * * or if ctrl-left button, start a drag-copy event - * * or if just plain left button, resize if we're resizeable - * * or if ctrl-middle button, mute the track content object - * * or if middle button, maybe delete the track content object. - * - * \param me The QMouseEvent to handle. - */ -void TrackContentObjectView::mousePressEvent( QMouseEvent * me ) -{ - setInitialPos( me->pos() ); - setInitialOffsets(); - if( !fixedTCOs() && me->button() == Qt::LeftButton ) - { - if( me->modifiers() & Qt::ControlModifier ) - { - if( isSelected() ) - { - m_action = CopySelection; - } - else - { - m_action = ToggleSelected; - } - } - else if( !me->modifiers() - || (me->modifiers() & Qt::AltModifier) - || (me->modifiers() & Qt::ShiftModifier) ) - { - if( isSelected() ) - { - m_action = MoveSelection; - } - else - { - gui->songEditor()->m_editor->selectAllTcos( false ); - m_tco->addJournalCheckPoint(); - - // move or resize - m_tco->setJournalling( false ); - - setInitialPos( me->pos() ); - setInitialOffsets(); - - SampleTCO * sTco = dynamic_cast( m_tco ); - if( me->x() < RESIZE_GRIP_WIDTH && sTco - && !m_tco->getAutoResize() ) - { - m_action = ResizeLeft; - setCursor( Qt::SizeHorCursor ); - } - else if( me->x() < width() - RESIZE_GRIP_WIDTH ) - { - m_action = Move; - setCursor( Qt::SizeAllCursor ); - } - else if( !m_tco->getAutoResize() ) - { - m_action = Resize; - setCursor( Qt::SizeHorCursor ); - } - - if( m_action == Move ) - { - s_textFloat->setTitle( tr( "Current position" ) ); - s_textFloat->setText( QString( "%1:%2" ). - arg( m_tco->startPosition().getBar() + 1 ). - arg( m_tco->startPosition().getTicks() % - 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().getBar() ). - arg( m_tco->length().getTicks() % - MidiTime::ticksPerBar() ). - arg( m_tco->startPosition().getBar() + 1 ). - arg( m_tco->startPosition().getTicks() % - MidiTime::ticksPerBar() ). - arg( m_tco->endPosition().getBar() + 1 ). - arg( m_tco->endPosition().getTicks() % - MidiTime::ticksPerBar() ) ); - } - // s_textFloat->reparent( this ); - // setup text-float as if TCO was already moved/resized - s_textFloat->moveGlobal( this, QPoint( width() + 2, height() + 2) ); - s_textFloat->show(); - } - - delete m_hint; - QString hint = m_action == Move || m_action == MoveSelection - ? tr( "Press <%1> and drag to make a copy." ) - : tr( "Press <%1> for free resizing." ); - m_hint = TextFloat::displayMessage( tr( "Hint" ), hint.arg(UI_CTRL_KEY), - embed::getIconPixmap( "hint" ), 0 ); - } - } - else if( me->button() == Qt::RightButton ) - { - if( me->modifiers() & Qt::ControlModifier ) - { - m_tco->toggleMute(); - } - else if( me->modifiers() & Qt::ShiftModifier && !fixedTCOs() ) - { - remove(); - } - } - else if( me->button() == Qt::MidButton ) - { - if( me->modifiers() & Qt::ControlModifier ) - { - m_tco->toggleMute(); - } - else if( !fixedTCOs() ) - { - remove(); - } - } -} - - - - -/*! \brief Handle a mouse movement (drag) on this trackContentObjectView. - * - * Handles the various ways in which a trackContentObjectView can be - * used with a mouse drag. - * - * * If in move mode, move ourselves in the track, - * * or if in move-selection mode, move the entire selection, - * * or if in resize mode, resize ourselves, - * * otherwise ??? - * - * \param me The QMouseEvent to handle. - * \todo what does the final else case do here? - */ -void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) -{ - if( m_action == CopySelection || m_action == ToggleSelected ) - { - if( mouseMovedDistance( me, 2 ) == true ) - { - QVector tcoViews; - if( m_action == CopySelection ) - { - // Collect all selected TCOs - QVector so = - m_trackView->trackContainerView()->selectedObjects(); - for( auto it = so.begin(); it != so.end(); ++it ) - { - TrackContentObjectView * tcov = - dynamic_cast( *it ); - if( tcov != NULL ) - { - tcoViews.push_back( tcov ); - } - } - } - else - { - gui->songEditor()->m_editor->selectAllTcos( false ); - tcoViews.push_back( this ); - } - // Clear the action here because mouseReleaseEvent will not get - // triggered once we go into drag. - m_action = NoAction; - - // Write the TCOs to the DataFile for copying - DataFile dataFile = createTCODataFiles( tcoViews ); - - // TODO -- thumbnail for all selected - QPixmap thumbnail = grab().scaled( - 128, 128, - Qt::KeepAspectRatio, - Qt::SmoothTransformation ); - new StringPairDrag( QString( "tco_%1" ).arg( - m_tco->getTrack()->type() ), - dataFile.toString(), thumbnail, this ); - } - } - - if( me->modifiers() & Qt::ControlModifier ) - { - delete m_hint; - m_hint = NULL; - } - - const float ppb = m_trackView->trackContainerView()->pixelsPerBar(); - if( m_action == Move ) - { - MidiTime newPos = draggedTCOPos( me ); - - // Don't go left of bar zero - newPos = max( 0, newPos.getTicks() ); - m_tco->movePosition( newPos ); - m_trackView->getTrackContentWidget()->changePosition(); - s_textFloat->setText( QString( "%1:%2" ). - arg( newPos.getBar() + 1 ). - arg( newPos.getTicks() % - MidiTime::ticksPerBar() ) ); - s_textFloat->moveGlobal( this, QPoint( width() + 2, height() + 2 ) ); - } - else if( m_action == MoveSelection ) - { - // 1: Find the position we want to move the grabbed TCO to - MidiTime newPos = draggedTCOPos( me ); - - // 2: Handle moving the other selected TCOs the same distance - QVector so = - m_trackView->trackContainerView()->selectedObjects(); - QVector tcos; // List of selected clips - int leftmost = 0; // Leftmost clip's offset from grabbed clip - // Populate tcos, find leftmost - for( QVector::iterator it = so.begin(); - it != so.end(); ++it ) - { - TrackContentObjectView * tcov = - dynamic_cast( *it ); - if( tcov == NULL ) { continue; } - tcos.push_back( tcov->m_tco ); - int index = std::distance( so.begin(), it ); - leftmost = min (leftmost, m_initialOffsets[index].getTicks() ); - } - // Make sure the leftmost clip doesn't get moved to a negative position - if ( newPos.getTicks() + leftmost < 0 ) { newPos = -leftmost; } - - for( QVector::iterator it = tcos.begin(); - it != tcos.end(); ++it ) - { - int index = std::distance( tcos.begin(), it ); - ( *it )->movePosition( newPos + m_initialOffsets[index] ); - } - } - else if( m_action == Resize || m_action == ResizeLeft ) - { - // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize - 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::ticksPerBar()) ); - - if( m_action == Resize ) - { - // The clip's new length - MidiTime l = static_cast( me->x() * MidiTime::ticksPerBar() / ppb ); - - if ( unquantized ) - { // We want to preserve this adjusted offset, - // even if the user switches to snapping later - setInitialPos( m_initialMousePos ); - // Don't resize to less than 1 tick - m_tco->changeLength( qMax( 1, l ) ); - } - else if ( me->modifiers() & Qt::ShiftModifier ) - { // If shift is held, quantize clip's end position - MidiTime end = MidiTime( m_initialTCOPos + l ).quantize( snapSize ); - // The end position has to be after the clip's start - MidiTime min = m_initialTCOPos.quantize( snapSize ); - if ( min <= m_initialTCOPos ) min += snapLength; - m_tco->changeLength( qMax(min - m_initialTCOPos, end - m_initialTCOPos) ); - } - else - { // Otherwise, resize in fixed increments - MidiTime initialLength = m_initialTCOEnd - m_initialTCOPos; - MidiTime offset = MidiTime( l - initialLength ).quantize( snapSize ); - // Don't resize to less than 1 tick - MidiTime min = MidiTime( initialLength % snapLength ); - if (min < 1) min += snapLength; - m_tco->changeLength( qMax( min, initialLength + offset) ); - } - } - else - { - SampleTCO * sTco = dynamic_cast( m_tco ); - if( sTco ) - { - const int x = mapToParent( me->pos() ).x() - m_initialMousePos.x(); - - MidiTime t = qMax( 0, (int) - m_trackView->trackContainerView()->currentPosition() + - static_cast( x * MidiTime::ticksPerBar() / ppb ) ); - - if( unquantized ) - { // We want to preserve this adjusted offset, - // even if the user switches to snapping later - setInitialPos( m_initialMousePos ); - //Don't resize to less than 1 tick - t = qMin( m_initialTCOEnd - 1, t); - } - else if( me->modifiers() & Qt::ShiftModifier ) - { // If shift is held, quantize clip's start position - // Don't let the start position move past the end position - MidiTime max = m_initialTCOEnd.quantize( snapSize ); - if ( max >= m_initialTCOEnd ) max -= snapLength; - t = qMin( max, t.quantize( snapSize ) ); - } - else - { // Otherwise, resize in fixed increments - // Don't resize to less than 1 tick - MidiTime initialLength = m_initialTCOEnd - m_initialTCOPos; - MidiTime minLength = MidiTime( initialLength % snapLength ); - if (minLength < 1) minLength += snapLength; - MidiTime offset = MidiTime(t - m_initialTCOPos).quantize( snapSize ); - t = qMin( m_initialTCOEnd - minLength, m_initialTCOPos + offset ); - } - - MidiTime oldPos = m_tco->startPosition(); - if( m_tco->length() + ( oldPos - t ) >= 1 ) - { - m_tco->movePosition( t ); - m_trackView->getTrackContentWidget()->changePosition(); - m_tco->changeLength( m_tco->length() + ( oldPos - t ) ); - sTco->setStartTimeOffset( sTco->startTimeOffset() + ( oldPos - t ) ); - } - } - } - s_textFloat->setText( tr( "%1:%2 (%3:%4 to %5:%6)" ). - arg( m_tco->length().getBar() ). - arg( m_tco->length().getTicks() % - MidiTime::ticksPerBar() ). - arg( m_tco->startPosition().getBar() + 1 ). - arg( m_tco->startPosition().getTicks() % - MidiTime::ticksPerBar() ). - arg( m_tco->endPosition().getBar() + 1 ). - arg( m_tco->endPosition().getTicks() % - MidiTime::ticksPerBar() ) ); - s_textFloat->moveGlobal( this, QPoint( width() + 2, height() + 2) ); - } - else - { - SampleTCO * sTco = dynamic_cast( m_tco ); - if( ( me->x() > width() - RESIZE_GRIP_WIDTH && !me->buttons() && !m_tco->getAutoResize() ) - || ( me->x() < RESIZE_GRIP_WIDTH && !me->buttons() && sTco && !m_tco->getAutoResize() ) ) - { - setCursor( Qt::SizeHorCursor ); - } - else - { - leaveEvent( NULL ); - } - } -} - - - - -/*! \brief Handle a mouse release on this trackContentObjectView. - * - * If we're in move or resize mode, journal the change as appropriate. - * Then tidy up. - * - * \param me The QMouseEvent to handle. - */ -void TrackContentObjectView::mouseReleaseEvent( QMouseEvent * me ) -{ - // If the CopySelection was chosen as the action due to mouse movement, - // it will have been cleared. At this point Toggle is the desired action. - // An active StringPairDrag will prevent this method from being called, - // so a real CopySelection would not have occurred. - if( m_action == CopySelection || - ( m_action == ToggleSelected && mouseMovedDistance( me, 2 ) == false ) ) - { - setSelected( !isSelected() ); - } - - if( m_action == Move || m_action == Resize || m_action == ResizeLeft ) - { - // TODO: Fix m_tco->setJournalling() consistency - m_tco->setJournalling( true ); - } - m_action = NoAction; - delete m_hint; - m_hint = NULL; - s_textFloat->hide(); - leaveEvent( NULL ); - selectableObject::mouseReleaseEvent( me ); -} - - - - -/*! \brief Set up the context menu for this trackContentObjectView. - * - * Set up the various context menu events that can apply to a - * track content object view. - * - * \param cme The QContextMenuEvent to add the actions to. - */ -void TrackContentObjectView::contextMenuEvent( QContextMenuEvent * cme ) -{ - if( cme->modifiers() ) - { - return; - } - - QMenu contextMenu( this ); - if( fixedTCOs() == false ) - { - contextMenu.addAction( embed::getIconPixmap( "cancel" ), - tr( "Delete (middle mousebutton)" ), - this, SLOT( remove() ) ); - contextMenu.addSeparator(); - contextMenu.addAction( embed::getIconPixmap( "edit_cut" ), - tr( "Cut" ), this, SLOT( cut() ) ); - } - contextMenu.addAction( embed::getIconPixmap( "edit_copy" ), - tr( "Copy" ), m_tco, SLOT( copy() ) ); - contextMenu.addAction( embed::getIconPixmap( "edit_paste" ), - tr( "Paste" ), m_tco, SLOT( paste() ) ); - contextMenu.addSeparator(); - contextMenu.addAction( embed::getIconPixmap( "muted" ), - tr( "Mute/unmute (<%1> + middle click)" ).arg(UI_CTRL_KEY), - m_tco, SLOT( toggleMute() ) ); - constructContextMenu( &contextMenu ); - - contextMenu.exec( QCursor::pos() ); -} - - - - -/*! \brief How many pixels a bar takes for this trackContentObjectView. - * - * \return the number of pixels per bar. - */ -float TrackContentObjectView::pixelsPerBar() -{ - return m_trackView->trackContainerView()->pixelsPerBar(); -} - - -/*! \brief Save the offsets between all selected tracks and a clicked track */ -void TrackContentObjectView::setInitialOffsets() -{ - QVector so = m_trackView->trackContainerView()->selectedObjects(); - QVector offsets; - for( QVector::iterator it = so.begin(); - it != so.end(); ++it ) - { - TrackContentObjectView * tcov = - dynamic_cast( *it ); - if( tcov == NULL ) - { - continue; - } - offsets.push_back( tcov->m_tco->startPosition() - m_initialTCOPos ); - } - - m_initialOffsets = offsets; -} - - - - -/*! \brief Detect whether the mouse moved more than n pixels on screen. - * - * \param _me The QMouseEvent. - * \param distance The threshold distance that the mouse has moved to return true. - */ -bool TrackContentObjectView::mouseMovedDistance( QMouseEvent * me, int distance ) -{ - QPoint dPos = mapToGlobal( me->pos() ) - m_initialMouseGlobalPos; - const int pixelsMoved = dPos.manhattanLength(); - return ( pixelsMoved > distance || pixelsMoved < -distance ); -} - - - -/*! \brief Calculate the new position of a dragged TCO from a mouse event - * - * - * \param me The QMouseEvent - */ -MidiTime TrackContentObjectView::draggedTCOPos( QMouseEvent * me ) -{ - //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::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 - || (me->modifiers() & Qt::ControlModifier) - || (me->modifiers() & Qt::AltModifier) ) - { - // We want to preserve this adjusted offset, - // even if the user switches to snapping - setInitialPos( m_initialMousePos ); - } - else if ( me->modifiers() & Qt::ShiftModifier ) - { // If shift is held, quantize position (Default in 1.2.0 and earlier) - // or end position, whichever is closest to the actual position - MidiTime startQ = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); - // Find start position that gives snapped clip end position - MidiTime endQ = ( newPos + m_tco->length() ); - endQ = endQ.quantize( gui->songEditor()->m_editor->getSnapSize() ); - endQ = endQ - m_tco->length(); - // Select the position closest to actual position - if ( abs(newPos - startQ) < abs(newPos - endQ) ) newPos = startQ; - else newPos = endQ; - } - else - { // Otherwise, quantize moved distance (preserves user offsets) - newPos = m_initialTCOPos + offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); - } - return newPos; -} - - - - -// =========================================================================== -// trackContentWidget -// =========================================================================== -/*! \brief Create a new trackContentWidget - * - * Creates a new track content widget for the given track. - * The content widget comprises the 'grip bar' and the 'tools' button - * for the track's context menu. - * - * \param parent The parent track. - */ -TrackContentWidget::TrackContentWidget( TrackView * parent ) : - QWidget( parent ), - m_trackView( parent ), - m_darkerColor( Qt::SolidPattern ), - m_lighterColor( Qt::SolidPattern ), - m_gridColor( Qt::SolidPattern ), - m_embossColor( Qt::SolidPattern ) -{ - setAcceptDrops( true ); - - connect( parent->trackContainerView(), - SIGNAL( positionChanged( const MidiTime & ) ), - this, SLOT( changePosition( const MidiTime & ) ) ); - - setStyle( QApplication::style() ); - - updateBackground(); -} - - - - -/*! \brief Destroy this trackContentWidget - * - * Destroys the trackContentWidget. - */ -TrackContentWidget::~TrackContentWidget() -{ -} - - - - -void TrackContentWidget::updateBackground() -{ - const TrackContainerView * tcv = m_trackView->trackContainerView(); - - // Assume even-pixels-per-bar. Makes sense, should be like this anyways - int ppb = static_cast( tcv->pixelsPerBar() ); - - int w = ppb * BARS_PER_GROUP; - int h = height(); - m_background = QPixmap( w * 2, height() ); - QPainter pmp( &m_background ); - - pmp.fillRect( 0, 0, w, h, darkerColor() ); - pmp.fillRect( w, 0, w , h, lighterColor() ); - - // draw lines - // vertical lines - pmp.setPen( QPen( gridColor(), 1 ) ); - 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 += ppb ) - { - pmp.drawLine( QLineF( x, 0.0, x, h ) ); - } - - // horizontal line - pmp.setPen( QPen( gridColor(), 1 ) ); - pmp.drawLine( 0, h-1, w*2, h-1 ); - - pmp.end(); - - // Force redraw - update(); -} - - - - -/*! \brief Adds a trackContentObjectView to this widget. - * - * Adds a(nother) trackContentObjectView to our list of views. We also - * check that our position is up-to-date. - * - * \param tcov The trackContentObjectView to add. - */ -void TrackContentWidget::addTCOView( TrackContentObjectView * tcov ) -{ - TrackContentObject * tco = tcov->getTrackContentObject(); - - m_tcoViews.push_back( tcov ); - - tco->saveJournallingState( false ); - changePosition(); - tco->restoreJournallingState(); -} - - - - -/*! \brief Removes the given trackContentObjectView to this widget. - * - * Removes the given trackContentObjectView from our list of views. - * - * \param tcov The trackContentObjectView to add. - */ -void TrackContentWidget::removeTCOView( TrackContentObjectView * tcov ) -{ - tcoViewVector::iterator it = std::find( m_tcoViews.begin(), - m_tcoViews.end(), - tcov ); - if( it != m_tcoViews.end() ) - { - m_tcoViews.erase( it ); - Engine::getSong()->setModified(); - } -} - - - - -/*! \brief Update ourselves by updating all the tCOViews attached. - * - */ -void TrackContentWidget::update() -{ - for( tcoViewVector::iterator it = m_tcoViews.begin(); - it != m_tcoViews.end(); ++it ) - { - ( *it )->setFixedHeight( height() - 1 ); - ( *it )->update(); - } - QWidget::update(); -} - - - - -// resposible for moving track-content-widgets to appropriate position after -// change of visible viewport -/*! \brief Move the trackContentWidget to a new place in time - * - * \param newPos The MIDI time to move to. - */ -void TrackContentWidget::changePosition( const MidiTime & newPos ) -{ - if( m_trackView->trackContainerView() == gui->getBBEditor()->trackContainerView() ) - { - const int curBB = Engine::getBBTrackContainer()->currentBB(); - setUpdatesEnabled( false ); - - // first show TCO for current BB... - for( tcoViewVector::iterator it = m_tcoViews.begin(); - it != m_tcoViews.end(); ++it ) - { - if( ( *it )->getTrackContentObject()-> - startPosition().getBar() == curBB ) - { - ( *it )->move( 0, ( *it )->y() ); - ( *it )->raise(); - ( *it )->show(); - } - else - { - ( *it )->lower(); - } - } - // ...then hide others to avoid flickering - for( tcoViewVector::iterator it = m_tcoViews.begin(); - it != m_tcoViews.end(); ++it ) - { - if( ( *it )->getTrackContentObject()-> - startPosition().getBar() != curBB ) - { - ( *it )->hide(); - } - } - setUpdatesEnabled( true ); - return; - } - - MidiTime pos = newPos; - if( pos < 0 ) - { - pos = m_trackView->trackContainerView()->currentPosition(); - } - - const int begin = pos; - const int end = endPosition( pos ); - const float ppb = m_trackView->trackContainerView()->pixelsPerBar(); - - setUpdatesEnabled( false ); - for( tcoViewVector::iterator it = m_tcoViews.begin(); - it != m_tcoViews.end(); ++it ) - { - TrackContentObjectView * tcov = *it; - TrackContentObject * tco = tcov->getTrackContentObject(); - - tco->changeLength( tco->length() ); - - const int ts = tco->startPosition(); - const int te = tco->endPosition()-3; - if( ( ts >= begin && ts <= end ) || - ( te >= begin && te <= end ) || - ( ts <= begin && te >= end ) ) - { - tcov->move( static_cast( ( ts - begin ) * ppb / - MidiTime::ticksPerBar() ), - tcov->y() ); - if( !tcov->isVisible() ) - { - tcov->show(); - } - } - else - { - tcov->move( -tcov->width()-10, tcov->y() ); - } - } - setUpdatesEnabled( true ); - - // redraw background -// update(); -} - - - - -/*! \brief Return the position of the trackContentWidget in bars. - * - * \param mouseX the mouse's current X position in pixels. - */ -MidiTime TrackContentWidget::getPosition( int mouseX ) -{ - TrackContainerView * tv = m_trackView->trackContainerView(); - return MidiTime( tv->currentPosition() + - mouseX * - MidiTime::ticksPerBar() / - static_cast( tv->pixelsPerBar() ) ); -} - - - - -/*! \brief Respond to a drag enter event on the trackContentWidget - * - * \param dee the Drag Enter Event to respond to - */ -void TrackContentWidget::dragEnterEvent( QDragEnterEvent * dee ) -{ - MidiTime tcoPos = getPosition( dee->pos().x() ); - if( canPasteSelection( tcoPos, dee ) == false ) - { - dee->ignore(); - } - else - { - StringPairDrag::processDragEnterEvent( dee, "tco_" + - QString::number( getTrack()->type() ) ); - } -} - - - - -/*! \brief Returns whether a selection of TCOs can be pasted into this - * - * \param tcoPos the position of the TCO slot being pasted on - * \param de the DropEvent generated - */ -bool TrackContentWidget::canPasteSelection( MidiTime tcoPos, const QDropEvent* de ) -{ - const QMimeData * mimeData = de->mimeData(); - - Track * t = getTrack(); - QString type = StringPairDrag::decodeMimeKey( mimeData ); - QString value = StringPairDrag::decodeMimeValue( mimeData ); - - // We can only paste into tracks of the same type - if( type != ( "tco_" + QString::number( t->type() ) ) || - m_trackView->trackContainerView()->fixedTCOs() == true ) - { - return false; - } - - // value contains XML needed to reconstruct TCOs and place them - DataFile dataFile( value.toUtf8() ); - - // Extract the metadata and which TCO was grabbed - QDomElement metadata = dataFile.content().firstChildElement( "copyMetadata" ); - QDomAttr tcoPosAttr = metadata.attributeNode( "grabbedTCOPos" ); - MidiTime grabbedTCOPos = tcoPosAttr.value().toInt(); - MidiTime grabbedTCOBar = MidiTime( grabbedTCOPos.getBar(), 0 ); - - // Extract the track index that was originally clicked - QDomAttr tiAttr = metadata.attributeNode( "initialTrackIndex" ); - const int initialTrackIndex = tiAttr.value().toInt(); - - // Get the current track's index - const TrackContainer::TrackList tracks = t->trackContainer()->tracks(); - const int currentTrackIndex = tracks.indexOf( t ); - - // 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 == grabbedTCOBar && currentTrackIndex == initialTrackIndex ) - { - return false; - } - - // Extract the tco data - QDomElement tcoParent = dataFile.content().firstChildElement( "tcos" ); - QDomNodeList tcoNodes = tcoParent.childNodes(); - - // Determine if all the TCOs will land on a valid track - for( int i = 0; i < tcoNodes.length(); i++ ) - { - QDomElement tcoElement = tcoNodes.item( i ).toElement(); - int trackIndex = tcoElement.attributeNode( "trackIndex" ).value().toInt(); - int finalTrackIndex = trackIndex + currentTrackIndex - initialTrackIndex; - - // Track must be in TrackContainer's tracks - if( finalTrackIndex < 0 || finalTrackIndex >= tracks.size() ) - { - return false; - } - - // Track must be of the same type - auto startTrackType = tcoElement.attributeNode("trackType").value().toInt(); - Track * endTrack = tracks.at( finalTrackIndex ); - if( startTrackType != endTrack->type() ) - { - return false; - } - } - - return true; -} - -/*! \brief Pastes a selection of TCOs onto the track - * - * \param tcoPos the position of the TCO slot being pasted on - * \param de the DropEvent generated - */ -bool TrackContentWidget::pasteSelection( MidiTime tcoPos, QDropEvent * de ) -{ - if( canPasteSelection( tcoPos, de ) == false ) - { - return false; - } - - QString type = StringPairDrag::decodeKey( de ); - QString value = StringPairDrag::decodeValue( de ); - - getTrack()->addJournalCheckPoint(); - - // value contains XML needed to reconstruct TCOs and place them - DataFile dataFile( value.toUtf8() ); - - // Extract the tco data - QDomElement tcoParent = dataFile.content().firstChildElement( "tcos" ); - QDomNodeList tcoNodes = tcoParent.childNodes(); - - // Extract the track index that was originally clicked - QDomElement metadata = dataFile.content().firstChildElement( "copyMetadata" ); - QDomAttr tiAttr = metadata.attributeNode( "initialTrackIndex" ); - int initialTrackIndex = tiAttr.value().toInt(); - QDomAttr tcoPosAttr = metadata.attributeNode( "grabbedTCOPos" ); - MidiTime grabbedTCOPos = tcoPosAttr.value().toInt(); - - // 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() ); - - bool wasSelection = m_trackView->trackContainerView()->rubberBand()->selectedObjects().count(); - - // Unselect the old group - const QVector so = - m_trackView->trackContainerView()->selectedObjects(); - for( QVector::const_iterator it = so.begin(); - it != so.end(); ++it ) - { - ( *it )->setSelected( false ); - } - - - // TODO -- Need to draw the hovericon either way, or ghost the TCOs - // onto their final position. - - float snapSize = gui->songEditor()->m_editor->getSnapSize(); - // All patterns should be offset the same amount as the grabbed pattern - MidiTime offset = MidiTime(tcoPos - grabbedTCOPos); - // Users expect clips to "fall" backwards, so bias the offset - offset = offset - MidiTime::ticksPerBar() * snapSize / 2; - // The offset is quantized (rather than the positions) to preserve fine adjustments - offset = offset.quantize(snapSize); - - for( int i = 0; isongEditor()->m_editor->getSnapSize(); - if (offset == 0) { pos += shift; } - - TrackContentObject * tco = t->createTCO( pos ); - tco->restoreState( tcoElement ); - tco->movePosition( pos ); - if( wasSelection ) - { - tco->selectViewOnCreate( true ); - } - - //check tco name, if the same as source track name dont copy - QString sourceTrackName = outerTCOElement.attributeNode( "trackName" ).value(); - if( tco->name() == sourceTrackName ) - { - tco->setName( "" ); - } - } - - AutomationPattern::resolveAllIDs(); - - return true; -} - - -/*! \brief Respond to a drop event on the trackContentWidget - * - * \param de the Drop Event to respond to - */ -void TrackContentWidget::dropEvent( QDropEvent * de ) -{ - MidiTime tcoPos = MidiTime( getPosition( de->pos().x() ) ); - if( pasteSelection( tcoPos, de ) == true ) - { - de->accept(); - } -} - - - - -/*! \brief Respond to a mouse press on the trackContentWidget - * - * \param me the mouse press event to respond to - */ -void TrackContentWidget::mousePressEvent( QMouseEvent * me ) -{ - if( m_trackView->trackContainerView()->allowRubberband() == true ) - { - QWidget::mousePressEvent( me ); - } - else if( me->modifiers() & Qt::ShiftModifier ) - { - QWidget::mousePressEvent( me ); - } - else if( me->button() == Qt::LeftButton && - !m_trackView->trackContainerView()->fixedTCOs() ) - { - QVector so = m_trackView->trackContainerView()->rubberBand()->selectedObjects(); - for( int i = 0; i < so.count(); ++i ) - { - so.at( i )->setSelected( false); - } - getTrack()->addJournalCheckPoint(); - const MidiTime pos = getPosition( me->x() ).getBar() * - MidiTime::ticksPerBar(); - TrackContentObject * tco = getTrack()->createTCO( pos ); - - tco->saveJournallingState( false ); - tco->movePosition( pos ); - tco->restoreJournallingState(); - } -} - - - - -/*! \brief Repaint the trackContentWidget on command - * - * \param pe the Paint Event to respond to - */ -void TrackContentWidget::paintEvent( QPaintEvent * pe ) -{ - // Assume even-pixels-per-bar. Makes sense, should be like this anyways - const TrackContainerView * tcv = m_trackView->trackContainerView(); - 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().getBar() * ppb, 0 ) ); - } -} - - - - -/*! \brief Updates the background tile pixmap on size changes. - * - * \param resizeEvent the resize event to pass to base class - */ -void TrackContentWidget::resizeEvent( QResizeEvent * resizeEvent ) -{ - // Update backgroud - updateBackground(); - // Force redraw - QWidget::resizeEvent( resizeEvent ); -} - - - - -/*! \brief Return the track shown by the trackContentWidget - * - */ -Track * TrackContentWidget::getTrack() -{ - return m_trackView->getTrack(); -} - - - - -/*! \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 ppb = m_trackView->trackContainerView()->pixelsPerBar(); - const int w = width(); - return posStart + static_cast( w * MidiTime::ticksPerBar() / ppb ); -} - - - - -// qproperty access methods -//! \brief CSS theming qproperty access method -QBrush TrackContentWidget::darkerColor() const -{ return m_darkerColor; } - -//! \brief CSS theming qproperty access method -QBrush TrackContentWidget::lighterColor() const -{ return m_lighterColor; } - -//! \brief CSS theming qproperty access method -QBrush TrackContentWidget::gridColor() const -{ return m_gridColor; } - -//! \brief CSS theming qproperty access method -QBrush TrackContentWidget::embossColor() const -{ return m_embossColor; } - -//! \brief CSS theming qproperty access method -void TrackContentWidget::setDarkerColor( const QBrush & c ) -{ m_darkerColor = c; } - -//! \brief CSS theming qproperty access method -void TrackContentWidget::setLighterColor( const QBrush & c ) -{ m_lighterColor = c; } - -//! \brief CSS theming qproperty access method -void TrackContentWidget::setGridColor( const QBrush & c ) -{ m_gridColor = c; } - -//! \brief CSS theming qproperty access method -void TrackContentWidget::setEmbossColor( const QBrush & c ) -{ m_embossColor = c; } - - -// =========================================================================== -// trackOperationsWidget -// =========================================================================== - - -QPixmap * TrackOperationsWidget::s_grip = NULL; /*!< grip pixmap */ - - -/*! \brief Create a new trackOperationsWidget - * - * The trackOperationsWidget is the grip and the mute button of a track. - * - * \param parent the trackView to contain this widget - */ -TrackOperationsWidget::TrackOperationsWidget( TrackView * parent ) : - QWidget( parent ), /*!< The parent widget */ - m_trackView( parent ) /*!< The parent track view */ -{ - ToolTip::add( this, tr( "Press <%1> while clicking on move-grip " - "to begin a new drag'n'drop action." ).arg(UI_CTRL_KEY) ); - - QMenu * toMenu = new QMenu( this ); - toMenu->setFont( pointSize<9>( toMenu->font() ) ); - connect( toMenu, SIGNAL( aboutToShow() ), this, SLOT( updateMenu() ) ); - - - setObjectName( "automationEnabled" ); - - - m_trackOps = new QPushButton( this ); - m_trackOps->move( 12, 1 ); - m_trackOps->setFocusPolicy( Qt::NoFocus ); - m_trackOps->setMenu( toMenu ); - ToolTip::add( m_trackOps, tr( "Actions" ) ); - - - m_muteBtn = new PixmapButton( this, tr( "Mute" ) ); - m_muteBtn->setActiveGraphic( embed::getIconPixmap( "led_off" ) ); - m_muteBtn->setInactiveGraphic( embed::getIconPixmap( "led_green" ) ); - m_muteBtn->setCheckable( true ); - - m_soloBtn = new PixmapButton( this, tr( "Solo" ) ); - m_soloBtn->setActiveGraphic( embed::getIconPixmap( "led_red" ) ); - m_soloBtn->setInactiveGraphic( embed::getIconPixmap( "led_off" ) ); - m_soloBtn->setCheckable( true ); - - if( ConfigManager::inst()->value( "ui", - "compacttrackbuttons" ).toInt() ) - { - m_muteBtn->move( 46, 0 ); - m_soloBtn->move( 46, 16 ); - } - else - { - m_muteBtn->move( 46, 8 ); - m_soloBtn->move( 62, 8 ); - } - - m_muteBtn->show(); - ToolTip::add( m_muteBtn, tr( "Mute" ) ); - - m_soloBtn->show(); - ToolTip::add( m_soloBtn, tr( "Solo" ) ); - - connect( this, SIGNAL( trackRemovalScheduled( TrackView * ) ), - m_trackView->trackContainerView(), - SLOT( deleteTrackView( TrackView * ) ), - Qt::QueuedConnection ); -} - - - - -/*! \brief Destroy an existing trackOperationsWidget - * - */ -TrackOperationsWidget::~TrackOperationsWidget() -{ -} - - - - -/*! \brief Respond to trackOperationsWidget mouse events - * - * If it's the left mouse button, and Ctrl is held down, and we're - * not a Beat+Bassline Editor track, then start a new drag event to - * copy this track. - * - * Otherwise, ignore all other events. - * - * \param me The mouse event to respond to. - */ -void TrackOperationsWidget::mousePressEvent( QMouseEvent * me ) -{ - if( me->button() == Qt::LeftButton && - me->modifiers() & Qt::ControlModifier && - m_trackView->getTrack()->type() != Track::BBTrack ) - { - DataFile dataFile( DataFile::DragNDropData ); - m_trackView->getTrack()->saveState( dataFile, dataFile.content() ); - new StringPairDrag( QString( "track_%1" ).arg( - m_trackView->getTrack()->type() ), - dataFile.toString(), m_trackView->getTrackSettingsWidget()->grab(), - this ); - } - else if( me->button() == Qt::LeftButton ) - { - // track-widget (parent-widget) initiates track-move - me->ignore(); - } -} - - - - -/*! \brief Repaint the trackOperationsWidget - * - * If we're not moving, and in the Beat+Bassline Editor, then turn - * automation on or off depending on its previous state and show - * ourselves. - * - * Otherwise, hide ourselves. - * - * \todo Flesh this out a bit - is it correct? - * \param pe The paint event to respond to - */ -void TrackOperationsWidget::paintEvent( QPaintEvent * pe ) -{ - QPainter p( this ); - p.fillRect( rect(), palette().brush(QPalette::Background) ); - - if( m_trackView->isMovingTrack() == false ) - { - s_grip = new QPixmap( embed::getIconPixmap( - "track_op_grip" ) ); - - p.drawPixmap( 2, 2, *s_grip ); - } - else - { - s_grip = new QPixmap( embed::getIconPixmap( - "track_op_grip_c" ) ); - - p.drawPixmap( 2, 2, *s_grip ); - } -} - - - - -/*! \brief Clone this track - * - */ -void TrackOperationsWidget::cloneTrack() -{ - TrackContainerView *tcView = m_trackView->trackContainerView(); - - Track *newTrack = m_trackView->getTrack()->clone(); - TrackView *newTrackView = tcView->createTrackView( newTrack ); - - int index = tcView->trackViews().indexOf( m_trackView ); - int i = tcView->trackViews().size(); - while ( i != index + 1 ) - { - tcView->moveTrackView( newTrackView, i - 1 ); - i--; - } -} - - -/*! \brief Clear this track - clears all TCOs from the track */ -void TrackOperationsWidget::clearTrack() -{ - Track * t = m_trackView->getTrack(); - t->addJournalCheckPoint(); - t->lock(); - t->deleteTCOs(); - t->unlock(); -} - - - -/*! \brief Remove this track from the track list - * - */ -void TrackOperationsWidget::removeTrack() -{ - emit trackRemovalScheduled( m_trackView ); -} - - - - -/*! \brief Update the trackOperationsWidget context menu - * - * For all track types, we have the Clone and Remove options. - * For instrument-tracks we also offer the MIDI-control-menu - * For automation tracks, extra options: turn on/off recording - * on all TCOs (same should be added for sample tracks when - * sampletrack recording is implemented) - */ -void TrackOperationsWidget::updateMenu() -{ - QMenu * toMenu = m_trackOps->menu(); - toMenu->clear(); - toMenu->addAction( embed::getIconPixmap( "edit_copy", 16, 16 ), - tr( "Clone this track" ), - this, SLOT( cloneTrack() ) ); - toMenu->addAction( embed::getIconPixmap( "cancel", 16, 16 ), - tr( "Remove this track" ), - this, SLOT( removeTrack() ) ); - - if( ! m_trackView->trackContainerView()->fixedTCOs() ) - { - toMenu->addAction( tr( "Clear this track" ), this, SLOT( clearTrack() ) ); - } - if (QMenu *fxMenu = m_trackView->createFxMenu(tr("FX %1: %2"), tr("Assign to new FX Channel"))) - { - toMenu->addMenu(fxMenu); - } - - if (InstrumentTrackView * trackView = dynamic_cast(m_trackView)) - { - toMenu->addSeparator(); - toMenu->addMenu(trackView->midiMenu()); - } - if( dynamic_cast( m_trackView ) ) - { - toMenu->addAction( tr( "Turn all recording on" ), this, SLOT( recordingOn() ) ); - toMenu->addAction( tr( "Turn all recording off" ), this, SLOT( recordingOff() ) ); - } -} - - -void TrackOperationsWidget::toggleRecording( bool on ) -{ - AutomationTrackView * atv = dynamic_cast( m_trackView ); - if( atv ) - { - for( TrackContentObject * tco : atv->getTrack()->getTCOs() ) - { - AutomationPattern * ap = dynamic_cast( tco ); - if( ap ) { ap->setRecording( on ); } - } - atv->update(); - } -} - - - -void TrackOperationsWidget::recordingOn() -{ - toggleRecording( true ); -} +#include "Track.h" -void TrackOperationsWidget::recordingOff() -{ - toggleRecording( false ); -} +#include +#include "AutomationPattern.h" +#include "AutomationTrack.h" +#include "BBTrack.h" +#include "BBTrackContainer.h" +#include "ConfigManager.h" +#include "Engine.h" +#include "InstrumentTrack.h" +#include "SampleTrack.h" +#include "Song.h" -// =========================================================================== -// track -// =========================================================================== /*! \brief Create a new (empty) track object * @@ -2094,12 +57,12 @@ Track::Track( TrackTypes type, TrackContainer * tc ) : m_trackContainer( tc ), /*!< The track container object */ m_type( type ), /*!< The track type */ m_name(), /*!< The track's name */ - m_mutedModel( false, this, tr( "Mute" ) ), - /*!< For controlling track muting */ - m_soloModel( false, this, tr( "Solo" ) ), - /*!< For controlling track soloing */ + m_mutedModel( false, this, tr( "Mute" ) ), /*!< For controlling track muting */ + m_soloModel( false, this, tr( "Solo" ) ), /*!< For controlling track soloing */ m_simpleSerializingMode( false ), - m_trackContentObjects() /*!< The track content objects (segments) */ + m_trackContentObjects(), /*!< The track content objects (segments) */ + m_color( 0, 0, 0 ), + m_hasColor( false ) { m_trackContainer->addTrack( this ); m_height = -1; @@ -2203,12 +166,15 @@ Track * Track::create( const QDomElement & element, TrackContainer * tc ) /*! \brief Clone a track from this track * */ -Track * Track::clone() +Track* Track::clone() { QDomDocument doc; - QDomElement parent = doc.createElement( "clone" ); - saveState( doc, parent ); - return create( parent.firstChild().toElement(), m_trackContainer ); + QDomElement parent = doc.createElement("clone"); + saveState(doc, parent); + Track* t = create(parent.firstChild().toElement(), m_trackContainer); + + AutomationPattern::resolveAllIDs(); + return t; } @@ -2237,12 +203,19 @@ void Track::saveSettings( QDomDocument & doc, QDomElement & element ) element.setAttribute( "name", name() ); m_mutedModel.saveSettings( doc, element, "muted" ); m_soloModel.saveSettings( doc, element, "solo" ); + // Save the mutedBeforeSolo value so we can recover the muted state if any solo was active (issue 5562) + element.setAttribute( "mutedBeforeSolo", int(m_mutedBeforeSolo) ); if( m_height >= MINIMAL_TRACK_HEIGHT ) { element.setAttribute( "trackheight", m_height ); } - + + if( m_hasColor ) + { + element.setAttribute( "color", m_color.name() ); + } + QDomElement tsDe = doc.createElement( nodeName() ); // let actual track (InstrumentTrack, bbTrack, sampleTrack etc.) save // its settings @@ -2291,6 +264,15 @@ void Track::loadSettings( const QDomElement & element ) m_mutedModel.loadSettings( element, "muted" ); m_soloModel.loadSettings( element, "solo" ); + // Get the mutedBeforeSolo value so we can recover the muted state if any solo was active. + // Older project files that didn't have this attribute will set the value to false (issue 5562) + m_mutedBeforeSolo = QVariant( element.attribute( "mutedBeforeSolo", "0" ) ).toBool(); + + if( element.hasAttribute( "color" ) ) + { + m_color.setNamedColor( element.attribute( "color" ) ); + m_hasColor = true; + } if( m_simpleSerializingMode ) { @@ -2328,10 +310,8 @@ void Track::loadSettings( const QDomElement & element ) && !node.toElement().attribute( "metadata" ).toInt() ) { TrackContentObject * tco = createTCO( - MidiTime( 0 ) ); + TimePos( 0 ) ); tco->restoreState( node.toElement() ); - saveJournallingState( false ); - restoreJournallingState(); } } node = node.nextSibling(); @@ -2426,7 +406,7 @@ TrackContentObject * Track::getTCO( int tcoNum ) } printf( "called Track::getTCO( %d ), " "but TCO %d doesn't exist\n", tcoNum, tcoNum ); - return createTCO( tcoNum * MidiTime::ticksPerBar() ); + return createTCO( tcoNum * TimePos::ticksPerBar() ); } @@ -2470,8 +450,8 @@ int Track::getTCONum( const TrackContentObject * tco ) * \param start The MIDI start time of the range. * \param end The MIDI endi time of the range. */ -void Track::getTCOsInRange( tcoVector & tcoV, const MidiTime & start, - const MidiTime & end ) +void Track::getTCOsInRange( tcoVector & tcoV, const TimePos & start, + const TimePos & end ) { for( TrackContentObject* tco : m_trackContentObjects ) { @@ -2503,7 +483,7 @@ void Track::swapPositionOfTCOs( int tcoNum1, int tcoNum2 ) qSwap( m_trackContentObjects[tcoNum1], m_trackContentObjects[tcoNum2] ); - const MidiTime pos = m_trackContentObjects[tcoNum1]->startPosition(); + const TimePos pos = m_trackContentObjects[tcoNum1]->startPosition(); m_trackContentObjects[tcoNum1]->movePosition( m_trackContentObjects[tcoNum2]->startPosition() ); @@ -2517,10 +497,9 @@ void Track::createTCOsForBB( int bb ) { while( numOfTCOs() < bb + 1 ) { - MidiTime position = MidiTime( numOfTCOs(), 0 ); + TimePos position = TimePos( numOfTCOs(), 0 ); TrackContentObject * tco = createTCO( position ); - tco->movePosition( position ); - tco->changeLength( MidiTime( 1, 0 ) ); + tco->changeLength( TimePos( 1, 0 ) ); } } @@ -2534,7 +513,7 @@ 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::insertBar( const MidiTime & pos ) +void Track::insertBar( const TimePos & pos ) { // we'll increase the position of every TCO, positioned behind pos, by // one bar @@ -2544,7 +523,7 @@ void Track::insertBar( const MidiTime & pos ) if( ( *it )->startPosition() >= pos ) { ( *it )->movePosition( (*it)->startPosition() + - MidiTime::ticksPerBar() ); + TimePos::ticksPerBar() ); } } } @@ -2556,7 +535,7 @@ void Track::insertBar( const MidiTime & pos ) * * \param pos The time at which we want to remove the bar. */ -void Track::removeBar( const MidiTime & pos ) +void Track::removeBar( const TimePos & pos ) { // we'll decrease the position of every TCO, positioned behind pos, by // one bar @@ -2565,8 +544,7 @@ void Track::removeBar( const MidiTime & pos ) { if( ( *it )->startPosition() >= pos ) { - ( *it )->movePosition( qMax( ( *it )->startPosition() - - MidiTime::ticksPerBar(), 0 ) ); + (*it)->movePosition((*it)->startPosition() - TimePos::ticksPerBar()); } } } @@ -2600,7 +578,7 @@ bar_t Track::length() const } } - return last / MidiTime::ticksPerBar(); + return last / TimePos::ticksPerBar(); } @@ -2630,6 +608,9 @@ void Track::toggleSolo() } const bool solo = m_soloModel.value(); + // Should we use the new behavior of solo or the older/legacy one? + const bool soloLegacyBehavior = ConfigManager::inst()->value("app", "sololegacybehavior", "0").toInt(); + for( TrackContainer::TrackList::const_iterator it = tl.begin(); it != tl.end(); ++it ) { @@ -2640,7 +621,15 @@ void Track::toggleSolo() { ( *it )->m_mutedBeforeSolo = ( *it )->isMuted(); } - ( *it )->setMuted( *it == this ? false : true ); + // Don't mute AutomationTracks (keep their original state) unless we are on the sololegacybehavior mode + if( *it == this ) + { + ( *it )->setMuted( false ); + } + else if( soloLegacyBehavior || ( *it )->type() != AutomationTrack ) + { + ( *it )->setMuted( true ); + } if( *it != this ) { ( *it )->m_soloModel.setValue( false ); @@ -2648,427 +637,38 @@ void Track::toggleSolo() } else if( !soloBefore ) { - ( *it )->setMuted( ( *it )->m_mutedBeforeSolo ); - } - } -} - - - - -BoolModel *Track::getMutedModel() -{ - return &m_mutedModel; -} - - - - - - -// =========================================================================== -// trackView -// =========================================================================== - -/*! \brief Create a new track View. - * - * The track View is handles the actual display of the track, including - * displaying its various widgets and the track segments. - * - * \param track The track to display. - * \param tcv The track Container View for us to be displayed in. - * \todo Is my description of these properties correct? - */ -TrackView::TrackView( Track * track, TrackContainerView * tcv ) : - QWidget( tcv->contentWidget() ), /*!< The Track Container View's content widget. */ - ModelView( NULL, this ), /*!< The model view of this track */ - m_track( track ), /*!< The track we're displaying */ - m_trackContainerView( tcv ), /*!< The track Container View we're displayed in */ - m_trackOperationsWidget( this ), /*!< Our trackOperationsWidget */ - m_trackSettingsWidget( this ), /*!< Our trackSettingsWidget */ - m_trackContentWidget( this ), /*!< Our trackContentWidget */ - m_action( NoAction ) /*!< The action we're currently performing */ -{ - setAutoFillBackground( true ); - QPalette pal; - pal.setColor( backgroundRole(), QColor( 32, 36, 40 ) ); - setPalette( pal ); - - m_trackSettingsWidget.setAutoFillBackground( true ); - - QHBoxLayout * layout = new QHBoxLayout( this ); - layout->setMargin( 0 ); - layout->setSpacing( 0 ); - layout->addWidget( &m_trackOperationsWidget ); - layout->addWidget( &m_trackSettingsWidget ); - layout->addWidget( &m_trackContentWidget, 1 ); - setFixedHeight( m_track->getHeight() ); - - resizeEvent( NULL ); - - setAcceptDrops( true ); - setAttribute( Qt::WA_DeleteOnClose, true ); - - - connect( m_track, SIGNAL( destroyedTrack() ), this, SLOT( close() ) ); - connect( m_track, - SIGNAL( trackContentObjectAdded( TrackContentObject * ) ), - this, SLOT( createTCOView( TrackContentObject * ) ), - Qt::QueuedConnection ); - - connect( &m_track->m_mutedModel, SIGNAL( dataChanged() ), - &m_trackContentWidget, SLOT( update() ) ); - - connect(&m_track->m_mutedModel, SIGNAL(dataChanged()), - this, SLOT(muteChanged())); - - connect( &m_track->m_soloModel, SIGNAL( dataChanged() ), - m_track, SLOT( toggleSolo() ), Qt::DirectConnection ); - // create views for already existing TCOs - for( Track::tcoVector::iterator it = - m_track->m_trackContentObjects.begin(); - it != m_track->m_trackContentObjects.end(); ++it ) - { - createTCOView( *it ); - } - - m_trackContainerView->addTrackView( this ); -} - - - - -/*! \brief Destroy this track View. - * - */ -TrackView::~TrackView() -{ -} - - - - -/*! \brief Resize this track View. - * - * \param re the Resize Event to handle. - */ -void TrackView::resizeEvent( QResizeEvent * re ) -{ - if( ConfigManager::inst()->value( "ui", - "compacttrackbuttons" ).toInt() ) - { - m_trackOperationsWidget.setFixedSize( TRACK_OP_WIDTH_COMPACT, height() - 1 ); - m_trackSettingsWidget.setFixedSize( DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT, height() - 1 ); - } - else - { - m_trackOperationsWidget.setFixedSize( TRACK_OP_WIDTH, height() - 1 ); - m_trackSettingsWidget.setFixedSize( DEFAULT_SETTINGS_WIDGET_WIDTH, height() - 1 ); - } - m_trackContentWidget.setFixedHeight( height() ); -} - - - - -/*! \brief Update this track View and all its content objects. - * - */ -void TrackView::update() -{ - m_trackContentWidget.update(); - if( !m_trackContainerView->fixedTCOs() ) - { - m_trackContentWidget.changePosition(); - } - QWidget::update(); -} - - - - -/*! \brief Create a menu for assigning/creating channels for this track. - * - */ -QMenu * TrackView::createFxMenu(QString title, QString newFxLabel) -{ - Q_UNUSED(title) - Q_UNUSED(newFxLabel) - return NULL; -} - - - - -/*! \brief Close this track View. - * - */ -bool TrackView::close() -{ - m_trackContainerView->removeTrackView( this ); - return QWidget::close(); -} - - - - -/*! \brief Register that the model of this track View has changed. - * - */ -void TrackView::modelChanged() -{ - m_track = castModel(); - assert( m_track != NULL ); - connect( m_track, SIGNAL( destroyedTrack() ), this, SLOT( close() ) ); - m_trackOperationsWidget.m_muteBtn->setModel( &m_track->m_mutedModel ); - m_trackOperationsWidget.m_soloBtn->setModel( &m_track->m_soloModel ); - ModelView::modelChanged(); - setFixedHeight( m_track->getHeight() ); -} - - - - -/*! \brief Start a drag event on this track View. - * - * \param dee the DragEnterEvent to start. - */ -void TrackView::dragEnterEvent( QDragEnterEvent * dee ) -{ - StringPairDrag::processDragEnterEvent( dee, "track_" + - QString::number( m_track->type() ) ); -} - - - - -/*! \brief Accept a drop event on this track View. - * - * We only accept drop events that are of the same type as this track. - * If so, we decode the data from the drop event by just feeding it - * back into the engine as a state. - * - * \param de the DropEvent to handle. - */ -void TrackView::dropEvent( QDropEvent * de ) -{ - QString type = StringPairDrag::decodeKey( de ); - QString value = StringPairDrag::decodeValue( de ); - if( type == ( "track_" + QString::number( m_track->type() ) ) ) - { - // value contains our XML-data so simply create a - // DataFile which does the rest for us... - DataFile dataFile( value.toUtf8() ); - Engine::mixer()->requestChangeInModel(); - m_track->restoreState( dataFile.content().firstChild().toElement() ); - Engine::mixer()->doneChangeInModel(); - de->accept(); - } -} - - - - -/*! \brief Handle a mouse press event on this track View. - * - * If this track container supports rubber band selection, let the - * widget handle that and don't bother with any other handling. - * - * If the left mouse button is pressed, we handle two things. If - * SHIFT is pressed, then we resize vertically. Otherwise we start - * the process of moving this track to a new position. - * - * Otherwise we let the widget handle the mouse event as normal. - * - * \param me the MouseEvent to handle. - */ -void TrackView::mousePressEvent( QMouseEvent * me ) -{ - - // If previously dragged too small, restore on shift-leftclick - if( height() < DEFAULT_TRACK_HEIGHT && - me->modifiers() & Qt::ShiftModifier && - me->button() == Qt::LeftButton ) - { - setFixedHeight( DEFAULT_TRACK_HEIGHT ); - m_track->setHeight( DEFAULT_TRACK_HEIGHT ); - } - - - int widgetTotal = ConfigManager::inst()->value( "ui", - "compacttrackbuttons" ).toInt()==1 ? - DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT + TRACK_OP_WIDTH_COMPACT : - DEFAULT_SETTINGS_WIDGET_WIDTH + TRACK_OP_WIDTH; - if( m_trackContainerView->allowRubberband() == true && me->x() > widgetTotal ) - { - QWidget::mousePressEvent( me ); - } - else if( me->button() == Qt::LeftButton ) - { - if( me->modifiers() & Qt::ShiftModifier ) - { - m_action = ResizeTrack; - QCursor::setPos( mapToGlobal( QPoint( me->x(), - height() ) ) ); - QCursor c( Qt::SizeVerCursor); - QApplication::setOverrideCursor( c ); - } - else - { - if( me->x()>10 ) // 10 = The width of the grip + 2 pixels to the left and right. - { - QWidget::mousePressEvent( me ); - return; - } - - m_action = MoveTrack; - - QCursor c( Qt::SizeVerCursor ); - QApplication::setOverrideCursor( c ); - // update because in move-mode, all elements in - // track-op-widgets are hidden as a visual feedback - m_trackOperationsWidget.update(); - } - - me->accept(); - } - else - { - QWidget::mousePressEvent( me ); - } -} - - - - -/*! \brief Handle a mouse move event on this track View. - * - * If this track container supports rubber band selection, let the - * widget handle that and don't bother with any other handling. - * - * Otherwise if we've started the move process (from mousePressEvent()) - * then move ourselves into that position, reordering the track list - * with moveTrackViewUp() and moveTrackViewDown() to suit. We make a - * note of this in the undo journal in case the user wants to undo this - * move. - * - * Likewise if we've started a resize process, handle this too, making - * sure that we never go below the minimum track height. - * - * \param me the MouseEvent to handle. - */ -void TrackView::mouseMoveEvent( QMouseEvent * me ) -{ - int widgetTotal = ConfigManager::inst()->value( "ui", - "compacttrackbuttons" ).toInt()==1 ? - DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT + TRACK_OP_WIDTH_COMPACT : - DEFAULT_SETTINGS_WIDGET_WIDTH + TRACK_OP_WIDTH; - if( m_trackContainerView->allowRubberband() == true && me->x() > widgetTotal ) - { - QWidget::mouseMoveEvent( me ); - } - else if( m_action == MoveTrack ) - { - // look which track-widget the mouse-cursor is over - const int yPos = - m_trackContainerView->contentWidget()->mapFromGlobal( me->globalPos() ).y(); - const TrackView * trackAtY = m_trackContainerView->trackViewAt( yPos ); - - // debug code - // qDebug( "y position %d", yPos ); - - // a track-widget not equal to ourself? - if( trackAtY != NULL && trackAtY != this ) - { - // then move us up/down there! - if( me->y() < 0 ) - { - m_trackContainerView->moveTrackViewUp( this ); - } - else + // Unless we are on the sololegacybehavior mode, only restores the + // mute state if the track isn't an Automation Track + if( soloLegacyBehavior || ( *it )->type() != AutomationTrack ) { - m_trackContainerView->moveTrackViewDown( this ); + ( *it )->setMuted( ( *it )->m_mutedBeforeSolo ); } } } - else if( m_action == ResizeTrack ) - { - setFixedHeight( qMax( me->y(), MINIMAL_TRACK_HEIGHT ) ); - m_trackContainerView->realignTracks(); - m_track->setHeight( height() ); - } - - if( height() < DEFAULT_TRACK_HEIGHT ) - { - ToolTip::add( this, m_track->m_name ); - } } - - -/*! \brief Handle a mouse release event on this track View. - * - * \param me the MouseEvent to handle. - */ -void TrackView::mouseReleaseEvent( QMouseEvent * me ) +void Track::trackColorChanged( QColor & c ) { - m_action = NoAction; - while( QApplication::overrideCursor() != NULL ) + for (int i = 0; i < numOfTCOs(); i++) { - QApplication::restoreOverrideCursor(); + m_trackContentObjects[i]->updateColor(); } - m_trackOperationsWidget.update(); - - QWidget::mouseReleaseEvent( me ); -} - - - - -/*! \brief Repaint this track View. - * - * \param pe the PaintEvent to start. - */ -void TrackView::paintEvent( QPaintEvent * pe ) -{ - QStyleOption opt; - opt.initFrom( this ); - QPainter p( this ); - style()->drawPrimitive( QStyle::PE_Widget, &opt, &p, this ); + m_hasColor = true; + m_color = c; } - - - -/*! \brief Create a TrackContentObject View in this track View. - * - * \param tco the TrackContentObject to create the view for. - * \todo is this a good description for what this method does? - */ -void TrackView::createTCOView( TrackContentObject * tco ) +void Track::trackColorReset() { - TrackContentObjectView * tv = tco->createView( this ); - if( tco->getSelectViewOnCreate() == true ) + for (int i = 0; i < numOfTCOs(); i++) { - tv->setSelected( true ); + m_trackContentObjects[i]->updateColor(); } - tco->selectViewOnCreate( false ); + m_hasColor = false; } - - -void TrackView::muteChanged() +BoolModel *Track::getMutedModel() { - FadeButton * indicator = getActivityIndicator(); - if (indicator) { setIndicatorMute(indicator, m_track->m_mutedModel.value()); } + return &m_mutedModel; } - - - -void TrackView::setIndicatorMute(FadeButton* indicator, bool muted) -{ - QPalette::ColorRole role = muted ? QPalette::Highlight : QPalette::BrightText; - indicator->setActiveColor(QApplication::palette().color(QPalette::Active, role)); -} diff --git a/src/core/TrackContainer.cpp b/src/core/TrackContainer.cpp index 95dd46f298c..84846a77ca3 100644 --- a/src/core/TrackContainer.cpp +++ b/src/core/TrackContainer.cpp @@ -248,13 +248,13 @@ bool TrackContainer::isEmpty() const -AutomatedValueMap TrackContainer::automatedValuesAt(MidiTime time, int tcoNum) const +AutomatedValueMap TrackContainer::automatedValuesAt(TimePos time, int tcoNum) const { return automatedValuesFromTracks(tracks(), time, tcoNum); } -AutomatedValueMap TrackContainer::automatedValuesFromTracks(const TrackList &tracks, MidiTime time, int tcoNum) +AutomatedValueMap TrackContainer::automatedValuesFromTracks(const TrackList &tracks, TimePos time, int tcoNum) { Track::tcoVector tcos; @@ -295,7 +295,7 @@ AutomatedValueMap TrackContainer::automatedValuesFromTracks(const TrackList &tra if (! p->hasAutomation()) { continue; } - MidiTime relTime = time - p->startPosition(); + TimePos relTime = time - p->startPosition(); if (! p->getAutoResize()) { relTime = qMin(relTime, p->length()); } @@ -311,9 +311,9 @@ AutomatedValueMap TrackContainer::automatedValuesFromTracks(const TrackList &tra auto bbIndex = dynamic_cast(bb->getTrack())->index(); auto bbContainer = Engine::getBBTrackContainer(); - MidiTime bbTime = time - tco->startPosition(); + TimePos bbTime = time - tco->startPosition(); bbTime = std::min(bbTime, tco->length()); - bbTime = bbTime % (bbContainer->lengthOfBB(bbIndex) * MidiTime::ticksPerBar()); + bbTime = bbTime % (bbContainer->lengthOfBB(bbIndex) * TimePos::ticksPerBar()); auto bbValues = bbContainer->automatedValuesAt(bbTime, bbIndex); for (auto it=bbValues.begin(); it != bbValues.end(); it++) @@ -331,16 +331,3 @@ AutomatedValueMap TrackContainer::automatedValuesFromTracks(const TrackList &tra return valueMap; }; - - -DummyTrackContainer::DummyTrackContainer() : - TrackContainer(), - m_dummyInstrumentTrack( NULL ) -{ - setJournalling( false ); - m_dummyInstrumentTrack = dynamic_cast( - Track::create( Track::InstrumentTrack, - this ) ); - m_dummyInstrumentTrack->setJournalling( false ); -} - diff --git a/src/core/TrackContentObject.cpp b/src/core/TrackContentObject.cpp new file mode 100644 index 00000000000..ad41fd11099 --- /dev/null +++ b/src/core/TrackContentObject.cpp @@ -0,0 +1,206 @@ +/* + * TrackContentObject.cpp - implementation of TrackContentObject class + * + * Copyright (c) 2004-2014 Tobias Doerffel + * + * 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. + * + */ + +#include "TrackContentObject.h" + +#include + +#include "AutomationEditor.h" +#include "AutomationPattern.h" +#include "Engine.h" +#include "GuiApplication.h" +#include "Song.h" + + +/*! \brief Create a new TrackContentObject + * + * Creates a new track content object for the given track. + * + * \param _track The track that will contain the new object + */ +TrackContentObject::TrackContentObject( Track * track ) : + Model( track ), + m_track( track ), + m_startPosition(), + m_length(), + m_mutedModel( false, this, tr( "Mute" ) ), + m_selectViewOnCreate( false ), + m_color( 128, 128, 128 ), + m_useCustomClipColor( false ) +{ + if( getTrack() ) + { + getTrack()->addTCO( this ); + } + setJournalling( false ); + movePosition( 0 ); + changeLength( 0 ); + setJournalling( true ); +} + + + + +/*! \brief Destroy a TrackContentObject + * + * Destroys the given track content object. + * + */ +TrackContentObject::~TrackContentObject() +{ + emit destroyedTCO(); + + if( getTrack() ) + { + getTrack()->removeTCO( this ); + } +} + + + + +/*! \brief Move this TrackContentObject's position in time + * + * If the track content object has moved, update its position. We + * also add a journal entry for undo and update the display. + * + * \param _pos The new position of the track content object. + */ +void TrackContentObject::movePosition( const TimePos & pos ) +{ + TimePos newPos = qMax(0, pos.getTicks()); + if (m_startPosition != newPos) + { + Engine::mixer()->requestChangeInModel(); + m_startPosition = newPos; + Engine::mixer()->doneChangeInModel(); + Engine::getSong()->updateLength(); + emit positionChanged(); + } +} + + + + +/*! \brief Change the length of this TrackContentObject + * + * If the track content object's length has changed, update it. We + * also add a journal entry for undo and update the display. + * + * \param _length The new length of the track content object. + */ +void TrackContentObject::changeLength( const TimePos & length ) +{ + m_length = length; + Engine::getSong()->updateLength(); + emit lengthChanged(); +} + + + + +bool TrackContentObject::comparePosition(const TrackContentObject *a, const TrackContentObject *b) +{ + return a->startPosition() < b->startPosition(); +} + + + + +/*! \brief Copies the state of a TrackContentObject to another TrackContentObject + * + * This method copies the state of a TCO to another TCO + */ +void TrackContentObject::copyStateTo( TrackContentObject *src, TrackContentObject *dst ) +{ + // If the node names match we copy the state + if( src->nodeName() == dst->nodeName() ){ + QDomDocument doc; + QDomElement parent = doc.createElement( "StateCopy" ); + src->saveState( doc, parent ); + + const TimePos pos = dst->startPosition(); + dst->restoreState( parent.firstChild().toElement() ); + dst->movePosition( pos ); + + AutomationPattern::resolveAllIDs(); + GuiApplication::instance()->automationEditor()->m_editor->updateAfterPatternChange(); + } +} + + + + +/*! \brief Mutes this TrackContentObject + * + * Restore the previous state of this track content object. This will + * restore the position or the length of the track content object + * depending on what was changed. + * + * \param _je The journal entry to undo + */ +void TrackContentObject::toggleMute() +{ + m_mutedModel.setValue( !m_mutedModel.value() ); + emit dataChanged(); +} + + + + +TimePos TrackContentObject::startTimeOffset() const +{ + return m_startTimeOffset; +} + + + + +void TrackContentObject::setStartTimeOffset( const TimePos &startTimeOffset ) +{ + m_startTimeOffset = startTimeOffset; +} + +// Update TCO color if it follows the track color +void TrackContentObject::updateColor() +{ + if( ! m_useCustomClipColor ) + { + emit trackColorChanged(); + } +} + + +void TrackContentObject::useCustomClipColor( bool b ) +{ + m_useCustomClipColor = b; + updateColor(); +} + + +bool TrackContentObject::hasColor() +{ + return usesCustomClipColor() || getTrack()->useColor(); +} + diff --git a/src/core/audio/AudioDevice.cpp b/src/core/audio/AudioDevice.cpp index ab69e144b12..a57fa2bd636 100644 --- a/src/core/audio/AudioDevice.cpp +++ b/src/core/audio/AudioDevice.cpp @@ -93,10 +93,8 @@ fpp_t AudioDevice::getNextBuffer( surroundSampleFrame * _ab ) // resample if necessary if( mixer()->processingSampleRate() != m_sampleRate ) { - resample( b, frames, _ab, mixer()->processingSampleRate(), - m_sampleRate ); - frames = frames * m_sampleRate / - mixer()->processingSampleRate(); + frames = resample( b, frames, _ab, mixer()->processingSampleRate(), + m_sampleRate ); } else { @@ -184,7 +182,7 @@ void AudioDevice::renamePort( AudioPort * ) -void AudioDevice::resample( const surroundSampleFrame * _src, +fpp_t AudioDevice::resample( const surroundSampleFrame * _src, const fpp_t _frames, surroundSampleFrame * _dst, const sample_rate_t _src_sr, @@ -192,12 +190,12 @@ void AudioDevice::resample( const surroundSampleFrame * _src, { if( m_srcState == NULL ) { - return; + return _frames; } m_srcData.input_frames = _frames; m_srcData.output_frames = _frames; - m_srcData.data_in = (float *) _src[0]; - m_srcData.data_out = _dst[0]; + m_srcData.data_in = const_cast(_src[0].data()); + m_srcData.data_out = _dst[0].data (); m_srcData.src_ratio = (double) _dst_sr / _src_sr; m_srcData.end_of_input = 0; int error; @@ -206,6 +204,7 @@ void AudioDevice::resample( const surroundSampleFrame * _src, printf( "AudioDevice::resample(): error while resampling: %s\n", src_strerror( error ) ); } + return static_cast(m_srcData.output_frames_gen); } diff --git a/src/core/audio/AudioFileFlac.cpp b/src/core/audio/AudioFileFlac.cpp index d9d91f54bea..cb159e46d5e 100644 --- a/src/core/audio/AudioFileFlac.cpp +++ b/src/core/audio/AudioFileFlac.cpp @@ -22,6 +22,9 @@ * */ +#include + +#include #include #include "AudioFileFlac.h" @@ -86,6 +89,7 @@ bool AudioFileFlac::startEncoding() void AudioFileFlac::writeBuffer(surroundSampleFrame const* _ab, fpp_t const frames, float master_gain) { OutputSettings::BitDepth depth = getOutputSettings().getBitDepth(); + float clipvalue = std::nextafterf( -1.0f, 0.0f ); if (depth == OutputSettings::Depth_24Bit || depth == OutputSettings::Depth_32Bit) // Float encoding { @@ -94,7 +98,10 @@ void AudioFileFlac::writeBuffer(surroundSampleFrame const* _ab, fpp_t const fram { for(ch_cnt_t channel=0; channel(buf.get()),frames); diff --git a/src/core/audio/AudioFileOgg.cpp b/src/core/audio/AudioFileOgg.cpp index 86f265b1270..7e1cb48b4a8 100644 --- a/src/core/audio/AudioFileOgg.cpp +++ b/src/core/audio/AudioFileOgg.cpp @@ -30,7 +30,9 @@ #ifdef LMMS_HAVE_OGGVORBIS - +#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0)) +#include +#endif #include #include @@ -136,8 +138,13 @@ bool AudioFileOgg::startEncoding() // We give our ogg file a random serial number and avoid // 0 and UINT32_MAX which can get you into trouble. - qsrand( time( 0 ) ); +#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0)) + // QRandomGenerator::global() is already initialized, and we can't seed() it. + m_serialNo = 0xD0000000 + QRandomGenerator::global()->generate() % 0x0FFFFFFF; +#else + qsrand(time(0)); m_serialNo = 0xD0000000 + qrand() % 0x0FFFFFFF; +#endif ogg_stream_init( &m_os, m_serialNo ); // Now, build the three header packets and send through to the stream diff --git a/src/core/audio/AudioJack.cpp b/src/core/audio/AudioJack.cpp index aebfe5e1c61..7e7b703a1a3 100644 --- a/src/core/audio/AudioJack.cpp +++ b/src/core/audio/AudioJack.cpp @@ -55,6 +55,8 @@ AudioJack::AudioJack( bool & _success_ful, Mixer* _mixer ) : m_framesDoneInCurBuf( 0 ), m_framesToDoInCurBuf( 0 ) { + m_stopped = true; + _success_ful = initJackClient(); if( _success_ful ) { @@ -200,10 +202,9 @@ bool AudioJack::initJackClient() void AudioJack::startProcessing() { - m_stopped = false; - if( m_active || m_client == NULL ) { + m_stopped = false; return; } @@ -244,6 +245,7 @@ void AudioJack::startProcessing() } } + m_stopped = false; free( ports ); } @@ -344,8 +346,8 @@ int AudioJack::processCallback( jack_nframes_t _nframes, void * _udata ) // add to the following sound processing if( m_midiClient && _nframes > 0 ) { - m_midiClient->JackMidiRead(_nframes); - m_midiClient->JackMidiWrite(_nframes); + m_midiClient.load()->JackMidiRead(_nframes); + m_midiClient.load()->JackMidiWrite(_nframes); } for( int c = 0; c < channels(); ++c ) diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index ad67277ab35..865eeca8d5a 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -410,14 +410,14 @@ AudioPortAudio::setupWidget::setupWidget( QWidget * _parent ) : AudioDeviceSetupWidget( AudioPortAudio::name(), _parent ) { m_backend = new ComboBox( this, "BACKEND" ); - m_backend->setGeometry( 64, 15, 260, 20 ); + m_backend->setGeometry( 64, 15, 260, ComboBox::DEFAULT_HEIGHT ); 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 ); + m_device->setGeometry( 64, 35, 260, ComboBox::DEFAULT_HEIGHT ); QLabel * dev_lbl = new QLabel( tr( "Device" ), this ); dev_lbl->setFont( pointSize<7>( dev_lbl->font() ) ); diff --git a/src/core/audio/AudioSoundIo.cpp b/src/core/audio/AudioSoundIo.cpp index 2c3d493a6de..34deec1d0b8 100644 --- a/src/core/audio/AudioSoundIo.cpp +++ b/src/core/audio/AudioSoundIo.cpp @@ -50,6 +50,7 @@ AudioSoundIo::AudioSoundIo( bool & outSuccessful, Mixer * _mixer ) : m_outBufFrameIndex = 0; m_outBufFramesTotal = 0; m_stopped = true; + m_outstreamStarted = false; m_soundio = soundio_create(); if (!m_soundio) @@ -196,6 +197,12 @@ void AudioSoundIo::onBackendDisconnect(int err) AudioSoundIo::~AudioSoundIo() { stopProcessing(); + + if (m_outstream) + { + soundio_outstream_destroy(m_outstream); + } + if (m_soundio) { soundio_destroy(m_soundio); @@ -205,28 +212,50 @@ AudioSoundIo::~AudioSoundIo() void AudioSoundIo::startProcessing() { + int err; + m_outBufFrameIndex = 0; m_outBufFramesTotal = 0; m_outBufSize = mixer()->framesPerPeriod(); m_outBuf = new surroundSampleFrame[m_outBufSize]; + if (! m_outstreamStarted) + { + if ((err = soundio_outstream_start(m_outstream))) + { + fprintf(stderr, + "AudioSoundIo::startProcessing() :: soundio unable to start stream: %s\n", + soundio_strerror(err)); + } else { + m_outstreamStarted = true; + } + } + m_stopped = false; - int err; - if ((err = soundio_outstream_start(m_outstream))) + + if ((err = soundio_outstream_pause(m_outstream, false))) { m_stopped = true; - fprintf(stderr, "soundio unable to start stream: %s\n", soundio_strerror(err)); + fprintf(stderr, + "AudioSoundIo::startProcessing() :: resuming result error: %s\n", + soundio_strerror(err)); } } void AudioSoundIo::stopProcessing() { + int err; + m_stopped = true; if (m_outstream) { - soundio_outstream_destroy(m_outstream); - m_outstream = NULL; + if ((err = soundio_outstream_pause(m_outstream, true))) + { + fprintf(stderr, + "AudioSoundIo::stopProcessing() :: pausing result error: %s\n", + soundio_strerror(err)); + } } if (m_outBuf) diff --git a/src/core/lv2/Lv2Basics.cpp b/src/core/lv2/Lv2Basics.cpp new file mode 100644 index 00000000000..b6be53a2cf6 --- /dev/null +++ b/src/core/lv2/Lv2Basics.cpp @@ -0,0 +1,49 @@ +/* + * Lv2Basics.cpp - basic Lv2 functions + * + * Copyright (c) 2019-2020 Johannes Lorenz + * + * 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. + * + */ + +#include "Lv2Basics.h" + +#ifdef LMMS_HAVE_LV2 + +QString qStringFromPluginNode(const LilvPlugin* plug, + LilvNode* (*getFunc)(const LilvPlugin*)) +{ + return QString::fromUtf8( + lilv_node_as_string(AutoLilvNode((*getFunc)(plug)).get())); +} + +QString qStringFromPortName(const LilvPlugin* plug, const LilvPort* port) +{ + return QString::fromUtf8( + lilv_node_as_string(AutoLilvNode(lilv_port_get_name(plug, port)).get())); +} + +std::string stdStringFromPortName(const LilvPlugin* plug, const LilvPort* port) +{ + return std::string( + lilv_node_as_string(AutoLilvNode(lilv_port_get_name(plug, port)).get())); +} + +#endif // LMMS_HAVE_LV2 + diff --git a/src/core/lv2/Lv2ControlBase.cpp b/src/core/lv2/Lv2ControlBase.cpp new file mode 100644 index 00000000000..98fe7b13b20 --- /dev/null +++ b/src/core/lv2/Lv2ControlBase.cpp @@ -0,0 +1,217 @@ +/* + * Lv2ControlBase.cpp - Lv2 control base class + * + * Copyright (c) 2018-2020 Johannes Lorenz + * + * 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. + * + */ + +#include "Lv2ControlBase.h" + +#ifdef LMMS_HAVE_LV2 + +#include +#include + +#include "Engine.h" +#include "Lv2Manager.h" +#include "Lv2Proc.h" + + + + +Plugin::PluginTypes Lv2ControlBase::check(const LilvPlugin *plugin, + std::vector &issues) +{ + // for some reason, all checks can be done by one processor... + return Lv2Proc::check(plugin, issues); +} + + + + +Lv2ControlBase::Lv2ControlBase(Model* that, const QString &uri) : + m_plugin(Engine::getLv2Manager()->getPlugin(uri)) +{ + if (m_plugin) + { + int channelsLeft = DEFAULT_CHANNELS; // LMMS plugins are stereo + while (channelsLeft > 0) + { + std::unique_ptr newOne = std::make_unique(m_plugin, that); + if (newOne->isValid()) + { + channelsLeft -= std::max( + 1 + static_cast(newOne->inPorts().m_right), + 1 + static_cast(newOne->outPorts().m_right)); + Q_ASSERT(channelsLeft >= 0); + m_procs.push_back(std::move(newOne)); + } + else + { + qCritical() << "Failed instantiating LV2 processor"; + m_valid = false; + channelsLeft = 0; + } + } + if (m_valid) + { + m_channelsPerProc = DEFAULT_CHANNELS / m_procs.size(); + linkAllModels(); + } + } + else + { + qCritical() << "No Lv2 plugin found for URI" << uri; + m_valid = false; + } +} + + + + +Lv2ControlBase::~Lv2ControlBase() {} + + + + +LinkedModelGroup *Lv2ControlBase::getGroup(std::size_t idx) +{ + return (m_procs.size() > idx) ? m_procs[idx].get() : nullptr; +} + + + + +const LinkedModelGroup *Lv2ControlBase::getGroup(std::size_t idx) const +{ + return (m_procs.size() > idx) ? m_procs[idx].get() : nullptr; +} + + + + +void Lv2ControlBase::copyModelsFromLmms() { + for (auto& c : m_procs) { c->copyModelsFromCore(); } +} + + + + +void Lv2ControlBase::copyModelsToLmms() const +{ + for (auto& c : m_procs) { c->copyModelsToCore(); } +} + + + + +void Lv2ControlBase::copyBuffersFromLmms(const sampleFrame *buf, fpp_t frames) { + unsigned firstChan = 0; // tell the procs which channels they shall read from + for (auto& c : m_procs) { + c->copyBuffersFromCore(buf, firstChan, m_channelsPerProc, frames); + firstChan += m_channelsPerProc; + } +} + + + + +void Lv2ControlBase::copyBuffersToLmms(sampleFrame *buf, fpp_t frames) const { + unsigned firstChan = 0; // tell the procs which channels they shall write to + for (const auto& c : m_procs) { + c->copyBuffersToCore(buf, firstChan, m_channelsPerProc, frames); + firstChan += m_channelsPerProc; + } +} + + + + +void Lv2ControlBase::run(fpp_t frames) { + for (auto& c : m_procs) { c->run(frames); } +} + + + + +void Lv2ControlBase::saveSettings(QDomDocument &doc, QDomElement &that) +{ + LinkedModelGroups::saveSettings(doc, that); + + // TODO: save state if supported by plugin +} + + + + +void Lv2ControlBase::loadSettings(const QDomElement &that) +{ + LinkedModelGroups::loadSettings(that); + + // TODO: load state if supported by plugin +} + + + + +void Lv2ControlBase::loadFile(const QString &file) +{ + (void)file; +} + + + + +void Lv2ControlBase::reloadPlugin() +{ + // TODO +} + + + + +std::size_t Lv2ControlBase::controlCount() const { + std::size_t res = 0; + for (const auto& c : m_procs) { res += c->controlCount(); } + return res; +} + + + + +bool Lv2ControlBase::hasNoteInput() const +{ + return std::any_of(m_procs.begin(), m_procs.end(), + [](const auto& c) { return c->hasNoteInput(); }); +} + + + + +void Lv2ControlBase::handleMidiInputEvent(const MidiEvent &event, + const TimePos &time, f_cnt_t offset) +{ + for (auto& c : m_procs) { c->handleMidiInputEvent(event, time, offset); } +} + + + + +#endif // LMMS_HAVE_LV2 diff --git a/src/core/lv2/Lv2Evbuf.cpp b/src/core/lv2/Lv2Evbuf.cpp new file mode 100644 index 00000000000..335dfd36224 --- /dev/null +++ b/src/core/lv2/Lv2Evbuf.cpp @@ -0,0 +1,193 @@ +/* + * lv2_evbuf.cpp - Lv2 event buffer implementation + * + * Copyright (c) 2019-2020 Johannes Lorenz + * + * 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. + * + */ + +/* + * The original code was written by David Robillard + */ + +#include "Lv2Evbuf.h" + +#ifdef LMMS_HAVE_LV2 + +#include +#include +#include + +#include + +struct LV2_Evbuf_Impl { + uint32_t capacity; + uint32_t atom_Chunk; + uint32_t atom_Sequence; + LV2_Atom_Sequence buf; +}; + +static inline uint32_t +lv2_evbuf_pad_size(uint32_t size) +{ + return (size + 7) & (~7); +} + +LV2_Evbuf* +lv2_evbuf_new(uint32_t capacity, uint32_t atom_Chunk, uint32_t atom_Sequence) +{ + // FIXME: memory must be 64-bit aligned + LV2_Evbuf* evbuf = (LV2_Evbuf*)malloc( + sizeof(LV2_Evbuf) + sizeof(LV2_Atom_Sequence) + capacity); + evbuf->capacity = capacity; + evbuf->atom_Chunk = atom_Chunk; + evbuf->atom_Sequence = atom_Sequence; + lv2_evbuf_reset(evbuf, true); + return evbuf; +} + +void +lv2_evbuf_free(LV2_Evbuf* evbuf) +{ + free(evbuf); +} + +void +lv2_evbuf_reset(LV2_Evbuf* evbuf, bool input) +{ + if (input) { + evbuf->buf.atom.size = sizeof(LV2_Atom_Sequence_Body); + evbuf->buf.atom.type = evbuf->atom_Sequence; + } else { + evbuf->buf.atom.size = evbuf->capacity; + evbuf->buf.atom.type = evbuf->atom_Chunk; + } +} + +uint32_t +lv2_evbuf_get_size(LV2_Evbuf* evbuf) +{ + assert(evbuf->buf.atom.type != evbuf->atom_Sequence + || evbuf->buf.atom.size >= sizeof(LV2_Atom_Sequence_Body)); + return evbuf->buf.atom.type == evbuf->atom_Sequence + ? evbuf->buf.atom.size - sizeof(LV2_Atom_Sequence_Body) + : 0; +} + +void* +lv2_evbuf_get_buffer(LV2_Evbuf* evbuf) +{ + return &evbuf->buf; +} + +LV2_Evbuf_Iterator +lv2_evbuf_begin(LV2_Evbuf* evbuf) +{ + LV2_Evbuf_Iterator iter = { evbuf, 0 }; + return iter; +} + +LV2_Evbuf_Iterator +lv2_evbuf_end(LV2_Evbuf* evbuf) +{ + const uint32_t size = lv2_evbuf_get_size(evbuf); + const LV2_Evbuf_Iterator iter = { evbuf, lv2_evbuf_pad_size(size) }; + return iter; +} + +bool +lv2_evbuf_is_valid(LV2_Evbuf_Iterator iter) +{ + return iter.offset < lv2_evbuf_get_size(iter.evbuf); +} + +LV2_Evbuf_Iterator +lv2_evbuf_next(LV2_Evbuf_Iterator iter) +{ + if (!lv2_evbuf_is_valid(iter)) { + return iter; + } + + LV2_Evbuf* evbuf = iter.evbuf; + uint32_t offset = iter.offset; + uint32_t size; + size = ((LV2_Atom_Event*) + ((char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, &evbuf->buf.atom) + + offset))->body.size; + offset += lv2_evbuf_pad_size(sizeof(LV2_Atom_Event) + size); + + LV2_Evbuf_Iterator next = { evbuf, offset }; + return next; +} + +bool +lv2_evbuf_get(LV2_Evbuf_Iterator iter, + uint32_t* frames, + uint32_t* type, + uint32_t* size, + uint8_t** data) +{ + *frames = *type = *size = 0; + *data = NULL; + + if (!lv2_evbuf_is_valid(iter)) { + return false; + } + + LV2_Atom_Sequence* aseq = &iter.evbuf->buf; + LV2_Atom_Event* aev = (LV2_Atom_Event*)( + (char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, aseq) + iter.offset); + + *frames = aev->time.frames; + *type = aev->body.type; + *size = aev->body.size; + *data = (uint8_t*)LV2_ATOM_BODY(&aev->body); + + return true; +} + +bool +lv2_evbuf_write(LV2_Evbuf_Iterator* iter, + uint32_t frames, + uint32_t type, + uint32_t size, + const uint8_t* data) +{ + LV2_Atom_Sequence* aseq = &iter->evbuf->buf; + if (iter->evbuf->capacity - sizeof(LV2_Atom) - aseq->atom.size < + sizeof(LV2_Atom_Event) + size) { + return false; + } + + LV2_Atom_Event* aev = (LV2_Atom_Event*)( + (char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, aseq) + iter->offset); + + aev->time.frames = frames; + aev->body.type = type; + aev->body.size = size; + memcpy(LV2_ATOM_BODY(&aev->body), data, size); + + size = lv2_evbuf_pad_size(sizeof(LV2_Atom_Event) + size); + aseq->atom.size += size; + iter->offset += size; + + return true; +} + +#endif // LMMS_HAVE_LV2 diff --git a/src/core/lv2/Lv2Features.cpp b/src/core/lv2/Lv2Features.cpp new file mode 100644 index 00000000000..fe668807e06 --- /dev/null +++ b/src/core/lv2/Lv2Features.cpp @@ -0,0 +1,97 @@ +/* + * Lv2Features.cpp - Lv2Features implementation + * + * Copyright (c) 2020-2020 Johannes Lorenz + * + * 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. + * + */ + +#include "Lv2Features.h" + +#ifdef LMMS_HAVE_LV2 + +#include + +#include "Engine.h" +#include "Lv2Manager.h" + + +bool Lv2Features::isFeatureSupported(const char* featName) +{ + return Engine::getLv2Manager()->isFeatureSupported(featName); +} + + + + +Lv2Features::Lv2Features() +{ + const Lv2Manager* man = Engine::getLv2Manager(); + // create (yet empty) map feature URI -> feature + for(const char* uri : man->supportedFeatureURIs()) + { + m_featureByUri.emplace(uri, nullptr); + } +} + + + + +void Lv2Features::initCommon() +{ + Lv2Manager* man = Engine::getLv2Manager(); + // init m_featureByUri with the plugin-common features + operator[](LV2_URID__map) = man->uridMap().mapFeature(); + operator[](LV2_URID__unmap) = man->uridMap().unmapFeature(); +} + + + + +void Lv2Features::createFeatureVectors() +{ + // create vector of features + for(std::pair& pr : m_featureByUri) + { + Q_ASSERT(pr.second != nullptr); + m_features.push_back(LV2_Feature { pr.first, pr.second }); + } + + // create pointer vector (for lilv_plugin_instantiate) + m_featurePointers.reserve(m_features.size() + 1); + for(std::size_t i = 0; i < m_features.size(); ++i) + { + m_featurePointers.push_back(&m_features[i]); + } + m_featurePointers.push_back(nullptr); +} + + + + +void *&Lv2Features::operator[](const char *featName) +{ + auto itr = m_featureByUri.find(featName); + Q_ASSERT(itr != m_featureByUri.end()); + return itr->second; +} + + +#endif // LMMS_HAVE_LV2 + diff --git a/src/core/lv2/Lv2Manager.cpp b/src/core/lv2/Lv2Manager.cpp new file mode 100644 index 00000000000..ed2d0505340 --- /dev/null +++ b/src/core/lv2/Lv2Manager.cpp @@ -0,0 +1,265 @@ +/* + * Lv2Manager.cpp - Implementation of Lv2Manager class + * + * Copyright (c) 2018-2020 Johannes Lorenz + * + * 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. + * + */ + +#include "Lv2Manager.h" + +#ifdef LMMS_HAVE_LV2 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ConfigManager.h" +#include "Engine.h" +#include "Plugin.h" +#include "PluginFactory.h" +#include "Lv2ControlBase.h" +#include "Lv2Options.h" +#include "PluginIssue.h" + + + + +const std::set Lv2Manager::pluginBlacklist = +{ + // github.com/calf-studio-gear/calf, #278 + "http://calf.sourceforge.net/plugins/Analyzer", + "http://calf.sourceforge.net/plugins/BassEnhancer", + "http://calf.sourceforge.net/plugins/CompensationDelay", + "http://calf.sourceforge.net/plugins/Crusher", + "http://calf.sourceforge.net/plugins/Exciter", + "http://calf.sourceforge.net/plugins/Saturator", + "http://calf.sourceforge.net/plugins/StereoTools", + "http://calf.sourceforge.net/plugins/TapeSimulator", + "http://calf.sourceforge.net/plugins/TransientDesigner", + "http://calf.sourceforge.net/plugins/Vinyl" +}; + + + + +Lv2Manager::Lv2Manager() : + m_uridCache(m_uridMap) +{ + const char* dbgStr = getenv("LMMS_LV2_DEBUG"); + m_debug = (dbgStr && *dbgStr); + + m_world = lilv_world_new(); + lilv_world_load_all(m_world); + + m_supportedFeatureURIs.insert(LV2_URID__map); + m_supportedFeatureURIs.insert(LV2_URID__unmap); + m_supportedFeatureURIs.insert(LV2_OPTIONS__options); + + auto supportOpt = [this](Lv2UridCache::Id id) + { + Lv2Options::supportOption(uridCache()[id]); + }; + supportOpt(Lv2UridCache::Id::param_sampleRate); + supportOpt(Lv2UridCache::Id::bufsz_maxBlockLength); + supportOpt(Lv2UridCache::Id::bufsz_minBlockLength); + supportOpt(Lv2UridCache::Id::bufsz_nominalBlockLength); + supportOpt(Lv2UridCache::Id::bufsz_sequenceSize); +} + + + + +Lv2Manager::~Lv2Manager() +{ + lilv_world_free(m_world); +} + + + + +AutoLilvNode Lv2Manager::uri(const char *uriStr) +{ + return AutoLilvNode(lilv_new_uri(m_world, uriStr)); +} + + + + +const LilvPlugin *Lv2Manager::getPlugin(const std::string &uri) +{ + auto itr = m_lv2InfoMap.find(uri); + return itr == m_lv2InfoMap.end() ? nullptr : itr->second.plugin(); +} + + + + +const LilvPlugin *Lv2Manager::getPlugin(const QString &uri) +{ + return getPlugin(uri.toStdString()); +} + + + + +void Lv2Manager::initPlugins() +{ + const LilvPlugins* plugins = lilv_world_get_all_plugins(m_world); + std::size_t pluginCount = 0, pluginsLoaded = 0; + QElapsedTimer timer; + timer.start(); + + unsigned blacklisted = 0; + LILV_FOREACH(plugins, itr, plugins) + { + const LilvPlugin* curPlug = lilv_plugins_get(plugins, itr); + + std::vector issues; + Plugin::PluginTypes type = Lv2ControlBase::check(curPlug, issues); + std::sort(issues.begin(), issues.end()); + auto last = std::unique(issues.begin(), issues.end()); + issues.erase(last, issues.end()); + if (m_debug && issues.size()) + { + qDebug() << "Lv2 plugin" + << qStringFromPluginNode(curPlug, lilv_plugin_get_name) + << "(URI:" + << lilv_node_as_uri(lilv_plugin_get_uri(curPlug)) + << ") can not be loaded:"; + for (const PluginIssue& iss : issues) { qDebug() << " - " << iss; } + } + + Lv2Info info(curPlug, type, issues.empty()); + + m_lv2InfoMap[lilv_node_as_uri(lilv_plugin_get_uri(curPlug))] + = std::move(info); + if(issues.empty()) { ++pluginsLoaded; } + else + { + if(std::any_of(issues.begin(), issues.end(), + [](const PluginIssue& iss) { + return iss.type() == PluginIssueType::blacklisted; })) + { + ++blacklisted; + } + } + ++pluginCount; + } + + qDebug() << "Lv2 plugin SUMMARY:" + << pluginsLoaded << "of" << pluginCount << " loaded in" + << timer.elapsed() << "msecs."; + if(pluginsLoaded != pluginCount) + { + if (m_debug) + { + qDebug() << + "If you don't want to see all this debug output, please set\n" + " environment variable \"LMMS_LV2_DEBUG\" to empty or\n" + " do not set it."; + } + else + { + qDebug() << + "For details about not loaded plugins, please set\n" + " environment variable \"LMMS_LV2_DEBUG\" to nonempty."; + } + } + + // TODO: might be better in the LMMS core + if(Engine::ignorePluginBlacklist()) + { + qWarning() << + "WARNING! Plugin blacklist disabled! If you want to use the blacklist,\n" + " please set environment variable \"LMMS_IGNORE_BLACKLIST\" to empty or\n" + " do not set it."; + } + else if(blacklisted > 0) + { + qDebug() << + "Lv2 Plugins blacklisted:" << blacklisted << "of" << pluginCount << "\n" + " If you want to ignore the blacklist (dangerous!), please set\n" + " environment variable \"LMMS_IGNORE_BLACKLIST\" to nonempty."; + } +} + + + + +bool Lv2Manager::CmpStr::operator()(const char *a, const char *b) const +{ + return std::strcmp(a, b) < 0; +} + + + + +bool Lv2Manager::isFeatureSupported(const char *featName) const +{ + return m_supportedFeatureURIs.find(featName) != m_supportedFeatureURIs.end(); +} + + + + +AutoLilvNodes Lv2Manager::findNodes(const LilvNode *subject, + const LilvNode *predicate, const LilvNode *object) +{ + return AutoLilvNodes(lilv_world_find_nodes (m_world, subject, predicate, object)); +} + + + + +// unused + untested yet +bool Lv2Manager::isSubclassOf(const LilvPluginClass* clvss, const char* uriStr) +{ + const LilvPluginClasses* allClasses = lilv_world_get_plugin_classes(m_world); + const LilvPluginClass* root = lilv_world_get_plugin_class(m_world); + const LilvPluginClass* search = lilv_plugin_classes_get_by_uri(allClasses, + uri(uriStr).get()); + + auto clssEq = [](const LilvPluginClass* pc1, + const LilvPluginClass* pc2) -> bool + { + return lilv_node_equals( + lilv_plugin_class_get_uri(pc1), + lilv_plugin_class_get_uri(pc2)); + }; + bool isFound = false; + while (!(isFound = clssEq(clvss, search)) && !clssEq(clvss, root)) + { + clvss = lilv_plugin_classes_get_by_uri(allClasses, + lilv_plugin_class_get_parent_uri(clvss)); + } + return isFound; +} + + + + +#endif // LMMS_HAVE_LV2 diff --git a/src/core/lv2/Lv2Options.cpp b/src/core/lv2/Lv2Options.cpp new file mode 100644 index 00000000000..e941165f090 --- /dev/null +++ b/src/core/lv2/Lv2Options.cpp @@ -0,0 +1,93 @@ +/* + * Lv2Options.cpp - Lv2Options implementation + * + * Copyright (c) 2020-2020 Johannes Lorenz + * + * 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. + * + */ + +#include "Lv2Options.h" + +#ifdef LMMS_HAVE_LV2 + +#include + + +std::set Lv2Options::s_supportedOptions; + + + + +bool Lv2Options::isOptionSupported(LV2_URID key) +{ + return s_supportedOptions.find(key) != s_supportedOptions.end(); +} + + + + +void Lv2Options::supportOption(LV2_URID key) +{ + const auto result = s_supportedOptions.insert(key); + Q_ASSERT(result.second); +} + + + + +void Lv2Options::createOptionVectors() +{ + // create vector of options + for(LV2_URID urid : s_supportedOptions) + { + auto itr = m_optionByUrid.find(urid); + Q_ASSERT(itr != m_optionByUrid.end()); + m_options.push_back(itr->second); + } + LV2_Options_Option nullOption; + nullOption.key = 0; + nullOption.value = nullptr; + m_options.push_back(nullOption); +} + + + + +void Lv2Options::initOption(LV2_URID key, uint32_t size, LV2_URID type, + std::shared_ptr value, + LV2_Options_Context context, uint32_t subject) +{ + Q_ASSERT(isOptionSupported(key)); + + LV2_Options_Option opt; + opt.key = key; + opt.context = context; + opt.subject = subject; + opt.size = size; + opt.type = type; + opt.value = value.get(); + + const auto optResult = m_optionByUrid.emplace(key, opt); + const auto valResult = m_optionValues.emplace(key, std::move(value)); + Q_ASSERT(optResult.second); + Q_ASSERT(valResult.second); +} + + +#endif // LMMS_HAVE_LV2 diff --git a/src/core/lv2/Lv2Ports.cpp b/src/core/lv2/Lv2Ports.cpp new file mode 100644 index 00000000000..4db7f3e2a5a --- /dev/null +++ b/src/core/lv2/Lv2Ports.cpp @@ -0,0 +1,365 @@ +/* + * Lv2Ports.cpp - Lv2 port classes implementation + * + * Copyright (c) 2019-2020 Johannes Lorenz + * + * 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. + * + */ + + +#include "Lv2Ports.h" + +#ifdef LMMS_HAVE_LV2 + +#include +#include + +#include "Engine.h" +#include "Lv2Basics.h" +#include "Lv2Manager.h" +#include "Lv2Evbuf.h" + +namespace Lv2Ports { + + + + +const char *toStr(Flow pf) +{ + switch(pf) + { + case Flow::Unknown: return "unknown"; + case Flow::Input: return "input"; + case Flow::Output: return "output"; + } + return ""; +} + + + + +const char *toStr(Type pt) +{ + switch(pt) + { + case Type::Unknown: return "unknown"; + case Type::Control: return "control"; + case Type::Audio: return "audio"; + case Type::AtomSeq: return "atom-sequence"; + case Type::Cv: return "cv"; + } + return ""; +} + + + + +const char *toStr(Vis pv) +{ + switch(pv) + { + case Vis::Toggled: return "toggled"; + case Vis::Enumeration: return "enumeration"; + case Vis::Integer: return "integer"; + case Vis::Generic: return "none"; + } + return ""; +} + + + + +std::vector Meta::get(const LilvPlugin *plugin, + std::size_t portNum) +{ + std::vector portIssues; + auto issue = [&portIssues](PluginIssueType i, std::string msg = "") { + portIssues.emplace_back(i, std::move(msg)); }; + + Lv2Manager* man = Engine::getLv2Manager(); + + const LilvPort* lilvPort = lilv_plugin_get_port_by_index( + plugin, static_cast(portNum)); + + auto portFunc = [&plugin, &lilvPort, &man]( + bool (*fptr)(const LilvPlugin*, const LilvPort*, const LilvNode*), + const char* str) { + return fptr(plugin, lilvPort, man->uri(str).get()); + }; + + auto hasProperty = [&portFunc](const char* str) { + return portFunc(lilv_port_has_property, str); }; + auto isA = [&portFunc](const char* str) { + return portFunc(lilv_port_is_a, str); }; + + const std::string portName = stdStringFromPortName(plugin, lilvPort); + + m_optional = hasProperty(LV2_CORE__connectionOptional); + + m_vis = hasProperty(LV2_CORE__integer) + ? Vis::Integer // WARNING: this may still be changed below + : hasProperty(LV2_CORE__enumeration) + ? Vis::Enumeration + : hasProperty(LV2_CORE__toggled) + ? Vis::Toggled + : Vis::Generic; + + if (isA(LV2_CORE__InputPort)) { m_flow = Flow::Input; } + else if (isA(LV2_CORE__OutputPort)) { m_flow = Flow::Output; } + else { + m_flow = Flow::Unknown; + issue(unknownPortFlow, portName); + } + + m_def = .0f; + m_min = std::numeric_limits::lowest(); + m_max = std::numeric_limits::max(); + auto m_min_set = [this]{ return m_min != std::numeric_limits::lowest(); }; + auto m_max_set = [this]{ return m_max != std::numeric_limits::max(); }; + + m_type = Type::Unknown; + if (isA(LV2_CORE__ControlPort) || isA(LV2_CORE__CVPort)) + { + // Read metadata for control ports + // CV ports are mostly the same as control ports, so we take + // mostly the same metadata + + if (isA(LV2_CORE__CVPort)) + { + // currently not supported, but we can still check the metadata + issue(badPortType, "cvPort"); + } + + m_type = isA(LV2_CORE__CVPort) ? Type::Cv : Type::Control; + + bool isToggle = m_vis == Vis::Toggled; + + LilvNode * defN, * minN = nullptr, * maxN = nullptr; + lilv_port_get_range(plugin, lilvPort, &defN, + isToggle ? nullptr : &minN, + isToggle ? nullptr : &maxN); + AutoLilvNode def(defN), min(minN), max(maxN); + + auto takeRangeValue = [&](LilvNode* node, + float& storeHere, PluginIssueType it) + { + if (node) { storeHere = lilv_node_as_float(node); } + else + { + // CV ports do not require ranges + if(m_flow == Flow::Input && m_type != Type::Cv) + { + issue(it, portName); + } + } + }; + + takeRangeValue(def.get(), m_def, portHasNoDef); + if (isToggle) + { + m_min = .0f; + m_max = 1.f; + if(def.get() && m_def != m_min && m_def != m_max) + { + issue(defaultValueNotInRange, portName); + } + } + else + { + // take min/max + takeRangeValue(min.get(), m_min, portHasNoMin); + takeRangeValue(max.get(), m_max, portHasNoMax); + if(m_type == Type::Cv) + { + // no range is allowed and bashed to [-1,+1], + // but only min or only max does not make sense + if(!m_min_set() && !m_max_set()) + { + m_min = -1.f; + m_max = +1.f; + } + else if(!m_min_set()) { issue(portHasNoMin, portName); } + else if(!m_max_set()) { issue(portHasNoMax, portName); } + } + if(m_min > m_max) { issue(minGreaterMax, portName); } + + // sampleRate + if (hasProperty(LV2_CORE__sampleRate)) { m_sampleRate = true; } + + // default value + if (def.get()) + { + if (m_def < m_min) { issue(defaultValueNotInRange, portName); } + else if (m_def > m_max) + { + if(m_sampleRate) + { + // multiplying with sample rate will hopefully lead us + // to a good default value + } + else { issue(defaultValueNotInRange, portName); } + } + } + + // visualization + if (!m_min_set() || + !m_max_set() || + // if we get here, min and max are set, so max-min should not overflow: + (m_vis == Vis::Integer && m_max - m_min > 15.0f)) + { + // range too large for spinbox visualisation, use knobs + // e.g. 0...15 would be OK + m_vis = Vis::Generic; + } + } + } + else if (isA(LV2_CORE__AudioPort)) { m_type = Type::Audio; } + else if (isA(LV2_ATOM__AtomPort)) + { + AutoLilvNode uriAtomSequence(Engine::getLv2Manager()->uri(LV2_ATOM__Sequence)); + AutoLilvNode uriAtomBufferType(Engine::getLv2Manager()->uri(LV2_ATOM__bufferType)); + AutoLilvNodes bufferTypes(lilv_port_get_value(plugin, lilvPort, uriAtomBufferType.get())); + + if (lilv_nodes_contains(bufferTypes.get(), uriAtomSequence.get())) + { + // we accept all kinds of atom sequence ports, even if they take or + // offer atom types that we do not support: + // * atom input ports only say what *can* be input, but not what is + // required as input + // * atom output ports only say what *can* be output, but not what must + // be evaluated + m_type = Type::AtomSeq; + } + } + + if(m_type == Type::Unknown) + { + if (m_optional) { m_used = false; } + else { + issue(PluginIssueType::unknownPortType, portName); + } + } + + if (hasProperty(LV2_PORT_PROPS__logarithmic)) + { + // check min/max available + // we requre them anyways, but this will detect plugins that will + // be non-Lv2-conforming + if(m_min == std::numeric_limits::lowest()) + { + issue(PluginIssueType::logScaleMinMissing, portName); + } + if(m_max == std::numeric_limits::max()) + { + issue(PluginIssueType::logScaleMaxMissing, portName); + } + // forbid min < 0 < max + if(m_min < 0.f && m_max > 0.f) + { + issue(PluginIssueType::logScaleMinMaxDifferentSigns, portName); + } + m_logarithmic = true; + } + + return portIssues; +} + + + + +QString PortBase::name() const +{ + AutoLilvNode node(lilv_port_get_name(m_plugin, m_port)); + QString res = lilv_node_as_string(node.get()); + return res; +} + + + + +QString PortBase::uri() const +{ + return lilv_node_as_string(lilv_port_get_symbol(m_plugin, m_port)); +} + + + + +Audio::Audio(std::size_t bufferSize, bool isSidechain) + : m_buffer(bufferSize), m_sidechain(isSidechain) +{ +} + + + + +void Audio::copyBuffersFromCore(const sampleFrame *lmmsBuf, + unsigned channel, fpp_t frames) +{ + for (std::size_t f = 0; f < static_cast(frames); ++f) + { + m_buffer[f] = lmmsBuf[f][channel]; + } +} + + + + +void Audio::averageWithBuffersFromCore(const sampleFrame *lmmsBuf, + unsigned channel, fpp_t frames) +{ + for (std::size_t f = 0; f < static_cast(frames); ++f) + { + m_buffer[f] = (m_buffer[f] + lmmsBuf[f][channel]) / 2.0f; + } +} + + + + +void Audio::copyBuffersToCore(sampleFrame *lmmsBuf, + unsigned channel, fpp_t frames) const +{ + for (std::size_t f = 0; f < static_cast(frames); ++f) + { + lmmsBuf[f][channel] = m_buffer[f]; + } +} + + + + +void AtomSeq::Lv2EvbufDeleter::operator()(LV2_Evbuf *n) { lv2_evbuf_free(n); } + + + + +// make the compiler happy, give each class with virtuals +// a function (the destructor here) which is in a cpp file +PortBase::~PortBase() {} +ConstVisitor::~ConstVisitor() {} +Visitor::~Visitor() {} + + + + +} // namespace Lv2Ports + +#endif // LMMS_HAVE_LV2 + diff --git a/src/core/lv2/Lv2Proc.cpp b/src/core/lv2/Lv2Proc.cpp new file mode 100644 index 00000000000..1ae5221507e --- /dev/null +++ b/src/core/lv2/Lv2Proc.cpp @@ -0,0 +1,841 @@ +/* + * Lv2Proc.cpp - Lv2 processor class + * + * Copyright (c) 2019-2020 Johannes Lorenz + * + * 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. + * + */ + +#include "Lv2Proc.h" + +#ifdef LMMS_HAVE_LV2 + +#include +#include +#include +#include +#include +#include + +#include "AutomatableModel.h" +#include "ComboBoxModel.h" +#include "Engine.h" +#include "Lv2Features.h" +#include "Lv2Manager.h" +#include "Lv2Ports.h" +#include "Lv2Evbuf.h" +#include "MidiEventToByteSeq.h" +#include "Mixer.h" + + + + +// container for everything required to store MIDI events going to the plugin +struct MidiInputEvent +{ + MidiEvent ev; + TimePos time; + f_cnt_t offset; +}; + + + + +Plugin::PluginTypes Lv2Proc::check(const LilvPlugin *plugin, + std::vector& issues) +{ + unsigned maxPorts = lilv_plugin_get_num_ports(plugin); + enum { inCount, outCount, maxCount }; + unsigned audioChannels[maxCount] = { 0, 0 }; // audio input and output count + unsigned midiChannels[maxCount] = { 0, 0 }; // MIDI input and output count + + const char* pluginUri = lilv_node_as_uri(lilv_plugin_get_uri(plugin)); + //qDebug() << "Checking plugin" << pluginUri << "..."; + + // TODO: manage a global blacklist outside of the code + // for now, this will help + // this is only a fix for the meantime + const auto& pluginBlacklist = Lv2Manager::getPluginBlacklist(); + if (!Engine::ignorePluginBlacklist() && + pluginBlacklist.find(pluginUri) != pluginBlacklist.end()) + { + issues.emplace_back(blacklisted); + } + + for (unsigned portNum = 0; portNum < maxPorts; ++portNum) + { + Lv2Ports::Meta meta; + // does all port checks: + std::vector tmp = meta.get(plugin, portNum); + std::move(tmp.begin(), tmp.end(), std::back_inserter(issues)); + + bool portMustBeUsed = + !portIsSideChain(plugin, + lilv_plugin_get_port_by_index(plugin, portNum)) && + !meta.m_optional; + if (meta.m_type == Lv2Ports::Type::Audio && portMustBeUsed) + { + ++audioChannels[meta.m_flow == Lv2Ports::Flow::Output + ? outCount : inCount]; + } + else if(meta.m_type == Lv2Ports::Type::AtomSeq && portMustBeUsed) + { + ++midiChannels[meta.m_flow == Lv2Ports::Flow::Output + ? outCount : inCount]; + } + } + + if (audioChannels[inCount] > 2) + issues.emplace_back(tooManyInputChannels, + std::to_string(audioChannels[inCount])); + if (audioChannels[outCount] == 0) + issues.emplace_back(noOutputChannel); + else if (audioChannels[outCount] > 2) + issues.emplace_back(tooManyOutputChannels, + std::to_string(audioChannels[outCount])); + + if (midiChannels[inCount] > 1) + issues.emplace_back(tooManyMidiInputChannels, + std::to_string(midiChannels[inCount])); + if (midiChannels[outCount] > 1) + issues.emplace_back(tooManyMidiOutputChannels, + std::to_string(midiChannels[outCount])); + + AutoLilvNodes reqFeats(lilv_plugin_get_required_features(plugin)); + LILV_FOREACH (nodes, itr, reqFeats.get()) + { + const char* reqFeatName = lilv_node_as_string( + lilv_nodes_get(reqFeats.get(), itr)); + if(!Lv2Features::isFeatureSupported(reqFeatName)) + { + issues.emplace_back(featureNotSupported, reqFeatName); + } + } + + Lv2Manager* mgr = Engine::getLv2Manager(); + AutoLilvNode requiredOptionNode(mgr->uri(LV2_OPTIONS__requiredOption)); + AutoLilvNodes requiredOptions = mgr->findNodes(lilv_plugin_get_uri (plugin), requiredOptionNode.get(), nullptr); + if (requiredOptions) + { + LILV_FOREACH(nodes, i, requiredOptions.get()) + { + const char* ro = lilv_node_as_uri (lilv_nodes_get (requiredOptions.get(), i)); + if (!Lv2Options::isOptionSupported(mgr->uridMap().map(ro))) + { + // yes, this is not a Lv2 feature, + // but it's a feature in abstract sense + issues.emplace_back(featureNotSupported, ro); + } + } + } + + return (audioChannels[inCount] > 2 || audioChannels[outCount] > 2) + ? Plugin::Undefined + : (audioChannels[inCount] > 0) + ? Plugin::Effect + : Plugin::Instrument; +} + + + + +Lv2Proc::Lv2Proc(const LilvPlugin *plugin, Model* parent) : + LinkedModelGroup(parent), + m_plugin(plugin), + m_midiInputBuf(m_maxMidiInputEvents), + m_midiInputReader(m_midiInputBuf) +{ + initPlugin(); +} + + + + +Lv2Proc::~Lv2Proc() { shutdownPlugin(); } + + + + +void Lv2Proc::dumpPorts() +{ + std::size_t num = 0; + for (const std::unique_ptr& port: m_ports) + { + (void)port; + dumpPort(num++); + } +} + + + + +void Lv2Proc::copyModelsFromCore() +{ + struct FloatFromModelVisitor : public ConstModelVisitor + { + const std::vector* m_scalePointMap; // in + float m_res; // out + void visit(const FloatModel& m) override { m_res = m.value(); } + void visit(const IntModel& m) override { + m_res = static_cast(m.value()); } + void visit(const BoolModel& m) override { + m_res = static_cast(m.value()); } + void visit(const ComboBoxModel& m) override { + m_res = (*m_scalePointMap)[static_cast(m.value())]; } + }; + + struct Copy : public Lv2Ports::Visitor + { + void visit(Lv2Ports::Control& ctrl) override + { + FloatFromModelVisitor ffm; + ffm.m_scalePointMap = &ctrl.m_scalePointMap; + ctrl.m_connectedModel->accept(ffm); + ctrl.m_val = ffm.m_res; + } + void visit(Lv2Ports::Cv& cv) override + { + FloatFromModelVisitor ffm; + ffm.m_scalePointMap = &cv.m_scalePointMap; + cv.m_connectedModel->accept(ffm); + // dirty fix, needs better interpolation + std::fill(cv.m_buffer.begin(), cv.m_buffer.end(), ffm.m_res); + } + void visit(Lv2Ports::AtomSeq& atomPort) override + { + lv2_evbuf_reset(atomPort.m_buf.get(), true); + } + } copy; + + // feed each input port with the respective data from the LMMS core + for (const std::unique_ptr& port : m_ports) + { + if (port->m_flow == Lv2Ports::Flow::Input) + { + port->accept(copy); + } + } + + // send pending MIDI events to atom port + if(m_midiIn) + { + LV2_Evbuf_Iterator iter = lv2_evbuf_begin(m_midiIn->m_buf.get()); + // MIDI events waiting to go to the plugin? + while(m_midiInputReader.read_space() > 0) + { + const MidiInputEvent ev = m_midiInputReader.read(1)[0]; + uint32_t atomStamp = + ev.time.frames(Engine::framesPerTick()) + ev.offset; + uint32_t type = Engine::getLv2Manager()-> + uridCache()[Lv2UridCache::Id::midi_MidiEvent]; + uint8_t buf[4]; + std::size_t bufsize = writeToByteSeq(ev.ev, buf, sizeof(buf)); + if(bufsize) + { + lv2_evbuf_write(&iter, atomStamp, type, bufsize, buf); + } + } + } +} + + + + +void Lv2Proc::copyModelsToCore() +{ + struct Copy : public Lv2Ports::Visitor + { + void visit(Lv2Ports::AtomSeq& atomPort) override + { + // we currently don't copy anything, but we need to clear the buffer + // for the plugin to write again + lv2_evbuf_reset(atomPort.m_buf.get(), false); + } + } copy; + + // fetch data from each output port and bring it to the LMMS core + for (const std::unique_ptr& port : m_ports) + { + if (port->m_flow == Lv2Ports::Flow::Output) + { + port->accept(copy); + } + } +} + + + + +void Lv2Proc::copyBuffersFromCore(const sampleFrame *buf, + unsigned firstChan, unsigned num, + fpp_t frames) +{ + inPorts().m_left->copyBuffersFromCore(buf, firstChan, frames); + if (num > 1) + { + // if the caller requests to take input from two channels, but we only + // have one input channel... take medium of left and right for + // mono input + // (this happens if we have two outputs and only one input) + if (inPorts().m_right) + { + inPorts().m_right->copyBuffersFromCore(buf, firstChan + 1, frames); + } + else + { + inPorts().m_left->averageWithBuffersFromCore(buf, firstChan + 1, frames); + } + } +} + + + + +void Lv2Proc::copyBuffersToCore(sampleFrame* buf, + unsigned firstChan, unsigned num, + fpp_t frames) const +{ + outPorts().m_left->copyBuffersToCore(buf, firstChan + 0, frames); + if (num > 1) + { + // if the caller requests to copy into two channels, but we only have + // one output channel, duplicate our output + // (this happens if we have two inputs and only one output) + Lv2Ports::Audio* ap = outPorts().m_right + ? outPorts().m_right : outPorts().m_left; + ap->copyBuffersToCore(buf, firstChan + 1, frames); + } +} + + + + +void Lv2Proc::run(fpp_t frames) +{ + lilv_instance_run(m_instance, static_cast(frames)); +} + + + + +// in case there will be a PR which removes this callback and instead adds a +// `ringbuffer_t` to `class Instrument`, this +// function (and the ringbuffer and its reader in `Lv2Proc`) will simply vanish +void Lv2Proc::handleMidiInputEvent(const MidiEvent &event, const TimePos &time, f_cnt_t offset) +{ + if(m_midiIn) + { + // ringbuffer allows only one writer at a time + // however, this function can be called by multiple threads + // (different RT and non-RT!) at the same time + // for now, a spinlock looks like the most safe/easy compromise + + // source: https://en.cppreference.com/w/cpp/atomic/atomic_flag + while (m_ringLock.test_and_set(std::memory_order_acquire)) // acquire lock + ; // spin + + MidiInputEvent ev { event, time, offset }; + std::size_t written = m_midiInputBuf.write(&ev, 1); + if(written != 1) + { + qWarning("MIDI ringbuffer is too small! Discarding MIDI event."); + } + + m_ringLock.clear(std::memory_order_release); + } + else + { + qWarning() << "Warning: Caught MIDI event for an Lv2 instrument" + << "that can not hande MIDI... Ignoring"; + } +} + + + + +AutomatableModel *Lv2Proc::modelAtPort(const QString &uri) +{ + // unused currently + AutomatableModel *mod; + auto itr = m_connectedModels.find(uri.toUtf8().data()); + if (itr != m_connectedModels.end()) { mod = itr->second; } + else { mod = nullptr; } + return mod; +} + + + + +void Lv2Proc::initPlugin() +{ + m_features.initCommon(); + initPluginSpecificFeatures(); + m_features.createFeatureVectors(); + + createPorts(); + + m_instance = lilv_plugin_instantiate(m_plugin, + Engine::mixer()->processingSampleRate(), + m_features.featurePointers()); + + if (m_instance) + { + for (std::size_t portNum = 0; portNum < m_ports.size(); ++portNum) + connectPort(portNum); + lilv_instance_activate(m_instance); + } + else + { + qCritical() << "Failed to create an instance of" + << qStringFromPluginNode(m_plugin, lilv_plugin_get_name) + << "(URI:" + << lilv_node_as_uri(lilv_plugin_get_uri(m_plugin)) + << ")"; + m_valid = false; + } +} + + + + +void Lv2Proc::shutdownPlugin() +{ + if (m_valid) + { + lilv_instance_deactivate(m_instance); + lilv_instance_free(m_instance); + m_instance = nullptr; + } +} + + + + +bool Lv2Proc::hasNoteInput() const +{ + return m_midiIn; + // we could additionally check for + // http://lv2plug.in/ns/lv2core#InstrumentPlugin + // however, jalv does not do that, too + // so, if there's any MIDI input, we just assume we can send notes there +} + + + + +void Lv2Proc::initMOptions() +{ + /* + sampleRate: + LMMS can in theory inform plugins of a new sample rate. + However, Lv2 plugins seem to not allow sample rate changes + (not even through LV2_Options_Interface) - it's assumed to be + fixed after being passed via LV2_Descriptor::instantiate. + So, if the sampleRate would change, the plugin will need to + re-initialize, and this code section will be + executed again, creating a new option vector. + */ + float sampleRate = Engine::mixer()->processingSampleRate(); + int32_t blockLength = Engine::mixer()->framesPerPeriod(); + int32_t sequenceSize = defaultEvbufSize(); + + using Id = Lv2UridCache::Id; + m_options.initOption(Id::param_sampleRate, sampleRate); + m_options.initOption(Id::bufsz_maxBlockLength, blockLength); + m_options.initOption(Id::bufsz_minBlockLength, blockLength); + m_options.initOption(Id::bufsz_nominalBlockLength, blockLength); + m_options.initOption(Id::bufsz_sequenceSize, sequenceSize); + m_options.createOptionVectors(); +} + + + + +void Lv2Proc::initPluginSpecificFeatures() +{ + initMOptions(); + m_features[LV2_OPTIONS__options] = const_cast(m_options.feature()); +} + + + + +void Lv2Proc::loadFileInternal(const QString &file) +{ + (void)file; +} + + + + +void Lv2Proc::createPort(std::size_t portNum) +{ + Lv2Ports::Meta meta; + meta.get(m_plugin, portNum); + + const LilvPort* lilvPort = lilv_plugin_get_port_by_index(m_plugin, + static_cast(portNum)); + Lv2Ports::PortBase* port; + + switch (meta.m_type) + { + case Lv2Ports::Type::Control: + { + Lv2Ports::Control* ctrl = new Lv2Ports::Control; + if (meta.m_flow == Lv2Ports::Flow::Input) + { + AutoLilvNode node(lilv_port_get_name(m_plugin, lilvPort)); + QString dispName = lilv_node_as_string(node.get()); + sample_rate_t sr = Engine::mixer()->processingSampleRate(); + if(meta.def() < meta.min(sr) || meta.def() > meta.max(sr)) + { + qWarning() << "Warning: Plugin" + << qStringFromPluginNode(m_plugin, lilv_plugin_get_name) + << "(URI:" + << lilv_node_as_uri(lilv_plugin_get_uri(m_plugin)) + << ") has a default value for port" + << dispName + << "which is not in range [min, max]."; + } + switch (meta.m_vis) + { + case Lv2Ports::Vis::Generic: + { + // allow ~1000 steps + float stepSize = (meta.max(sr) - meta.min(sr)) / 1000.0f; + + // make multiples of 0.01 (or 0.1 for larger values) + float minStep = (stepSize >= 1.0f) ? 0.1f : 0.01f; + stepSize -= fmodf(stepSize, minStep); + stepSize = std::max(stepSize, minStep); + + ctrl->m_connectedModel.reset( + new FloatModel(meta.def(), meta.min(sr), meta.max(sr), + stepSize, nullptr, dispName)); + break; + } + case Lv2Ports::Vis::Integer: + ctrl->m_connectedModel.reset( + new IntModel(static_cast(meta.def()), + static_cast(meta.min(sr)), + static_cast(meta.max(sr)), + nullptr, dispName)); + break; + case Lv2Ports::Vis::Enumeration: + { + ComboBoxModel* comboModel + = new ComboBoxModel( + nullptr, dispName); + LilvScalePoints* sps = + lilv_port_get_scale_points(m_plugin, lilvPort); + LILV_FOREACH(scale_points, i, sps) + { + const LilvScalePoint* sp = lilv_scale_points_get(sps, i); + ctrl->m_scalePointMap.push_back(lilv_node_as_float( + lilv_scale_point_get_value(sp))); + comboModel->addItem( + lilv_node_as_string( + lilv_scale_point_get_label(sp))); + } + lilv_scale_points_free(sps); + ctrl->m_connectedModel.reset(comboModel); + // TODO: use default value on comboModel, too? + break; + } + case Lv2Ports::Vis::Toggled: + ctrl->m_connectedModel.reset( + new BoolModel(static_cast(meta.def()), + nullptr, dispName)); + break; + } + if(meta.m_logarithmic) + { + ctrl->m_connectedModel->setScaleLogarithmic(); + } + + } // if m_flow == Input + port = ctrl; + break; + } + case Lv2Ports::Type::Audio: + { + Lv2Ports::Audio* audio = + new Lv2Ports::Audio( + static_cast( + Engine::mixer()->framesPerPeriod()), + portIsSideChain(m_plugin, lilvPort) + ); + port = audio; + break; + } + case Lv2Ports::Type::AtomSeq: + { + Lv2Ports::AtomSeq* atomPort = new Lv2Ports::AtomSeq; + + { + AutoLilvNode uriAtomSupports(Engine::getLv2Manager()->uri(LV2_ATOM__supports)); + AutoLilvNodes atomSupports(lilv_port_get_value(m_plugin, lilvPort, uriAtomSupports.get())); + AutoLilvNode uriMidiEvent(Engine::getLv2Manager()->uri(LV2_MIDI__MidiEvent)); + + LILV_FOREACH (nodes, itr, atomSupports.get()) + { + if(lilv_node_equals(lilv_nodes_get(atomSupports.get(), itr), uriMidiEvent.get())) + { + atomPort->flags |= Lv2Ports::AtomSeq::FlagType::Midi; + } + } + } + + int minimumSize = defaultEvbufSize(); + + Lv2Manager* mgr = Engine::getLv2Manager(); + + // check for alternative minimum size + { + AutoLilvNode rszMinimumSize = mgr->uri(LV2_RESIZE_PORT__minimumSize); + AutoLilvNodes minSizeV(lilv_port_get_value(m_plugin, lilvPort, rszMinimumSize.get())); + LilvNode* minSize = minSizeV ? lilv_nodes_get_first(minSizeV.get()) : nullptr; + if (minSize && lilv_node_is_int(minSize)) { + minimumSize = std::max(minimumSize, lilv_node_as_int(minSize)); + } + } + + atomPort->m_buf.reset( + lv2_evbuf_new(static_cast(minimumSize), + mgr->uridMap().map(LV2_ATOM__Chunk), + mgr->uridMap().map(LV2_ATOM__Sequence))); + + port = atomPort; + break; + } + default: + port = new Lv2Ports::Unknown; + } + + // `meta` is of class `Lv2Ports::Meta` and `port` is of a child class + // we can now assign the `Lv2Ports::Meta` part of meta to ports, leaving + // the additional members of `port` unchanged + *static_cast(port) = meta; + port->m_port = lilvPort; + port->m_plugin = m_plugin; + + m_ports[portNum].reset(port); +} + + + + +void Lv2Proc::createPorts() +{ + // register ports at the processor after creation, + // i.e. link their data or count them + struct RegisterPort : public Lv2Ports::Visitor + { + Lv2Proc* m_proc; + + void visit(Lv2Ports::Control& ctrl) override + { + if (ctrl.m_flow == Lv2Ports::Flow::Input) + { + AutomatableModel* amo = ctrl.m_connectedModel.get(); + m_proc->m_connectedModels.emplace( + lilv_node_as_string(lilv_port_get_symbol( + m_proc->m_plugin, ctrl.m_port)), + amo); + m_proc->addModel(amo, ctrl.uri()); + } + } + + void visit(Lv2Ports::Audio& audio) override + { + if (audio.mustBeUsed()) + { + StereoPortRef dummy; + StereoPortRef* portRef = &dummy; + switch (audio.m_flow) + { + case Lv2Ports::Flow::Input: + portRef = &m_proc->m_inPorts; + break; + case Lv2Ports::Flow::Output: + portRef = &m_proc->m_outPorts; + break; + case Lv2Ports::Flow::Unknown: + break; + } + // in Lv2, leftPort is defined to be the first port + if (!portRef->m_left) { portRef->m_left = &audio; } + else if (!portRef->m_right) { portRef->m_right = &audio; } + } + } + + void visit(Lv2Ports::AtomSeq& atomPort) override + { + if(atomPort.m_flow == Lv2Ports::Flow::Input) + { + if(atomPort.flags & Lv2Ports::AtomSeq::FlagType::Midi) + { + // take any MIDI input, prefer mandatory MIDI input + // (Lv2Proc::check() assures there are <=1 mandatory MIDI + // input ports) + if(!m_proc->m_midiIn || !atomPort.m_optional) + m_proc->m_midiIn = &atomPort; + } + } + else if(atomPort.m_flow == Lv2Ports::Flow::Output) + { + if(atomPort.flags & Lv2Ports::AtomSeq::FlagType::Midi) + { + // take any MIDI output, prefer mandatory MIDI output + // (Lv2Proc::check() assures there are <=1 mandatory MIDI + // output ports) + if(!m_proc->m_midiOut || !atomPort.m_optional) + m_proc->m_midiOut = &atomPort; + } + } + else { Q_ASSERT(false); } + } + }; + + std::size_t maxPorts = lilv_plugin_get_num_ports(m_plugin); + m_ports.resize(maxPorts); + + for (std::size_t portNum = 0; portNum < maxPorts; ++portNum) + { + createPort(portNum); + RegisterPort registerPort; + registerPort.m_proc = this; + m_ports[portNum]->accept(registerPort); + } + + // initially assign model values to port values + copyModelsFromCore(); + + // debugging: + //dumpPorts(); +} + + + + +struct ConnectPortVisitor : public Lv2Ports::Visitor +{ + std::size_t m_num; + LilvInstance* m_instance; + void connectPort(void* location) + { + lilv_instance_connect_port(m_instance, + static_cast(m_num), location); + } + void visit(Lv2Ports::AtomSeq& atomSeq) override + { + connectPort(lv2_evbuf_get_buffer(atomSeq.m_buf.get())); + } + void visit(Lv2Ports::Control& ctrl) override { connectPort(&ctrl.m_val); } + void visit(Lv2Ports::Audio& audio) override + { + connectPort((audio.mustBeUsed()) ? audio.m_buffer.data() : nullptr); + } + void visit(Lv2Ports::Unknown&) override { connectPort(nullptr); } + ~ConnectPortVisitor() override; +}; + +ConnectPortVisitor::~ConnectPortVisitor() {} + +// !This function must be realtime safe! +// use createPort to create any port before connecting +void Lv2Proc::connectPort(std::size_t num) +{ + ConnectPortVisitor connect; + connect.m_num = num; + connect.m_instance = m_instance; + m_ports[num]->accept(connect); +} + + + + +void Lv2Proc::dumpPort(std::size_t num) +{ + struct DumpPortDetail : public Lv2Ports::ConstVisitor + { + void visit(const Lv2Ports::Control& ctrl) override { + qDebug() << " control port"; + // output ports may be uninitialized yet, only print inputs + if (ctrl.m_flow == Lv2Ports::Flow::Input) + { + qDebug() << " value:" << ctrl.m_val; + } + } + void visit(const Lv2Ports::Audio& audio) override { + qDebug() << (audio.isSideChain() ? " audio port (sidechain)" + : " audio port"); + qDebug() << " buffer size:" << audio.bufferSize(); + } + }; + + const Lv2Ports::PortBase& port = *m_ports[num]; + qDebug().nospace() << "port " << num << ":"; + qDebug() << " name:" + << qStringFromPortName(m_plugin, port.m_port); + qDebug() << " flow: " << Lv2Ports::toStr(port.m_flow); + qDebug() << " type: " << Lv2Ports::toStr(port.m_type); + qDebug() << " visualization: " << Lv2Ports::toStr(port.m_vis); + if (port.m_type == Lv2Ports::Type::Control || port.m_type == Lv2Ports::Type::Cv) + { + sample_rate_t sr = Engine::mixer()->processingSampleRate(); + qDebug() << " default:" << port.def(); + qDebug() << " min:" << port.min(sr); + qDebug() << " max:" << port.max(sr); + } + qDebug() << " optional: " << port.m_optional; + qDebug() << " => USED: " << port.m_used; + + DumpPortDetail dumper; + port.accept(dumper); +} + + + + +bool Lv2Proc::portIsSideChain(const LilvPlugin *plugin, const LilvPort *port) +{ + return lilv_port_has_property(plugin, port, + uri(LV2_CORE_PREFIX "isSidechain").get()); +} + + + + +bool Lv2Proc::portIsOptional(const LilvPlugin *plugin, const LilvPort *port) +{ + return lilv_port_has_property(plugin, port, + uri(LV2_CORE__connectionOptional).get()); +} + + + + +AutoLilvNode Lv2Proc::uri(const char *uriStr) +{ + return Engine::getLv2Manager()->uri(uriStr); +} + + +#endif // LMMS_HAVE_LV2 diff --git a/src/core/lv2/Lv2SubPluginFeatures.cpp b/src/core/lv2/Lv2SubPluginFeatures.cpp new file mode 100644 index 00000000000..3f86c5324e2 --- /dev/null +++ b/src/core/lv2/Lv2SubPluginFeatures.cpp @@ -0,0 +1,184 @@ +/* + * Lv2SubPluginFeatures.cpp - derivation from + * Plugin::Descriptor::SubPluginFeatures for + * hosting LV2 plugins + * + * Copyright (c) 2018-2020 Johannes Lorenz + * + * 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. + * + */ + +#include "Lv2SubPluginFeatures.h" + +#ifdef LMMS_HAVE_LV2 + +#include +#include +#include + +#include "Engine.h" +#include "Lv2Basics.h" +#include "Lv2Manager.h" + + +const LilvPlugin *Lv2SubPluginFeatures::getPlugin( + const Plugin::Descriptor::SubPluginFeatures::Key &k) +{ + const LilvPlugin* result = Engine::getLv2Manager()-> + getPlugin(k.attributes["uri"]); + Q_ASSERT(result); + return result; +} + + + + +QString Lv2SubPluginFeatures::pluginName(const LilvPlugin *plug) +{ + return qStringFromPluginNode(plug, lilv_plugin_get_name); +} + + + + +Lv2SubPluginFeatures::Lv2SubPluginFeatures(Plugin::PluginTypes type) : + SubPluginFeatures(type) +{ +} + + + + +void Lv2SubPluginFeatures::fillDescriptionWidget(QWidget *parent, + const Key *k) const +{ + const LilvPlugin *plug = getPlugin(*k); + + QLabel *label = new QLabel(parent); + label->setText(QWidget::tr("Name: ") + pluginName(plug)); + + QLabel *label2 = new QLabel(parent); + label2->setText(QWidget::tr("URI: ") + + lilv_node_as_uri(lilv_plugin_get_uri(plug))); + + QWidget *maker = new QWidget(parent); + QHBoxLayout *l = new QHBoxLayout(maker); + l->setMargin(0); + l->setSpacing(0); + + QLabel *maker_label = new QLabel(maker); + maker_label->setText(QWidget::tr("Maker: ")); + maker_label->setAlignment(Qt::AlignTop); + + QLabel *maker_content = new QLabel(maker); + maker_content->setText( + qStringFromPluginNode(plug, lilv_plugin_get_author_name)); + maker_content->setWordWrap(true); + + l->addWidget(maker_label); + l->addWidget(maker_content, 1); + + QWidget *copyright = new QWidget(parent); + l = new QHBoxLayout(copyright); + l->setMargin(0); + l->setSpacing(0); + copyright->setMinimumWidth(parent->minimumWidth()); + + QLabel *copyright_label = new QLabel(copyright); + copyright_label->setText(QWidget::tr("Copyright: ")); + copyright_label->setAlignment(Qt::AlignTop); + + QLabel *copyright_content = new QLabel(copyright); + copyright_content->setText(""); + copyright_content->setWordWrap(true); + l->addWidget(copyright_label); + l->addWidget(copyright_content, 1); + + AutoLilvNodes extensions(lilv_plugin_get_extension_data(plug)); + (void)extensions; + // possibly TODO: version, project, plugin type, number of channels +} + + + + +QString Lv2SubPluginFeatures::additionalFileExtensions( + const Plugin::Descriptor::SubPluginFeatures::Key &k) const +{ + (void)k; + // lv2 only loads .lv2 files + // maybe add conversions later, e.g. for loading xmz + return QString(); +} + + + + +QString Lv2SubPluginFeatures::displayName( + const Plugin::Descriptor::SubPluginFeatures::Key &k) const +{ + return pluginName(getPlugin(k)); +} + + + + +QString Lv2SubPluginFeatures::description( + const Plugin::Descriptor::SubPluginFeatures::Key &k) const +{ + (void)k; + return QString::fromUtf8("description not implemented yet"); // TODO +} + + + + +const PixmapLoader *Lv2SubPluginFeatures::logo( + const Plugin::Descriptor::SubPluginFeatures::Key &k) const +{ + (void)k; // TODO + return nullptr; +} + + + + +void Lv2SubPluginFeatures::listSubPluginKeys(const Plugin::Descriptor *desc, + KeyList &kl) const +{ + Lv2Manager *lv2Mgr = Engine::getLv2Manager(); + for (const auto &uriInfoPair : *lv2Mgr) + { + if (uriInfoPair.second.type() == m_type && uriInfoPair.second.isValid()) + { + using KeyType = + Plugin::Descriptor::SubPluginFeatures::Key; + KeyType::AttributeMap atm; + atm["uri"] = QString::fromUtf8(uriInfoPair.first.c_str()); + const LilvPlugin* plug = uriInfoPair.second.plugin(); + + kl.push_back(KeyType(desc, pluginName(plug), atm)); + //qDebug() << "Found LV2 sub plugin key of type" << + // m_type << ":" << pr.first.c_str(); + } + } +} + +#endif // LMMS_HAVE_LV2 + diff --git a/src/core/lv2/Lv2UridCache.cpp b/src/core/lv2/Lv2UridCache.cpp new file mode 100644 index 00000000000..3392f9bd2f7 --- /dev/null +++ b/src/core/lv2/Lv2UridCache.cpp @@ -0,0 +1,72 @@ +/* + * Lv2UridCache.cpp - Lv2UridCache implementation + * + * Copyright (c) 2020-2020 Johannes Lorenz + * + * 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. + * + */ + +#include "Lv2UridCache.h" + +#ifdef LMMS_HAVE_LV2 + +#include +#include +#include +#include +#include + +#include "Lv2UridMap.h" + +// support newer URIs on old systems +#ifndef LV2_BUF_SIZE__nominalBlockLength +#define LV2_BUF_SIZE__nominalBlockLength LV2_BUF_SIZE_PREFIX "nominalBlockLength" +#endif + +uint32_t Lv2UridCache::operator[](Lv2UridCache::Id id) const +{ + Q_ASSERT(id != Id::size); + return m_cache[static_cast(id)]; +} + +Lv2UridCache::Lv2UridCache(UridMap &mapper) +{ + const uint32_t noIdYet = 0; + std::fill_n(m_cache, static_cast(Id::size), noIdYet); + + auto init = [this, &mapper](Id id, const char* uridStr) + { + m_cache[static_cast(id)] = mapper.map(uridStr); + }; + + init(Id::atom_Float, LV2_ATOM__Float); + init(Id::atom_Int, LV2_ATOM__Int); + init(Id::bufsz_minBlockLength, LV2_BUF_SIZE__minBlockLength); + init(Id::bufsz_maxBlockLength, LV2_BUF_SIZE__maxBlockLength); + init(Id::bufsz_nominalBlockLength, LV2_BUF_SIZE__nominalBlockLength); + init(Id::bufsz_sequenceSize, LV2_BUF_SIZE__sequenceSize); + init(Id::midi_MidiEvent, LV2_MIDI__MidiEvent); + init(Id::param_sampleRate, LV2_PARAMETERS__sampleRate); + + for(uint32_t urid : m_cache) { Q_ASSERT(urid != noIdYet); } +} + +#endif // LMMS_HAVE_LV2 + + diff --git a/src/core/lv2/Lv2UridMap.cpp b/src/core/lv2/Lv2UridMap.cpp new file mode 100644 index 00000000000..7e4fa864f1e --- /dev/null +++ b/src/core/lv2/Lv2UridMap.cpp @@ -0,0 +1,99 @@ +/* + * Lv2UridMap.cpp - Lv2UridMap implementation + * + * Copyright (c) 2019 Johannes Lorenz + * + * 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. + * + */ + + +#include "Lv2UridMap.h" + +#ifdef LMMS_HAVE_LV2 + +static LV2_URID staticMap(LV2_URID_Map_Handle handle, const char* uri) +{ + UridMap* map = static_cast(handle); + return map->map(uri); +} + +static const char* staticUnmap(LV2_URID_Unmap_Handle handle, LV2_URID urid) +{ + UridMap* map = static_cast(handle); + return map->unmap(urid); +} + +UridMap::UridMap() +{ + m_mapFeature.handle = static_cast(this); + m_mapFeature.map = staticMap; + m_unmapFeature.handle = static_cast(this); + m_unmapFeature.unmap = staticUnmap; +} + +LV2_URID UridMap::map(const char *uri) +{ + LV2_URID result = 0u; + + // the Lv2 docs say that 0 should be returned in any case + // where creating an ID for the given URI fails + try + { + // TODO: + // when using C++14, we can get around any string allocation + // in the case the URI is already inside the map: + // * use `m_map.find(uri)` instead of `m_map.find(uriStr)` + // * to avoid temporary string construction in the `find` call, create + // m_map like this: + // std::unordered_map, std::equal<>> m_map; + // * move the try block inside the case where the URI is not in the map + const std::string uriStr = uri; + + std::lock_guard guard (m_MapMutex); + + auto itr = m_map.find(uriStr); + if (itr == m_map.end()) + { + // 1 is the first free URID + std::size_t index = 1u + m_unMap.size(); + auto pr = m_map.emplace(std::move(uriStr), index); + if (pr.second) + { + m_unMap.emplace_back(pr.first->first.c_str()); + result = static_cast(index); + } + } + else { result = itr->second; } + } + catch(...) { /* result variable is already 0 */ } + + return result; +} + +const char *UridMap::unmap(LV2_URID urid) +{ + std::size_t idx = static_cast(urid) - 1; + + std::lock_guard guard (m_MapMutex); + return (idx < m_unMap.size()) ? m_unMap[idx] : nullptr; +} + +#endif // LMMS_HAVE_LV2 + diff --git a/src/core/main.cpp b/src/core/main.cpp index e9f3f1e367c..9a376975615 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -59,6 +59,7 @@ #include "MainApplication.h" #include "ConfigManager.h" +#include "DataFile.h" #include "NotePlayHandle.h" #include "embed.h" #include "Engine.h" @@ -129,9 +130,10 @@ inline void loadTranslation( const QString & tname, QTranslator * t = new QTranslator( QCoreApplication::instance() ); QString name = tname + ".qm"; - t->load( name, dir ); - - QCoreApplication::instance()->installTranslator( t ); + if (t->load(name, dir)) + { + QCoreApplication::instance()->installTranslator(t); + } } @@ -161,6 +163,7 @@ void printHelp() "Actions:\n" " [options...] [] Start LMMS in normal GUI mode\n" " dump Dump XML of compressed file \n" + " compress Compress file \n" " render [options...] Render given project file\n" " rendertracks [options...] Render each track to a different file\n" " upgrade [out] Upgrade file and save as \n" @@ -424,6 +427,22 @@ int main( int argc, char * * argv ) return EXIT_SUCCESS; } + else if( arg == "compress" || arg == "--compress" ) + { + ++i; + + if( i == argc ) + { + return noInputFileError(); + } + + QFile f( QString::fromLocal8Bit( argv[i] ) ); + f.open( QIODevice::ReadOnly ); + QByteArray d = qCompress( f.readAll() ) ; + fwrite( d.constData(), sizeof(char), d.size(), stdout ); + + return EXIT_SUCCESS; + } else if( arg == "render" || arg == "--render" || arg == "-r" || arg == "rendertracks" || arg == "--rendertracks" ) { @@ -703,18 +722,16 @@ int main( int argc, char * * argv ) pos = QLocale::system().name().left( 2 ); } -#ifdef LMMS_BUILD_WIN32 -#undef QT_TRANSLATIONS_DIR -#define QT_TRANSLATIONS_DIR ConfigManager::inst()->localeDir() -#endif + // load actual translation for LMMS + loadTranslation( pos ); -#ifdef QT_TRANSLATIONS_DIR // load translation for Qt-widgets/-dialogs - loadTranslation( QString( "qt_" ) + pos, - QString( QT_TRANSLATIONS_DIR ) ); +#ifdef QT_TRANSLATIONS_DIR + // load from the original path first + loadTranslation(QString("qt_") + pos, QT_TRANSLATIONS_DIR); #endif - // load actual translation for LMMS - loadTranslation( pos ); + // override it with bundled/custom one, if exists + loadTranslation(QString("qt_") + pos, ConfigManager::inst()->localeDir()); // try to set realtime priority diff --git a/src/core/midi/MidiAlsaSeq.cpp b/src/core/midi/MidiAlsaSeq.cpp index 56fd956d46d..70c5a40c80a 100644 --- a/src/core/midi/MidiAlsaSeq.cpp +++ b/src/core/midi/MidiAlsaSeq.cpp @@ -157,7 +157,7 @@ QString MidiAlsaSeq::probeDevice() -void MidiAlsaSeq::processOutEvent( const MidiEvent& event, const MidiTime& time, const MidiPort* port ) +void MidiAlsaSeq::processOutEvent( const MidiEvent& event, const TimePos& time, const MidiPort* port ) { // HACK!!! - need a better solution which isn't that easy since we // cannot store const-ptrs in our map because we need to call non-const @@ -536,7 +536,7 @@ void MidiAlsaSeq::run() ev->data.note.velocity, source ), - MidiTime( ev->time.tick ) ); + TimePos( ev->time.tick ) ); break; case SND_SEQ_EVENT_NOTEOFF: @@ -547,7 +547,7 @@ void MidiAlsaSeq::run() ev->data.note.velocity, source ), - MidiTime( ev->time.tick) ); + TimePos( ev->time.tick) ); break; case SND_SEQ_EVENT_KEYPRESS: @@ -558,7 +558,7 @@ void MidiAlsaSeq::run() KeysPerOctave, ev->data.note.velocity, source - ), MidiTime() ); + ), TimePos() ); break; case SND_SEQ_EVENT_CONTROLLER: @@ -567,7 +567,7 @@ void MidiAlsaSeq::run() ev->data.control.channel, ev->data.control.param, ev->data.control.value, source ), - MidiTime() ); + TimePos() ); break; case SND_SEQ_EVENT_PGMCHANGE: @@ -576,7 +576,7 @@ void MidiAlsaSeq::run() ev->data.control.channel, ev->data.control.value, 0, source ), - MidiTime() ); + TimePos() ); break; case SND_SEQ_EVENT_CHANPRESS: @@ -585,14 +585,14 @@ void MidiAlsaSeq::run() ev->data.control.channel, ev->data.control.param, ev->data.control.value, source ), - MidiTime() ); + TimePos() ); break; case SND_SEQ_EVENT_PITCHBEND: dest->processInEvent( MidiEvent( MidiPitchBend, ev->data.control.channel, ev->data.control.value + 8192, 0, source ), - MidiTime() ); + TimePos() ); break; case SND_SEQ_EVENT_SENSING: diff --git a/src/core/midi/MidiApple.cpp b/src/core/midi/MidiApple.cpp index f4bc0d4dd97..67e2084cfde 100644 --- a/src/core/midi/MidiApple.cpp +++ b/src/core/midi/MidiApple.cpp @@ -57,7 +57,7 @@ MidiApple::~MidiApple() -void MidiApple::processOutEvent( const MidiEvent& event, const MidiTime& time, const MidiPort* port ) +void MidiApple::processOutEvent( const MidiEvent& event, const TimePos& time, const MidiPort* port ) { qDebug("MidiApple:processOutEvent displayName:'%s'",port->displayName().toLatin1().constData()); @@ -401,9 +401,9 @@ void MidiApple::midiInClose( MIDIEndpointRef reference ) char *getName( MIDIObjectRef &object ) { // Returns the name of a given MIDIObjectRef as char * - CFStringRef name = nil; + CFStringRef name = nullptr; if (noErr != MIDIObjectGetStringProperty(object, kMIDIPropertyName, &name)) - return nil; + return nullptr; int len = CFStringGetLength(name)+1; char *value = (char *) malloc(len); @@ -615,8 +615,12 @@ char * MidiApple::getFullName(MIDIEndpointRef &endpoint_ref) char * deviceName = getName(device); char * endPointName = getName(endpoint_ref); qDebug("device name='%s' endpoint name='%s'",deviceName,endPointName); - char * fullName = (char *)malloc(strlen(deviceName) + strlen(":") + strlen(endPointName)+1); + size_t deviceNameLen = deviceName == nullptr ? 0 : strlen(deviceName); + size_t endPointNameLen = endPointName == nullptr ? 0 : strlen(endPointName); + char * fullName = (char *)malloc(deviceNameLen + endPointNameLen + 2); sprintf(fullName, "%s:%s", deviceName,endPointName); + if (deviceName != nullptr) { free(deviceName); } + if (endPointName != nullptr) { free(endPointName); } return fullName; } diff --git a/src/core/midi/MidiClient.cpp b/src/core/midi/MidiClient.cpp index e37f59c06ba..b3d7e63635d 100644 --- a/src/core/midi/MidiClient.cpp +++ b/src/core/midi/MidiClient.cpp @@ -266,7 +266,7 @@ void MidiClientRaw::processParsedEvent() -void MidiClientRaw::processOutEvent( const MidiEvent& event, const MidiTime & , const MidiPort* port ) +void MidiClientRaw::processOutEvent( const MidiEvent& event, const TimePos & , const MidiPort* port ) { // TODO: also evaluate _time and queue event if necessary switch( event.type() ) diff --git a/src/core/midi/MidiController.cpp b/src/core/midi/MidiController.cpp index 72128e18436..93cea4a00f5 100644 --- a/src/core/midi/MidiController.cpp +++ b/src/core/midi/MidiController.cpp @@ -80,7 +80,7 @@ void MidiController::updateName() -void MidiController::processInEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset ) +void MidiController::processInEvent( const MidiEvent& event, const TimePos& time, f_cnt_t offset ) { unsigned char controllerNum; switch( event.type() ) diff --git a/src/core/midi/MidiEventToByteSeq.cpp b/src/core/midi/MidiEventToByteSeq.cpp new file mode 100644 index 00000000000..98f0541d032 --- /dev/null +++ b/src/core/midi/MidiEventToByteSeq.cpp @@ -0,0 +1,107 @@ +/* + * MidiEventToByteSeq.cpp - writeToByteSeq implementation + * + * Copyright (c) 2020-2020 Johannes Lorenz + * + * 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. + * + */ + +#include "MidiEventToByteSeq.h" + +#include + +#include "MidiEvent.h" + + +std::size_t writeToByteSeq( + const MidiEvent& ev, uint8_t *data, std::size_t bufsize) +{ + Q_ASSERT(bufsize >= 3); + + std::size_t size = 0; + data[0] = ev.type() | (ev.channel() & 0x0F); + + switch (ev.type()) + { + case MidiNoteOn: + if (ev.velocity() > 0) + { + if (ev.key() < 0 || ev.key() > MidiMaxKey) + break; + + data[1] = ev.key(); + data[2] = ev.velocity(); + size = 3; + break; + } + else + { + // Lv2 MIDI specs: + // "Note On messages with velocity 0 are not allowed. + // These messages are equivalent to Note Off in standard + // MIDI streams, but here only proper Note Off messages + // are allowed." + data[0] = MidiNoteOff | (ev.channel() & 0x0F); + // nobreak + } + + case MidiNoteOff: + if (ev.key() < 0 || ev.key() > MidiMaxKey) + break; + data[1] = ev.key(); + data[2] = ev.velocity(); // release time + size = 3; + break; + + case MidiKeyPressure: + data[1] = ev.key(); + data[2] = ev.velocity(); + size = 3; + break; + + case MidiControlChange: + data[1] = ev.controllerNumber(); + data[2] = ev.controllerValue(); + size = 3; + break; + + case MidiProgramChange: + data[1] = ev.program(); + size = 2; + break; + + case MidiChannelPressure: + data[1] = ev.channelPressure(); + size = 2; + break; + + case MidiPitchBend: + data[1] = ev.pitchBend() & 0x7f; + data[2] = ev.pitchBend() >> 7; + size = 3; + break; + + default: + // unhandled + break; + } + + return size; +} + diff --git a/src/core/midi/MidiJack.cpp b/src/core/midi/MidiJack.cpp index 568b6dae164..bd1e651113c 100644 --- a/src/core/midi/MidiJack.cpp +++ b/src/core/midi/MidiJack.cpp @@ -95,6 +95,8 @@ MidiJack::MidiJack() : /* jack midi out not implemented JackMidiWrite and sendByte needs to be functional before enabling this + If you enable this, also enable the + corresponding jack_port_unregister line below m_output_port = jack_port_register( jackClient(), "MIDI out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); @@ -116,13 +118,18 @@ MidiJack::~MidiJack() { if(jackClient()) { + // remove ourselves first (atomically), so we will not get called again + m_jackAudio->removeMidiClient(); + if( jack_port_unregister( jackClient(), m_input_port) != 0){ printf("Failed to unregister jack midi input\n"); } + /* Unused yet, see the corresponding jack_port_register call if( jack_port_unregister( jackClient(), m_output_port) != 0){ printf("Failed to unregister jack midi output\n"); } + */ if(m_jackClient) { @@ -174,19 +181,22 @@ void MidiJack::JackMidiRead(jack_nframes_t nframes) jack_nframes_t event_index = 0; jack_nframes_t event_count = jack_midi_get_event_count(port_buf); - jack_midi_event_get(&in_event, port_buf, 0); - for(i=0; i -#include #include #include @@ -35,6 +34,7 @@ #include "GuiApplication.h" #include "MainWindow.h" #include "StringPairDrag.h" +#include "Clipboard.h" #include "AutomationEditor.h" @@ -42,7 +42,8 @@ static float floatFromClipboard(bool* ok=nullptr); AutomatableModelView::AutomatableModelView( ::Model* model, QWidget* _this ) : - ModelView( model, _this ) + ModelView( model, _this ), + m_conversionFactor( 1.0 ) { widget()->setAcceptDrops( true ); widget()->setCursor( QCursor( embed::getIconPixmap( "hand" ), 3, 3 ) ); @@ -56,14 +57,14 @@ void AutomatableModelView::addDefaultActions( QMenu* menu ) menu->addAction( embed::getIconPixmap( "reload" ), AutomatableModel::tr( "&Reset (%1%2)" ). - arg( model->displayValue( model->initValue() ) ). + arg( model->initValue() * m_conversionFactor ). arg( m_unit ), model, SLOT( reset() ) ); menu->addSeparator(); menu->addAction( embed::getIconPixmap( "edit_copy" ), AutomatableModel::tr( "&Copy value (%1%2)" ). - arg( model->displayValue( model->value() ) ). + arg( model->value() * m_conversionFactor ). arg( m_unit ), amvSlots, SLOT( copyToClipboard() ) ); @@ -71,7 +72,7 @@ void AutomatableModelView::addDefaultActions( QMenu* menu ) const float valueToPaste = floatFromClipboard(&canPaste); const QString pasteDesc = canPaste ? AutomatableModel::tr( "&Paste value (%1%2)"). - arg( model->displayValue( valueToPaste ) ). + arg( valueToPaste ). arg( m_unit ) : AutomatableModel::tr( "&Paste value"); QAction* pasteAction = menu->addAction( embed::getIconPixmap( "edit_paste" ), @@ -141,6 +142,31 @@ void AutomatableModelView::setModel( Model* model, bool isOldModelValid ) +// Unsets the current model by setting a dummy empty model. The dummy model is marked as +// "defaultConstructed", so the next call to setModel will delete it. +void AutomatableModelView::unsetModel() +{ + if (dynamic_cast(this)) + { + setModel(new FloatModel(0, 0, 0, 1, nullptr, QString(), true)); + } + else if (dynamic_cast(this)) + { + setModel(new IntModel(0, 0, 0, nullptr, QString(), true)); + } + else if (dynamic_cast(this)) + { + setModel(new BoolModel(false, nullptr, QString(), true)); + } + else + { + ModelView::unsetModel(); + } +} + + + + void AutomatableModelView::mousePressEvent( QMouseEvent* event ) { if( event->button() == Qt::LeftButton && event->modifiers() & Qt::ControlModifier ) @@ -155,7 +181,19 @@ void AutomatableModelView::mousePressEvent( QMouseEvent* event ) } +void AutomatableModelView::setConversionFactor( float factor ) +{ + if( factor != 0.0 ) + { + m_conversionFactor = factor; + } +} + +float AutomatableModelView::getConversionFactor() +{ + return m_conversionFactor; +} AutomatableModelViewSlots::AutomatableModelViewSlots( AutomatableModelView* amv, QObject* parent ) : @@ -242,8 +280,10 @@ void AutomatableModelViewSlots::unlinkAllModels() void AutomatableModelViewSlots::copyToClipboard() { - QClipboard* clipboard = QApplication::clipboard(); - clipboard->setText(QString::number(m_amv->value())); + // For copyString() and MimeType enum class + using namespace Clipboard; + + copyString( QString::number( m_amv->value() * m_amv->getConversionFactor() ), MimeType::Default ); } void AutomatableModelViewSlots::pasteFromClipboard() @@ -251,7 +291,7 @@ void AutomatableModelViewSlots::pasteFromClipboard() bool isNumber = false; const float number = floatFromClipboard(&isNumber); if (isNumber) { - m_amv->modelUntyped()->setValue(number); + m_amv->modelUntyped()->setValue(number / m_amv->getConversionFactor()); } } @@ -259,7 +299,9 @@ void AutomatableModelViewSlots::pasteFromClipboard() /// Attempt to parse a float from the clipboard static float floatFromClipboard(bool* ok) { - const QClipboard* clipboard = QApplication::clipboard(); - return clipboard->text().toFloat(ok); + // For getString() and MimeType enum class + using namespace Clipboard; + + return getString( MimeType::Default ).toFloat(ok); } diff --git a/src/gui/AutomationPatternView.cpp b/src/gui/AutomationPatternView.cpp index 130d51a0e6d..45412199400 100644 --- a/src/gui/AutomationPatternView.cpp +++ b/src/gui/AutomationPatternView.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include "AutomationEditor.h" @@ -215,8 +216,6 @@ void AutomationPatternView::constructContextMenu( QMenu * _cm ) this, SLOT( disconnectObject( QAction * ) ) ); _cm->addMenu( m ); } - - _cm->addSeparator(); } @@ -255,13 +254,9 @@ void AutomationPatternView::paintEvent( QPaintEvent * ) QPainter p( &m_paintPixmap ); QLinearGradient lingrad( 0, 0, 0, height() ); - QColor c; + QColor c = getColorForDisplay( painter.background().color() ); bool muted = m_pat->getTrack()->isMuted() || m_pat->isMuted(); bool current = gui->automationEditor()->currentPattern() == m_pat; - - // state: selected, muted, normal - c = isSelected() ? selectedColor() : ( muted ? mutedBackgroundColor() - : painter.background().color() ); lingrad.setColorAt( 1, c.darker( 300 ) ); lingrad.setColorAt( 0, c ); @@ -290,7 +285,7 @@ void AutomationPatternView::paintEvent( QPaintEvent * ) const float y_scale = max - min; const float h = ( height() - 2 * TCO_BORDER_WIDTH ) / y_scale; - const float ppTick = ppb / MidiTime::ticksPerBar(); + const float ppTick = ppb / TimePos::ticksPerBar(); p.translate( 0.0f, max * height() / y_scale - TCO_BORDER_WIDTH ); p.scale( 1.0f, -h ); diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index a340867a837..4b7018a5579 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -19,8 +19,10 @@ SET(LMMS_SRCS gui/LfoControllerDialog.cpp gui/LmmsPalette.cpp gui/LmmsStyle.cpp + gui/Lv2ViewBase.cpp gui/MainApplication.cpp gui/MainWindow.cpp + gui/MidiCCRackView.cpp gui/MidiSetupWidget.cpp gui/ModelView.cpp gui/PeakControllerDialog.cpp @@ -33,9 +35,12 @@ SET(LMMS_SRCS gui/TimeLineWidget.cpp gui/ToolPluginView.cpp gui/TrackContainerView.cpp + gui/TrackContentObjectView.cpp + gui/TrackView.cpp gui/dialogs/FileDialog.cpp gui/dialogs/VersionedSaveDialog.cpp + gui/dialogs/ColorChooser.cpp gui/editors/AutomationEditor.cpp gui/editors/BBEditor.cpp @@ -54,6 +59,7 @@ SET(LMMS_SRCS gui/widgets/ControllerView.cpp gui/widgets/Controls.cpp gui/widgets/CPULoadWidget.cpp + gui/widgets/CustomTextKnob.cpp gui/widgets/EffectRackView.cpp gui/widgets/EffectView.cpp gui/widgets/EnvelopeAndLfoView.cpp @@ -79,6 +85,7 @@ SET(LMMS_SRCS gui/widgets/NStateButton.cpp gui/widgets/Oscilloscope.cpp gui/widgets/PixmapButton.cpp + gui/widgets/PositionLine.cpp gui/widgets/ProjectNotes.cpp gui/widgets/RenameDialog.cpp gui/widgets/Rubberband.cpp @@ -93,6 +100,8 @@ SET(LMMS_SRCS gui/widgets/ToolButton.cpp gui/widgets/ToolTip.cpp gui/widgets/TrackLabelButton.cpp + gui/widgets/TrackContentWidget.cpp + gui/widgets/TrackOperationsWidget.cpp gui/widgets/TrackRenameLineEdit.cpp gui/widgets/StepRecorderWidget.cpp diff --git a/src/gui/ControllerConnectionDialog.cpp b/src/gui/ControllerConnectionDialog.cpp index f0d3d10e9c2..e15b5aeada6 100644 --- a/src/gui/ControllerConnectionDialog.cpp +++ b/src/gui/ControllerConnectionDialog.cpp @@ -63,7 +63,7 @@ class AutoDetectMidiController : public MidiController } - void processInEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset = 0 ) override + void processInEvent( const MidiEvent& event, const TimePos& time, f_cnt_t offset = 0 ) override { if( event.type() == MidiControlChange && ( m_midiPort.inputChannel() == 0 || m_midiPort.inputChannel() == event.channel() + 1 ) ) @@ -187,7 +187,7 @@ ControllerConnectionDialog::ControllerConnectionDialog( QWidget * _parent, this, SLOT( userToggled() ) ); m_userController = new ComboBox( m_userGroupBox, "Controller" ); - m_userController->setGeometry( 10, 24, 200, 22 ); + m_userController->setGeometry( 10, 24, 200, ComboBox::DEFAULT_HEIGHT ); for (Controller * c : Engine::getSong()->controllers()) { m_userController->model()->addItem( c->name() ); diff --git a/src/gui/EffectSelectDialog.cpp b/src/gui/EffectSelectDialog.cpp index 79e40427b28..4423ea707d7 100644 --- a/src/gui/EffectSelectDialog.cpp +++ b/src/gui/EffectSelectDialog.cpp @@ -234,7 +234,7 @@ void EffectSelectDialog::rowChanged( const QModelIndex & _idx, { QLabel *label = new QLabel(m_descriptionWidget); QString labelText = "

" + tr("Name") + ": " + QString::fromUtf8(descriptor.displayName) + "

"; - labelText += "

" + tr("Description") + ": " + qApp->translate( "pluginBrowser", descriptor.description ) + "

"; + labelText += "

" + tr("Description") + ": " + qApp->translate( "PluginBrowser", descriptor.description ) + "

"; labelText += "

" + tr("Author") + ": " + QString::fromUtf8(descriptor.author) + "

"; label->setText(labelText); diff --git a/src/gui/FileBrowser.cpp b/src/gui/FileBrowser.cpp index c976c39f689..9ba634ea56a 100644 --- a/src/gui/FileBrowser.cpp +++ b/src/gui/FileBrowser.cpp @@ -34,10 +34,12 @@ #include #include #include +#include #include "FileBrowser.h" #include "BBTrackContainer.h" #include "ConfigManager.h" +#include "DataFile.h" #include "embed.h" #include "Engine.h" #include "GuiApplication.h" @@ -50,12 +52,11 @@ #include "PluginFactory.h" #include "PresetPreviewPlayHandle.h" #include "SamplePlayHandle.h" +#include "SampleTrack.h" #include "Song.h" #include "StringPairDrag.h" #include "TextFloat.h" - - enum TreeWidgetItemTypes { TypeFileItem = QTreeWidgetItem::UserType, @@ -64,17 +65,50 @@ enum TreeWidgetItemTypes +void FileBrowser::addContentCheckBox() +{ + auto filterWidget = new QWidget(contentParent()); + filterWidget->setFixedHeight(15); + auto filterWidgetLayout = new QHBoxLayout(filterWidget); + filterWidgetLayout->setMargin(0); + filterWidgetLayout->setSpacing(0); + + auto configCheckBox = [this, &filterWidgetLayout](QCheckBox* box) + { + box->setCheckState(Qt::Checked); + connect(box, SIGNAL(stateChanged(int)), this, SLOT(reloadTree())); + filterWidgetLayout->addWidget(box); + }; + + m_showUserContent = new QCheckBox(tr("User content")); + configCheckBox(m_showUserContent); + m_showFactoryContent = new QCheckBox(tr("Factory content")); + configCheckBox(m_showFactoryContent); + + addContentWidget(filterWidget); +}; + + FileBrowser::FileBrowser(const QString & directories, const QString & filter, const QString & title, const QPixmap & pm, - QWidget * parent, bool dirs_as_items, bool recurse ) : + QWidget * parent, bool dirs_as_items, bool recurse, + const QString& userDir, + const QString& factoryDir): SideBarWidget( title, pm, parent ), m_directories( directories ), m_filter( filter ), m_dirsAsItems( dirs_as_items ), - m_recurse( recurse ) + m_recurse( recurse ), + m_userDir(userDir), + m_factoryDir(factoryDir) { setWindowTitle( tr( "Browser" ) ); + if (!userDir.isEmpty() && !factoryDir.isEmpty()) + { + addContentCheckBox(); + } + QWidget * searchWidget = new QWidget( contentParent() ); searchWidget->setFixedHeight( 24 ); @@ -161,19 +195,30 @@ bool FileBrowser::filterItems( const QString & filter, QTreeWidgetItem * item ) } - void FileBrowser::reloadTree( void ) { QList expandedDirs = m_fileBrowserTreeWidget->expandedDirs(); const QString text = m_filterEdit->text(); m_filterEdit->clear(); m_fileBrowserTreeWidget->clear(); - QStringList paths = m_directories.split( '*' ); - for( QStringList::iterator it = paths.begin(); it != paths.end(); ++it ) + QStringList paths = m_directories.split('*'); + if (m_showUserContent && !m_showUserContent->isChecked()) { - addItems( *it ); + paths.removeAll(m_userDir); } - expandItems(NULL, expandedDirs); + if (m_showFactoryContent && !m_showFactoryContent->isChecked()) + { + paths.removeAll(m_factoryDir); + } + + if (!paths.isEmpty()) + { + for (QStringList::iterator it = paths.begin(); it != paths.end(); ++it) + { + addItems(*it); + } + } + expandItems(nullptr, expandedDirs); m_filterEdit->setText( text ); filterItems( text ); } @@ -240,7 +285,7 @@ void FileBrowser::addItems(const QString & path ) { Directory * d = dynamic_cast( m_fileBrowserTreeWidget->topLevelItem( i ) ); - if( d == NULL || cur_file < d->text( 0 ) ) + if( d == nullptr || cur_file < d->text( 0 ) ) { // insert before item, we're done Directory *dd = new Directory( cur_file, path, @@ -300,13 +345,12 @@ void FileBrowser::addItems(const QString & path ) void FileBrowser::keyPressEvent(QKeyEvent * ke ) { - if( ke->key() == Qt::Key_F5 ) - { - reloadTree(); - } - else - { - ke->ignore(); + switch( ke->key() ){ + case Qt::Key_F5: + reloadTree(); + break; + default: + ke->ignore(); } } @@ -321,9 +365,8 @@ FileBrowserTreeWidget::FileBrowserTreeWidget(QWidget * parent ) : QTreeWidget( parent ), m_mousePressed( false ), m_pressPos(), - m_previewPlayHandle( NULL ), - m_pphMutex( QMutex::Recursive ), - m_contextMenuItem( NULL ) + m_previewPlayHandle( nullptr ), + m_pphMutex( QMutex::Recursive ) { setColumnCount( 1 ); headerItem()->setHidden( true ); @@ -336,8 +379,18 @@ FileBrowserTreeWidget::FileBrowserTreeWidget(QWidget * parent ) : connect( this, SIGNAL( itemExpanded( QTreeWidgetItem * ) ), SLOT( updateDirectory( QTreeWidgetItem * ) ) ); +#if QT_VERSION < QT_VERSION_CHECK(5, 12, 2) && defined LMMS_BUILD_WIN32 + // Set the font for the QTreeWidget to the Windows System font to make sure that + // truncated (elided) items use the same font as non-truncated items. + // This is a workaround for this qt bug, fixed in 5.12.2: https://bugreports.qt.io/browse/QTBUG-29232 + // TODO: remove this when all builds use a recent enough version of qt. + setFont( GuiApplication::getWin32SystemFont() ); +#endif } + + + QList FileBrowserTreeWidget::expandedDirs( QTreeWidgetItem * item ) const { int numChildren = item ? item->childCount() : topLevelItemCount(); @@ -362,59 +415,167 @@ QList FileBrowserTreeWidget::expandedDirs( QTreeWidgetItem * item ) con return dirs; } -void FileBrowserTreeWidget::contextMenuEvent(QContextMenuEvent * e ) + + + +void FileBrowserTreeWidget::keyPressEvent(QKeyEvent * ke ) { - FileItem * f = dynamic_cast(itemAt(e->pos())); - if (f == nullptr) + // Shorter names for some commonly used properties of the event + const auto key = ke->key(); + const bool vertical = (key == Qt::Key_Up || key == Qt::Key_Down); + const bool horizontal = (key == Qt::Key_Left || key == Qt::Key_Right); + const bool insert = (key == Qt::Key_Enter || key == Qt::Key_Return); + const bool preview = (key == Qt::Key_Space); + + // First of all, forward all keypresses + QTreeWidget::keyPressEvent(ke); + // Then, ignore all autorepeats (they would spam new tracks or previews) + if (ke->isAutoRepeat()) { return; } + // We should stop any running previews before we do anything new + else if (vertical || horizontal || preview || insert) { stopPreview(); } + + // Try to get the currently selected item as a FileItem + FileItem * file = dynamic_cast(currentItem()); + // If it's null (folder, separator, etc.), there's nothing left for us to do + if (file == nullptr) { return; } + + // When moving to a new sound, preview it. Skip presets, they can play forever + if (vertical && file->type() == FileItem::SampleFile) { - return; + previewFileItem(file); } - if (f->handling() == FileItem::LoadAsPreset || f->handling() == FileItem::LoadByPlugin) + // When enter is pressed, add the selected item... + if (insert) { - // Set the member to the current FileItem so that it is available during the - // execution of the slots of the context menu we are about to create and execute. - m_contextMenuItem = f; - - QMenu contextMenu(this); - - contextMenu.addAction(tr("Send to active instrument-track"), - this, - SLOT(sendToActiveInstrumentTrack())); - contextMenu.addAction(tr("Open in new instrument-track/Song Editor"), - this, - SLOT(openInNewInstrumentTrackSE())); - contextMenu.addAction(tr("Open in new instrument-track/B+B Editor"), - this, - SLOT(openInNewInstrumentTrackBBE())); + // ...to the song editor by default, or to the BB editor if ctrl is held + bool songEditor = !(ke->modifiers() & Qt::ControlModifier); + // If shift is held, we send the item to a new sample track... + bool sampleTrack = ke->modifiers() & Qt::ShiftModifier; + // ...but only in the song editor. So, ctrl+shift enter does nothing + if (sampleTrack && songEditor){ openInNewSampleTrack(file); } + // Otherwise we send the item as a new instrument track + else if (!sampleTrack){ openInNewInstrumentTrack(file, songEditor); } + } + + // When space is pressed, start a preview of the selected item + if (preview) { previewFileItem(file); } +} + + + + +void FileBrowserTreeWidget::keyReleaseEvent(QKeyEvent* ke) +{ + // Cancel previews when the space key is released + if (ke->key() == Qt::Key_Space && !ke->isAutoRepeat()) { stopPreview(); } +} + + + + +void FileBrowserTreeWidget::hideEvent(QHideEvent* he) +{ + // Cancel previews when the user switches tabs or hides the sidebar + stopPreview(); + QTreeWidget::hideEvent(he); +} + + + + +void FileBrowserTreeWidget::focusOutEvent(QFocusEvent* fe) +{ + // Cancel previews when the user clicks outside the browser + stopPreview(); + QTreeWidget::focusOutEvent(fe); +} + + + + +void FileBrowserTreeWidget::contextMenuEvent(QContextMenuEvent * e ) +{ + FileItem * file = dynamic_cast( itemAt( e->pos() ) ); + if( file != nullptr && file->isTrack() ) + { + QMenu contextMenu( this ); + + contextMenu.addAction( + tr( "Send to active instrument-track" ), + [=]{ sendToActiveInstrumentTrack(file); } + ); contextMenu.addSeparator(); - contextMenu.addAction(QIcon(embed::getIconPixmap("folder")), - tr("Open containing folder"), - this, - SLOT(openContainingFolder())); + contextMenu.addAction( + QIcon(embed::getIconPixmap("folder")), + tr("Open containing folder"), + [=]{ openContainingFolder(file); } + ); + + QAction* songEditorHeader = new QAction( tr("Song Editor"), nullptr ); + songEditorHeader->setDisabled(true); + contextMenu.addAction( songEditorHeader ); + contextMenu.addActions( getContextActions(file, true) ); - contextMenu.exec(e->globalPos()); + QAction* bbEditorHeader = new QAction( tr("BB Editor"), nullptr ); + bbEditorHeader->setDisabled(true); + contextMenu.addAction( bbEditorHeader ); + contextMenu.addActions( getContextActions(file, false) ); - // The context menu has been executed so we can reset this member back to nullptr. - m_contextMenuItem = nullptr; + // We should only show the menu if it contains items + if (!contextMenu.isEmpty()) { contextMenu.exec( e->globalPos() ); } } } -void FileBrowserTreeWidget::mousePressEvent(QMouseEvent * me ) +QList FileBrowserTreeWidget::getContextActions(FileItem* file, bool songEditor) { - QTreeWidget::mousePressEvent( me ); - if( me->button() != Qt::LeftButton ) + QList result = QList(); + const bool fileIsSample = file->type() == FileItem::SampleFile; + + QString instrumentAction = fileIsSample ? + tr("Send to new AudioFileProcessor instance") : + tr("Send to new instrument track"); + QString shortcutMod = songEditor ? "" : UI_CTRL_KEY + QString(" + "); + + QAction* toInstrument = new QAction( + instrumentAction + tr(" (%2Enter)").arg(shortcutMod), + nullptr + ); + connect(toInstrument, &QAction::triggered, + [=]{ openInNewInstrumentTrack(file, songEditor); }); + result.append(toInstrument); + + if (songEditor && fileIsSample) { - return; + QAction* toSampleTrack = new QAction( + tr("Send to new sample track (Shift + Enter)"), + nullptr + ); + connect(toSampleTrack, &QAction::triggered, + [=]{ openInNewSampleTrack(file); }); + result.append(toSampleTrack); } - QTreeWidgetItem * i = itemAt( me->pos() ); - if ( i ) + return result; +} + + + + +void FileBrowserTreeWidget::mousePressEvent(QMouseEvent * me ) +{ + // Forward the event + QTreeWidget::mousePressEvent(me); + // QTreeWidget handles right clicks for us, so we only care about left clicks + if(me->button() != Qt::LeftButton) { return; } + + QTreeWidgetItem * i = itemAt(me->pos()); + if (i) { // TODO: Restrict to visible selection // if ( _me->x() > header()->cellPos( header()->mapToActual( 0 ) ) @@ -428,64 +589,84 @@ void FileBrowserTreeWidget::mousePressEvent(QMouseEvent * me ) // } } - FileItem * f = dynamic_cast( i ); - if( f != NULL ) - { - m_pphMutex.lock(); - if( m_previewPlayHandle != NULL ) - { - Engine::mixer()->removePlayHandle( - m_previewPlayHandle ); - m_previewPlayHandle = NULL; - } + FileItem * f = dynamic_cast(i); + if(f != nullptr) { previewFileItem(f); } +} - // in special case of sample-files we do not care about - // handling() rather than directly creating a SamplePlayHandle - if( f->type() == FileItem::SampleFile ) - { - TextFloat * tf = TextFloat::displayMessage( - tr( "Loading sample" ), - tr( "Please wait, loading sample for " - "preview..." ), - embed::getIconPixmap( "sample_file", - 24, 24 ), 0 ); - qApp->processEvents( - QEventLoop::ExcludeUserInputEvents ); - SamplePlayHandle * s = new SamplePlayHandle( - f->fullName() ); - s->setDoneMayReturnTrue( false ); - m_previewPlayHandle = s; - delete tf; - } - else if( ( f->extension ()== "xiz" || f->extension() == "sf2" || f->extension() == "sf3" || f->extension() == "gig" || f->extension() == "pat" ) && - ! pluginFactory->pluginSupportingExtension(f->extension()).info.isNull() ) + + + +void FileBrowserTreeWidget::previewFileItem(FileItem* file) +{ // TODO: We should do this work outside the event thread + // Lock the preview mutex + QMutexLocker previewLocker(&m_pphMutex); + // If something is already playing, stop it before we continue + stopPreview(); + + PlayHandle* newPPH = nullptr; + const QString fileName = file->fullName(); + const QString ext = file->extension(); + + // In special case of sample-files we do not care about + // handling() rather than directly creating a SamplePlayHandle + if (file->type() == FileItem::SampleFile) + { + TextFloat * tf = TextFloat::displayMessage( + tr("Loading sample"), + tr("Please wait, loading sample for preview..."), + embed::getIconPixmap("sample_file", 24, 24), 0); + // TODO: this can be removed once we do this outside the event thread + qApp->processEvents(QEventLoop::ExcludeUserInputEvents); + SamplePlayHandle* s = new SamplePlayHandle(fileName); + s->setDoneMayReturnTrue(false); + newPPH = s; + delete tf; + } + else if ( + (ext == "xiz" || ext == "sf2" || ext == "sf3" || + ext == "gig" || ext == "pat") + && !pluginFactory->pluginSupportingExtension(ext).isNull()) + { + const bool isPlugin = file->handling() == FileItem::LoadByPlugin; + newPPH = new PresetPreviewPlayHandle(fileName, isPlugin); + } + else if (file->type() != FileItem::VstPluginFile && file->isTrack()) + { + DataFile dataFile(fileName); + if (dataFile.validate(ext)) { - m_previewPlayHandle = new PresetPreviewPlayHandle( f->fullName(), f->handling() == FileItem::LoadByPlugin ); + const bool isPlugin = file->handling() == FileItem::LoadByPlugin; + newPPH = new PresetPreviewPlayHandle(fileName, isPlugin, &dataFile); } - else if( f->type() != FileItem::VstPluginFile && - ( f->handling() == FileItem::LoadAsPreset || - f->handling() == FileItem::LoadByPlugin ) ) + else { - DataFile dataFile( f->fullName() ); - if( !dataFile.validate( f->extension() ) ) - { - QMessageBox::warning( 0, tr ( "Error" ), - tr( "%1 does not appear to be a valid %2 file" ).arg( f->fullName(), f->extension() ), - QMessageBox::Ok, QMessageBox::NoButton ); - m_pphMutex.unlock(); - return; - } - m_previewPlayHandle = new PresetPreviewPlayHandle( f->fullName(), f->handling() == FileItem::LoadByPlugin, &dataFile ); + QMessageBox::warning(0, tr ("Error"), + tr("%1 does not appear to be a valid %2 file") + .arg(fileName, ext), + QMessageBox::Ok, QMessageBox::NoButton); } - if( m_previewPlayHandle != NULL ) + } + + if (newPPH != nullptr) + { + if (Engine::mixer()->addPlayHandle(newPPH)) { - if( !Engine::mixer()->addPlayHandle( - m_previewPlayHandle ) ) - { - m_previewPlayHandle = NULL; - } + m_previewPlayHandle = newPPH; } - m_pphMutex.unlock(); + else { m_previewPlayHandle = nullptr; } + } +} + + + + +void FileBrowserTreeWidget::stopPreview() +{ + QMutexLocker previewLocker(&m_pphMutex); + if (m_previewPlayHandle != nullptr) + { + Engine::mixer()->removePlayHandle(m_previewPlayHandle); + m_previewPlayHandle = nullptr; } } @@ -499,10 +680,10 @@ void FileBrowserTreeWidget::mouseMoveEvent( QMouseEvent * me ) QApplication::startDragDistance() ) { // make sure any playback is stopped - mouseReleaseEvent( NULL ); + mouseReleaseEvent( nullptr ); FileItem * f = dynamic_cast( itemAt( m_pressPos ) ); - if( f != NULL ) + if( f != nullptr ) { switch( f->type() ) { @@ -552,36 +733,22 @@ void FileBrowserTreeWidget::mouseReleaseEvent(QMouseEvent * me ) { m_mousePressed = false; - m_pphMutex.lock(); - if( m_previewPlayHandle != NULL ) - { - // if there're samples shorter than 3 seconds, we don't - // stop them if the user releases mouse-button... - if( m_previewPlayHandle->type() == PlayHandle::TypeSamplePlayHandle ) - { - SamplePlayHandle * s = dynamic_cast( - m_previewPlayHandle ); - if( s && s->totalFrames() - s->framesDone() <= - static_cast( Engine::mixer()-> - processingSampleRate() * 3 ) ) - { - s->setDoneMayReturnTrue( true ); - m_previewPlayHandle = NULL; - m_pphMutex.unlock(); - return; - } - } - Engine::mixer()->removePlayHandle( m_previewPlayHandle ); - m_previewPlayHandle = NULL; - } - m_pphMutex.unlock(); -} + // If a preview is running, we may need to stop it. Otherwise, we're done + QMutexLocker previewLocker(&m_pphMutex); + if (m_previewPlayHandle == nullptr) { return; } + // Only sample previews may continue after mouse up. Is this a sample preview? + bool isSample = m_previewPlayHandle->type() == PlayHandle::TypeSamplePlayHandle; + // Even sample previews should only continue if the user wants them to. Do they? + bool shouldContinue = ConfigManager::inst()->value("ui", "letpreviewsfinish").toInt(); + // If both are true the preview may continue, otherwise we stop it + if (!(isSample && shouldContinue)) { stopPreview(); } +} -void FileBrowserTreeWidget::handleFile(FileItem * f, InstrumentTrack * it ) +void FileBrowserTreeWidget::handleFile(FileItem * f, InstrumentTrack * it) { Engine::mixer()->requestChangeInModel(); switch( f->handling() ) @@ -597,7 +764,7 @@ void FileBrowserTreeWidget::handleFile(FileItem * f, InstrumentTrack * it ) { const QString e = f->extension(); Instrument * i = it->instrument(); - if( i == NULL || + if( i == nullptr || !i->descriptor()->supportsFileType( e ) ) { PluginFactory::PluginInfoAndKey piakn = @@ -637,7 +804,7 @@ void FileBrowserTreeWidget::activateListItem(QTreeWidgetItem * item, int column ) { FileItem * f = dynamic_cast( item ); - if( f == NULL ) + if( f == nullptr ) { return; } @@ -645,7 +812,7 @@ void FileBrowserTreeWidget::activateListItem(QTreeWidgetItem * item, if( f->handling() == FileItem::LoadAsProject || f->handling() == FileItem::ImportAsProject ) { - handleFile( f, NULL ); + handleFile( f, nullptr ); } else if( f->handling() != FileItem::NotSupported ) { @@ -659,53 +826,66 @@ void FileBrowserTreeWidget::activateListItem(QTreeWidgetItem * item, -void FileBrowserTreeWidget::openInNewInstrumentTrack( TrackContainer* tc ) +void FileBrowserTreeWidget::openInNewInstrumentTrack(TrackContainer* tc, FileItem* item) { - if( m_contextMenuItem->handling() == FileItem::LoadAsPreset || - m_contextMenuItem->handling() == FileItem::LoadByPlugin ) + if(item->isTrack()) { InstrumentTrack * it = dynamic_cast( - Track::create( Track::InstrumentTrack, tc ) ); - handleFile( m_contextMenuItem, it ); + Track::create(Track::InstrumentTrack, tc)); + handleFile(item, it); } } -void FileBrowserTreeWidget::openInNewInstrumentTrackBBE( void ) +void FileBrowserTreeWidget::openInNewInstrumentTrack(FileItem* item, bool songEditor) { - openInNewInstrumentTrack( Engine::getBBTrackContainer() ); + // Get the correct TrackContainer. Ternary doesn't compile here + TrackContainer* tc = Engine::getSong(); + if (!songEditor) { tc = Engine::getBBTrackContainer(); } + openInNewInstrumentTrack(tc, item); } -void FileBrowserTreeWidget::openInNewInstrumentTrackSE( void ) +bool FileBrowserTreeWidget::openInNewSampleTrack(FileItem* item) { - openInNewInstrumentTrack( Engine::getSong() ); + // Can't add non-samples to a sample track + if (item->type() != FileItem::SampleFile) { return false; } + + // Create a new sample track for this sample + SampleTrack* sampleTrack = static_cast( + Track::create(Track::SampleTrack, Engine::getSong())); + + // Add the sample clip to the track + Engine::mixer()->requestChangeInModel(); + SampleTCO* clip = static_cast(sampleTrack->createTCO(0)); + clip->setSampleFile(item->fullName()); + Engine::mixer()->doneChangeInModel(); + return true; } -void FileBrowserTreeWidget::openContainingFolder() + +void FileBrowserTreeWidget::openContainingFolder(FileItem* item) { - if (m_contextMenuItem) - { - // Delegate to QDesktopServices::openUrl with the directory of the selected file. Please note that - // this will only open the directory but not select the file as this is much more complicated due - // to different implementations that are needed for different platforms (Linux/Windows/MacOS). - - // Using QDesktopServices::openUrl seems to be the most simple cross platform way which uses - // functionality that's already available in Qt. - QFileInfo fileInfo(m_contextMenuItem->fullName()); - QDesktopServices::openUrl(QUrl::fromLocalFile(fileInfo.dir().path())); - } + // Delegate to QDesktopServices::openUrl with the directory of the selected file. Please note that + // this will only open the directory but not select the file as this is much more complicated due + // to different implementations that are needed for different platforms (Linux/Windows/MacOS). + + // Using QDesktopServices::openUrl seems to be the most simple cross platform way which uses + // functionality that's already available in Qt. + QFileInfo fileInfo(item->fullName()); + QDesktopServices::openUrl(QUrl::fromLocalFile(fileInfo.dir().path())); } -void FileBrowserTreeWidget::sendToActiveInstrumentTrack( void ) + +void FileBrowserTreeWidget::sendToActiveInstrumentTrack( FileItem* item ) { // get all windows opened in the workspace QList pl = @@ -720,9 +900,9 @@ void FileBrowserTreeWidget::sendToActiveInstrumentTrack( void ) InstrumentTrackWindow * itw = dynamic_cast( w.previous()->widget() ); - if( itw != NULL && itw->isHidden() == false ) + if( itw != nullptr && itw->isHidden() == false ) { - handleFile( m_contextMenuItem, itw->model() ); + handleFile( item, itw->model() ); break; } } @@ -734,7 +914,7 @@ void FileBrowserTreeWidget::sendToActiveInstrumentTrack( void ) void FileBrowserTreeWidget::updateDirectory(QTreeWidgetItem * item ) { Directory * dir = dynamic_cast( item ); - if( dir != NULL ) + if( dir != nullptr ) { dir->update(); } @@ -745,9 +925,9 @@ void FileBrowserTreeWidget::updateDirectory(QTreeWidgetItem * item ) -QPixmap * Directory::s_folderPixmap = NULL; -QPixmap * Directory::s_folderOpenedPixmap = NULL; -QPixmap * Directory::s_folderLockedPixmap = NULL; +QPixmap * Directory::s_folderPixmap = nullptr; +QPixmap * Directory::s_folderOpenedPixmap = nullptr; +QPixmap * Directory::s_folderLockedPixmap = nullptr; Directory::Directory(const QString & filename, const QString & path, @@ -776,19 +956,19 @@ Directory::Directory(const QString & filename, const QString & path, void Directory::initPixmaps( void ) { - if( s_folderPixmap == NULL ) + if( s_folderPixmap == nullptr ) { s_folderPixmap = new QPixmap( embed::getIconPixmap( "folder" ) ); } - if( s_folderOpenedPixmap == NULL ) + if( s_folderOpenedPixmap == nullptr ) { s_folderOpenedPixmap = new QPixmap( embed::getIconPixmap( "folder_opened" ) ); } - if( s_folderLockedPixmap == NULL ) + if( s_folderLockedPixmap == nullptr ) { s_folderLockedPixmap = new QPixmap( embed::getIconPixmap( "folder_locked" ) ); @@ -866,7 +1046,7 @@ bool Directory::addItems(const QString & path ) { Directory * d = dynamic_cast( child( i ) ); - if( d == NULL || cur_file < d->text( 0 ) ) + if( d == nullptr || cur_file < d->text( 0 ) ) { // insert before item, we're done insertChild( i, new Directory( cur_file, @@ -924,13 +1104,13 @@ bool Directory::addItems(const QString & path ) -QPixmap * FileItem::s_projectFilePixmap = NULL; -QPixmap * FileItem::s_presetFilePixmap = NULL; -QPixmap * FileItem::s_sampleFilePixmap = NULL; -QPixmap * FileItem::s_soundfontFilePixmap = NULL; -QPixmap * FileItem::s_vstPluginFilePixmap = NULL; -QPixmap * FileItem::s_midiFilePixmap = NULL; -QPixmap * FileItem::s_unknownFilePixmap = NULL; +QPixmap * FileItem::s_projectFilePixmap = nullptr; +QPixmap * FileItem::s_presetFilePixmap = nullptr; +QPixmap * FileItem::s_sampleFilePixmap = nullptr; +QPixmap * FileItem::s_soundfontFilePixmap = nullptr; +QPixmap * FileItem::s_vstPluginFilePixmap = nullptr; +QPixmap * FileItem::s_midiFilePixmap = nullptr; +QPixmap * FileItem::s_unknownFilePixmap = nullptr; FileItem::FileItem(QTreeWidget * parent, const QString & name, @@ -958,43 +1138,43 @@ FileItem::FileItem(const QString & name, const QString & path ) : void FileItem::initPixmaps( void ) { - if( s_projectFilePixmap == NULL ) + if( s_projectFilePixmap == nullptr ) { s_projectFilePixmap = new QPixmap( embed::getIconPixmap( "project_file", 16, 16 ) ); } - if( s_presetFilePixmap == NULL ) + if( s_presetFilePixmap == nullptr ) { s_presetFilePixmap = new QPixmap( embed::getIconPixmap( "preset_file", 16, 16 ) ); } - if( s_sampleFilePixmap == NULL ) + if( s_sampleFilePixmap == nullptr ) { s_sampleFilePixmap = new QPixmap( embed::getIconPixmap( "sample_file", 16, 16 ) ); } - if ( s_soundfontFilePixmap == NULL ) + if ( s_soundfontFilePixmap == nullptr ) { s_soundfontFilePixmap = new QPixmap( embed::getIconPixmap( "soundfont_file", 16, 16 ) ); } - if ( s_vstPluginFilePixmap == NULL ) + if ( s_vstPluginFilePixmap == nullptr ) { s_vstPluginFilePixmap = new QPixmap( embed::getIconPixmap( "vst_plugin_file", 16, 16 ) ); } - if( s_midiFilePixmap == NULL ) + if( s_midiFilePixmap == nullptr ) { s_midiFilePixmap = new QPixmap( embed::getIconPixmap( "midi_file", 16, 16 ) ); } - if( s_unknownFilePixmap == NULL ) + if( s_unknownFilePixmap == nullptr ) { s_unknownFilePixmap = new QPixmap( embed::getIconPixmap( "unknown_file" ) ); @@ -1069,6 +1249,11 @@ void FileItem::determineFileType( void ) m_type = VstPluginFile; m_handling = LoadByPlugin; } + else if ( ext == "lv2" ) + { + m_type = PresetFile; + m_handling = LoadByPlugin; + } else { m_type = UnknownFile; @@ -1102,7 +1287,3 @@ QString FileItem::extension(const QString & file ) { return QFileInfo( file ).suffix().toLower(); } - - - - diff --git a/src/gui/FxMixerView.cpp b/src/gui/FxMixerView.cpp index 54bbff70f9d..149e132e200 100644 --- a/src/gui/FxMixerView.cpp +++ b/src/gui/FxMixerView.cpp @@ -50,6 +50,7 @@ #include "SampleTrack.h" #include "Song.h" #include "BBTrackContainer.h" +#include "TrackContainer.h" // For TrackContainer::TrackList typedef FxMixerView::FxMixerView() : QWidget(), @@ -237,13 +238,13 @@ void FxMixerView::refreshDisplay() // update the and max. channel number for every instrument void FxMixerView::updateMaxChannelSelector() { - QVector songTrackList = Engine::getSong()->tracks(); - QVector bbTrackList = Engine::getBBTrackContainer()->tracks(); + TrackContainer::TrackList songTrackList = Engine::getSong()->tracks(); + TrackContainer::TrackList bbTrackList = Engine::getBBTrackContainer()->tracks(); - QVector trackLists[] = {songTrackList, bbTrackList}; + TrackContainer::TrackList trackLists[] = {songTrackList, bbTrackList}; for(int tl=0; tl<2; ++tl) { - QVector trackList = trackLists[tl]; + TrackContainer::TrackList trackList = trackLists[tl]; for(int i=0; itype() == Track::InstrumentTrack ) @@ -318,7 +319,7 @@ FxMixerView::FxChannelView::FxChannelView(QWidget * _parent, FxMixerView * _mv, // Create EffectRack for the channel m_rackView = new EffectRackView( &fxChannel->m_fxChain, _mv->m_racksWidget ); - m_rackView->setFixedSize( 245, FxLine::FxLineHeight ); + m_rackView->setFixedSize( EffectRackView::DEFAULT_WIDTH, FxLine::FxLineHeight ); } @@ -412,12 +413,9 @@ void FxMixerView::deleteChannel(int index) m_channelAreaWidget->adjustSize(); // make sure every channel knows what index it is - for(int i=0; i index ) - { - m_fxChannelViews[i]->m_fxLine->setChannelIndex(i-1); - } + m_fxChannelViews[i]->m_fxLine->setChannelIndex(i-1); } m_fxChannelViews.remove(index); @@ -439,29 +437,32 @@ void FxMixerView::deleteUnusedChannels() tracks += Engine::getSong()->tracks(); tracks += Engine::getBBTrackContainer()->tracks(); - // go through all FX Channels - for(int i = m_fxChannelViews.size()-1; i > 0; --i) + std::vector inUse(m_fxChannelViews.size(), false); + + //Populate inUse by checking the destination channel for every track + for (Track* t: tracks) { - // check if an instrument references to the current channel - bool empty=true; - for( Track* t : tracks ) + //The channel that this track sends to. Since master channel is always in use, + //setting this to 0 is a safe default (for tracks that don't sent to the mixer). + int channel = 0; + if (t->type() == Track::InstrumentTrack) { - if( t->type() == Track::InstrumentTrack ) - { - InstrumentTrack* inst = dynamic_cast( t ); - if( i == inst->effectChannelModel()->value(0) ) - { - empty=false; - break; - } - } + InstrumentTrack* inst = dynamic_cast(t); + channel = inst->effectChannelModel()->value(); } - FxChannel * ch = Engine::fxMixer()->effectChannel( i ); - // delete channel if no references found - if( empty && ch->m_receives.isEmpty() ) + else if (t->type() == Track::SampleTrack) { - deleteChannel( i ); + SampleTrack *strack = dynamic_cast(t); + channel = strack->effectChannelModel()->value(); } + inUse[channel] = true; + } + + //Check all channels except master, delete those with no incoming sends + for(int i = m_fxChannelViews.size()-1; i > 0; --i) + { + if (!inUse[i] && Engine::fxMixer()->effectChannel(i)->m_receives.isEmpty()) + { deleteChannel(i); } } } diff --git a/src/gui/GuiApplication.cpp b/src/gui/GuiApplication.cpp index fb2e3eae376..3effe20afde 100644 --- a/src/gui/GuiApplication.cpp +++ b/src/gui/GuiApplication.cpp @@ -34,6 +34,7 @@ #include "ConfigManager.h" #include "ControllerRackView.h" #include "FxMixerView.h" +#include "InstrumentTrack.h" #include "MainWindow.h" #include "PianoRoll.h" #include "ProjectNotes.h" @@ -45,6 +46,10 @@ #include #include +#ifdef LMMS_BUILD_WIN32 +#include +#endif + GuiApplication* GuiApplication::s_instance = nullptr; GuiApplication* GuiApplication::instance() @@ -159,7 +164,6 @@ GuiApplication::GuiApplication() GuiApplication::~GuiApplication() { - InstrumentTrackView::cleanupWindowCache(); s_instance = nullptr; } @@ -211,3 +215,24 @@ void GuiApplication::childDestroyed(QObject *obj) m_controllerRackView = nullptr; } } + +#ifdef LMMS_BUILD_WIN32 +/*! + * @brief Returns the Windows System font. + */ +QFont GuiApplication::getWin32SystemFont() +{ + NONCLIENTMETRICS metrics = { sizeof( NONCLIENTMETRICS ) }; + SystemParametersInfo( SPI_GETNONCLIENTMETRICS, sizeof( NONCLIENTMETRICS ), &metrics, 0 ); + int pointSize = metrics.lfMessageFont.lfHeight; + if ( pointSize < 0 ) + { + // height is in pixels, convert to points + HDC hDC = GetDC( NULL ); + pointSize = MulDiv( abs( pointSize ), 72, GetDeviceCaps( hDC, LOGPIXELSY ) ); + ReleaseDC( NULL, hDC ); + } + + return QFont( QString::fromUtf8( metrics.lfMessageFont.lfFaceName ), pointSize ); +} +#endif diff --git a/src/gui/LmmsStyle.cpp b/src/gui/LmmsStyle.cpp index b6a139bbba7..1f6d6f1cd3b 100644 --- a/src/gui/LmmsStyle.cpp +++ b/src/gui/LmmsStyle.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include diff --git a/src/gui/Lv2ViewBase.cpp b/src/gui/Lv2ViewBase.cpp new file mode 100644 index 00000000000..767adea5a48 --- /dev/null +++ b/src/gui/Lv2ViewBase.cpp @@ -0,0 +1,248 @@ +/* + * Lv2ViewBase.cpp - base class for Lv2 plugin views + * + * Copyright (c) 2018-2020 Johannes Lorenz + * + * 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. + * + */ + +#include "Lv2ViewBase.h" + +#ifdef LMMS_HAVE_LV2 + +#include +#include +#include +#include +#include +#include + +#include "Controls.h" +#include "Engine.h" +#include "GuiApplication.h" +#include "embed.h" +#include "gui_templates.h" +#include "LedCheckbox.h" +#include "Lv2ControlBase.h" +#include "Lv2Manager.h" +#include "Lv2Proc.h" +#include "Lv2Ports.h" +#include "MainWindow.h" +#include "Mixer.h" +#include "SubWindow.h" + + + + +Lv2ViewProc::Lv2ViewProc(QWidget* parent, Lv2Proc* ctrlBase, int colNum) : + LinkedModelGroupView (parent, ctrlBase, colNum) +{ + class SetupWidget : public Lv2Ports::ConstVisitor + { + public: + QWidget* m_par; // input + const LilvNode* m_commentUri; // input + Control* m_control = nullptr; // output + void visit(const Lv2Ports::Control& port) override + { + if (port.m_flow == Lv2Ports::Flow::Input) + { + using PortVis = Lv2Ports::Vis; + + switch (port.m_vis) + { + case PortVis::Generic: + m_control = new KnobControl(m_par); + break; + case PortVis::Integer: + { + sample_rate_t sr = Engine::mixer()->processingSampleRate(); + m_control = new LcdControl((port.max(sr) <= 9.0f) ? 1 : 2, + m_par); + break; + } + case PortVis::Enumeration: + m_control = new ComboControl(m_par); + break; + case PortVis::Toggled: + m_control = new CheckControl(m_par); + break; + } + m_control->setText(port.name()); + + AutoLilvNodes props(lilv_port_get_value( + port.m_plugin, port.m_port, m_commentUri)); + LILV_FOREACH(nodes, itr, props.get()) + { + const LilvNode* nod = lilv_nodes_get(props.get(), itr); + m_control->topWidget()->setToolTip(lilv_node_as_string(nod)); + break; + } + } + } + }; + + AutoLilvNode commentUri = uri(LILV_NS_RDFS "comment"); + ctrlBase->foreach_port( + [this, &commentUri](const Lv2Ports::PortBase* port) + { + SetupWidget setup; + setup.m_par = this; + setup.m_commentUri = commentUri.get(); + port->accept(setup); + + if (setup.m_control) + { + addControl(setup.m_control, + lilv_node_as_string(lilv_port_get_symbol( + port->m_plugin, port->m_port)), + port->name().toUtf8().data(), + false); + } + }); +} + + + + +Lv2ViewProc::~Lv2ViewProc() {} + + + + +AutoLilvNode Lv2ViewProc::uri(const char *uriStr) +{ + return Engine::getLv2Manager()->uri(uriStr); +} + + + + +Lv2ViewBase::Lv2ViewBase(QWidget* meAsWidget, Lv2ControlBase *ctrlBase) +{ + QGridLayout* grid = new QGridLayout(meAsWidget); + + QHBoxLayout* btnBox = new QHBoxLayout(); + if (/* DISABLES CODE */ (false)) + { + m_reloadPluginButton = new QPushButton(QObject::tr("Reload Plugin"), + meAsWidget); + btnBox->addWidget(m_reloadPluginButton, 0); + } + + if (/* DISABLES CODE */ (false)) // TODO: check if the plugin has the UI extension + { + m_toggleUIButton = new QPushButton(QObject::tr("Show GUI"), + meAsWidget); + m_toggleUIButton->setCheckable(true); + m_toggleUIButton->setChecked(false); + m_toggleUIButton->setIcon(embed::getIconPixmap("zoom")); + m_toggleUIButton->setFont( + pointSize<8>(m_toggleUIButton->font())); + btnBox->addWidget(m_toggleUIButton, 0); + } + btnBox->addStretch(1); + + meAsWidget->setAcceptDrops(true); + + // note: the lifetime of C++ objects ends after the top expression in the + // expression syntax tree, so the AutoLilvNode gets freed after the function + // has been called + AutoLilvNodes props(lilv_plugin_get_value(ctrlBase->getPlugin(), + uri(LILV_NS_RDFS "comment").get())); + LILV_FOREACH(nodes, itr, props.get()) + { + const LilvNode* node = lilv_nodes_get(props.get(), itr); + QLabel* infoLabel = new QLabel(lilv_node_as_string(node)); + infoLabel->setWordWrap(true); + infoLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding); + + m_helpButton = new QPushButton(QObject::tr("Help")); + m_helpButton->setCheckable(true); + btnBox->addWidget(m_helpButton); + + m_helpWindow = gui->mainWindow()->addWindowedWidget(infoLabel); + m_helpWindow->setSizePolicy(QSizePolicy::Minimum, + QSizePolicy::Expanding); + m_helpWindow->setAttribute(Qt::WA_DeleteOnClose, false); + m_helpWindow->hide(); + + break; + } + + if (m_reloadPluginButton || m_toggleUIButton || m_helpButton) + { + grid->addLayout(btnBox, Rows::ButtonRow, 0, 1, m_colNum); + } + else { delete btnBox; } + + m_procView = new Lv2ViewProc(meAsWidget, ctrlBase->control(0), m_colNum); + grid->addWidget(m_procView, Rows::ProcRow, 0); +} + + + + +Lv2ViewBase::~Lv2ViewBase() { + // TODO: hide UI if required +} + + + + +void Lv2ViewBase::toggleUI() +{ +} + + + + +void Lv2ViewBase::toggleHelp(bool visible) +{ + if (m_helpWindow) + { + if (visible) { m_helpWindow->show(); m_helpWindow->raise(); } + else { m_helpWindow->hide(); } + } +} + + + + +void Lv2ViewBase::modelChanged(Lv2ControlBase *ctrlBase) +{ + // reconnect models + if (m_toggleUIButton) + { + m_toggleUIButton->setChecked(ctrlBase->hasGui()); + } + + LinkedModelGroupsView::modelChanged(ctrlBase); +} + + + + +AutoLilvNode Lv2ViewBase::uri(const char *uriStr) +{ + return Engine::getLv2Manager()->uri(uriStr); +} + + +#endif // LMMS_HAVE_LV2 diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index bf8863ec616..c5b179b9fc6 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,7 @@ #include "FxMixerView.h" #include "GuiApplication.h" #include "ImportFilter.h" +#include "InstrumentTrack.h" #include "PianoRoll.h" #include "PluginBrowser.h" #include "PluginFactory.h" @@ -71,6 +73,7 @@ #include "lmmsversion.h" + #if !defined(LMMS_BUILD_WIN32) && !defined(LMMS_BUILD_APPLE) && !defined(LMMS_BUILD_HAIKU) //Work around an issue on KDE5 as per https://bugs.kde.org/show_bug.cgi?id=337491#c21 void disableAutoKeyAccelerators(QWidget* mainWindow) @@ -128,20 +131,26 @@ MainWindow::MainWindow() : "*.mmp *.mmpz *.xml *.mid", tr( "My Projects" ), embed::getIconPixmap( "project_file" ).transformed( QTransform().rotate( 90 ) ), - splitter, false, true ) ); + splitter, false, true, + confMgr->userProjectsDir(), + confMgr->factoryProjectsDir())); sideBar->appendTab( new FileBrowser( confMgr->userSamplesDir() + "*" + confMgr->factorySamplesDir(), "*", tr( "My Samples" ), embed::getIconPixmap( "sample_file" ).transformed( QTransform().rotate( 90 ) ), - splitter, false, true ) ); + splitter, false, true, + confMgr->userSamplesDir(), + confMgr->factorySamplesDir())); sideBar->appendTab( new FileBrowser( confMgr->userPresetsDir() + "*" + confMgr->factoryPresetsDir(), - "*.xpf *.cs.xml *.xiz", + "*.xpf *.cs.xml *.xiz *.lv2", tr( "My Presets" ), embed::getIconPixmap( "preset_file" ).transformed( QTransform().rotate( 90 ) ), - splitter , false, true ) ); + splitter , false, true, + confMgr->userPresetsDir(), + confMgr->factoryPresetsDir())); sideBar->appendTab( new FileBrowser( QDir::homePath(), "*", tr( "My Home" ), embed::getIconPixmap( "home" ).transformed( QTransform().rotate( 90 ) ), @@ -245,6 +254,9 @@ MainWindow::MainWindow() : connect(Engine::getSong(), SIGNAL(modified()), SLOT(onSongModified())); connect(Engine::getSong(), SIGNAL(projectFileNameChanged()), SLOT(onProjectFileNameChanged())); + + maximized = isMaximized(); + new QShortcut(QKeySequence(Qt::Key_F11), this, SLOT(toggleFullscreen())); } @@ -479,60 +491,60 @@ void MainWindow::finalize() // window-toolbar ToolButton * song_editor_window = new ToolButton( embed::getIconPixmap( "songeditor" ), - tr( "Song Editor" ) + " (F5)", + tr( "Song Editor" ) + " (Ctrl+1)", this, SLOT( toggleSongEditorWin() ), m_toolBar ); - song_editor_window->setShortcut( Qt::Key_F5 ); + song_editor_window->setShortcut( Qt::CTRL + Qt::Key_1 ); ToolButton * bb_editor_window = new ToolButton( embed::getIconPixmap( "bb_track_btn" ), tr( "Beat+Bassline Editor" ) + - " (F6)", + " (Ctrl+2)", this, SLOT( toggleBBEditorWin() ), m_toolBar ); - bb_editor_window->setShortcut( Qt::Key_F6 ); + bb_editor_window->setShortcut( Qt::CTRL + Qt::Key_2 ); ToolButton * piano_roll_window = new ToolButton( embed::getIconPixmap( "piano" ), tr( "Piano Roll" ) + - " (F7)", + " (Ctrl+3)", this, SLOT( togglePianoRollWin() ), m_toolBar ); - piano_roll_window->setShortcut( Qt::Key_F7 ); + piano_roll_window->setShortcut( Qt::CTRL + Qt::Key_3 ); ToolButton * automation_editor_window = new ToolButton( embed::getIconPixmap( "automation" ), tr( "Automation Editor" ) + - " (F8)", + " (Ctrl+4)", this, SLOT( toggleAutomationEditorWin() ), m_toolBar ); - automation_editor_window->setShortcut( Qt::Key_F8 ); + automation_editor_window->setShortcut( Qt::CTRL + Qt::Key_4 ); ToolButton * fx_mixer_window = new ToolButton( embed::getIconPixmap( "fx_mixer" ), - tr( "FX Mixer" ) + " (F9)", + tr( "FX Mixer" ) + " (Ctrl+5)", this, SLOT( toggleFxMixerWin() ), m_toolBar ); - fx_mixer_window->setShortcut( Qt::Key_F9 ); + fx_mixer_window->setShortcut( Qt::CTRL + Qt::Key_5 ); ToolButton * controllers_window = new ToolButton( embed::getIconPixmap( "controller" ), tr( "Show/hide controller rack" ) + - " (F10)", + " (Ctrl+6)", this, SLOT( toggleControllerRack() ), m_toolBar ); - controllers_window->setShortcut( Qt::Key_F10 ); + controllers_window->setShortcut( Qt::CTRL + Qt::Key_6 ); ToolButton * project_notes_window = new ToolButton( embed::getIconPixmap( "project_notes" ), tr( "Show/hide project notes" ) + - " (F11)", + " (Ctrl+7)", this, SLOT( toggleProjectNotesWin() ), m_toolBar ); - project_notes_window->setShortcut( Qt::Key_F11 ); + project_notes_window->setShortcut( Qt::CTRL + Qt::Key_7 ); m_toolBarLayout->addWidget( song_editor_window, 1, 1 ); m_toolBarLayout->addWidget( bb_editor_window, 1, 2 ); @@ -1007,6 +1019,20 @@ void MainWindow::toggleWindow( QWidget *window, bool forceShow ) +void MainWindow::toggleFullscreen() +{ + if ( !isFullScreen() ) + { + maximized = isMaximized(); + showFullScreen(); + } + else + { + maximized ? showMaximized() : showNormal(); + } +} + + /* * When an editor window with focus is toggled off, attempt to set focus @@ -1093,36 +1119,43 @@ void MainWindow::updateViewMenu() // Not that it's straight visible <-> invisible, more like // not on top -> top <-> invisible m_viewMenu->addAction(embed::getIconPixmap( "songeditor" ), - tr( "Song Editor" ) + " (F5)", + tr( "Song Editor" ) + "\tCtrl+1", this, SLOT( toggleSongEditorWin() ) ); m_viewMenu->addAction(embed::getIconPixmap( "bb_track" ), - tr( "Beat+Bassline Editor" ) + " (F6)", + tr( "Beat+Bassline Editor" ) + "\tCtrl+2", this, SLOT( toggleBBEditorWin() ) ); m_viewMenu->addAction(embed::getIconPixmap( "piano" ), - tr( "Piano Roll" ) + " (F7)", + tr( "Piano Roll" ) + "\tCtrl+3", this, SLOT( togglePianoRollWin() ) ); m_viewMenu->addAction(embed::getIconPixmap( "automation" ), - tr( "Automation Editor" ) + " (F8)", + tr( "Automation Editor" ) + "\tCtrl+4", this, SLOT( toggleAutomationEditorWin()) ); m_viewMenu->addAction(embed::getIconPixmap( "fx_mixer" ), - tr( "FX Mixer" ) + " (F9)", + tr( "FX Mixer" ) + "\tCtrl+5", this, SLOT( toggleFxMixerWin() ) ); m_viewMenu->addAction(embed::getIconPixmap( "controller" ), - tr( "Controller Rack" ) + " (F10)", + tr( "Controller Rack" ) + "\tCtrl+6", this, SLOT( toggleControllerRack() ) ); m_viewMenu->addAction(embed::getIconPixmap( "project_notes" ), - tr( "Project Notes" ) + " (F11)", + tr( "Project Notes" ) + "\tCtrl+7", this, SLOT( toggleProjectNotesWin() ) ); m_viewMenu->addSeparator(); + + m_viewMenu->addAction(embed::getIconPixmap( "fullscreen" ), + tr( "Fullscreen" ) + "\tF11", + this, SLOT( toggleFullscreen() ) + ); + + m_viewMenu->addSeparator(); // Here we should put all look&feel -stuff from configmanager // that is safe to change on the fly. There is probably some @@ -1641,7 +1674,7 @@ void MainWindow::onSongStopped() { if(songEditor && ( tl->autoScroll() == TimeLineWidget::AutoScrollEnabled ) ) { - songEditor->m_editor->updatePosition( MidiTime(tl->savedPos().getTicks() ) ); + songEditor->m_editor->updatePosition( TimePos(tl->savedPos().getTicks() ) ); } tl->savePos( -1 ); } diff --git a/src/gui/MidiCCRackView.cpp b/src/gui/MidiCCRackView.cpp new file mode 100644 index 00000000000..4d932fd1c5d --- /dev/null +++ b/src/gui/MidiCCRackView.cpp @@ -0,0 +1,133 @@ +/* + * MidiCCRackView.cpp - implementation of the MIDI CC rack widget + * + * Copyright (c) 2020 Ian Caio + * + * 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. + * + */ + + +#include "MidiCCRackView.h" + +#include +#include +#include +#include +#include + +#include "embed.h" +#include "GroupBox.h" +#include "GuiApplication.h" +#include "InstrumentTrack.h" +#include "Knob.h" +#include "MainWindow.h" +#include "Track.h" + + +MidiCCRackView::MidiCCRackView(InstrumentTrack * track) : + QWidget(), + m_track(track) +{ + setWindowIcon(embed::getIconPixmap("midi_cc_rack")); + setWindowTitle(tr("MIDI CC Rack - %1").arg(m_track->name())); + + QMdiSubWindow * subWin = gui->mainWindow()->addWindowedWidget(this); + + // Remove maximize button + Qt::WindowFlags flags = subWin->windowFlags(); + flags &= ~Qt::WindowMaximizeButtonHint; + subWin->setWindowFlags(flags); + + // Adjust window attributes, sizing and position + subWin->setAttribute(Qt::WA_DeleteOnClose, false); + subWin->resize(350, 300); + subWin->setFixedWidth(350); + subWin->setMinimumHeight(300); + subWin->hide(); + + // Main window layout + QVBoxLayout *mainLayout = new QVBoxLayout(this); + + // Knobs GroupBox - Here we have the MIDI CC controller knobs for the selected track + m_midiCCGroupBox = new GroupBox(tr("MIDI CC Knobs:")); + + // Layout to keep scrollable area under the GroupBox header + QVBoxLayout *knobsGroupBoxLayout = new QVBoxLayout(); + knobsGroupBoxLayout->setContentsMargins(5, 16, 5, 5); + + m_midiCCGroupBox->setLayout(knobsGroupBoxLayout); + + // Scrollable area + widget + its layout that will have all the knobs + QScrollArea *knobsScrollArea = new QScrollArea(); + QWidget *knobsArea = new QWidget(); + QGridLayout *knobsAreaLayout = new QGridLayout(); + + knobsArea->setLayout(knobsAreaLayout); + knobsScrollArea->setWidget(knobsArea); + knobsScrollArea->setWidgetResizable(true); + + knobsGroupBoxLayout->addWidget(knobsScrollArea); + + // Adds the controller knobs + for (int i = 0; i < MidiControllerCount; ++i) + { + m_controllerKnob[i] = new Knob(knobBright_26); + m_controllerKnob[i]->setLabel(tr("CC %1").arg(i)); + knobsAreaLayout->addWidget(m_controllerKnob[i], i/4, i%4); + } + + // Set all the models + // Set the LED button to enable/disable the track midi cc + m_midiCCGroupBox->setModel(m_track->m_midiCCEnable.get()); + + // Set the model for each Knob + for (int i = 0; i < MidiControllerCount; ++i) + { + m_controllerKnob[i]->setModel(m_track->m_midiCCModel[i].get()); + } + + // Connection to update the name of the track on the label + connect(m_track, SIGNAL(nameChanged()), + this, SLOT(renameWindow())); + + // Adding everything to the main layout + mainLayout->addWidget(m_midiCCGroupBox); +} + +MidiCCRackView::~MidiCCRackView() +{ + if(parentWidget()) + { + parentWidget()->hide(); + parentWidget()->deleteLater(); + } +} + +void MidiCCRackView::renameWindow() +{ + setWindowTitle(tr("MIDI CC Rack - %1").arg(m_track->name())); +} + +void MidiCCRackView::saveSettings(QDomDocument & doc, QDomElement & parent) +{ +} + +void MidiCCRackView::loadSettings(const QDomElement &) +{ +} diff --git a/src/gui/MidiSetupWidget.cpp b/src/gui/MidiSetupWidget.cpp index 0c34544d6bf..8342070571b 100644 --- a/src/gui/MidiSetupWidget.cpp +++ b/src/gui/MidiSetupWidget.cpp @@ -31,7 +31,7 @@ MidiSetupWidget::MidiSetupWidget(const QString & caption, const QString & configSection, const QString & devName, QWidget * parent) : - TabWidget(TabWidget::tr("Settings for %1").arg(tr(caption.toLatin1())), parent), + TabWidget(TabWidget::tr("Settings for %1").arg(tr(caption.toUtf8())), parent), m_configSection(configSection), m_device(nullptr) { diff --git a/src/gui/ModelView.cpp b/src/gui/ModelView.cpp index 3b250fbcd3f..f9031ea9484 100644 --- a/src/gui/ModelView.cpp +++ b/src/gui/ModelView.cpp @@ -74,6 +74,16 @@ void ModelView::setModel( Model* model, bool isOldModelValid ) +// Unsets the current model by setting a dummy empty model. The dummy model is marked as +// "defaultConstructed", so the next call to setModel will delete it. +void ModelView::unsetModel() +{ + setModel(new Model(nullptr, QString(), true)); +} + + + + void ModelView::doConnections() { if( m_model != NULL ) diff --git a/src/gui/PianoView.cpp b/src/gui/PianoView.cpp index c5f1b623fca..58eb59dafbc 100644 --- a/src/gui/PianoView.cpp +++ b/src/gui/PianoView.cpp @@ -673,10 +673,17 @@ void PianoView::focusOutEvent( QFocusEvent * ) m_piano->midiEventProcessor()->processInEvent( MidiEvent( MidiNoteOff, -1, i, 0 ) ); m_piano->setKeyState( i, false ); } + + update(); } +void PianoView::focusInEvent( QFocusEvent * ) +{ + m_piano->instrumentTrack()->autoAssignMidiDevice(true); +} + /*! \brief update scrollbar range after resize diff --git a/src/gui/PluginBrowser.cpp b/src/gui/PluginBrowser.cpp index 671b58381ea..f27ba51c396 100644 --- a/src/gui/PluginBrowser.cpp +++ b/src/gui/PluginBrowser.cpp @@ -79,18 +79,7 @@ PluginBrowser::PluginBrowser( QWidget * _parent ) : view_layout->addWidget( searchBar ); view_layout->addWidget( m_descTree ); - // Add LMMS root to the tree - m_lmmsRoot = new QTreeWidgetItem(); - m_lmmsRoot->setText( 0, "LMMS" ); - m_descTree->insertTopLevelItem( 0, m_lmmsRoot ); - m_lmmsRoot->setExpanded( true ); - - // Add LV2 root to the tree - m_lv2Root = new QTreeWidgetItem(); - m_lv2Root->setText( 0, "LV2" ); - m_descTree->insertTopLevelItem( 1, m_lv2Root ); - - // Add plugins to the tree roots + // Add plugins to the tree addPlugins(); // Resize @@ -146,49 +135,62 @@ void PluginBrowser::onFilterChanged( const QString & filter ) void PluginBrowser::addPlugins() { - QList descs = pluginFactory->descriptors(Plugin::Instrument); - std::sort( - descs.begin(), - descs.end(), - []( const Plugin::Descriptor* d1, const Plugin::Descriptor* d2 ) -> bool - { - return qstricmp( d1->displayName, d2->displayName ) < 0 ? true : false; - } - ); - - typedef Plugin::Descriptor::SubPluginFeatures::KeyList PluginKeyList; - typedef Plugin::Descriptor::SubPluginFeatures::Key PluginKey; - PluginKeyList subPluginKeys, pluginKeys; - - for (const Plugin::Descriptor* desc: descs) + // Add a root node to the plugin tree with the specified `label` and return it + const auto addRoot = [this](auto label) { - if ( desc->subPluginFeatures ) - { - desc->subPluginFeatures->listSubPluginKeys( - desc, - subPluginKeys ); - } - else + const auto root = new QTreeWidgetItem(); + root->setText(0, label); + m_descTree->addTopLevelItem(root); + return root; + }; + + // Add the plugin identified by `key` to the tree under the root node `root` + const auto addPlugin = [this](const auto& key, auto root) + { + const auto item = new QTreeWidgetItem(); + root->addChild(item); + m_descTree->setItemWidget(item, 0, new PluginDescWidget(key, m_descTree)); + }; + + // Remove any existing plugins from the tree + m_descTree->clear(); + + // Fetch and sort all instrument plugin descriptors + auto descs = pluginFactory->descriptors(Plugin::Instrument); + std::sort(descs.begin(), descs.end(), + [](auto d1, auto d2) { - pluginKeys << PluginKey( desc, desc->name ); + return qstricmp(d1->displayName, d2->displayName) < 0; } - } + ); - pluginKeys += subPluginKeys; + // Add a root node to the tree for native LMMS plugins + const auto lmmsRoot = addRoot("LMMS"); + lmmsRoot->setExpanded(true); - for (const PluginKey& key : pluginKeys) + // Add all of the descriptors to the tree + for (const auto desc : descs) { - QTreeWidgetItem * item = new QTreeWidgetItem(); - if ( key.desc->name == QStringLiteral("lv2instrument") ) + if (desc->subPluginFeatures) { - m_lv2Root->addChild( item ); + // Fetch and sort all subplugins for this plugin descriptor + auto subPluginKeys = Plugin::Descriptor::SubPluginFeatures::KeyList{}; + desc->subPluginFeatures->listSubPluginKeys(desc, subPluginKeys); + std::sort(subPluginKeys.begin(), subPluginKeys.end(), + [](const auto& l, const auto& r) + { + return QString::compare(l.displayName(), r.displayName(), Qt::CaseInsensitive) < 0; + } + ); + + // Create a root node for this plugin and add the subplugins under it + const auto root = addRoot(desc->displayName); + for (const auto& key : subPluginKeys) { addPlugin(key, root); } } else { - m_lmmsRoot->addChild( item ); + addPlugin(Plugin::Descriptor::SubPluginFeatures::Key(desc, desc->name), lmmsRoot); } - PluginDescWidget* p = new PluginDescWidget( key, m_descTree ); - m_descTree->setItemWidget( item, 0, p ); } } @@ -205,7 +207,9 @@ PluginDescWidget::PluginDescWidget(const PluginKey &_pk, setFixedHeight( DEFAULT_HEIGHT ); setMouseTracking( true ); setCursor( Qt::PointingHandCursor ); - setToolTip(_pk.description()); + setToolTip(_pk.desc->subPluginFeatures + ? _pk.description() + : tr(_pk.desc->description)); } diff --git a/src/gui/SetupDialog.cpp b/src/gui/SetupDialog.cpp index 6de547b5ae2..cf6b7b7e06b 100644 --- a/src/gui/SetupDialog.cpp +++ b/src/gui/SetupDialog.cpp @@ -31,12 +31,14 @@ #include #include +#include "AudioDeviceSetupWidget.h" #include "debug.h" #include "embed.h" #include "Engine.h" #include "FileDialog.h" #include "gui_templates.h" #include "MainWindow.h" +#include "MidiSetupWidget.h" #include "Mixer.h" #include "ProjectJournal.h" #include "SetupDialog.h" @@ -102,6 +104,10 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) : "ui", "oneinstrumenttrackwindow").toInt()), m_sideBarOnRight(ConfigManager::inst()->value( "ui", "sidebaronright").toInt()), + m_letPreviewsFinish(ConfigManager::inst()->value( + "ui", "letpreviewsfinish").toInt()), + m_soloLegacyBehavior(ConfigManager::inst()->value( + "app", "sololegacybehavior", "0").toInt()), m_MMPZ(!ConfigManager::inst()->value( "app", "nommpz").toInt()), m_disableBackup(!ConfigManager::inst()->value( @@ -193,14 +199,14 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) : auto addLedCheckBox = [&XDelta, &YDelta, this]( - const char* ledText, + const QString &ledText, TabWidget* tw, int& counter, bool initialState, const char* toggledSlot, bool showRestartWarning ){ - LedCheckBox * checkBox = new LedCheckBox(tr(ledText), tw); + LedCheckBox * checkBox = new LedCheckBox(ledText, tw); counter++; checkBox->move(XDelta, YDelta * counter); checkBox->setChecked(initialState); @@ -219,20 +225,24 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) : tr("Graphical user interface (GUI)"), general_w); - addLedCheckBox("Display volume as dBFS ", gui_tw, counter, + addLedCheckBox(tr("Display volume as dBFS "), gui_tw, counter, m_displaydBFS, SLOT(toggleDisplaydBFS(bool)), true); - addLedCheckBox("Enable tooltips", gui_tw, counter, + addLedCheckBox(tr("Enable tooltips"), gui_tw, counter, m_tooltips, SLOT(toggleTooltips(bool)), true); - addLedCheckBox("Enable master oscilloscope by default", gui_tw, counter, + addLedCheckBox(tr("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, + addLedCheckBox(tr("Enable all note labels in piano roll"), gui_tw, counter, m_printNoteLabels, SLOT(toggleNoteLabels(bool)), false); - addLedCheckBox("Enable compact track buttons", gui_tw, counter, + addLedCheckBox(tr("Enable compact track buttons"), gui_tw, counter, m_compactTrackButtons, SLOT(toggleCompactTrackButtons(bool)), true); - addLedCheckBox("Enable one instrument-track-window mode", gui_tw, counter, + addLedCheckBox(tr("Enable one instrument-track-window mode"), gui_tw, counter, m_oneInstrumentTrackWindow, SLOT(toggleOneInstrumentTrackWindow(bool)), true); - addLedCheckBox("Show sidebar on the right-hand side", gui_tw, counter, + addLedCheckBox(tr("Show sidebar on the right-hand side"), gui_tw, counter, m_sideBarOnRight, SLOT(toggleSideBarOnRight(bool)), true); + addLedCheckBox(tr("Let sample previews continue when mouse is released"), gui_tw, counter, + m_letPreviewsFinish, SLOT(toggleLetPreviewsFinish(bool)), false); + addLedCheckBox(tr("Mute automation tracks during solo"), gui_tw, counter, + m_soloLegacyBehavior, SLOT(toggleSoloLegacyBehavior(bool)), false); gui_tw->setFixedHeight(YDelta + YDelta * counter); @@ -244,11 +254,11 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) : tr("Projects"), general_w); - addLedCheckBox("Compress project files by default", projects_tw, counter, + addLedCheckBox(tr("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, + addLedCheckBox(tr("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, + addLedCheckBox(tr("Reopen last project on startup"), projects_tw, counter, m_openLastProject, SLOT(toggleOpenLastProject(bool)), false); projects_tw->setFixedHeight(YDelta + YDelta * counter); @@ -368,9 +378,9 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) : 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, + addLedCheckBox(tr("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, + addLedCheckBox(tr("Display playback cursor in AudioFileProcessor"), ui_fx_tw, counter, m_animateAFP, SLOT(toggleAnimateAFP(bool)), false); ui_fx_tw->setFixedHeight(YDelta + YDelta * counter); @@ -389,7 +399,7 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) : m_vstEmbedComboBox = new QComboBox(plugins_tw); m_vstEmbedComboBox->move(XDelta, YDelta * ++counter); - QStringList embedMethods = ConfigManager::availabeVstEmbedMethods(); + QStringList embedMethods = ConfigManager::availableVstEmbedMethods(); m_vstEmbedComboBox->addItem(tr("No embedding"), "none"); if(embedMethods.contains("qt")) { @@ -417,10 +427,10 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) : connect(m_vstAlwaysOnTopCheckBox, SIGNAL(toggled(bool)), this, SLOT(toggleVSTAlwaysOnTop(bool))); - addLedCheckBox("Sync VST plugins to host playback", plugins_tw, counter, + addLedCheckBox(tr("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, + addLedCheckBox(tr("Keep effects running even without input"), plugins_tw, counter, m_disableAutoQuit, SLOT(toggleDisableAutoQuit(bool)), false); plugins_tw->setFixedHeight(YDelta + YDelta * counter); @@ -460,7 +470,7 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) : as_w_layout->setMargin(0); #ifdef LMMS_HAVE_JACK - m_audioIfaceSetupWidgets[AudioJack::name()] = + m_audioIfaceSetupWidgets[AudioJack::name()] = new AudioJack::setupWidget(as_w); #endif @@ -507,7 +517,7 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) : it != m_audioIfaceSetupWidgets.end(); ++it) { m_audioIfaceNames[ - tr(it.key().toLatin1())] = it.key(); + AudioDeviceSetupWidget::tr(it.key().toUtf8())] = it.key(); } for(trMap::iterator it = m_audioIfaceNames.begin(); it != m_audioIfaceNames.end(); ++it) @@ -653,7 +663,7 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) : it != m_midiIfaceSetupWidgets.end(); ++it) { m_midiIfaceNames[ - tr(it.key().toLatin1())] = it.key(); + MidiSetupWidget::tr(it.key().toUtf8())] = it.key(); } for(trMap::iterator it = m_midiIfaceNames.begin(); it != m_midiIfaceNames.end(); ++it) @@ -677,9 +687,32 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) : this, SLOT(midiInterfaceChanged(const QString &))); + // MIDI autoassign tab. + TabWidget * midiAutoAssign_tw = new TabWidget( + tr("Automatically assign MIDI controller to selected track"), midi_w); + midiAutoAssign_tw->setFixedHeight(56); + + m_assignableMidiDevices = new QComboBox(midiAutoAssign_tw); + m_assignableMidiDevices->setGeometry(10, 20, 240, 28); + m_assignableMidiDevices->addItem("none"); + if ( !Engine::mixer()->midiClient()->isRaw() ) + { + m_assignableMidiDevices->addItems(Engine::mixer()->midiClient()->readablePorts()); + } + else + { + m_assignableMidiDevices->addItem("all"); + } + int current = m_assignableMidiDevices->findText(ConfigManager::inst()->value("midi", "midiautoassign")); + if (current >= 0) + { + m_assignableMidiDevices->setCurrentIndex(current); + } + // MIDI layout ordering. midi_layout->addWidget(midiiface_tw); midi_layout->addWidget(ms_w); + midi_layout->addWidget(midiAutoAssign_tw); midi_layout->addStretch(); @@ -709,14 +742,14 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) : QVBoxLayout * pathSelectorsLayout = new QVBoxLayout; pathSelectorsLayout->setSpacing(10); - auto addPathEntry = [&](const char* caption, + auto addPathEntry = [&](const QString &caption, const QString& content, const char* setSlot, const char* openSlot, QLineEdit*& lineEdit, const char* pixmap = "project_open") { - TabWidget * newTw = new TabWidget(tr(caption), + TabWidget * newTw = new TabWidget(caption, pathSelectors); newTw->setFixedHeight(48); @@ -736,37 +769,37 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) : pathSelectorsLayout->addSpacing(10); }; - addPathEntry("LMMS working directory", m_workingDir, + addPathEntry(tr("LMMS working directory"), m_workingDir, SLOT(setWorkingDir(const QString &)), SLOT(openWorkingDir()), m_workingDirLineEdit); - addPathEntry("VST plugins directory", m_vstDir, + addPathEntry(tr("VST plugins directory"), m_vstDir, SLOT(setVSTDir(const QString &)), SLOT(openVSTDir()), m_vstDirLineEdit); - addPathEntry("LADSPA plugins directories", m_ladspaDir, + addPathEntry(tr("LADSPA plugins directories"), m_ladspaDir, SLOT(setLADSPADir(const QString &)), SLOT(openLADSPADir()), m_ladspaDirLineEdit, "add_folder"); - addPathEntry("SF2 directory", m_sf2Dir, + addPathEntry(tr("SF2 directory"), m_sf2Dir, SLOT(setSF2Dir(const QString &)), SLOT(openSF2Dir()), m_sf2DirLineEdit); #ifdef LMMS_HAVE_FLUIDSYNTH - addPathEntry("Default SF2", m_sf2File, + addPathEntry(tr("Default SF2"), m_sf2File, SLOT(setSF2File(const QString &)), SLOT(openSF2File()), m_sf2FileLineEdit); #endif - addPathEntry("GIG directory", m_gigDir, + addPathEntry(tr("GIG directory"), m_gigDir, SLOT(setGIGDir(const QString &)), SLOT(openGIGDir()), m_gigDirLineEdit); - addPathEntry("Theme directory", m_themeDir, + addPathEntry(tr("Theme directory"), m_themeDir, SLOT(setThemeDir(const QString &)), SLOT(openThemeDir()), m_themeDirLineEdit); - addPathEntry("Background artwork", m_backgroundPicFile, + addPathEntry(tr("Background artwork"), m_backgroundPicFile, SLOT(setBackgroundPicFile(const QString &)), SLOT(openBackgroundPicFile()), m_backgroundPicFileLineEdit); @@ -882,6 +915,10 @@ void SetupDialog::accept() QString::number(m_oneInstrumentTrackWindow)); ConfigManager::inst()->setValue("ui", "sidebaronright", QString::number(m_sideBarOnRight)); + ConfigManager::inst()->setValue("ui", "letpreviewsfinish", + QString::number(m_letPreviewsFinish)); + ConfigManager::inst()->setValue("app", "sololegacybehavior", + QString::number(m_soloLegacyBehavior)); ConfigManager::inst()->setValue("app", "nommpz", QString::number(!m_MMPZ)); ConfigManager::inst()->setValue("app", "disablebackup", @@ -917,6 +954,8 @@ void SetupDialog::accept() QString::number(m_bufferSize)); ConfigManager::inst()->setValue("mixer", "mididev", m_midiIfaceNames[m_midiInterfaces->currentText()]); + ConfigManager::inst()->setValue("midi", "midiautoassign", + m_assignableMidiDevices->currentText()); ConfigManager::inst()->setWorkingDir(QDir::fromNativeSeparators(m_workingDir)); @@ -992,6 +1031,12 @@ void SetupDialog::toggleSideBarOnRight(bool enabled) } +void SetupDialog::toggleLetPreviewsFinish(bool enabled) +{ + m_letPreviewsFinish = enabled; +} + + void SetupDialog::toggleMMPZ(bool enabled) { m_MMPZ = enabled; @@ -1016,6 +1061,10 @@ void SetupDialog::setLanguage(int lang) } +void SetupDialog::toggleSoloLegacyBehavior(bool enabled) +{ + m_soloLegacyBehavior = enabled; +} // Performance settings slots. @@ -1266,7 +1315,7 @@ void SetupDialog::openGIGDir() { QString new_dir = FileDialog::getExistingDirectory(this, tr("Choose your GIG directory"), m_gigDir); - if(new_dir != QString::null) + if(!new_dir.isEmpty()) { m_gigDirLineEdit->setText(new_dir); } @@ -1283,7 +1332,7 @@ void SetupDialog::openThemeDir() { QString new_dir = FileDialog::getExistingDirectory(this, tr("Choose your theme directory"), m_themeDir); - if(new_dir != QString::null) + if(!new_dir.isEmpty()) { m_themeDirLineEdit->setText(new_dir); } @@ -1318,7 +1367,7 @@ void SetupDialog::openBackgroundPicFile() QString new_file = FileDialog::getOpenFileName(this, tr("Choose your background picture"), dir, "Picture files (" + fileTypes + ")"); - if(new_file != QString::null) + if(!new_file.isEmpty()) { m_backgroundPicFileLineEdit->setText(new_file); } diff --git a/src/gui/StringPairDrag.cpp b/src/gui/StringPairDrag.cpp index b2b3b0c4a4e..b08f4adc5f6 100644 --- a/src/gui/StringPairDrag.cpp +++ b/src/gui/StringPairDrag.cpp @@ -32,12 +32,16 @@ #include "StringPairDrag.h" #include "GuiApplication.h" #include "MainWindow.h" +#include "Clipboard.h" StringPairDrag::StringPairDrag( const QString & _key, const QString & _value, const QPixmap & _icon, QWidget * _w ) : QDrag( _w ) { + // For mimeType() and MimeType enum class + using namespace Clipboard; + if( _icon.isNull() && _w ) { setPixmap( _w->grab().scaled( @@ -51,7 +55,7 @@ StringPairDrag::StringPairDrag( const QString & _key, const QString & _value, } QString txt = _key + ":" + _value; QMimeData * m = new QMimeData(); - m->setData( mimeType(), txt.toUtf8() ); + m->setData( mimeType( MimeType::StringPair ), txt.toUtf8() ); setMimeData( m ); exec( Qt::LinkAction, Qt::LinkAction ); } @@ -75,11 +79,14 @@ StringPairDrag::~StringPairDrag() bool StringPairDrag::processDragEnterEvent( QDragEnterEvent * _dee, const QString & _allowed_keys ) { - if( !_dee->mimeData()->hasFormat( mimeType() ) ) + // For mimeType() and MimeType enum class + using namespace Clipboard; + + if( !_dee->mimeData()->hasFormat( mimeType( MimeType::StringPair ) ) ) { return( false ); } - QString txt = _dee->mimeData()->data( mimeType() ); + QString txt = _dee->mimeData()->data( mimeType( MimeType::StringPair ) ); if( _allowed_keys.split( ',' ).contains( txt.section( ':', 0, 0 ) ) ) { _dee->acceptProposedAction(); @@ -92,25 +99,9 @@ bool StringPairDrag::processDragEnterEvent( QDragEnterEvent * _dee, -QString StringPairDrag::decodeMimeKey( const QMimeData * mimeData ) -{ - return( QString::fromUtf8( mimeData->data( mimeType() ) ).section( ':', 0, 0 ) ); -} - - - - -QString StringPairDrag::decodeMimeValue( const QMimeData * mimeData ) -{ - return( QString::fromUtf8( mimeData->data( mimeType() ) ).section( ':', 1, -1 ) ); -} - - - - QString StringPairDrag::decodeKey( QDropEvent * _de ) { - return decodeMimeKey( _de->mimeData() ); + return Clipboard::decodeKey( _de->mimeData() ); } @@ -118,5 +109,5 @@ QString StringPairDrag::decodeKey( QDropEvent * _de ) QString StringPairDrag::decodeValue( QDropEvent * _de ) { - return decodeMimeValue( _de->mimeData() ); + return Clipboard::decodeValue( _de->mimeData() ); } diff --git a/src/gui/TimeLineWidget.cpp b/src/gui/TimeLineWidget.cpp index bd196de7f6c..e7e7ca113e0 100644 --- a/src/gui/TimeLineWidget.cpp +++ b/src/gui/TimeLineWidget.cpp @@ -43,7 +43,7 @@ QPixmap * TimeLineWidget::s_posMarkerPixmap = NULL; TimeLineWidget::TimeLineWidget( const int xoff, const int yoff, const float ppb, - Song::PlayPos & pos, const MidiTime & begin, Song::PlayModes mode, + Song::PlayPos & pos, const TimePos & begin, Song::PlayModes mode, QWidget * parent ) : QWidget( parent ), m_inactiveLoopColor( 52, 63, 53, 64 ), @@ -109,6 +109,14 @@ TimeLineWidget::~TimeLineWidget() +void TimeLineWidget::setXOffset(const int x) +{ + m_xOffset = x; + if (s_posMarkerPixmap != nullptr) { m_xOffset -= s_posMarkerPixmap->width() / 2; } +} + + + void TimeLineWidget::addToolButtons( QToolBar * _tool_bar ) { @@ -130,7 +138,7 @@ void TimeLineWidget::addToolButtons( QToolBar * _tool_bar ) NStateButton * behaviourAtStop = new NStateButton( _tool_bar ); behaviourAtStop->addState( embed::getIconPixmap( "back_to_zero" ), - tr( "After stopping go back to begin" ) + tr( "After stopping go back to beginning" ) ); behaviourAtStop->addState( embed::getIconPixmap( "back_to_start" ), tr( "After stopping go back to " @@ -140,6 +148,9 @@ void TimeLineWidget::addToolButtons( QToolBar * _tool_bar ) tr( "After stopping keep position" ) ); connect( behaviourAtStop, SIGNAL( changedState( int ) ), this, SLOT( toggleBehaviourAtStop( int ) ) ); + connect( this, SIGNAL( loadBehaviourAtStop( int ) ), behaviourAtStop, + SLOT( changeState( int ) ) ); + behaviourAtStop->changeState( BackToStart ); _tool_bar->addWidget( autoScroll ); _tool_bar->addWidget( loopPoints ); @@ -154,6 +165,7 @@ void TimeLineWidget::saveSettings( QDomDocument & _doc, QDomElement & _this ) _this.setAttribute( "lp0pos", (int) loopBegin() ); _this.setAttribute( "lp1pos", (int) loopEnd() ); _this.setAttribute( "lpstate", m_loopPoints ); + _this.setAttribute( "stopbehaviour", m_behaviourAtStop ); } @@ -167,12 +179,17 @@ void TimeLineWidget::loadSettings( const QDomElement & _this ) _this.attribute( "lpstate" ).toInt() ); update(); emit loopPointStateLoaded( m_loopPoints ); + + if( _this.hasAttribute( "stopbehaviour" ) ) + { + emit loadBehaviourAtStop( _this.attribute( "stopbehaviour" ).toInt() ); + } } -void TimeLineWidget::updatePosition( const MidiTime & ) +void TimeLineWidget::updatePosition( const TimePos & ) { const int new_x = markerX( m_pos ); @@ -249,14 +266,14 @@ void TimeLineWidget::paintEvent( QPaintEvent * ) bar_t barNumber = m_begin.getBar(); int const x = m_xOffset + s_posMarkerPixmap->width() / 2 - - ( ( static_cast( m_begin * m_ppb ) / MidiTime::ticksPerBar() ) % static_cast( m_ppb ) ); + ( ( static_cast( m_begin * m_ppb ) / TimePos::ticksPerBar() ) % static_cast( m_ppb ) ); for( int i = 0; x + i * m_ppb < width(); ++i ) { ++barNumber; if( ( barNumber - 1 ) % qMax( 1, qRound( 1.0f / 3.0f * - MidiTime::ticksPerBar() / m_ppb ) ) == 0 ) + TimePos::ticksPerBar() / m_ppb ) ) == 0 ) { const int cx = x + qRound( i * m_ppb ); p.setPen( barLineColor ); @@ -313,8 +330,8 @@ 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::ticksPerBar() / m_ppb ); - const MidiTime loopMid = ( m_loopPos[0] + m_loopPos[1] ) / 2; + const TimePos t = m_begin + static_cast( qMax( event->x() - m_xOffset - m_moveXOff, 0 ) * TimePos::ticksPerBar() / m_ppb ); + const TimePos loopMid = ( m_loopPos[0] + m_loopPos[1] ) / 2; if( t < loopMid ) { @@ -349,7 +366,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::ticksPerBar() / m_ppb ); + const TimePos t = m_begin + static_cast( qMax( event->x() - m_xOffset - m_moveXOff, 0 ) * TimePos::ticksPerBar() / m_ppb ); switch( m_action ) { @@ -388,13 +405,13 @@ 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::ticksPerBar(); - } + { + m_loopPos[0] -= TimePos::ticksPerBar(); + } else - { - m_loopPos[1] += MidiTime::ticksPerBar(); - } + { + m_loopPos[1] += TimePos::ticksPerBar(); + } } update(); break; diff --git a/src/gui/TrackContainerView.cpp b/src/gui/TrackContainerView.cpp index 9b51c76f272..2ee33586812 100644 --- a/src/gui/TrackContainerView.cpp +++ b/src/gui/TrackContainerView.cpp @@ -29,15 +29,18 @@ #include #include #include +#include #include #include "TrackContainer.h" #include "BBTrack.h" +#include "DataFile.h" #include "MainWindow.h" #include "Mixer.h" #include "FileBrowser.h" #include "ImportFilter.h" #include "Instrument.h" +#include "InstrumentTrack.h" #include "Song.h" #include "StringPairDrag.h" #include "GuiApplication.h" @@ -122,9 +125,9 @@ TrackView * TrackContainerView::addTrackView( TrackView * _tv ) { m_trackViews.push_back( _tv ); m_scrollLayout->addWidget( _tv ); - connect( this, SIGNAL( positionChanged( const MidiTime & ) ), + connect( this, SIGNAL( positionChanged( const TimePos & ) ), _tv->getTrackContentWidget(), - SLOT( changePosition( const MidiTime & ) ) ); + SLOT( changePosition( const TimePos & ) ) ); realignTracks(); return( _tv ); } diff --git a/src/gui/TrackContentObjectView.cpp b/src/gui/TrackContentObjectView.cpp new file mode 100644 index 00000000000..0cd34bdd117 --- /dev/null +++ b/src/gui/TrackContentObjectView.cpp @@ -0,0 +1,1243 @@ +/* + * TrackContentObjectView.cpp - implementation of TrackContentObjectView class + * + * Copyright (c) 2004-2014 Tobias Doerffel + * + * 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. + * + */ + +#include "TrackContentObjectView.h" + +#include +#include +#include + +#include "AutomationPattern.h" +#include "Clipboard.h" +#include "ColorChooser.h" +#include "ComboBoxModel.h" +#include "DataFile.h" +#include "embed.h" +#include "GuiApplication.h" +#include "SampleTrack.h" +#include "SongEditor.h" +#include "StringPairDrag.h" +#include "TextFloat.h" +#include "TrackContainer.h" +#include "TrackContainerView.h" +#include "TrackView.h" + + +/*! The width of the resize grip in pixels + */ +const int RESIZE_GRIP_WIDTH = 4; + + +/*! A pointer for that text bubble used when moving segments, etc. + * + * In a number of situations, LMMS displays a floating text bubble + * beside the cursor as you move or resize elements of a track about. + * This pointer keeps track of it, as you only ever need one at a time. + */ +TextFloat * TrackContentObjectView::s_textFloat = NULL; + + +/*! \brief Create a new trackContentObjectView + * + * Creates a new track content object view for the given + * track content object in the given track view. + * + * \param _tco The track content object to be displayed + * \param _tv The track view that will contain the new object + */ +TrackContentObjectView::TrackContentObjectView( TrackContentObject * tco, + TrackView * tv ) : + selectableObject( tv->getTrackContentWidget() ), + ModelView( NULL, this ), + m_tco( tco ), + m_trackView( tv ), + m_action( NoAction ), + m_initialMousePos( QPoint( 0, 0 ) ), + m_initialMouseGlobalPos( QPoint( 0, 0 ) ), + m_initialTCOPos( TimePos(0) ), + m_initialTCOEnd( TimePos(0) ), + m_initialOffsets( QVector() ), + m_hint( NULL ), + m_mutedColor( 0, 0, 0 ), + m_mutedBackgroundColor( 0, 0, 0 ), + m_selectedColor( 0, 0, 0 ), + m_textColor( 0, 0, 0 ), + m_textShadowColor( 0, 0, 0 ), + m_BBPatternBackground( 0, 0, 0 ), + m_gradient( true ), + m_mouseHotspotHand( 0, 0 ), + m_cursorSetYet( false ), + m_needsUpdate( true ) +{ + if( s_textFloat == NULL ) + { + s_textFloat = new TextFloat; + s_textFloat->setPixmap( embed::getIconPixmap( "clock" ) ); + } + + setAttribute( Qt::WA_OpaquePaintEvent, true ); + setAttribute( Qt::WA_DeleteOnClose, true ); + setFocusPolicy( Qt::StrongFocus ); + setCursor( QCursor( embed::getIconPixmap( "hand" ), m_mouseHotspotHand.width(), m_mouseHotspotHand.height() ) ); + move( 0, 0 ); + show(); + + setFixedHeight( tv->getTrackContentWidget()->height() - 1); + setAcceptDrops( true ); + setMouseTracking( true ); + + connect( m_tco, SIGNAL( lengthChanged() ), + this, SLOT( updateLength() ) ); + connect( gui->songEditor()->m_editor->zoomingModel(), SIGNAL( dataChanged() ), this, SLOT( updateLength() ) ); + connect( m_tco, SIGNAL( positionChanged() ), + this, SLOT( updatePosition() ) ); + connect( m_tco, SIGNAL( destroyedTCO() ), this, SLOT( close() ) ); + setModel( m_tco ); + connect( m_tco, SIGNAL( trackColorChanged() ), this, SLOT( update() ) ); + connect( m_trackView->getTrackOperationsWidget(), SIGNAL( colorParented() ), this, SLOT( useTrackColor() ) ); + + m_trackView->getTrackContentWidget()->addTCOView( this ); + updateLength(); + updatePosition(); +} + + + + +/*! \brief Destroy a trackContentObjectView + * + * Destroys the given track content object view. + * + */ +TrackContentObjectView::~TrackContentObjectView() +{ + delete m_hint; + // we have to give our track-container the focus because otherwise the + // op-buttons of our track-widgets could become focus and when the user + // presses space for playing song, just one of these buttons is pressed + // which results in unwanted effects + m_trackView->trackContainerView()->setFocus(); +} + + +/*! \brief Update a TrackContentObjectView + * + * TCO's get drawn only when needed, + * and when a TCO is updated, + * it needs to be redrawn. + * + */ +void TrackContentObjectView::update() +{ + if( !m_cursorSetYet ) + { + setCursor( QCursor( embed::getIconPixmap( "hand" ), m_mouseHotspotHand.width(), m_mouseHotspotHand.height() ) ); + m_cursorSetYet = true; + } + + if( fixedTCOs() ) + { + updateLength(); + } + m_needsUpdate = true; + selectableObject::update(); +} + + + +/*! \brief Does this trackContentObjectView have a fixed TCO? + * + * Returns whether the containing trackView has fixed + * TCOs. + * + * \todo What the hell is a TCO here - track content object? And in + * what circumstance are they fixed? + */ +bool TrackContentObjectView::fixedTCOs() +{ + return m_trackView->trackContainerView()->fixedTCOs(); +} + + + +// qproperty access functions, to be inherited & used by TCOviews +//! \brief CSS theming qproperty access method +QColor TrackContentObjectView::mutedColor() const +{ return m_mutedColor; } + +QColor TrackContentObjectView::mutedBackgroundColor() const +{ return m_mutedBackgroundColor; } + +QColor TrackContentObjectView::selectedColor() const +{ return m_selectedColor; } + +QColor TrackContentObjectView::textColor() const +{ return m_textColor; } + +QColor TrackContentObjectView::textBackgroundColor() const +{ + return m_textBackgroundColor; +} + +QColor TrackContentObjectView::textShadowColor() const +{ return m_textShadowColor; } + +QColor TrackContentObjectView::BBPatternBackground() const +{ return m_BBPatternBackground; } + +bool TrackContentObjectView::gradient() const +{ return m_gradient; } + +//! \brief CSS theming qproperty access method +void TrackContentObjectView::setMutedColor( const QColor & c ) +{ m_mutedColor = QColor( c ); } + +void TrackContentObjectView::setMutedBackgroundColor( const QColor & c ) +{ m_mutedBackgroundColor = QColor( c ); } + +void TrackContentObjectView::setSelectedColor( const QColor & c ) +{ m_selectedColor = QColor( c ); } + +void TrackContentObjectView::setTextColor( const QColor & c ) +{ m_textColor = QColor( c ); } + +void TrackContentObjectView::setTextBackgroundColor( const QColor & c ) +{ + m_textBackgroundColor = c; +} + +void TrackContentObjectView::setTextShadowColor( const QColor & c ) +{ m_textShadowColor = QColor( c ); } + +void TrackContentObjectView::setBBPatternBackground( const QColor & c ) +{ m_BBPatternBackground = QColor( c ); } + +void TrackContentObjectView::setGradient( const bool & b ) +{ m_gradient = b; } + +void TrackContentObjectView::setMouseHotspotHand(const QSize & s) +{ + m_mouseHotspotHand = s; +} + +// access needsUpdate member variable +bool TrackContentObjectView::needsUpdate() +{ return m_needsUpdate; } +void TrackContentObjectView::setNeedsUpdate( bool b ) +{ m_needsUpdate = b; } + +/*! \brief Close a trackContentObjectView + * + * Closes a track content object view by asking the track + * view to remove us and then asking the QWidget to close us. + * + * \return Boolean state of whether the QWidget was able to close. + */ +bool TrackContentObjectView::close() +{ + m_trackView->getTrackContentWidget()->removeTCOView( this ); + return QWidget::close(); +} + + + + +/*! \brief Removes a trackContentObjectView from its track view. + * + * Like the close() method, this asks the track view to remove this + * track content object view. However, the track content object is + * scheduled for later deletion rather than closed immediately. + * + */ +void TrackContentObjectView::remove() +{ + m_trackView->getTrack()->addJournalCheckPoint(); + + // delete ourself + close(); + m_tco->deleteLater(); +} + + + + +/*! \brief Updates a trackContentObjectView's length + * + * If this track content object view has a fixed TCO, then we must + * keep the width of our parent. Otherwise, calculate our width from + * the track content object's length in pixels adding in the border. + * + */ +void TrackContentObjectView::updateLength() +{ + if( fixedTCOs() ) + { + setFixedWidth( parentWidget()->width() ); + } + else + { + setFixedWidth( + static_cast( m_tco->length() * pixelsPerBar() / + TimePos::ticksPerBar() ) + 1 /*+ + TCO_BORDER_WIDTH * 2-1*/ ); + } + m_trackView->trackContainerView()->update(); +} + + + + +/*! \brief Updates a trackContentObjectView's position. + * + * Ask our track view to change our position. Then make sure that the + * track view is updated in case this position has changed the track + * view's length. + * + */ +void TrackContentObjectView::updatePosition() +{ + m_trackView->getTrackContentWidget()->changePosition(); + // moving a TCO can result in change of song-length etc., + // therefore we update the track-container + m_trackView->trackContainerView()->update(); +} + + + + +void TrackContentObjectView::changeClipColor() +{ + // Get a color from the user + QColor new_color = ColorChooser( this ).withPalette( ColorChooser::Palette::Track )->getColor( m_tco->color() ); + if( ! new_color.isValid() ) + { return; } + + // Use that color + m_tco->setColor( new_color ); + m_tco->useCustomClipColor( true ); + update(); +} + + + +void TrackContentObjectView::useTrackColor() +{ + m_tco->useCustomClipColor( false ); + update(); +} + + + + + +/*! \brief Change the trackContentObjectView's display when something + * being dragged enters it. + * + * We need to notify Qt to change our display if something being + * dragged has entered our 'airspace'. + * + * \param dee The QDragEnterEvent to watch. + */ +void TrackContentObjectView::dragEnterEvent( QDragEnterEvent * dee ) +{ + TrackContentWidget * tcw = getTrackView()->getTrackContentWidget(); + TimePos tcoPos = TimePos( m_tco->startPosition() ); + + if( tcw->canPasteSelection( tcoPos, dee ) == false ) + { + dee->ignore(); + } + else + { + StringPairDrag::processDragEnterEvent( dee, "tco_" + + QString::number( m_tco->getTrack()->type() ) ); + } +} + + + + +/*! \brief Handle something being dropped on this trackContentObjectView. + * + * When something has been dropped on this trackContentObjectView, and + * it's a track content object, then use an instance of our dataFile reader + * to take the xml of the track content object and turn it into something + * we can write over our current state. + * + * \param de The QDropEvent to handle. + */ +void TrackContentObjectView::dropEvent( QDropEvent * de ) +{ + QString type = StringPairDrag::decodeKey( de ); + QString value = StringPairDrag::decodeValue( de ); + + // Track must be the same type to paste into + if( type != ( "tco_" + QString::number( m_tco->getTrack()->type() ) ) ) + { + return; + } + + // Defer to rubberband paste if we're in that mode + if( m_trackView->trackContainerView()->allowRubberband() == true ) + { + TrackContentWidget * tcw = getTrackView()->getTrackContentWidget(); + TimePos tcoPos = TimePos( m_tco->startPosition() ); + + if( tcw->pasteSelection( tcoPos, de ) == true ) + { + de->accept(); + } + return; + } + + // Don't allow pasting a tco into itself. + QObject* qwSource = de->source(); + if( qwSource != NULL && + dynamic_cast( qwSource ) == this ) + { + return; + } + + // Copy state into existing tco + DataFile dataFile( value.toUtf8() ); + TimePos pos = m_tco->startPosition(); + QDomElement tcos = dataFile.content().firstChildElement( "tcos" ); + m_tco->restoreState( tcos.firstChildElement().firstChildElement() ); + m_tco->movePosition( pos ); + AutomationPattern::resolveAllIDs(); + de->accept(); +} + + + + +/*! \brief Handle a dragged selection leaving our 'airspace'. + * + * \param e The QEvent to watch. + */ +void TrackContentObjectView::leaveEvent( QEvent * e ) +{ + if( cursor().shape() != Qt::BitmapCursor ) + { + setCursor( QCursor( embed::getIconPixmap( "hand" ), m_mouseHotspotHand.width(), m_mouseHotspotHand.height() ) ); + } + if( e != NULL ) + { + QWidget::leaveEvent( e ); + } +} + +/*! \brief Create a DataFile suitable for copying multiple trackContentObjects. + * + * trackContentObjects in the vector are written to the "tcos" node in the + * DataFile. The trackContentObjectView's initial mouse position is written + * to the "initialMouseX" node in the DataFile. When dropped on a track, + * this is used to create copies of the TCOs. + * + * \param tcos The trackContectObjects to save in a DataFile + */ +DataFile TrackContentObjectView::createTCODataFiles( + const QVector & tcoViews) const +{ + Track * t = m_trackView->getTrack(); + TrackContainer * tc = t->trackContainer(); + DataFile dataFile( DataFile::DragNDropData ); + QDomElement tcoParent = dataFile.createElement( "tcos" ); + + typedef QVector tcoViewVector; + for( tcoViewVector::const_iterator it = tcoViews.begin(); + it != tcoViews.end(); ++it ) + { + // Insert into the dom under the "tcos" element + Track* tcoTrack = ( *it )->m_trackView->getTrack(); + int trackIndex = tc->tracks().indexOf( tcoTrack ); + QDomElement tcoElement = dataFile.createElement( "tco" ); + tcoElement.setAttribute( "trackIndex", trackIndex ); + tcoElement.setAttribute( "trackType", tcoTrack->type() ); + tcoElement.setAttribute( "trackName", tcoTrack->name() ); + ( *it )->m_tco->saveState( dataFile, tcoElement ); + tcoParent.appendChild( tcoElement ); + } + + dataFile.content().appendChild( tcoParent ); + + // Add extra metadata needed for calculations later + int initialTrackIndex = tc->tracks().indexOf( t ); + if( initialTrackIndex < 0 ) + { + printf("Failed to find selected track in the TrackContainer.\n"); + return dataFile; + } + QDomElement metadata = dataFile.createElement( "copyMetadata" ); + // 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 bar containing the TCO we grabbed + metadata.setAttribute( "grabbedTCOPos", m_tco->startPosition() ); + + dataFile.content().appendChild( metadata ); + + return dataFile; +} + +void TrackContentObjectView::paintTextLabel(QString const & text, QPainter & painter) +{ + if (text.trimmed() == "") + { + return; + } + + painter.setRenderHint( QPainter::TextAntialiasing ); + + QFont labelFont = this->font(); + labelFont.setHintingPreference( QFont::PreferFullHinting ); + painter.setFont( labelFont ); + + const int textTop = TCO_BORDER_WIDTH + 1; + const int textLeft = TCO_BORDER_WIDTH + 3; + + QFontMetrics fontMetrics(labelFont); + QString elidedPatternName = fontMetrics.elidedText(text, Qt::ElideMiddle, width() - 2 * textLeft); + + if (elidedPatternName.length() < 2) + { + elidedPatternName = text.trimmed(); + } + + painter.fillRect(QRect(0, 0, width(), fontMetrics.height() + 2 * textTop), textBackgroundColor()); + + int const finalTextTop = textTop + fontMetrics.ascent(); + painter.setPen(textShadowColor()); + painter.drawText( textLeft + 1, finalTextTop + 1, elidedPatternName ); + painter.setPen( textColor() ); + painter.drawText( textLeft, finalTextTop, elidedPatternName ); +} + +/*! \brief Handle a mouse press on this trackContentObjectView. + * + * Handles the various ways in which a trackContentObjectView can be + * used with a click of a mouse button. + * + * * If our container supports rubber band selection then handle + * selection events. + * * or if shift-left button, add this object to the selection + * * or if ctrl-left button, start a drag-copy event + * * or if just plain left button, resize if we're resizeable + * * or if ctrl-middle button, mute the track content object + * * or if middle button, maybe delete the track content object. + * + * \param me The QMouseEvent to handle. + */ +void TrackContentObjectView::mousePressEvent( QMouseEvent * me ) +{ + // Right now, active is only used on right/mid clicks actions, so we use a ternary operator + // to avoid the overhead of calling getClickedTCOs when it's not used + auto active = me->button() == Qt::LeftButton + ? QVector() + : getClickedTCOs(); + + setInitialPos( me->pos() ); + setInitialOffsets(); + if( !fixedTCOs() && me->button() == Qt::LeftButton ) + { + if( me->modifiers() & Qt::ControlModifier ) + { + if( isSelected() ) + { + m_action = CopySelection; + } + else + { + m_action = ToggleSelected; + } + } + else if( !me->modifiers() + || (me->modifiers() & Qt::AltModifier) + || (me->modifiers() & Qt::ShiftModifier) ) + { + if( isSelected() ) + { + m_action = MoveSelection; + } + else + { + gui->songEditor()->m_editor->selectAllTcos( false ); + m_tco->addJournalCheckPoint(); + + // move or resize + m_tco->setJournalling( false ); + + setInitialPos( me->pos() ); + setInitialOffsets(); + + SampleTCO * sTco = dynamic_cast( m_tco ); + if( me->x() < RESIZE_GRIP_WIDTH && sTco + && !m_tco->getAutoResize() ) + { + m_action = ResizeLeft; + setCursor( Qt::SizeHorCursor ); + } + else if( m_tco->getAutoResize() || me->x() < width() - RESIZE_GRIP_WIDTH ) + { + m_action = Move; + setCursor( Qt::SizeAllCursor ); + } + else + { + m_action = Resize; + setCursor( Qt::SizeHorCursor ); + } + + if( m_action == Move ) + { + s_textFloat->setTitle( tr( "Current position" ) ); + s_textFloat->setText( QString( "%1:%2" ). + arg( m_tco->startPosition().getBar() + 1 ). + arg( m_tco->startPosition().getTicks() % + TimePos::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().getBar() ). + arg( m_tco->length().getTicks() % + TimePos::ticksPerBar() ). + arg( m_tco->startPosition().getBar() + 1 ). + arg( m_tco->startPosition().getTicks() % + TimePos::ticksPerBar() ). + arg( m_tco->endPosition().getBar() + 1 ). + arg( m_tco->endPosition().getTicks() % + TimePos::ticksPerBar() ) ); + } + // s_textFloat->reparent( this ); + // setup text-float as if TCO was already moved/resized + s_textFloat->moveGlobal( this, QPoint( width() + 2, height() + 2) ); + s_textFloat->show(); + } + + delete m_hint; + QString hint = m_action == Move || m_action == MoveSelection + ? tr( "Press <%1> and drag to make a copy." ) + : tr( "Press <%1> for free resizing." ); + m_hint = TextFloat::displayMessage( tr( "Hint" ), hint.arg(UI_CTRL_KEY), + embed::getIconPixmap( "hint" ), 0 ); + } + } + else if( me->button() == Qt::RightButton ) + { + if( me->modifiers() & Qt::ControlModifier ) + { + toggleMute( active ); + } + else if( me->modifiers() & Qt::ShiftModifier && !fixedTCOs() ) + { + remove( active ); + } + } + else if( me->button() == Qt::MidButton ) + { + if( me->modifiers() & Qt::ControlModifier ) + { + toggleMute( active ); + } + else if( !fixedTCOs() ) + { + remove( active ); + } + } +} + + + + +/*! \brief Handle a mouse movement (drag) on this trackContentObjectView. + * + * Handles the various ways in which a trackContentObjectView can be + * used with a mouse drag. + * + * * If in move mode, move ourselves in the track, + * * or if in move-selection mode, move the entire selection, + * * or if in resize mode, resize ourselves, + * * otherwise ??? + * + * \param me The QMouseEvent to handle. + * \todo what does the final else case do here? + */ +void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) +{ + if( m_action == CopySelection || m_action == ToggleSelected ) + { + if( mouseMovedDistance( me, 2 ) == true ) + { + QVector tcoViews; + if( m_action == CopySelection ) + { + // Collect all selected TCOs + QVector so = + m_trackView->trackContainerView()->selectedObjects(); + for( auto it = so.begin(); it != so.end(); ++it ) + { + TrackContentObjectView * tcov = + dynamic_cast( *it ); + if( tcov != NULL ) + { + tcoViews.push_back( tcov ); + } + } + } + else + { + gui->songEditor()->m_editor->selectAllTcos( false ); + tcoViews.push_back( this ); + } + // Clear the action here because mouseReleaseEvent will not get + // triggered once we go into drag. + m_action = NoAction; + + // Write the TCOs to the DataFile for copying + DataFile dataFile = createTCODataFiles( tcoViews ); + + // TODO -- thumbnail for all selected + QPixmap thumbnail = grab().scaled( + 128, 128, + Qt::KeepAspectRatio, + Qt::SmoothTransformation ); + new StringPairDrag( QString( "tco_%1" ).arg( + m_tco->getTrack()->type() ), + dataFile.toString(), thumbnail, this ); + } + } + + if( me->modifiers() & Qt::ControlModifier ) + { + delete m_hint; + m_hint = NULL; + } + + const float ppb = m_trackView->trackContainerView()->pixelsPerBar(); + if( m_action == Move ) + { + TimePos newPos = draggedTCOPos( me ); + + m_tco->movePosition(newPos); + newPos = m_tco->startPosition(); // Get the real position the TCO was dragged to for the label + m_trackView->getTrackContentWidget()->changePosition(); + s_textFloat->setText( QString( "%1:%2" ). + arg( newPos.getBar() + 1 ). + arg( newPos.getTicks() % + TimePos::ticksPerBar() ) ); + s_textFloat->moveGlobal( this, QPoint( width() + 2, height() + 2 ) ); + } + else if( m_action == MoveSelection ) + { + // 1: Find the position we want to move the grabbed TCO to + TimePos newPos = draggedTCOPos( me ); + + // 2: Handle moving the other selected TCOs the same distance + QVector so = + m_trackView->trackContainerView()->selectedObjects(); + QVector tcos; // List of selected clips + int leftmost = 0; // Leftmost clip's offset from grabbed clip + // Populate tcos, find leftmost + for( QVector::iterator it = so.begin(); + it != so.end(); ++it ) + { + TrackContentObjectView * tcov = + dynamic_cast( *it ); + if( tcov == NULL ) { continue; } + tcos.push_back( tcov->m_tco ); + int index = std::distance( so.begin(), it ); + leftmost = std::min(leftmost, m_initialOffsets[index].getTicks()); + } + // Make sure the leftmost clip doesn't get moved to a negative position + if ( newPos.getTicks() + leftmost < 0 ) { newPos = -leftmost; } + + for( QVector::iterator it = tcos.begin(); + it != tcos.end(); ++it ) + { + int index = std::distance( tcos.begin(), it ); + ( *it )->movePosition( newPos + m_initialOffsets[index] ); + } + } + else if( m_action == Resize || m_action == ResizeLeft ) + { + // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize + 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 TimePos snapLength = TimePos( (int)(snapSize * TimePos::ticksPerBar()) ); + + if( m_action == Resize ) + { + // The clip's new length + TimePos l = static_cast( me->x() * TimePos::ticksPerBar() / ppb ); + + if ( unquantized ) + { // We want to preserve this adjusted offset, + // even if the user switches to snapping later + setInitialPos( m_initialMousePos ); + // Don't resize to less than 1 tick + m_tco->changeLength( qMax( 1, l ) ); + } + else if ( me->modifiers() & Qt::ShiftModifier ) + { // If shift is held, quantize clip's end position + TimePos end = TimePos( m_initialTCOPos + l ).quantize( snapSize ); + // The end position has to be after the clip's start + TimePos min = m_initialTCOPos.quantize( snapSize ); + if ( min <= m_initialTCOPos ) min += snapLength; + m_tco->changeLength( qMax(min - m_initialTCOPos, end - m_initialTCOPos) ); + } + else + { // Otherwise, resize in fixed increments + TimePos initialLength = m_initialTCOEnd - m_initialTCOPos; + TimePos offset = TimePos( l - initialLength ).quantize( snapSize ); + // Don't resize to less than 1 tick + TimePos min = TimePos( initialLength % snapLength ); + if (min < 1) min += snapLength; + m_tco->changeLength( qMax( min, initialLength + offset) ); + } + } + else + { + SampleTCO * sTco = dynamic_cast( m_tco ); + if( sTco ) + { + const int x = mapToParent( me->pos() ).x() - m_initialMousePos.x(); + + TimePos t = qMax( 0, (int) + m_trackView->trackContainerView()->currentPosition() + + static_cast( x * TimePos::ticksPerBar() / ppb ) ); + + if( unquantized ) + { // We want to preserve this adjusted offset, + // even if the user switches to snapping later + setInitialPos( m_initialMousePos ); + //Don't resize to less than 1 tick + t = qMin( m_initialTCOEnd - 1, t); + } + else if( me->modifiers() & Qt::ShiftModifier ) + { // If shift is held, quantize clip's start position + // Don't let the start position move past the end position + TimePos max = m_initialTCOEnd.quantize( snapSize ); + if ( max >= m_initialTCOEnd ) max -= snapLength; + t = qMin( max, t.quantize( snapSize ) ); + } + else + { // Otherwise, resize in fixed increments + // Don't resize to less than 1 tick + TimePos initialLength = m_initialTCOEnd - m_initialTCOPos; + TimePos minLength = TimePos( initialLength % snapLength ); + if (minLength < 1) minLength += snapLength; + TimePos offset = TimePos(t - m_initialTCOPos).quantize( snapSize ); + t = qMin( m_initialTCOEnd - minLength, m_initialTCOPos + offset ); + } + + TimePos oldPos = m_tco->startPosition(); + if( m_tco->length() + ( oldPos - t ) >= 1 ) + { + m_tco->movePosition( t ); + m_tco->changeLength( m_tco->length() + ( oldPos - t ) ); + sTco->setStartTimeOffset( sTco->startTimeOffset() + ( oldPos - t ) ); + } + } + } + s_textFloat->setText( tr( "%1:%2 (%3:%4 to %5:%6)" ). + arg( m_tco->length().getBar() ). + arg( m_tco->length().getTicks() % + TimePos::ticksPerBar() ). + arg( m_tco->startPosition().getBar() + 1 ). + arg( m_tco->startPosition().getTicks() % + TimePos::ticksPerBar() ). + arg( m_tco->endPosition().getBar() + 1 ). + arg( m_tco->endPosition().getTicks() % + TimePos::ticksPerBar() ) ); + s_textFloat->moveGlobal( this, QPoint( width() + 2, height() + 2) ); + } + else + { + SampleTCO * sTco = dynamic_cast( m_tco ); + if( ( me->x() > width() - RESIZE_GRIP_WIDTH && !me->buttons() && !m_tco->getAutoResize() ) + || ( me->x() < RESIZE_GRIP_WIDTH && !me->buttons() && sTco && !m_tco->getAutoResize() ) ) + { + setCursor( Qt::SizeHorCursor ); + } + else + { + leaveEvent( NULL ); + } + } +} + + + + +/*! \brief Handle a mouse release on this trackContentObjectView. + * + * If we're in move or resize mode, journal the change as appropriate. + * Then tidy up. + * + * \param me The QMouseEvent to handle. + */ +void TrackContentObjectView::mouseReleaseEvent( QMouseEvent * me ) +{ + // If the CopySelection was chosen as the action due to mouse movement, + // it will have been cleared. At this point Toggle is the desired action. + // An active StringPairDrag will prevent this method from being called, + // so a real CopySelection would not have occurred. + if( m_action == CopySelection || + ( m_action == ToggleSelected && mouseMovedDistance( me, 2 ) == false ) ) + { + setSelected( !isSelected() ); + } + + if( m_action == Move || m_action == Resize || m_action == ResizeLeft ) + { + // TODO: Fix m_tco->setJournalling() consistency + m_tco->setJournalling( true ); + } + m_action = NoAction; + delete m_hint; + m_hint = NULL; + s_textFloat->hide(); + leaveEvent( NULL ); + selectableObject::mouseReleaseEvent( me ); +} + + + + +/*! \brief Set up the context menu for this trackContentObjectView. + * + * Set up the various context menu events that can apply to a + * track content object view. + * + * \param cme The QContextMenuEvent to add the actions to. + */ +void TrackContentObjectView::contextMenuEvent( QContextMenuEvent * cme ) +{ + // Depending on whether we right-clicked a selection or an individual TCO we will have + // different labels for the actions. + bool individualTCO = getClickedTCOs().size() <= 1; + + if( cme->modifiers() ) + { + return; + } + + QMenu contextMenu( this ); + + if( fixedTCOs() == false ) + { + contextMenu.addAction( + embed::getIconPixmap( "cancel" ), + individualTCO + ? tr("Delete (middle mousebutton)") + : tr("Delete selection (middle mousebutton)"), + [this](){ contextMenuAction( Remove ); } ); + + contextMenu.addSeparator(); + + contextMenu.addAction( + embed::getIconPixmap( "edit_cut" ), + individualTCO + ? tr("Cut") + : tr("Cut selection"), + [this](){ contextMenuAction( Cut ); } ); + } + + contextMenu.addAction( + embed::getIconPixmap( "edit_copy" ), + individualTCO + ? tr("Copy") + : tr("Copy selection"), + [this](){ contextMenuAction( Copy ); } ); + + contextMenu.addAction( + embed::getIconPixmap( "edit_paste" ), + tr( "Paste" ), + [this](){ contextMenuAction( Paste ); } ); + + contextMenu.addSeparator(); + + contextMenu.addAction( + embed::getIconPixmap( "muted" ), + (individualTCO + ? tr("Mute/unmute (<%1> + middle click)") + : tr("Mute/unmute selection (<%1> + middle click)")).arg(UI_CTRL_KEY), + [this](){ contextMenuAction( Mute ); } ); + + contextMenu.addSeparator(); + + contextMenu.addAction( embed::getIconPixmap( "colorize" ), + tr( "Set clip color" ), this, SLOT( changeClipColor() ) ); + contextMenu.addAction( embed::getIconPixmap( "colorize" ), + tr( "Use track color" ), this, SLOT( useTrackColor() ) ); + + constructContextMenu( &contextMenu ); + + contextMenu.exec( QCursor::pos() ); +} + +// This method processes the actions from the context menu of the TCO View. +void TrackContentObjectView::contextMenuAction( ContextMenuAction action ) +{ + QVector active = getClickedTCOs(); + // active will be later used for the remove, copy, cut or toggleMute methods + + switch( action ) + { + case Remove: + remove( active ); + break; + case Cut: + cut( active ); + break; + case Copy: + copy( active ); + break; + case Paste: + paste(); + break; + case Mute: + toggleMute( active ); + break; + } +} + +QVector TrackContentObjectView::getClickedTCOs() +{ + // Get a list of selected selectableObjects + QVector sos = gui->songEditor()->m_editor->selectedObjects(); + + // Convert to a list of selected TCOVs + QVector selection; + selection.reserve( sos.size() ); + for( auto so: sos ) + { + TrackContentObjectView *tcov = dynamic_cast ( so ); + if( tcov != nullptr ) + { + selection.append( tcov ); + } + } + + // If we clicked part of the selection, affect all selected clips. Otherwise affect the clip we clicked + return selection.contains(this) + ? selection + : QVector( 1, this ); +} + +void TrackContentObjectView::remove( QVector tcovs ) +{ + for( auto tcov: tcovs ) + { + // No need to check if it's nullptr because we check when building the QVector + tcov->remove(); + } +} + +void TrackContentObjectView::copy( QVector tcovs ) +{ + // For copyStringPair() + using namespace Clipboard; + + // Write the TCOs to a DataFile for copying + DataFile dataFile = createTCODataFiles( tcovs ); + + // Copy the TCO type as a key and the TCO data file to the clipboard + copyStringPair( QString( "tco_%1" ).arg( m_tco->getTrack()->type() ), + dataFile.toString() ); +} + +void TrackContentObjectView::cut( QVector tcovs ) +{ + // Copy the selected TCOs + copy( tcovs ); + + // Now that the TCOs are copied we can delete them, since we are cutting + remove( tcovs ); +} + +void TrackContentObjectView::paste() +{ + // For getMimeData() + using namespace Clipboard; + + // If possible, paste the selection on the TimePos of the selected Track and remove it + TimePos tcoPos = TimePos( m_tco->startPosition() ); + + TrackContentWidget *tcw = getTrackView()->getTrackContentWidget(); + + if( tcw->pasteSelection( tcoPos, getMimeData() ) ) + { + // If we succeed on the paste we delete the TCO we pasted on + remove(); + } +} + +void TrackContentObjectView::toggleMute( QVector tcovs ) +{ + for( auto tcov: tcovs ) + { + // No need to check for nullptr because we check while building the tcovs QVector + tcov->getTrackContentObject()->toggleMute(); + } +} + + + + +/*! \brief How many pixels a bar takes for this trackContentObjectView. + * + * \return the number of pixels per bar. + */ +float TrackContentObjectView::pixelsPerBar() +{ + return m_trackView->trackContainerView()->pixelsPerBar(); +} + + +/*! \brief Save the offsets between all selected tracks and a clicked track */ +void TrackContentObjectView::setInitialOffsets() +{ + QVector so = m_trackView->trackContainerView()->selectedObjects(); + QVector offsets; + for( QVector::iterator it = so.begin(); + it != so.end(); ++it ) + { + TrackContentObjectView * tcov = + dynamic_cast( *it ); + if( tcov == NULL ) + { + continue; + } + offsets.push_back( tcov->m_tco->startPosition() - m_initialTCOPos ); + } + + m_initialOffsets = offsets; +} + + + + +/*! \brief Detect whether the mouse moved more than n pixels on screen. + * + * \param _me The QMouseEvent. + * \param distance The threshold distance that the mouse has moved to return true. + */ +bool TrackContentObjectView::mouseMovedDistance( QMouseEvent * me, int distance ) +{ + QPoint dPos = mapToGlobal( me->pos() ) - m_initialMouseGlobalPos; + const int pixelsMoved = dPos.manhattanLength(); + return ( pixelsMoved > distance || pixelsMoved < -distance ); +} + + + +/*! \brief Calculate the new position of a dragged TCO from a mouse event + * + * + * \param me The QMouseEvent + */ +TimePos TrackContentObjectView::draggedTCOPos( QMouseEvent * me ) +{ + //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(); + TimePos newPos = m_initialTCOPos + mouseOff * TimePos::ticksPerBar() / ppb; + TimePos 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 + || (me->modifiers() & Qt::ControlModifier) + || (me->modifiers() & Qt::AltModifier) ) + { + // We want to preserve this adjusted offset, + // even if the user switches to snapping + setInitialPos( m_initialMousePos ); + } + else if ( me->modifiers() & Qt::ShiftModifier ) + { // If shift is held, quantize position (Default in 1.2.0 and earlier) + // or end position, whichever is closest to the actual position + TimePos startQ = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); + // Find start position that gives snapped clip end position + TimePos endQ = ( newPos + m_tco->length() ); + endQ = endQ.quantize( gui->songEditor()->m_editor->getSnapSize() ); + endQ = endQ - m_tco->length(); + // Select the position closest to actual position + if ( abs(newPos - startQ) < abs(newPos - endQ) ) newPos = startQ; + else newPos = endQ; + } + else + { // Otherwise, quantize moved distance (preserves user offsets) + newPos = m_initialTCOPos + offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); + } + return newPos; +} + + +// Return the color that the TCO's background should be +QColor TrackContentObjectView::getColorForDisplay( QColor defaultColor ) +{ + // Get the pure TCO color + auto tcoColor = m_tco->hasColor() + ? m_tco->usesCustomClipColor() + ? m_tco->color() + : m_tco->getTrack()->color() + : defaultColor; + + // Set variables + QColor c, mutedCustomColor; + bool muted = m_tco->getTrack()->isMuted() || m_tco->isMuted(); + mutedCustomColor = tcoColor; + mutedCustomColor.setHsv( mutedCustomColor.hsvHue(), mutedCustomColor.hsvSaturation() / 4, mutedCustomColor.value() ); + + // Change the pure color by state: selected, muted, colored, normal + if( isSelected() ) + { + c = m_tco->hasColor() + ? ( muted + ? mutedCustomColor.darker( 350 ) + : tcoColor.darker( 150 ) ) + : selectedColor(); + } + else + { + if( muted ) + { + c = m_tco->hasColor() + ? mutedCustomColor.darker( 250 ) + : mutedBackgroundColor(); + } + else + { + c = tcoColor; + } + } + + // Return color to caller + return c; +} + diff --git a/src/gui/TrackView.cpp b/src/gui/TrackView.cpp new file mode 100644 index 00000000000..a9387ea0d80 --- /dev/null +++ b/src/gui/TrackView.cpp @@ -0,0 +1,458 @@ +/* + * TrackView.cpp - implementation of TrackView class + * + * Copyright (c) 2004-2014 Tobias Doerffel + * + * 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. + * + */ + + +#include "TrackView.h" + +#include +#include +#include +#include +#include +#include +#include + + +#include "ConfigManager.h" +#include "DataFile.h" +#include "Engine.h" +#include "FadeButton.h" +#include "Mixer.h" +#include "PixmapButton.h" +#include "StringPairDrag.h" +#include "ToolTip.h" +#include "Track.h" +#include "TrackContainerView.h" +#include "TrackContentObjectView.h" + + +/*! \brief Create a new track View. + * + * The track View is handles the actual display of the track, including + * displaying its various widgets and the track segments. + * + * \param track The track to display. + * \param tcv The track Container View for us to be displayed in. + * \todo Is my description of these properties correct? + */ +TrackView::TrackView( Track * track, TrackContainerView * tcv ) : + QWidget( tcv->contentWidget() ), /*!< The Track Container View's content widget. */ + ModelView( NULL, this ), /*!< The model view of this track */ + m_track( track ), /*!< The track we're displaying */ + m_trackContainerView( tcv ), /*!< The track Container View we're displayed in */ + m_trackOperationsWidget( this ), /*!< Our trackOperationsWidget */ + m_trackSettingsWidget( this ), /*!< Our trackSettingsWidget */ + m_trackContentWidget( this ), /*!< Our trackContentWidget */ + m_action( NoAction ) /*!< The action we're currently performing */ +{ + setAutoFillBackground( true ); + QPalette pal; + pal.setColor( backgroundRole(), QColor( 32, 36, 40 ) ); + setPalette( pal ); + + m_trackSettingsWidget.setAutoFillBackground( true ); + + QHBoxLayout * layout = new QHBoxLayout( this ); + layout->setMargin( 0 ); + layout->setSpacing( 0 ); + layout->addWidget( &m_trackOperationsWidget ); + layout->addWidget( &m_trackSettingsWidget ); + layout->addWidget( &m_trackContentWidget, 1 ); + setFixedHeight( m_track->getHeight() ); + + resizeEvent( NULL ); + + setAcceptDrops( true ); + setAttribute( Qt::WA_DeleteOnClose, true ); + + + connect( m_track, SIGNAL( destroyedTrack() ), this, SLOT( close() ) ); + connect( m_track, + SIGNAL( trackContentObjectAdded( TrackContentObject * ) ), + this, SLOT( createTCOView( TrackContentObject * ) ), + Qt::QueuedConnection ); + + connect( &m_track->m_mutedModel, SIGNAL( dataChanged() ), + &m_trackContentWidget, SLOT( update() ) ); + + connect(&m_track->m_mutedModel, SIGNAL(dataChanged()), + this, SLOT(muteChanged())); + + connect( &m_track->m_soloModel, SIGNAL( dataChanged() ), + m_track, SLOT( toggleSolo() ), Qt::DirectConnection ); + + connect( &m_trackOperationsWidget, SIGNAL( colorChanged( QColor & ) ), + m_track, SLOT( trackColorChanged( QColor & ) ) ); + + connect( &m_trackOperationsWidget, SIGNAL( colorReset() ), + m_track, SLOT( trackColorReset() ) ); + + // create views for already existing TCOs + for( Track::tcoVector::iterator it = + m_track->m_trackContentObjects.begin(); + it != m_track->m_trackContentObjects.end(); ++it ) + { + createTCOView( *it ); + } + + m_trackContainerView->addTrackView( this ); +} + + + + +/*! \brief Destroy this track View. + * + */ +TrackView::~TrackView() +{ +} + + + + +/*! \brief Resize this track View. + * + * \param re the Resize Event to handle. + */ +void TrackView::resizeEvent( QResizeEvent * re ) +{ + if( ConfigManager::inst()->value( "ui", + "compacttrackbuttons" ).toInt() ) + { + m_trackOperationsWidget.setFixedSize( TRACK_OP_WIDTH_COMPACT, height() - 1 ); + m_trackSettingsWidget.setFixedSize( DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT, height() - 1 ); + } + else + { + m_trackOperationsWidget.setFixedSize( TRACK_OP_WIDTH, height() - 1 ); + m_trackSettingsWidget.setFixedSize( DEFAULT_SETTINGS_WIDGET_WIDTH, height() - 1 ); + } + m_trackContentWidget.setFixedHeight( height() ); +} + + + + +/*! \brief Update this track View and all its content objects. + * + */ +void TrackView::update() +{ + m_trackContentWidget.update(); + if( !m_trackContainerView->fixedTCOs() ) + { + m_trackContentWidget.changePosition(); + } + QWidget::update(); +} + + + + +/*! \brief Create a menu for assigning/creating channels for this track. + * + */ +QMenu * TrackView::createFxMenu(QString title, QString newFxLabel) +{ + Q_UNUSED(title) + Q_UNUSED(newFxLabel) + return NULL; +} + + + + +/*! \brief Close this track View. + * + */ +bool TrackView::close() +{ + m_trackContainerView->removeTrackView( this ); + return QWidget::close(); +} + + + + +/*! \brief Register that the model of this track View has changed. + * + */ +void TrackView::modelChanged() +{ + m_track = castModel(); + Q_ASSERT( m_track != NULL ); + connect( m_track, SIGNAL( destroyedTrack() ), this, SLOT( close() ) ); + m_trackOperationsWidget.m_muteBtn->setModel( &m_track->m_mutedModel ); + m_trackOperationsWidget.m_soloBtn->setModel( &m_track->m_soloModel ); + ModelView::modelChanged(); + setFixedHeight( m_track->getHeight() ); +} + + + + +/*! \brief Start a drag event on this track View. + * + * \param dee the DragEnterEvent to start. + */ +void TrackView::dragEnterEvent( QDragEnterEvent * dee ) +{ + StringPairDrag::processDragEnterEvent( dee, "track_" + + QString::number( m_track->type() ) ); +} + + + + +/*! \brief Accept a drop event on this track View. + * + * We only accept drop events that are of the same type as this track. + * If so, we decode the data from the drop event by just feeding it + * back into the engine as a state. + * + * \param de the DropEvent to handle. + */ +void TrackView::dropEvent( QDropEvent * de ) +{ + QString type = StringPairDrag::decodeKey( de ); + QString value = StringPairDrag::decodeValue( de ); + if( type == ( "track_" + QString::number( m_track->type() ) ) ) + { + // value contains our XML-data so simply create a + // DataFile which does the rest for us... + DataFile dataFile( value.toUtf8() ); + Engine::mixer()->requestChangeInModel(); + m_track->restoreState( dataFile.content().firstChild().toElement() ); + Engine::mixer()->doneChangeInModel(); + de->accept(); + } +} + + + + +/*! \brief Handle a mouse press event on this track View. + * + * If this track container supports rubber band selection, let the + * widget handle that and don't bother with any other handling. + * + * If the left mouse button is pressed, we handle two things. If + * SHIFT is pressed, then we resize vertically. Otherwise we start + * the process of moving this track to a new position. + * + * Otherwise we let the widget handle the mouse event as normal. + * + * \param me the MouseEvent to handle. + */ +void TrackView::mousePressEvent( QMouseEvent * me ) +{ + + // If previously dragged too small, restore on shift-leftclick + if( height() < DEFAULT_TRACK_HEIGHT && + me->modifiers() & Qt::ShiftModifier && + me->button() == Qt::LeftButton ) + { + setFixedHeight( DEFAULT_TRACK_HEIGHT ); + m_track->setHeight( DEFAULT_TRACK_HEIGHT ); + } + + + int widgetTotal = ConfigManager::inst()->value( "ui", + "compacttrackbuttons" ).toInt()==1 ? + DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT + TRACK_OP_WIDTH_COMPACT : + DEFAULT_SETTINGS_WIDGET_WIDTH + TRACK_OP_WIDTH; + if( m_trackContainerView->allowRubberband() == true && me->x() > widgetTotal ) + { + QWidget::mousePressEvent( me ); + } + else if( me->button() == Qt::LeftButton ) + { + if( me->modifiers() & Qt::ShiftModifier ) + { + m_action = ResizeTrack; + QCursor::setPos( mapToGlobal( QPoint( me->x(), + height() ) ) ); + QCursor c( Qt::SizeVerCursor); + QApplication::setOverrideCursor( c ); + } + else + { + if( me->x()>10 ) // 10 = The width of the grip + 2 pixels to the left and right. + { + QWidget::mousePressEvent( me ); + return; + } + + m_action = MoveTrack; + + QCursor c( Qt::SizeVerCursor ); + QApplication::setOverrideCursor( c ); + // update because in move-mode, all elements in + // track-op-widgets are hidden as a visual feedback + m_trackOperationsWidget.update(); + } + + me->accept(); + } + else + { + QWidget::mousePressEvent( me ); + } +} + + + + +/*! \brief Handle a mouse move event on this track View. + * + * If this track container supports rubber band selection, let the + * widget handle that and don't bother with any other handling. + * + * Otherwise if we've started the move process (from mousePressEvent()) + * then move ourselves into that position, reordering the track list + * with moveTrackViewUp() and moveTrackViewDown() to suit. We make a + * note of this in the undo journal in case the user wants to undo this + * move. + * + * Likewise if we've started a resize process, handle this too, making + * sure that we never go below the minimum track height. + * + * \param me the MouseEvent to handle. + */ +void TrackView::mouseMoveEvent( QMouseEvent * me ) +{ + int widgetTotal = ConfigManager::inst()->value( "ui", + "compacttrackbuttons" ).toInt()==1 ? + DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT + TRACK_OP_WIDTH_COMPACT : + DEFAULT_SETTINGS_WIDGET_WIDTH + TRACK_OP_WIDTH; + if( m_trackContainerView->allowRubberband() == true && me->x() > widgetTotal ) + { + QWidget::mouseMoveEvent( me ); + } + else if( m_action == MoveTrack ) + { + // look which track-widget the mouse-cursor is over + const int yPos = + m_trackContainerView->contentWidget()->mapFromGlobal( me->globalPos() ).y(); + const TrackView * trackAtY = m_trackContainerView->trackViewAt( yPos ); + + // debug code + // qDebug( "y position %d", yPos ); + + // a track-widget not equal to ourself? + if( trackAtY != NULL && trackAtY != this ) + { + // then move us up/down there! + if( me->y() < 0 ) + { + m_trackContainerView->moveTrackViewUp( this ); + } + else + { + m_trackContainerView->moveTrackViewDown( this ); + } + } + } + else if( m_action == ResizeTrack ) + { + setFixedHeight( qMax( me->y(), MINIMAL_TRACK_HEIGHT ) ); + m_trackContainerView->realignTracks(); + m_track->setHeight( height() ); + } + + if( height() < DEFAULT_TRACK_HEIGHT ) + { + ToolTip::add( this, m_track->m_name ); + } +} + + + +/*! \brief Handle a mouse release event on this track View. + * + * \param me the MouseEvent to handle. + */ +void TrackView::mouseReleaseEvent( QMouseEvent * me ) +{ + m_action = NoAction; + while( QApplication::overrideCursor() != NULL ) + { + QApplication::restoreOverrideCursor(); + } + m_trackOperationsWidget.update(); + + QWidget::mouseReleaseEvent( me ); +} + + + + +/*! \brief Repaint this track View. + * + * \param pe the PaintEvent to start. + */ +void TrackView::paintEvent( QPaintEvent * pe ) +{ + QStyleOption opt; + opt.initFrom( this ); + QPainter p( this ); + style()->drawPrimitive( QStyle::PE_Widget, &opt, &p, this ); +} + + + + +/*! \brief Create a TrackContentObject View in this track View. + * + * \param tco the TrackContentObject to create the view for. + * \todo is this a good description for what this method does? + */ +void TrackView::createTCOView( TrackContentObject * tco ) +{ + TrackContentObjectView * tv = tco->createView( this ); + if( tco->getSelectViewOnCreate() == true ) + { + tv->setSelected( true ); + } + tco->selectViewOnCreate( false ); +} + + + + +void TrackView::muteChanged() +{ + FadeButton * indicator = getActivityIndicator(); + if (indicator) { setIndicatorMute(indicator, m_track->m_mutedModel.value()); } +} + + + + +void TrackView::setIndicatorMute(FadeButton* indicator, bool muted) +{ + QPalette::ColorRole role = muted ? QPalette::Highlight : QPalette::BrightText; + indicator->setActiveColor(QApplication::palette().color(QPalette::Active, role)); +} diff --git a/src/gui/dialogs/ColorChooser.cpp b/src/gui/dialogs/ColorChooser.cpp new file mode 100644 index 00000000000..b25aa97be6c --- /dev/null +++ b/src/gui/dialogs/ColorChooser.cpp @@ -0,0 +1,93 @@ +/* ColorChooser.cpp - definition of ColorChooser class. + * + * Copyright (c) 2020 russiankumar + * + * 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. + * + */ + +#include + + + + +//! Set global palette via array, checking bounds +void ColorChooser::setPalette (QVector colors) +{ + const int max = qMin (colors.size(), 48); + for (int i = 0; i < max; i++) + { + ColorChooser::setStandardColor (i, colors[i]); + } +} + + +//! Set global paletter via enum +void ColorChooser::setPalette (Palette palette) +{ + setPalette (getPalette (palette)); +} + + +//! Set palette via enum, return self pointer for chaining +ColorChooser* ColorChooser::withPalette (Palette palette) +{ + setPalette (palette); + return this; +} + + +//! Return a certain palette +QVector ColorChooser::getPalette (Palette palette) +{ + switch (palette) + { + case Palette::Mixer: return nicePalette(140); + case Palette::Track: return nicePalette(150); + default: return defaultPalette(); + } +} + + + + +//! Copy the current QColorDialog palette into an array +QVector ColorChooser::defaultPalette() +{ + QVector result (48); + for (int i = 0; i < 48; i++) + { + result[i] = (QColorDialog::standardColor(i)); + } + return result; +} + + +//! Generate a nice palette, with adjustable value +QVector ColorChooser::nicePalette (int base) +{ + QVector result (48); + for (int x = 0; x < 8; x++) + { + for (int y = 0; y < 6; y++) + { + result[6 * x + y].setHsl (qMax(0, 44 * x - 1), 150 - 20 * y, base - 10 * y); + } + } + return result; +} diff --git a/src/gui/dialogs/FileDialog.cpp b/src/gui/dialogs/FileDialog.cpp index 54cc9d6e4d7..848a7f52a7c 100644 --- a/src/gui/dialogs/FileDialog.cpp +++ b/src/gui/dialogs/FileDialog.cpp @@ -84,11 +84,9 @@ QString FileDialog::getOpenFileName(QWidget *parent, const QString &caption, const QString &directory, const QString &filter, - QString *selectedFilter, - QFileDialog::Options options) + QString *selectedFilter) { FileDialog dialog(parent, caption, directory, filter); - dialog.setOptions(dialog.options() | options); if (selectedFilter && !selectedFilter->isEmpty()) dialog.selectNameFilter(*selectedFilter); if (dialog.exec() == QDialog::Accepted) { diff --git a/src/gui/dialogs/VersionedSaveDialog.cpp b/src/gui/dialogs/VersionedSaveDialog.cpp index 18993c23bf4..d26f198915a 100644 --- a/src/gui/dialogs/VersionedSaveDialog.cpp +++ b/src/gui/dialogs/VersionedSaveDialog.cpp @@ -31,6 +31,7 @@ #include #include +#include "DeprecationHelper.h" #include "VersionedSaveDialog.h" #include "LedCheckbox.h" @@ -50,8 +51,8 @@ VersionedSaveDialog::VersionedSaveDialog( QWidget *parent, plusButton->setToolTip( tr( "Increment version number" ) ); QPushButton *minusButton( new QPushButton( "-", this ) ); minusButton->setToolTip( tr( "Decrement version number" ) ); - plusButton->setFixedWidth( plusButton->fontMetrics().width( "+" ) + 30 ); - minusButton->setFixedWidth( minusButton->fontMetrics().width( "+" ) + 30 ); + plusButton->setFixedWidth(horizontalAdvance(plusButton->fontMetrics(), "+") + 30); + minusButton->setFixedWidth(horizontalAdvance(minusButton->fontMetrics(), "+") + 30); // Add buttons to grid layout. For doing this, remove the lineEdit and // replace it with a HBox containing lineEdit and the buttons. diff --git a/src/gui/editors/AutomationEditor.cpp b/src/gui/editors/AutomationEditor.cpp index 048123ef5f8..c5116b9281a 100644 --- a/src/gui/editors/AutomationEditor.cpp +++ b/src/gui/editors/AutomationEditor.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -44,21 +45,22 @@ #endif #include "ActionGroup.h" -#include "SongEditor.h" -#include "MainWindow.h" +#include "BBTrackContainer.h" +#include "ComboBox.h" +#include "debug.h" +#include "DeprecationHelper.h" #include "GuiApplication.h" +#include "MainWindow.h" #include "embed.h" #include "Engine.h" #include "gui_templates.h" -#include "TimeLineWidget.h" -#include "ToolTip.h" -#include "TextFloat.h" -#include "ComboBox.h" -#include "BBTrackContainer.h" #include "PianoRoll.h" -#include "debug.h" -#include "StringPairDrag.h" #include "ProjectJournal.h" +#include "SongEditor.h" +#include "StringPairDrag.h" +#include "TextFloat.h" +#include "TimeLineWidget.h" +#include "ToolTip.h" QPixmap * AutomationEditor::s_toolDraw = NULL; @@ -123,16 +125,9 @@ AutomationEditor::AutomationEditor() : connect( m_tensionModel, SIGNAL( dataChanged() ), this, SLOT( setTension() ) ); - for( int i = 0; i < 7; ++i ) - { - m_quantizeModel.addItem( "1/" + QString::number( 1 << i ) ); - } - for( int i = 0; i < 5; ++i ) - { - m_quantizeModel.addItem( "1/" + - QString::number( ( 1 << i ) * 3 ) ); + for (auto q : Quantizations) { + m_quantizeModel.addItem(QString("1/%1").arg(q)); } - m_quantizeModel.addItem( "1/192" ); connect( &m_quantizeModel, SIGNAL(dataChanged() ), this, SLOT( setQuantization() ) ); @@ -155,10 +150,10 @@ AutomationEditor::AutomationEditor() : Song::Mode_PlayAutomationPattern ), m_currentPosition, Song::Mode_PlayAutomationPattern, this ); - connect( this, SIGNAL( positionChanged( const MidiTime & ) ), - m_timeLine, SLOT( updatePosition( const MidiTime & ) ) ); - connect( m_timeLine, SIGNAL( positionChanged( const MidiTime & ) ), - this, SLOT( updatePosition( const MidiTime & ) ) ); + connect( this, SIGNAL( positionChanged( const TimePos & ) ), + m_timeLine, SLOT( updatePosition( const TimePos & ) ) ); + connect( m_timeLine, SIGNAL( positionChanged( const TimePos & ) ), + this, SLOT( updatePosition( const TimePos & ) ) ); removeSelection(); @@ -326,7 +321,7 @@ void AutomationEditor::updateAfterPatternChange() m_minLevel = m_pattern->firstObject()->minValue(); m_maxLevel = m_pattern->firstObject()->maxValue(); m_step = m_pattern->firstObject()->step(); - m_scrollLevel = ( m_minLevel + m_maxLevel ) / 2; + centerTopBottomScroll(); m_tensionModel->setValue( m_pattern->getTension() ); @@ -487,8 +482,8 @@ void AutomationEditor::drawLine( int x0In, float y0, int x1In, float y1 ) x += xstep; i += 1; - m_pattern->removeValue( MidiTime( x ) ); - m_pattern->putValue( MidiTime( x ), y ); + m_pattern->removeValue( TimePos( x ) ); + m_pattern->putValue( TimePos( x ), y ); } } @@ -515,7 +510,7 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent ) x -= VALUES_WIDTH; // get tick in which the user clicked - int pos_ticks = x * MidiTime::ticksPerBar() / m_ppb + + int pos_ticks = x * TimePos::ticksPerBar() / m_ppb + m_currentPosition; // get time map of current pattern @@ -532,7 +527,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::ticksPerBar() *4 / m_ppb ) && + ( pos_ticks<= it.key() + TimePos::ticksPerBar() *4 / m_ppb ) && ( level == it.value() || mouseEvent->button() == Qt::RightButton ) ) { break; @@ -570,9 +565,9 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent ) if( it == time_map.end() ) { // then set new value - MidiTime value_pos( pos_ticks ); + TimePos value_pos( pos_ticks ); - MidiTime new_time = + TimePos new_time = m_pattern->setDragValue( value_pos, level, true, mouseEvent->modifiers() & @@ -589,7 +584,7 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent ) int aligned_x = (int)( (float)( ( it.key() - m_currentPosition ) * - m_ppb ) / MidiTime::ticksPerBar() ); + m_ppb ) / TimePos::ticksPerBar() ); m_moveXOffset = x - aligned_x - 1; // set move-cursor QCursor c( Qt::SizeAllCursor ); @@ -722,7 +717,7 @@ void AutomationEditor::removePoints( int x0, int x1 ) int i = 0; while( i <= deltax ) { - m_pattern->removeValue( MidiTime( x ) ); + m_pattern->removeValue( TimePos( x ) ); x += xstep; i += 1; } @@ -751,7 +746,7 @@ void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent ) x -= m_moveXOffset; } - int pos_ticks = x * MidiTime::ticksPerBar() / m_ppb + + int pos_ticks = x * TimePos::ticksPerBar() / m_ppb + m_currentPosition; // m_mouseDownLeft used to prevent drag when drawing line if (m_mouseDownLeft && m_editMode == DRAW) @@ -773,7 +768,7 @@ void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent ) // we moved the value so the value has to be // moved properly according to new starting- // time in the time map of pattern - m_pattern->setDragValue( MidiTime( pos_ticks ), + m_pattern->setDragValue( TimePos( pos_ticks ), level, true, mouseEvent->modifiers() & Qt::ControlModifier ); @@ -884,7 +879,7 @@ void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent ) } // get tick in which the cursor is posated - int pos_ticks = x * MidiTime::ticksPerBar() / m_ppb + + int pos_ticks = x * TimePos::ticksPerBar() / m_ppb + m_currentPosition; m_selectedTick = pos_ticks - m_selectStartTick; @@ -905,7 +900,7 @@ void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent ) // move selection + selected values // do horizontal move-stuff - int pos_ticks = x * MidiTime::ticksPerBar() / m_ppb + + int pos_ticks = x * TimePos::ticksPerBar() / m_ppb + m_currentPosition; int ticks_diff = pos_ticks - m_moveStartTick; @@ -930,8 +925,8 @@ void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent ) } m_selectStartTick += ticks_diff; - int bar_diff = ticks_diff / MidiTime::ticksPerBar(); - ticks_diff = ticks_diff % MidiTime::ticksPerBar(); + int bar_diff = ticks_diff / TimePos::ticksPerBar(); + ticks_diff = ticks_diff % TimePos::ticksPerBar(); // do vertical move-stuff @@ -976,27 +971,27 @@ void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent ) for( timeMap::iterator it = m_selValuesForMove.begin(); it != m_selValuesForMove.end(); ++it ) { - MidiTime new_value_pos; + TimePos new_value_pos; if( it.key() ) { int value_bar = ( it.key() / - MidiTime::ticksPerBar() ) + TimePos::ticksPerBar() ) + bar_diff; int value_ticks = ( it.key() % - MidiTime::ticksPerBar() ) + TimePos::ticksPerBar() ) + ticks_diff; // ensure value_ticks range - if( value_ticks / MidiTime::ticksPerBar() ) + if( value_ticks / TimePos::ticksPerBar() ) { value_bar += value_ticks - / MidiTime::ticksPerBar(); + / TimePos::ticksPerBar(); value_ticks %= - MidiTime::ticksPerBar(); + TimePos::ticksPerBar(); } m_pattern->removeValue( it.key() ); - new_value_pos = MidiTime( value_bar, + new_value_pos = TimePos( value_bar, value_ticks ); } new_selValuesForMove[ @@ -1044,7 +1039,7 @@ void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent ) } // get tick in which the cursor is posated - int pos_ticks = x * MidiTime::ticksPerBar() / m_ppb + + int pos_ticks = x * TimePos::ticksPerBar() / m_ppb + m_currentPosition; m_selectedTick = pos_ticks - @@ -1300,7 +1295,7 @@ 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::ticksPerBar(); + int leftBars = m_currentPosition * zoomFactor / TimePos::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_ppb, ++barCount ) @@ -1326,10 +1321,10 @@ void AutomationEditor::paintEvent(QPaintEvent * pe ) } // and finally bars - for( tick = m_currentPosition - m_currentPosition % MidiTime::ticksPerBar(), + for( tick = m_currentPosition - m_currentPosition % TimePos::ticksPerBar(), x = xCoordOfTick( tick ); x<=width(); - tick += MidiTime::ticksPerBar(), x = xCoordOfTick( tick ) ) + tick += TimePos::ticksPerBar(), x = xCoordOfTick( tick ) ) { p.setPen( barLineColor() ); p.drawLine( x, grid_bottom, x, x_line_end ); @@ -1465,8 +1460,8 @@ void AutomationEditor::paintEvent(QPaintEvent * pe ) // now draw selection-frame int x = ( sel_pos_start - m_currentPosition ) * m_ppb / - MidiTime::ticksPerBar(); - int w = ( sel_pos_end - sel_pos_start ) * m_ppb / MidiTime::ticksPerBar(); + TimePos::ticksPerBar(); + int w = ( sel_pos_end - sel_pos_start ) * m_ppb / TimePos::ticksPerBar(); int y, h; if( m_y_auto ) { @@ -1538,7 +1533,7 @@ void AutomationEditor::paintEvent(QPaintEvent * pe ) int AutomationEditor::xCoordOfTick(int tick ) { return VALUES_WIDTH + ( ( tick - m_currentPosition ) - * m_ppb / MidiTime::ticksPerBar() ); + * m_ppb / TimePos::ticksPerBar() ); } @@ -1601,12 +1596,36 @@ void AutomationEditor::drawLevelTick(QPainter & p, int tick, float value) p.fillRect( x, y_start, rect_width, rect_height, currentColor ); } - +#ifdef LMMS_DEBUG else { printf("not in range\n"); } +#endif +} + + + +// center the vertical scroll position on the first object's value +void AutomationEditor::centerTopBottomScroll() +{ + // default to the m_scrollLevel position + int pos = static_cast(m_scrollLevel); + // If a pattern exists... + if (m_pattern) + { + // get time map of current pattern + timeMap & time_map = m_pattern->getTimeMap(); + // If time_map is not empty... + if (!time_map.empty()) + { + // set the position to the inverted value ((max + min) - value) + // If we set just (max - value), we're off by m_pattern's minimum + pos = m_pattern->getMax() + m_pattern->getMin() - static_cast(time_map.begin().value()); + } + } + m_topBottomScroll->setValue(pos); } @@ -1638,8 +1657,7 @@ void AutomationEditor::resizeEvent(QResizeEvent * re) m_topBottomScroll->setRange( (int) m_scrollLevel, (int) m_scrollLevel ); } - - m_topBottomScroll->setValue( (int) m_scrollLevel ); + centerTopBottomScroll(); if( Engine::getSong() ) { @@ -1660,11 +1678,11 @@ void AutomationEditor::wheelEvent(QWheelEvent * we ) if( we->modifiers() & Qt::ControlModifier && we->modifiers() & Qt::ShiftModifier ) { int y = m_zoomingYModel.value(); - if( we->delta() > 0 ) + if(we->angleDelta().y() > 0) { y++; } - else if( we->delta() < 0 ) + else if(we->angleDelta().y() < 0) { y--; } @@ -1674,11 +1692,11 @@ void AutomationEditor::wheelEvent(QWheelEvent * we ) else if( we->modifiers() & Qt::ControlModifier && we->modifiers() & Qt::AltModifier ) { int q = m_quantizeModel.value(); - if( we->delta() > 0 ) + if((we->angleDelta().x() + we->angleDelta().y()) > 0) // alt + scroll becomes horizontal scroll on KDE { q--; } - else if( we->delta() < 0 ) + else if((we->angleDelta().x() + we->angleDelta().y()) < 0) // alt + scroll becomes horizontal scroll on KDE { q++; } @@ -1689,17 +1707,17 @@ void AutomationEditor::wheelEvent(QWheelEvent * we ) else if( we->modifiers() & Qt::ControlModifier ) { int x = m_zoomingXModel.value(); - if( we->delta() > 0 ) + if(we->angleDelta().y() > 0) { x++; } - else if( we->delta() < 0 ) + else if(we->angleDelta().y() < 0) { x--; } x = qBound( 0, x, m_zoomingXModel.size() - 1 ); - int mouseX = (we->x() - VALUES_WIDTH)* MidiTime::ticksPerBar(); + int mouseX = (position( we ).x() - VALUES_WIDTH)* TimePos::ticksPerBar(); // ticks based on the mouse x-position where the scroll wheel was used int ticks = mouseX / m_ppb; // what would be the ticks in the new zoom level on the very same mouse x @@ -1711,16 +1729,22 @@ void AutomationEditor::wheelEvent(QWheelEvent * we ) m_zoomingXModel.setValue( x ); } - else if( we->modifiers() & Qt::ShiftModifier - || we->orientation() == Qt::Horizontal ) + + // FIXME: Reconsider if determining orientation is necessary in Qt6. + else if(abs(we->angleDelta().x()) > abs(we->angleDelta().y())) // scrolling is horizontal + { + m_leftRightScroll->setValue(m_leftRightScroll->value() - + we->angleDelta().x() * 2 / 15); + } + else if(we->modifiers() & Qt::ShiftModifier) { - m_leftRightScroll->setValue( m_leftRightScroll->value() - - we->delta() * 2 / 15 ); + m_leftRightScroll->setValue(m_leftRightScroll->value() - + we->angleDelta().y() * 2 / 15); } else { - m_topBottomScroll->setValue( m_topBottomScroll->value() - - we->delta() / 30 ); + m_topBottomScroll->setValue(m_topBottomScroll->value() - + (we->angleDelta().x() + we->angleDelta().y()) / 30); } } @@ -1970,7 +1994,7 @@ void AutomationEditor::getSelectedValues( timeMap & selected_values ) ++it ) { //TODO: Add constant - tick_t len_ticks = MidiTime::ticksPerBar() / 16; + tick_t len_ticks = TimePos::ticksPerBar() / 16; float level = it.value(); tick_t pos_ticks = it.key(); @@ -2099,7 +2123,7 @@ void AutomationEditor::deleteSelectedValues() -void AutomationEditor::updatePosition(const MidiTime & t ) +void AutomationEditor::updatePosition(const TimePos & t ) { if( ( Engine::getSong()->isPlaying() && Engine::getSong()->playMode() == @@ -2107,17 +2131,17 @@ void AutomationEditor::updatePosition(const MidiTime & t ) m_scrollBack == true ) { const int w = width() - VALUES_WIDTH; - if( t > m_currentPosition + w * MidiTime::ticksPerBar() / m_ppb ) + if( t > m_currentPosition + w * TimePos::ticksPerBar() / m_ppb ) { m_leftRightScroll->setValue( t.getBar() * - MidiTime::ticksPerBar() ); + TimePos::ticksPerBar() ); } else if( t < m_currentPosition ) { - MidiTime t_ = qMax( t - w * MidiTime::ticksPerBar() * - MidiTime::ticksPerBar() / m_ppb, 0 ); + TimePos t_ = qMax( t - w * TimePos::ticksPerBar() * + TimePos::ticksPerBar() / m_ppb, 0 ); m_leftRightScroll->setValue( t_.getBar() * - MidiTime::ticksPerBar() ); + TimePos::ticksPerBar() ); } m_scrollBack = false; } @@ -2159,22 +2183,7 @@ void AutomationEditor::zoomingYChanged() void AutomationEditor::setQuantization() { - int quantization = m_quantizeModel.value(); - if( quantization < 7 ) - { - quantization = 1 << quantization; - } - else if( quantization < 12 ) - { - quantization = 1 << ( quantization - 7 ); - quantization *= 3; - } - else - { - quantization = DefaultTicksPerBar; - } - quantization = DefaultTicksPerBar / quantization; - AutomationPattern::setQuantization( quantization ); + AutomationPattern::setQuantization(DefaultTicksPerBar / Quantizations[m_quantizeModel.value()]); update(); } @@ -2347,7 +2356,7 @@ AutomationEditorWindow::AutomationEditorWindow() : zoom_x_label->setPixmap( embed::getIconPixmap( "zoom_x" ) ); m_zoomingXComboBox = new ComboBox( zoomToolBar ); - m_zoomingXComboBox->setFixedSize( 80, 22 ); + m_zoomingXComboBox->setFixedSize( 80, ComboBox::DEFAULT_HEIGHT ); m_zoomingXComboBox->setToolTip( tr( "Horizontal zooming" ) ); for( float const & zoomLevel : m_editor->m_zoomXLevels ) @@ -2366,7 +2375,7 @@ AutomationEditorWindow::AutomationEditorWindow() : zoom_y_label->setPixmap( embed::getIconPixmap( "zoom_y" ) ); m_zoomingYComboBox = new ComboBox( zoomToolBar ); - m_zoomingYComboBox->setFixedSize( 80, 22 ); + m_zoomingYComboBox->setFixedSize( 80, ComboBox::DEFAULT_HEIGHT ); m_zoomingYComboBox->setToolTip( tr( "Vertical zooming" ) ); m_editor->m_zoomingYModel.addItem( "Auto" ); @@ -2396,7 +2405,7 @@ AutomationEditorWindow::AutomationEditorWindow() : quantize_lbl->setPixmap( embed::getIconPixmap( "quantize" ) ); m_quantizeComboBox = new ComboBox( m_toolBar ); - m_quantizeComboBox->setFixedSize( 60, 22 ); + m_quantizeComboBox->setFixedSize( 60, ComboBox::DEFAULT_HEIGHT ); m_quantizeComboBox->setToolTip( tr( "Quantization" ) ); m_quantizeComboBox->setModel( &m_editor->m_quantizeModel ); diff --git a/src/gui/editors/BBEditor.cpp b/src/gui/editors/BBEditor.cpp index 56fe298561f..f40d30bdac8 100644 --- a/src/gui/editors/BBEditor.cpp +++ b/src/gui/editors/BBEditor.cpp @@ -29,7 +29,9 @@ #include #include "ComboBox.h" +#include "BBTrack.h" #include "BBTrackContainer.h" +#include "DataFile.h" #include "embed.h" #include "MainWindow.h" #include "Song.h" @@ -74,7 +76,7 @@ BBEditor::BBEditor( BBTrackContainer* tc ) : DropToolBar *beatSelectionToolBar = addDropToolBarToTop(tr("Beat selector")); m_bbComboBox = new ComboBox( m_toolBar ); - m_bbComboBox->setFixedSize( 200, 22 ); + m_bbComboBox->setFixedSize( 200, ComboBox::DEFAULT_HEIGHT ); m_bbComboBox->setModel( &tc->m_bbComboBoxModel ); beatSelectionToolBar->addWidget( m_bbComboBox ); @@ -86,6 +88,8 @@ BBEditor::BBEditor( BBTrackContainer* tc ) : trackAndStepActionsToolBar->addAction(embed::getIconPixmap("add_bb_track"), tr("Add beat/bassline"), Engine::getSong(), SLOT(addBBTrack())); + trackAndStepActionsToolBar->addAction(embed::getIconPixmap("clone_bb_track_pattern"), tr("Clone beat/bassline pattern"), + m_trackContainerView, SLOT(clonePattern())); trackAndStepActionsToolBar->addAction( embed::getIconPixmap("add_sample_track"), tr("Add sample-track"), m_trackContainerView, @@ -257,7 +261,7 @@ void BBTrackContainerView::dropEvent(QDropEvent* de) hasValidBBTCOs = true; for (int i = 0; i < t->getTCOs().size(); ++i) { - if (t->getTCOs()[i]->startPosition() != MidiTime(i, 0)) + if (t->getTCOs()[i]->startPosition() != TimePos(i, 0)) { hasValidBBTCOs = false; break; @@ -311,3 +315,22 @@ void BBTrackContainerView::makeSteps( bool clone ) } } } + +// Creates a clone of the current BB track with the same pattern, but no TCOs in the song editor +// TODO: Avoid repeated code from cloneTrack and clearTrack in TrackOperationsWidget somehow +void BBTrackContainerView::clonePattern() +{ + // Get the current BBTrack id + BBTrackContainer *bbtc = static_cast(model()); + const int cur_bb = bbtc->currentBB(); + + BBTrack *bbt = BBTrack::findBBTrack(cur_bb); + + // Clone the track + Track *newTrack = bbt->clone(); + + // Track still have the TCOs which is undesirable in this case, clear the track + newTrack->lock(); + newTrack->deleteTCOs(); + newTrack->unlock(); +} diff --git a/src/gui/editors/Editor.cpp b/src/gui/editors/Editor.cpp index c27eda4c06c..dc86a1789dc 100644 --- a/src/gui/editors/Editor.cpp +++ b/src/gui/editors/Editor.cpp @@ -74,6 +74,16 @@ void Editor::togglePlayStop() play(); } +void Editor::togglePause() +{ + Engine::getSong()->togglePause(); +} + +void Editor::toggleMaximize() +{ + isMaximized() ? showNormal() : showMaximized(); +} + Editor::Editor(bool record, bool stepRecord) : m_toolBar(new DropToolBar(this)), m_playAction(nullptr), @@ -104,6 +114,8 @@ Editor::Editor(bool record, bool stepRecord) : connect(m_toggleStepRecordingAction, SIGNAL(triggered()), this, SLOT(toggleStepRecording())); connect(m_stopAction, SIGNAL(triggered()), this, SLOT(stop())); new QShortcut(Qt::Key_Space, this, SLOT(togglePlayStop())); + new QShortcut(QKeySequence(Qt::SHIFT + Qt::Key_Space), this, SLOT(togglePause())); + new QShortcut(QKeySequence(Qt::SHIFT + Qt::Key_F11), this, SLOT(toggleMaximize())); // Add actions to toolbar addButton(m_playAction, "playButton"); diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 4682b3f20b7..cee6870b7a3 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -36,6 +36,8 @@ #include #include #include +#include +#include #ifndef __USE_XOPEN #define __USE_XOPEN @@ -46,11 +48,13 @@ #include "AutomationEditor.h" #include "ActionGroup.h" -#include "ConfigManager.h" #include "BBTrackContainer.h" #include "Clipboard.h" #include "ComboBox.h" +#include "ConfigManager.h" +#include "DataFile.h" #include "debug.h" +#include "DeprecationHelper.h" #include "DetuningHelper.h" #include "embed.h" #include "GuiApplication.h" @@ -59,10 +63,9 @@ #include "MainWindow.h" #include "Pattern.h" #include "SongEditor.h" -#include "stdshims.h" +#include "StepRecorderWidget.h" #include "TextFloat.h" #include "TimeLineWidget.h" -#include "StepRecorderWidget.h" using std::move; @@ -72,7 +75,7 @@ typedef AutomationPattern::timeMap timeMap; // some constants... const int INITIAL_PIANOROLL_WIDTH = 860; -const int INITIAL_PIANOROLL_HEIGHT = 480; +const int INITIAL_PIANOROLL_HEIGHT = 485; const int SCROLLBAR_SIZE = 12; const int PIANO_X = 0; @@ -86,9 +89,9 @@ const int DEFAULT_CELL_WIDTH = 12; const int NOTE_EDIT_RESIZE_BAR = 6; const int NOTE_EDIT_MIN_HEIGHT = 50; -const int KEY_AREA_MIN_HEIGHT = 100; +const int KEY_AREA_MIN_HEIGHT = DEFAULT_KEY_LINE_HEIGHT * 10; const int PR_BOTTOM_MARGIN = SCROLLBAR_SIZE; -const int PR_TOP_MARGIN = 16; +const int PR_TOP_MARGIN = 18; const int PR_RIGHT_MARGIN = SCROLLBAR_SIZE; @@ -107,12 +110,6 @@ const int NUM_TRIPLET_LENGTHS = 5; -QPixmap * PianoRoll::s_whiteKeySmallPm = NULL; -QPixmap * PianoRoll::s_whiteKeySmallPressedPm = NULL; -QPixmap * PianoRoll::s_whiteKeyBigPm = NULL; -QPixmap * PianoRoll::s_whiteKeyBigPressedPm = NULL; -QPixmap * PianoRoll::s_blackKeyPm = NULL; -QPixmap * PianoRoll::s_blackKeyPressedPm = NULL; QPixmap * PianoRoll::s_toolDraw = NULL; QPixmap * PianoRoll::s_toolErase = NULL; QPixmap * PianoRoll::s_toolSelect = NULL; @@ -170,17 +167,18 @@ PianoRoll::PianoRoll() : m_mouseDownTick( 0 ), m_lastMouseX( 0 ), m_lastMouseY( 0 ), - m_oldNotesEditHeight( 100 ), m_notesEditHeight( 100 ), + m_userSetNotesEditHeight(100), m_ppb( DEFAULT_PR_PPB ), m_keyLineHeight(DEFAULT_KEY_LINE_HEIGHT), m_octaveHeight(m_keyLineHeight * KeysPerOctave), - m_whiteKeySmallHeight(round(m_keyLineHeight * 1.5)), + m_whiteKeySmallHeight(qFloor(m_keyLineHeight * 1.5)), m_whiteKeyBigHeight(m_keyLineHeight * 2), - m_blackKeyHeight(round(m_keyLineHeight * 1.3333)), - m_lenOfNewNotes( MidiTime( 0, DefaultTicksPerBar/4 ) ), + m_blackKeyHeight(m_keyLineHeight), + m_lenOfNewNotes( TimePos( 0, DefaultTicksPerBar/4 ) ), m_lastNoteVolume( DefaultVolume ), m_lastNotePanning( DefaultPanning ), + m_minResizeLen( 0 ), m_startKey( INITIAL_START_KEY ), m_lastKey( 0 ), m_editMode( ModeDraw ), @@ -206,7 +204,9 @@ PianoRoll::PianoRoll() : m_ghostNoteOpacity( 255 ), m_noteBorders( true ), m_ghostNoteBorders( true ), - m_backgroundShade( 0, 0, 0 ) + m_backgroundShade( 0, 0, 0 ), + m_whiteKeyWidth(WHITE_KEY_WIDTH), + m_blackKeyWidth(BLACK_KEY_WIDTH) { // gui names of edit modes m_nemStr.push_back( tr( "Note Velocity" ) ); @@ -251,36 +251,6 @@ PianoRoll::PianoRoll() : m_semiToneMarkerMenu->addAction( copyAllNotesAction ); // init pixmaps - if( s_whiteKeySmallPm == NULL ) - { - s_whiteKeySmallPm = new QPixmap( embed::getIconPixmap( - "pr_white_key_small" ) ); - } - if( s_whiteKeySmallPressedPm == NULL ) - { - s_whiteKeySmallPressedPm = new QPixmap( embed::getIconPixmap( - "pr_white_key_small_pressed" ) ); - } - if( s_whiteKeyBigPm == NULL ) - { - s_whiteKeyBigPm = new QPixmap( embed::getIconPixmap( - "pr_white_key_big" ) ); - } - if( s_whiteKeyBigPressedPm == NULL ) - { - s_whiteKeyBigPressedPm = new QPixmap( embed::getIconPixmap( - "pr_white_key_big_pressed" ) ); - } - if( s_blackKeyPm == NULL ) - { - s_blackKeyPm = new QPixmap( embed::getIconPixmap( - "pr_black_key" ) ); - } - if( s_blackKeyPressedPm == NULL ) - { - s_blackKeyPressedPm = new QPixmap( embed::getIconPixmap( - "pr_black_key_pressed" ) ); - } if( s_toolDraw == NULL ) { s_toolDraw = new QPixmap( embed::getIconPixmap( "edit_draw" ) ); @@ -311,30 +281,33 @@ PianoRoll::PianoRoll() : setAttribute( Qt::WA_OpaquePaintEvent, true ); // add time-line - m_timeLine = new TimeLineWidget( WHITE_KEY_WIDTH, 0, m_ppb, + m_timeLine = new TimeLineWidget(m_whiteKeyWidth, 0, m_ppb, Engine::getSong()->getPlayPos( Song::Mode_PlayPattern ), m_currentPosition, Song::Mode_PlayPattern, this ); - connect( this, SIGNAL( positionChanged( const MidiTime & ) ), - m_timeLine, SLOT( updatePosition( const MidiTime & ) ) ); - connect( m_timeLine, SIGNAL( positionChanged( const MidiTime & ) ), - this, SLOT( updatePosition( const MidiTime & ) ) ); + connect( this, SIGNAL( positionChanged( const TimePos & ) ), + m_timeLine, SLOT( updatePosition( const TimePos & ) ) ); + connect( m_timeLine, SIGNAL( positionChanged( const TimePos & ) ), + this, SLOT( updatePosition( const TimePos & ) ) ); + + // white position line follows timeline marker + m_positionLine = new PositionLine(this); //update timeline when in step-recording mode - connect( &m_stepRecorderWidget, SIGNAL( positionChanged( const MidiTime & ) ), - this, SLOT( updatePositionStepRecording( const MidiTime & ) ) ); + connect( &m_stepRecorderWidget, SIGNAL( positionChanged( const TimePos & ) ), + this, SLOT( updatePositionStepRecording( const TimePos & ) ) ); // update timeline when in record-accompany mode connect( Engine::getSong()->getPlayPos( Song::Mode_PlaySong ).m_timeLine, - SIGNAL( positionChanged( const MidiTime & ) ), + SIGNAL( positionChanged( const TimePos & ) ), this, - SLOT( updatePositionAccompany( const MidiTime & ) ) ); + SLOT( updatePositionAccompany( const TimePos & ) ) ); // TODO /* connect( engine::getSong()->getPlayPos( Song::Mode_PlayBB ).m_timeLine, - SIGNAL( positionChanged( const MidiTime & ) ), + SIGNAL( positionChanged( const TimePos & ) ), this, - SLOT( updatePositionAccompany( const MidiTime & ) ) );*/ + SLOT( updatePositionAccompany( const TimePos & ) ) );*/ removeSelection(); @@ -370,15 +343,9 @@ PianoRoll::PianoRoll() : // Set up quantization model m_quantizeModel.addItem( tr( "Note lock" ) ); - for( int i = 0; i <= NUM_EVEN_LENGTHS; ++i ) - { - m_quantizeModel.addItem( "1/" + QString::number( 1 << i ) ); + for (auto q : Quantizations) { + m_quantizeModel.addItem(QString("1/%1").arg(q)); } - for( int i = 0; i < NUM_TRIPLET_LENGTHS; ++i ) - { - m_quantizeModel.addItem( "1/" + QString::number( (1 << i) * 3 ) ); - } - m_quantizeModel.addItem( "1/192" ); m_quantizeModel.setValue( m_quantizeModel.findText( "1/16" ) ); connect( &m_quantizeModel, SIGNAL( dataChanged() ), @@ -386,7 +353,7 @@ PianoRoll::PianoRoll() : // Set up note length model m_noteLenModel.addItem( tr( "Last note" ), - make_unique( "edit_draw" ) ); + std::make_unique( "edit_draw" ) ); const QString pixmaps[] = { "whole", "half", "quarter", "eighth", "sixteenth", "thirtysecond", "triplethalf", "tripletquarter", "tripleteighth", @@ -394,12 +361,12 @@ PianoRoll::PianoRoll() : for( int i = 0; i < NUM_EVEN_LENGTHS; ++i ) { - auto loader = make_unique( "note_" + pixmaps[i] ); + auto loader = std::make_unique( "note_" + pixmaps[i] ); m_noteLenModel.addItem( "1/" + QString::number( 1 << i ), ::move(loader) ); } for( int i = 0; i < NUM_TRIPLET_LENGTHS; ++i ) { - auto loader = make_unique( "note_" + pixmaps[i+NUM_EVEN_LENGTHS] ); + auto loader = std::make_unique( "note_" + pixmaps[i+NUM_EVEN_LENGTHS] ); m_noteLenModel.addItem( "1/" + QString::number( (1 << i) * 3 ), ::move(loader) ); } m_noteLenModel.setValue( 0 ); @@ -408,6 +375,13 @@ PianoRoll::PianoRoll() : connect( &m_noteLenModel, SIGNAL( dataChanged() ), this, SLOT( noteLengthChanged() ) ); + // Set up key selection dropdown + m_keyModel.addItem(tr("No key")); + // Use piano roll note strings for key dropdown + for (int i = 0; i < 12; i++) { m_keyModel.addItem(s_noteStrings[i]); } + m_keyModel.setValue(0); // start with "No key" + connect(&m_keyModel, &ComboBoxModel::dataChanged, this, &PianoRoll::keyChanged); + // Set up scale model const InstrumentFunctionNoteStacking::ChordTable& chord_table = InstrumentFunctionNoteStacking::ChordTable::getInstance(); @@ -422,6 +396,8 @@ PianoRoll::PianoRoll() : } m_scaleModel.setValue( 0 ); + // connect scale change to key change so it auto-highlights with scale as well + connect(&m_scaleModel, &ComboBoxModel::dataChanged, this, &PianoRoll::keyChanged); // change can update m_semiToneMarkerMenu connect( &m_scaleModel, SIGNAL( dataChanged() ), this, SLOT( updateSemiToneMarkerMenu() ) ); @@ -519,11 +495,17 @@ void PianoRoll::changeNoteEditMode( int i ) } -void PianoRoll::markSemiTone( int i ) +void PianoRoll::markSemiTone(int i, bool fromMenu) { - const int key = m_pianoKeySelected; + const int key = fromMenu + ? getKey(mapFromGlobal(m_semiToneMarkerMenu->pos()).y()) + : m_keyModel.value() - 1; const InstrumentFunctionNoteStacking::Chord * chord = nullptr; + // if "No key" is selected, key is -1, unmark all semitones + // or if scale changed from toolbar to "No scale", unmark all semitones + if (!fromMenu && (key < 0 || m_scaleModel.value() == 0)) { i = stmaUnmarkAll; } + switch( static_cast( i ) ) { case stmaUnmarkAll: @@ -612,6 +594,8 @@ void PianoRoll::markSemiTone( int i ) 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() ); + // until we move the mouse the window won't update, force redraw + update(); } @@ -662,6 +646,73 @@ void PianoRoll::clearGhostPattern() } +void PianoRoll::glueNotes() +{ + if (hasValidPattern()) + { + NoteVector selectedNotes = getSelectedNotes(); + if (selectedNotes.empty()) + { + TextFloat::displayMessage( tr( "Glue notes failed" ), + tr( "Please select notes to glue first." ), + embed::getIconPixmap( "glue", 24, 24 ), + 3000 ); + return; + } + + // Make undo possible + m_pattern->addJournalCheckPoint(); + + // Sort notes on key and then pos. + std::sort(selectedNotes.begin(), selectedNotes.end(), + [](const Note * note, const Note * compareNote) -> bool + { + if (note->key() == compareNote->key()) + { + return note->pos() < compareNote->pos(); + } + return note->key() < compareNote->key(); + }); + + QList noteToRemove; + + NoteVector::iterator note = selectedNotes.begin(); + auto nextNote = note+1; + NoteVector::iterator end = selectedNotes.end(); + + while (note != end && nextNote != end) + { + // key and position match for glue. The notes are already + // sorted so we don't need to test that nextNote is the same + // position or next in sequence. + if ((*note)->key() == (*nextNote)->key() + && (*nextNote)->pos() <= (*note)->pos() + + qMax(TimePos(0), (*note)->length())) + { + (*note)->setLength(qMax((*note)->length(), + TimePos((*nextNote)->endPos() - (*note)->pos()))); + noteToRemove.push_back(*nextNote); + ++nextNote; + } + // key or position doesn't match + else + { + note = nextNote; + nextNote = note+1; + } + } + + // Remove old notes + for (int i = 0; i < noteToRemove.count(); ++i) + { + m_pattern->removeNote(noteToRemove[i]); + } + + update(); + } +} + + void PianoRoll::loadMarkedSemiTones(const QDomElement & de) { // clear marked semitones to prevent leftover marks @@ -773,11 +824,11 @@ void PianoRoll::hidePattern( Pattern* pattern ) void PianoRoll::selectRegionFromPixels( int xStart, int xEnd ) { - xStart -= WHITE_KEY_WIDTH; - xEnd -= WHITE_KEY_WIDTH; + xStart -= m_whiteKeyWidth; + xEnd -= m_whiteKeyWidth; // select an area of notes - int posTicks = xStart * MidiTime::ticksPerBar() / m_ppb + + int posTicks = xStart * TimePos::ticksPerBar() / m_ppb + m_currentPosition; int keyNum = 0; m_selectStartTick = posTicks; @@ -787,7 +838,7 @@ void PianoRoll::selectRegionFromPixels( int xStart, int xEnd ) // change size of selection // get tick in which the cursor is posated - posTicks = xEnd * MidiTime::ticksPerBar() / m_ppb + + posTicks = xEnd * TimePos::ticksPerBar() / m_ppb + m_currentPosition; keyNum = 120; @@ -809,127 +860,6 @@ void PianoRoll::selectRegionFromPixels( int xStart, int xEnd ) - - -/** \brief qproperty access implementation */ - -QColor PianoRoll::barLineColor() const -{ return m_barLineColor; } - -void PianoRoll::setBarLineColor( const QColor & c ) -{ m_barLineColor = c; } - -QColor PianoRoll::beatLineColor() const -{ return m_beatLineColor; } - -void PianoRoll::setBeatLineColor( const QColor & c ) -{ m_beatLineColor = c; } - -QColor PianoRoll::lineColor() const -{ return m_lineColor; } - -void PianoRoll::setLineColor( const QColor & c ) -{ m_lineColor = c; } - -QColor PianoRoll::noteModeColor() const -{ return m_noteModeColor; } - -void PianoRoll::setNoteModeColor( const QColor & c ) -{ m_noteModeColor = c; } - -QColor PianoRoll::noteColor() const -{ return m_noteColor; } - -void PianoRoll::setNoteColor( const QColor & c ) -{ m_noteColor = c; } - -QColor PianoRoll::noteTextColor() const -{ return m_noteTextColor; } - -void PianoRoll::setNoteTextColor( const QColor & c ) -{ m_noteTextColor = c; } - -QColor PianoRoll::barColor() const -{ return m_barColor; } - -void PianoRoll::setBarColor( const QColor & c ) -{ m_barColor = c; } - -QColor PianoRoll::selectedNoteColor() const -{ return m_selectedNoteColor; } - -void PianoRoll::setSelectedNoteColor( const QColor & c ) -{ m_selectedNoteColor = c; } - -QColor PianoRoll::textColor() const -{ return m_textColor; } - -void PianoRoll::setTextColor( const QColor & c ) -{ m_textColor = c; } - -QColor PianoRoll::textColorLight() const -{ return m_textColorLight; } - -void PianoRoll::setTextColorLight( const QColor & c ) -{ m_textColorLight = c; } - -QColor PianoRoll::textShadow() const -{ return m_textShadow; } - -void PianoRoll::setTextShadow( const QColor & c ) -{ m_textShadow = c; } - -QColor PianoRoll::markedSemitoneColor() const -{ return m_markedSemitoneColor; } - -void PianoRoll::setMarkedSemitoneColor( const QColor & c ) -{ m_markedSemitoneColor = c; } - -int PianoRoll::noteOpacity() const -{ return m_noteOpacity; } - -void PianoRoll::setNoteOpacity( const int i ) -{ m_noteOpacity = i; } - -bool PianoRoll::noteBorders() const -{ return m_noteBorders; } - -void PianoRoll::setNoteBorders( const bool b ) -{ m_noteBorders = b; } - -QColor PianoRoll::ghostNoteColor() const -{ return m_ghostNoteColor; } - -void PianoRoll::setGhostNoteColor( const QColor & c ) -{ m_ghostNoteColor = c; } - -QColor PianoRoll::ghostNoteTextColor() const -{ return m_ghostNoteTextColor; } - -void PianoRoll::setGhostNoteTextColor( const QColor & c ) -{ m_ghostNoteTextColor = c; } - -int PianoRoll::ghostNoteOpacity() const -{ return m_ghostNoteOpacity; } - -void PianoRoll::setGhostNoteOpacity( const int i ) -{ m_ghostNoteOpacity = i; } - -bool PianoRoll::ghostNoteBorders() const -{ return m_ghostNoteBorders; } - -void PianoRoll::setGhostNoteBorders( const bool b ) -{ m_ghostNoteBorders = b; } - -QColor PianoRoll::backgroundShade() const -{ return m_backgroundShade; } - -void PianoRoll::setBackgroundShade( const QColor & c ) -{ m_backgroundShade = c; } - - - - void PianoRoll::drawNoteRect( QPainter & p, int x, int y, int width, const Note * n, const QColor & noteCol, const QColor & noteTextColor, const QColor & selCol, const int noteOpc, const bool borders, bool drawNoteName ) @@ -1010,8 +940,8 @@ void PianoRoll::drawNoteRect( QPainter & p, int x, int y, int const distanceToBorder = 2; int const xOffset = borderWidth + distanceToBorder; - // noteTextHeight, textSize are not suitable for determining vertical spacing, - // capHeight() can be used for this, but requires Qt 5.8. + // noteTextHeight, textSize are not suitable for determining vertical spacing, + // capHeight() can be used for this, but requires Qt 5.8. // We use boundingRect() with QChar (the QString version returns wrong value). QRect const boundingRect = fontMetrics.boundingRect(QChar::fromLatin1('H')); int const yOffset = (noteHeight - boundingRect.top() - boundingRect.bottom()) / 2; @@ -1044,9 +974,11 @@ void PianoRoll::drawDetuningInfo( QPainter & _p, const Note * _n, int _x, int _y ) const { int middle_y = _y + m_keyLineHeight / 2; - _p.setPen( noteColor() ); - _p.setClipRect(WHITE_KEY_WIDTH, PR_TOP_MARGIN, - width() - WHITE_KEY_WIDTH, + _p.setPen(m_noteColor); + _p.setClipRect( + m_whiteKeyWidth, + PR_TOP_MARGIN, + width() - m_whiteKeyWidth, keyAreaBottom() - PR_TOP_MARGIN); int old_x = 0; @@ -1056,7 +988,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_ppb / MidiTime::ticksPerBar(); + int pos_x = _x + pos_ticks * m_ppb / TimePos::ticksPerBar(); const float level = it.value(); @@ -1112,27 +1044,24 @@ void PianoRoll::clearSelectedNotes() - -void PianoRoll::shiftSemiTone( int amount ) // shift notes by amount semitones +void PianoRoll::shiftSemiTone(int amount) //Shift notes by amount semitones { - if (!hasValidPattern()) {return;} + if (!hasValidPattern()) { return; } + + auto selectedNotes = getSelectedNotes(); + //If no notes are selected, shift all of them, otherwise shift selection + if (selectedNotes.empty()) { return shiftSemiTone(m_pattern->notes(), amount); } + else { return shiftSemiTone(selectedNotes, amount); } +} +void PianoRoll::shiftSemiTone(NoteVector notes, int amount) +{ m_pattern->addJournalCheckPoint(); - bool useAllNotes = ! isSelection(); - for( Note *note : m_pattern->notes() ) - { - // if none are selected, move all notes, otherwise - // only move selected notes - if( useAllNotes || note->selected() ) - { - note->setKey( note->key() + amount ); - } - } + for (Note *note : notes) { note->setKey( note->key() + amount ); } m_pattern->rearrangeAllNotes(); m_pattern->dataChanged(); - - // we modified the song + //We modified the song update(); gui->songEditor()->update(); } @@ -1140,38 +1069,29 @@ void PianoRoll::shiftSemiTone( int amount ) // shift notes by amount semitones -void PianoRoll::shiftPos( int amount ) //shift notes pos by amount +void PianoRoll::shiftPos(int amount) //Shift notes pos by amount { - if (!hasValidPattern()) {return;} + if (!hasValidPattern()) { return; } + + auto selectedNotes = getSelectedNotes(); + //If no notes are selected, shift all of them, otherwise shift selection + if (selectedNotes.empty()) { return shiftPos(m_pattern->notes(), amount); } + else { return shiftPos(selectedNotes, amount); } +} +void PianoRoll::shiftPos(NoteVector notes, int amount) +{ m_pattern->addJournalCheckPoint(); - bool useAllNotes = ! isSelection(); + auto leftMostPos = notes.first()->pos(); + //Limit leftwards shifts to prevent moving left of pattern start + auto shiftAmount = (leftMostPos > -amount) ? amount : -leftMostPos; + if (shiftAmount == 0) { return; } - bool first = true; - for( Note *note : m_pattern->notes() ) - { - // if none are selected, move all notes, otherwise - // only move selected notes - if( note->selected() || (useAllNotes && note->length() > 0) ) - { - // don't let notes go to out of bounds - if( first ) - { - m_moveBoundaryLeft = note->pos(); - if( m_moveBoundaryLeft + amount < 0 ) - { - amount += 0 - (amount + m_moveBoundaryLeft); - } - first = false; - } - note->setPos( note->pos() + amount ); - } - } + for (Note *note : notes) { note->setPos( note->pos() + shiftAmount ); } m_pattern->rearrangeAllNotes(); m_pattern->updateLength(); m_pattern->dataChanged(); - // we modified the song update(); gui->songEditor()->update(); @@ -1197,17 +1117,7 @@ bool PianoRoll::isSelection() const // are any notes selected? int PianoRoll::selectionCount() const // how many notes are selected? { - int sum = 0; - - for( const Note *note : m_pattern->notes() ) - { - if( note->selected() ) - { - ++sum; - } - } - - return sum; + return getSelectedNotes().size(); } @@ -1291,7 +1201,7 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke) // Move selected notes by one bar to the left if (hasValidPattern()) { - shiftPos( direction * MidiTime::ticksPerBar() ); + shiftPos( direction * TimePos::ticksPerBar() ); } } else if( ke->modifiers() & Qt::ShiftModifier && m_action == ActionNone) @@ -1476,8 +1386,7 @@ void PianoRoll::leaveEvent(QEvent * e ) int PianoRoll::noteEditTop() const { - return height() - PR_BOTTOM_MARGIN - - m_notesEditHeight + NOTE_EDIT_RESIZE_BAR; + return keyAreaBottom() + NOTE_EDIT_RESIZE_BAR; } @@ -1501,7 +1410,7 @@ int PianoRoll::noteEditRight() const int PianoRoll::noteEditLeft() const { - return WHITE_KEY_WIDTH; + return m_whiteKeyWidth; } @@ -1566,11 +1475,11 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) m_moveStartY = me->y(); } - if( me->y() > keyAreaBottom() && me->y() < noteEditTop() ) + if(me->button() == Qt::LeftButton && + me->y() > keyAreaBottom() && me->y() < noteEditTop()) { // resizing the note edit area m_action = ActionResizeNoteEditArea; - m_oldNotesEditHeight = m_notesEditHeight; return; } @@ -1583,14 +1492,14 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) int x = me->x(); - if( x > WHITE_KEY_WIDTH ) + if (x > m_whiteKeyWidth) { // set, move or resize note - x -= WHITE_KEY_WIDTH; + x -= m_whiteKeyWidth; // get tick in which the user clicked - int pos_ticks = x * MidiTime::ticksPerBar() / m_ppb + + int pos_ticks = x * TimePos::ticksPerBar() / m_ppb + m_currentPosition; @@ -1604,7 +1513,7 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) for( int i = 0; i < notes.size(); ++i ) { Note *note = *it; - MidiTime len = note->length(); + TimePos len = note->length(); if( len < 0 ) { len = 4; @@ -1620,7 +1529,7 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) || ( edit_note && pos_ticks <= note->pos() + - NOTE_EDIT_LINE_WIDTH * MidiTime::ticksPerBar() / m_ppb ) + NOTE_EDIT_LINE_WIDTH * TimePos::ticksPerBar() / m_ppb ) ) ) { @@ -1661,8 +1570,8 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) // +32 to quanitize the note correctly when placing notes with // the mouse. We do this here instead of in note.quantized // because live notes should still be quantized at the half. - MidiTime note_pos( pos_ticks - ( quantization() / 2 ) ); - MidiTime note_len( newNoteLen() ); + TimePos note_pos( pos_ticks - ( quantization() / 2 ) ); + TimePos note_len( newNoteLen() ); Note new_note( note_len, note_pos, key_num ); new_note.setSelected( true ); @@ -1712,66 +1621,60 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) m_mouseDownKey = m_startKey; m_mouseDownTick = m_currentPosition; - bool first = true; - for( it = notes.begin(); it != notes.end(); ++it ) + //If clicked on an unselected note, remove selection and select that new note + if (!m_currentNote->selected()) { - Note *note = *it; + clearSelectedNotes(); + m_currentNote->setSelected( true ); + } + + auto selectedNotes = getSelectedNotes(); + + m_moveBoundaryLeft = selectedNotes.first()->pos().getTicks(); + m_moveBoundaryRight = selectedNotes.first()->endPos(); + m_moveBoundaryBottom = selectedNotes.first()->key(); + m_moveBoundaryTop = m_moveBoundaryBottom; + //Figure out the bounding box of all the selected notes + for (Note *note: selectedNotes) + { // remember note starting positions note->setOldKey( note->key() ); note->setOldPos( note->pos() ); note->setOldLength( note->length() ); - if( note->selected() ) - { - - // figure out the bounding box of all the selected notes - if( first ) - { - m_moveBoundaryLeft = note->pos().getTicks(); - m_moveBoundaryRight = note->endPos(); - m_moveBoundaryBottom = note->key(); - m_moveBoundaryTop = note->key(); - - first = false; - } - else - { - m_moveBoundaryLeft = qMin( - note->pos().getTicks(), - (tick_t) m_moveBoundaryLeft ); - m_moveBoundaryRight = qMax( (int) note->endPos(), - m_moveBoundaryRight ); - m_moveBoundaryBottom = qMin( note->key(), - m_moveBoundaryBottom ); - m_moveBoundaryTop = qMax( note->key(), - m_moveBoundaryTop ); - } - } + m_moveBoundaryLeft = qMin(note->pos().getTicks(), (tick_t) m_moveBoundaryLeft); + m_moveBoundaryRight = qMax((int) note->endPos(), m_moveBoundaryRight); + m_moveBoundaryBottom = qMin(note->key(), m_moveBoundaryBottom); + m_moveBoundaryTop = qMax(note->key(), m_moveBoundaryTop); } - // if clicked on an unselected note, remove selection - // and select that new note - if( ! m_currentNote->selected() ) - { - clearSelectedNotes(); - m_currentNote->setSelected( true ); - m_moveBoundaryLeft = m_currentNote->pos().getTicks(); - m_moveBoundaryRight = m_currentNote->endPos(); - m_moveBoundaryBottom = m_currentNote->key(); - m_moveBoundaryTop = m_currentNote->key(); - } - - // clicked at the "tail" of the note? - if( pos_ticks * m_ppb / MidiTime::ticksPerBar() > - m_currentNote->endPos() * m_ppb / MidiTime::ticksPerBar() - RESIZE_AREA_WIDTH + if( pos_ticks * m_ppb / TimePos::ticksPerBar() > + m_currentNote->endPos() * m_ppb / TimePos::ticksPerBar() - RESIZE_AREA_WIDTH && m_currentNote->length() > 0 ) { m_pattern->addJournalCheckPoint(); // then resize the note m_action = ActionResizeNote; + //Calculate the minimum length we should allow when resizing + //each note, and let all notes use the smallest one found + m_minResizeLen = quantization(); + for (Note *note : selectedNotes) + { + //Notes from the BB editor can have a negative length, so + //change their length to the displayed one before resizing + if (note->oldLength() <= 0) { note->setOldLength(4); } + //Let the note be sized down by quantized increments, stopping + //when the next step down would result in a negative length + int thisMin = note->oldLength() % quantization(); + //The initial value for m_minResizeLen is the minimum length of + //a note divisible by the current Q. Therefore we ignore notes + //where thisMin == 0 when checking for a new minimum + if (thisMin > 0 && thisMin < m_minResizeLen) { m_minResizeLen = thisMin; } + } + // set resize-cursor setCursor( Qt::SizeHorCursor ); } @@ -1791,28 +1694,14 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) // if they're holding shift, copy all selected notes if( ! is_new_note && me->modifiers() & Qt::ShiftModifier ) { - // vector to hold new notes until we're through the loop - QVector newNotes; - for( Note* const& note : notes ) + for (Note *note: selectedNotes) { - if( note->selected() ) - { - // copy this note - Note noteCopy( *note ); - newNotes.push_back( noteCopy ); - } - ++it; + Note *newNote = m_pattern->addNote(*note, false); + newNote->setSelected(false); } - if( newNotes.size() != 0 ) + if (!selectedNotes.empty()) { - //put notes from vector into piano roll - for( int i = 0; i < newNotes.size(); ++i) - { - Note * newNote = m_pattern->addNote( newNotes[i], false ); - newNote->setSelected( false ); - } - // added new notes, so must update engine, song, etc Engine::getSong()->setModified(); update(); @@ -1874,7 +1763,7 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) else if( me->buttons() == Qt::LeftButton ) { // left click - play the note - int v = ( (float) x ) / ( (float) WHITE_KEY_WIDTH ) * MidiDefaultVelocity; + int v = ((float) x) / ((float) m_whiteKeyWidth) * MidiDefaultVelocity; m_pattern->instrumentTrack()->pianoModel()->handleKeyPress(key_num, v); // if a chord is set, play the chords notes as well: playChordNotes(key_num, v); @@ -1917,12 +1806,12 @@ void PianoRoll::mouseDoubleClickEvent(QMouseEvent * me ) { // get values for going through notes int pixel_range = 4; - int x = me->x() - WHITE_KEY_WIDTH; + int x = me->x() - m_whiteKeyWidth; const int ticks_start = ( x-pixel_range/2 ) * - MidiTime::ticksPerBar() / m_ppb + m_currentPosition; + TimePos::ticksPerBar() / m_ppb + m_currentPosition; const int ticks_end = ( x+pixel_range/2 ) * - MidiTime::ticksPerBar() / m_ppb + m_currentPosition; - const int ticks_middle = x * MidiTime::ticksPerBar() / m_ppb + m_currentPosition; + TimePos::ticksPerBar() / m_ppb + m_currentPosition; + const int ticks_middle = x * TimePos::ticksPerBar() / m_ppb + m_currentPosition; // go through notes to figure out which one we want to change bool altPressed = me->modifiers() & Qt::AltModifier; @@ -2250,14 +2139,23 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) } else if( m_action == ActionResizeNoteEditArea ) { + // Don't try to show more keys than the full keyboard, bail if trying to + if (m_pianoKeysVisible == NumKeys && me->y() > m_moveStartY) + { + return; + } + int newHeight = height() - me->y(); + if (me->y() < KEY_AREA_MIN_HEIGHT) + { + newHeight = height() - KEY_AREA_MIN_HEIGHT - + PR_TOP_MARGIN - PR_BOTTOM_MARGIN; // - NOTE_EDIT_RESIZE_BAR + } // change m_notesEditHeight and then repaint - m_notesEditHeight = qBound( - NOTE_EDIT_MIN_HEIGHT, - m_oldNotesEditHeight - ( me->y() - m_moveStartY ), - height() - PR_TOP_MARGIN - NOTE_EDIT_RESIZE_BAR - - PR_BOTTOM_MARGIN - KEY_AREA_MIN_HEIGHT ); - + m_notesEditHeight = qMax(NOTE_EDIT_MIN_HEIGHT, newHeight); + m_userSetNotesEditHeight = m_notesEditHeight; m_stepRecorderWidget.setBottomMargin(PR_BOTTOM_MARGIN + m_notesEditHeight); + updateScrollbars(); + updatePositionLineHeight(); repaint(); return; } @@ -2272,17 +2170,17 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) int x = me->x(); // see if they clicked on the keyboard on the left - if( x < WHITE_KEY_WIDTH && m_action == ActionNone + if (x < m_whiteKeyWidth && m_action == ActionNone && ! edit_note && key_num != m_lastKey && me->buttons() & Qt::LeftButton ) { // clicked on a key, play the note - testPlayKey( key_num, ( (float) x ) / ( (float) WHITE_KEY_WIDTH ) * MidiDefaultVelocity, 0 ); + testPlayKey(key_num, ((float) x) / ((float) m_whiteKeyWidth) * MidiDefaultVelocity, 0); update(); return; } - x -= WHITE_KEY_WIDTH; + x -= m_whiteKeyWidth; if( me->buttons() & Qt::LeftButton && m_editMode == ModeDraw @@ -2321,9 +2219,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::ticksPerBar() / m_ppb + m_currentPosition; + TimePos::ticksPerBar() / m_ppb + m_currentPosition; int ticks_end = ( x+pixel_range/2 ) * - MidiTime::ticksPerBar() / m_ppb + m_currentPosition; + TimePos::ticksPerBar() / m_ppb + m_currentPosition; // get note-vector of current pattern const NoteVector & notes = m_pattern->notes(); @@ -2419,7 +2317,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) // set move- or resize-cursor // get tick in which the cursor is posated - int pos_ticks = ( x * MidiTime::ticksPerBar() ) / + int pos_ticks = ( x * TimePos::ticksPerBar() ) / m_ppb + m_currentPosition; // get note-vector of current pattern @@ -2452,7 +2350,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_ppb/MidiTime::ticksPerBar(); + m_currentPosition) * m_ppb/TimePos::ticksPerBar(); // cursor at the "tail" of the note? bool atTail = note->length() > 0 && x > noteRightX - RESIZE_AREA_WIDTH; @@ -2473,7 +2371,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) // change size of selection // get tick in which the cursor is posated - int pos_ticks = x * MidiTime::ticksPerBar() / m_ppb + + int pos_ticks = x * TimePos::ticksPerBar() / m_ppb + m_currentPosition; m_selectedTick = pos_ticks - m_selectStartTick; @@ -2495,7 +2393,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) // any key if in erase mode // get tick in which the user clicked - int pos_ticks = x * MidiTime::ticksPerBar() / m_ppb + + int pos_ticks = x * TimePos::ticksPerBar() / m_ppb + m_currentPosition; @@ -2509,7 +2407,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) while( it != notes.end() ) { Note *note = *it; - MidiTime len = note->length(); + TimePos len = note->length(); if( len < 0 ) { len = 4; @@ -2526,7 +2424,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) ( edit_note && pos_ticks <= note->pos() + NOTE_EDIT_LINE_WIDTH * - MidiTime::ticksPerBar() / + TimePos::ticksPerBar() / m_ppb ) ) ) @@ -2555,12 +2453,12 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) m_action == ActionSelectNotes ) { - int x = me->x() - WHITE_KEY_WIDTH; + int x = me->x() - m_whiteKeyWidth; if( x < 0 && m_currentPosition > 0 ) { x = 0; QCursor::setPos( mapToGlobal( QPoint( - WHITE_KEY_WIDTH, + m_whiteKeyWidth, me->y() ) ) ); if( m_currentPosition >= 4 ) { @@ -2572,9 +2470,9 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) m_leftRightScroll->setValue( 0 ); } } - else if( x > width() - WHITE_KEY_WIDTH ) + else if (x > width() - m_whiteKeyWidth) { - x = width() - WHITE_KEY_WIDTH; + x = width() - m_whiteKeyWidth; QCursor::setPos( mapToGlobal( QPoint( width(), me->y() ) ) ); m_leftRightScroll->setValue( m_currentPosition + @@ -2582,7 +2480,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) } // get tick in which the cursor is posated - int pos_ticks = x * MidiTime::ticksPerBar()/ m_ppb + + int pos_ticks = x * TimePos::ticksPerBar()/ m_ppb + m_currentPosition; m_selectedTick = pos_ticks - @@ -2643,7 +2541,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::ticksPerBar() / m_ppb; + int off_ticks = off_x * TimePos::ticksPerBar() / m_ppb; int off_key = getKey( y ) - getKey( m_moveStartY ); // handle scroll changes while dragging @@ -2681,36 +2579,33 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl ) if (m_action == ActionMoveNote) { - for (Note *note : notes) + for (Note *note : getSelectedNotes()) { - if( note->selected() ) + if (shift && ! m_startedWithShift) { - if( shift && ! m_startedWithShift ) + // quick resize, toggled by holding shift after starting a note move, but not before + int ticks_new = note->oldLength().getTicks() + off_ticks; + if( ticks_new <= 0 ) { - // quick resize, toggled by holding shift after starting a note move, but not before - int ticks_new = note->oldLength().getTicks() + off_ticks; - if( ticks_new <= 0 ) - { - ticks_new = 1; - } - note->setLength( MidiTime( ticks_new ) ); - m_lenOfNewNotes = note->length(); - } - else - { - // moving note - int pos_ticks = note->oldPos().getTicks() + off_ticks; - int key_num = note->oldKey() + off_key; - - // ticks can't be negative - pos_ticks = qMax(0, pos_ticks); - // upper/lower bound checks on key_num - key_num = qMax(0, key_num); - key_num = qMin(key_num, NumKeys); - - note->setPos( MidiTime( pos_ticks ) ); - note->setKey( key_num ); + ticks_new = 1; } + note->setLength( TimePos( ticks_new ) ); + m_lenOfNewNotes = note->length(); + } + else + { + // moving note + int pos_ticks = note->oldPos().getTicks() + off_ticks; + int key_num = note->oldKey() + off_key; + + // ticks can't be negative + pos_ticks = qMax(0, pos_ticks); + // upper/lower bound checks on key_num + key_num = qMax(0, key_num); + key_num = qMin(key_num, NumKeys); + + note->setPos( TimePos( pos_ticks ) ); + note->setKey( key_num ); } } } @@ -2722,6 +2617,8 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl ) // If shift + ctrl then we also rearrange all posterior notes (sticky) // If shift is pressed but only one note is selected, apply sticky + auto selectedNotes = getSelectedNotes(); + if (shift) { // Algorithm: @@ -2730,20 +2627,20 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl ) // This factor is such that the endpoint of the note whose handle is being dragged should lie under the cursor. // first, determine the start-point of the left-most selected note: int stretchStartTick = -1; - for (const Note *note : notes) + for (const Note *note : selectedNotes) { - if (note->selected() && (stretchStartTick < 0 || note->oldPos().getTicks() < stretchStartTick)) + if (stretchStartTick < 0 || note->oldPos().getTicks() < stretchStartTick) { stretchStartTick = note->oldPos().getTicks(); } } // determine the ending tick of the right-most selected note const Note *posteriorNote = nullptr; - for (const Note *note : notes) + for (const Note *note : selectedNotes) { - if (note->selected() && (posteriorNote == nullptr || + if (posteriorNote == nullptr || note->oldPos().getTicks() + note->oldLength().getTicks() > - posteriorNote->oldPos().getTicks() + posteriorNote->oldLength().getTicks())) + posteriorNote->oldPos().getTicks() + posteriorNote->oldLength().getTicks()) { posteriorNote = note; } @@ -2757,40 +2654,37 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl ) // process all selected notes & determine how much the endpoint of the right-most note was shifted int posteriorDeltaThisFrame = 0; - for (Note *note : notes) + for (Note *note : selectedNotes) { - if(note->selected()) + // scale relative start and end positions by scaleFactor + int newStart = stretchStartTick + scaleFactor * + (note->oldPos().getTicks() - stretchStartTick); + int newEnd = stretchStartTick + scaleFactor * + (note->oldPos().getTicks()+note->oldLength().getTicks() - stretchStartTick); + // if not holding alt, quantize the offsets + if (!alt) { - // scale relative start and end positions by scaleFactor - int newStart = stretchStartTick + scaleFactor * - (note->oldPos().getTicks() - stretchStartTick); - int newEnd = stretchStartTick + scaleFactor * - (note->oldPos().getTicks()+note->oldLength().getTicks() - stretchStartTick); - // if not holding alt, quantize the offsets - if(!alt) - { - // quantize start time - int oldStart = note->oldPos().getTicks(); - int startDiff = newStart - oldStart; - startDiff = floor(startDiff / quantization()) * quantization(); - newStart = oldStart + startDiff; - // quantize end time - int oldEnd = oldStart + note->oldLength().getTicks(); - int endDiff = newEnd - oldEnd; - endDiff = floor(endDiff / quantization()) * quantization(); - newEnd = oldEnd + endDiff; - } - int newLength = qMax(1, newEnd-newStart); - if (note == posteriorNote) - { - posteriorDeltaThisFrame = (newStart+newLength) - - (note->pos().getTicks() + note->length().getTicks()); - } - note->setLength( MidiTime(newLength) ); - note->setPos( MidiTime(newStart) ); - - m_lenOfNewNotes = note->length(); + // quantize start time + int oldStart = note->oldPos().getTicks(); + int startDiff = newStart - oldStart; + startDiff = floor(startDiff / quantization()) * quantization(); + newStart = oldStart + startDiff; + // quantize end time + int oldEnd = oldStart + note->oldLength().getTicks(); + int endDiff = newEnd - oldEnd; + endDiff = floor(endDiff / quantization()) * quantization(); + newEnd = oldEnd + endDiff; } + int newLength = qMax(1, newEnd-newStart); + if (note == posteriorNote) + { + posteriorDeltaThisFrame = (newStart+newLength) - + (note->pos().getTicks() + note->length().getTicks()); + } + note->setLength( TimePos(newLength) ); + note->setPos( TimePos(newStart) ); + + m_lenOfNewNotes = note->length(); } if (ctrl || selectionCount() == 1) { @@ -2800,7 +2694,7 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl ) if (!note->selected() && note->pos().getTicks() >= posteriorEndTick) { int newStart = note->pos().getTicks() + posteriorDeltaThisFrame; - note->setPos( MidiTime(newStart) ); + note->setPos( TimePos(newStart) ); } } } @@ -2808,16 +2702,14 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl ) else { // shift is not pressed; stretch length of selected notes but not their position - for (Note *note : notes) + int minLength = alt ? 1 : m_minResizeLen.getTicks(); + + for (Note *note : selectedNotes) { - if (note->selected()) - { - int newLength = note->oldLength() + off_ticks; - newLength = qMax(1, newLength); - note->setLength( MidiTime(newLength) ); + int newLength = qMax(minLength, note->oldLength() + off_ticks); + note->setLength(TimePos(newLength)); - m_lenOfNewNotes = note->length(); - } + m_lenOfNewNotes = note->length(); } } } @@ -2827,11 +2719,8 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl ) Engine::getSong()->setModified(); } -int PianoRoll::xCoordOfTick( int tick ) -{ - return WHITE_KEY_WIDTH + ( ( tick - m_currentPosition ) - * m_ppb / MidiTime::ticksPerBar() ); -} + + void PianoRoll::paintEvent(QPaintEvent * pe ) { @@ -2847,353 +2736,337 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) // fill with bg color p.fillRect( 0, 0, width(), height(), bgColor ); - // set font-size to 8 - p.setFont( pointSize<8>( p.font() ) ); + // set font-size to 80% of key line height + QFont f = p.font(); + f.setPixelSize(m_keyLineHeight * 0.8); + p.setFont(f); // font size doesn't change without this for some reason QFontMetrics fontMetrics(p.font()); - QRect const boundingRect = fontMetrics.boundingRect(QChar::fromLatin1('H')); - // This is two times of the y coordinate of the center of the bounding rectangle - // (-(top+bottom)=-2(center)) but labelHeight is more intuitive/describing name - int const labelHeight = - boundingRect.top() - boundingRect.bottom(); - - // y_offset is used to align the piano-keys on the key-lines - int y_offset = 0; + // G4 is one of the widest + QRect const boundingRect = fontMetrics.boundingRect(QString("G4")); + + // Order of drawing + // - vertical quantization lines + // - piano roll + horizontal key lines + // - alternating bar colors + // - vertical beat lines + // - vertical bar lines + // - marked semitones + // - note editing + // - notes + // - selection frame + // - highlight hovered note + // - note edit area resize bar + // - cursor mode icon - // calculate y_offset according to first key - switch( prKeyOrder[m_startKey % KeysPerOctave] ) + if (hasValidPattern()) { - case PR_BLACK_KEY: y_offset = m_keyLineHeight / 4; break; - case PR_WHITE_KEY_BIG: y_offset = m_keyLineHeight / 2; break; - case PR_WHITE_KEY_SMALL: - if( prKeyOrder[( ( m_startKey + 1 ) % - KeysPerOctave)] != PR_BLACK_KEY ) + int pianoAreaHeight, partialKeyVisible, topKey, topNote; + pianoAreaHeight = keyAreaBottom() - keyAreaTop(); + m_pianoKeysVisible = pianoAreaHeight / m_keyLineHeight; + partialKeyVisible = pianoAreaHeight % m_keyLineHeight; + // check if we're below the minimum key area size + if (m_pianoKeysVisible * m_keyLineHeight < KEY_AREA_MIN_HEIGHT) + { + m_pianoKeysVisible = KEY_AREA_MIN_HEIGHT / m_keyLineHeight; + partialKeyVisible = KEY_AREA_MIN_HEIGHT % m_keyLineHeight; + // if we have a partial key, just show it + if (partialKeyVisible > 0) { - y_offset = m_keyLineHeight / 2; + m_pianoKeysVisible += 1; + partialKeyVisible = 0; } - break; - } - // start drawing at the bottom - int key_line_y = qMin(keyAreaBottom() - 1, m_keyLineHeight * NumKeys); - // we need to set m_notesEditHeight here because it needs to fill in the - // rest of the window if key_line_y is bound to m_keyLineHeight * NumKeys - if (key_line_y == m_keyLineHeight * NumKeys) { - m_notesEditHeight = height() - (PR_TOP_MARGIN + m_keyLineHeight * NumKeys); - } - // used for aligning black-keys later - int first_white_key_height = m_whiteKeySmallHeight; - // key-counter - only needed for finding out whether the processed - // key is the first one - int keys_processed = 0; - - int key = m_startKey; - - // draw all white keys... - for( int y = key_line_y + 1 + y_offset; y > PR_TOP_MARGIN; - key_line_y -= m_keyLineHeight, ++keys_processed ) - { - // check for white key that is only half visible on the - // bottom of piano-roll - if( keys_processed == 0 && - prKeyOrder[m_startKey % KeysPerOctave] == - PR_BLACK_KEY ) + // have to modifiy the notes edit area height instead + m_notesEditHeight = height() - (m_pianoKeysVisible * m_keyLineHeight) + - PR_TOP_MARGIN - PR_BOTTOM_MARGIN; + } + // check if we're trying to show more keys than available + else if (m_pianoKeysVisible >= NumKeys) { - // draw it! - p.drawPixmap( PIANO_X, y - m_whiteKeySmallHeight, WHITE_KEY_WIDTH, m_whiteKeySmallHeight, - *s_whiteKeySmallPm ); - // update y-pos - y -= m_whiteKeySmallHeight / 2; - // move first black key down (we didn't draw whole - // white key so black key needs to be lifted down) - // (default for first_white_key_height = - // m_whiteKeySmallHeight, so m_whiteKeySmallHeight/2 - // is smaller) - first_white_key_height = m_whiteKeySmallHeight / 2; + m_pianoKeysVisible = NumKeys; + // have to modify the notes edit area height instead + m_notesEditHeight = height() - (NumKeys * m_keyLineHeight) - + PR_TOP_MARGIN - PR_BOTTOM_MARGIN; + partialKeyVisible = 0; } - // check whether to draw a big or a small white key - if( prKeyOrder[key % KeysPerOctave] == PR_WHITE_KEY_SMALL ) + topKey = qBound(0, m_startKey + m_pianoKeysVisible - 1, NumKeys - 1); + topNote = topKey % KeysPerOctave; + // if not resizing the note edit area, we can change m_notesEditHeight + if (m_action != ActionResizeNoteEditArea && partialKeyVisible != 0) { - // draw a small one while checking if it is pressed or not - if( hasValidPattern() && m_pattern->instrumentTrack()->pianoModel()->isKeyPressed( key ) ) + // calculate the height change adding and subtracting the partial key + int noteAreaPlus = (m_notesEditHeight + partialKeyVisible) - m_userSetNotesEditHeight; + int noteAreaMinus = m_userSetNotesEditHeight - (m_notesEditHeight - partialKeyVisible); + // if adding the partial key to height is more distant from the set height + // we want to subtract the partial key + if (noteAreaPlus > noteAreaMinus) { - p.drawPixmap(PIANO_X, y - m_whiteKeySmallHeight, WHITE_KEY_WIDTH, m_whiteKeySmallHeight, - *s_whiteKeySmallPressedPm); + m_notesEditHeight -= partialKeyVisible; + // since we're adding a partial key, we add one to the number visible + m_pianoKeysVisible += 1; } - else - { - p.drawPixmap(PIANO_X, y - m_whiteKeySmallHeight, WHITE_KEY_WIDTH, m_whiteKeySmallHeight, - *s_whiteKeySmallPm); - } - // update y-pos - y -= m_whiteKeySmallHeight; + // otherwise we add height + else { m_notesEditHeight += partialKeyVisible; } + } + updatePositionLineHeight(); + int x, q = quantization(), tick; + // draw vertical quantization lines + // If we're over 100% zoom, we allow all quantization level grids + if (m_zoomingModel.value() <= 3) + { + // we're under 100% zoom + // allow quantization grid up to 1/24 for triplets + if (q % 3 != 0 && q < 8) { q = 8; } + // allow quantization grid up to 1/32 for normal notes + else if (q < 6) { q = 6; } } - else if( prKeyOrder[key % KeysPerOctave] == PR_WHITE_KEY_BIG ) + auto xCoordOfTick = [=](int tick) { + return m_whiteKeyWidth + ( + (tick - m_currentPosition) * m_ppb / TimePos::ticksPerBar() + ); + }; + p.setPen(m_lineColor); + for (tick = m_currentPosition - m_currentPosition % q, + x = xCoordOfTick(tick); + x <= width(); + tick += q, x = xCoordOfTick(tick)) { - // draw a big one while checking if it is pressed or not - if( hasValidPattern() && m_pattern->instrumentTrack()->pianoModel()->isKeyPressed( key ) ) - { - p.drawPixmap(PIANO_X, y - m_whiteKeyBigHeight, WHITE_KEY_WIDTH, m_whiteKeyBigHeight, - *s_whiteKeyBigPressedPm); - } - else - { - p.drawPixmap(PIANO_X, y-m_whiteKeyBigHeight, WHITE_KEY_WIDTH, m_whiteKeyBigHeight, - *s_whiteKeyBigPm); - } - // if a big white key has been the first key, - // black keys needs to be lifted up - if( keys_processed == 0 ) - { - first_white_key_height = m_whiteKeyBigHeight; - } - // update y-pos - y -= m_whiteKeyBigHeight; + p.drawLine(x, keyAreaTop(), x, noteEditBottom()); } - // Compute the corrections for the note names - int yCorrectionForNoteLabels = 0; + // draw horizontal grid lines and piano notes + p.setClipRect(0, keyAreaTop(), width(), keyAreaBottom() - keyAreaTop()); + // the first grid line from the top Y position + int grid_line_y = keyAreaTop() + m_keyLineHeight - 1; - int keyCode = key % KeysPerOctave; - switch (keyCode) + // lambda function for returning the height of a key + auto keyHeight = [&]( + const int key + ) -> int { - case 0: // C - case 5: // F - yCorrectionForNoteLabels = (m_whiteKeySmallHeight - labelHeight + 1) / -2; - break; - case 2: // D - case 7: // G - case 9: // A - yCorrectionForNoteLabels = (m_whiteKeyBigHeight / 2 - labelHeight + 1) / -2; - break; - case 4: // E - case 11: // B - // calculate center point of key and move half of text - yCorrectionForNoteLabels = -(((m_whiteKeySmallHeight - (m_whiteKeySmallHeight * 2 + 3) / 6) / 4) - - labelHeight / 2); - break; - } - - if( Piano::isWhiteKey( key ) ) + switch (prKeyOrder[key % KeysPerOctave]) + { + case PR_WHITE_KEY_BIG: + return m_whiteKeyBigHeight; + case PR_WHITE_KEY_SMALL: + return m_whiteKeySmallHeight; + case PR_BLACK_KEY: + return m_blackKeyHeight; + } + return 0; // should never happen + }; + // lambda function for returning the distance to the top of a key + auto gridCorrection = [&]( + const int key + ) -> int { - // Draw note names if activated in the preferences, C notes are always drawn - if ( (key % 12 == 0 || drawNoteNames) && m_keyLineHeight > 10 ) + const int keyCode = key % KeysPerOctave; + switch (prKeyOrder[keyCode]) { - QString noteString = getNoteString( key ); - - QPoint textStart( WHITE_KEY_WIDTH - 18, key_line_y ); - textStart += QPoint( 0, yCorrectionForNoteLabels ); - - p.setPen( textShadow() ); - p.drawText( textStart + QPoint( 1, 1 ), noteString ); - // The C key is painted darker than the other ones - if ( key % 12 == 0 ) - { - p.setPen( textColor() ); - } - else + case PR_WHITE_KEY_BIG: + return m_whiteKeySmallHeight; + case PR_WHITE_KEY_SMALL: + // These two keys need to adjust up small height instead of only key line height + if (keyCode == Key_C || keyCode == Key_F) { - p.setPen( textColorLight() ); + return m_whiteKeySmallHeight; } - p.drawText( textStart, noteString ); + case PR_BLACK_KEY: + return m_blackKeyHeight; } - } - ++key; - } - - // reset all values, because now we're going to draw all black keys - key = m_startKey; - keys_processed = 0; - int white_cnt = 0; - key_line_y = qMin(keyAreaBottom(), m_keyLineHeight * NumKeys); - - // and go! - for( int y = key_line_y + y_offset; - y > PR_TOP_MARGIN; ++keys_processed ) - { - // check for black key that is only half visible on the bottom - // of piano-roll - if( keys_processed == 0 - // current key may not be a black one - && prKeyOrder[key % KeysPerOctave] != PR_BLACK_KEY - // but the previous one must be black (we must check this - // because there might be two white keys (E-F) - && prKeyOrder[( key - 1 ) % KeysPerOctave] == - PR_BLACK_KEY ) + return 0; // should never happen + }; + auto keyWidth = [&]( + const int key + ) -> int { - // draw the black key! - p.drawPixmap( PIANO_X, y - m_blackKeyHeight / 2, BLACK_KEY_WIDTH, m_blackKeyHeight, - *s_blackKeyPm ); - // is the one after the start-note a black key?? - if( prKeyOrder[( key + 1 ) % KeysPerOctave] != - PR_BLACK_KEY ) + switch (prKeyOrder[key % KeysPerOctave]) { - // no, then move it up! - y -= m_keyLineHeight / 2; + case PR_WHITE_KEY_SMALL: + case PR_WHITE_KEY_BIG: + return m_whiteKeyWidth; + case PR_BLACK_KEY: + return m_blackKeyWidth; } - } - // current key black? - if( prKeyOrder[key % KeysPerOctave] == PR_BLACK_KEY) + return 0; // should never happen + }; + // lambda function to draw a key + auto drawKey = [&]( + const int key, + const int yb) { - // then draw it (calculation of y very complicated, - // but that's the only working solution, sorry...) - // check if the key is pressed or not - if( hasValidPattern() && m_pattern->instrumentTrack()->pianoModel()->isKeyPressed( key ) ) + const bool pressed = m_pattern->instrumentTrack()->pianoModel()->isKeyPressed(key); + const int keyCode = key % KeysPerOctave; + const int yt = yb - gridCorrection(key); + const int kh = keyHeight(key); + const int kw = keyWidth(key); + // set key colors + p.setPen(QColor(0, 0, 0)); + switch (prKeyOrder[keyCode]) { - p.drawPixmap( PIANO_X, y - ( first_white_key_height - - m_whiteKeySmallHeight ) - - m_whiteKeySmallHeight/2 - 1 - - m_blackKeyHeight, BLACK_KEY_WIDTH, m_blackKeyHeight, *s_blackKeyPressedPm ); + case PR_WHITE_KEY_SMALL: + case PR_WHITE_KEY_BIG: + p.setBrush(pressed ? m_whiteKeyActiveBackground : m_whiteKeyInactiveBackground); + break; + case PR_BLACK_KEY: + p.setBrush(pressed ? m_blackKeyActiveBackground : m_blackKeyInactiveBackground); } - else + // draw key + p.drawRect(PIANO_X, yt, kw, kh); + // draw note name + if (keyCode == Key_C || (drawNoteNames && Piano::isWhiteKey(key))) { - p.drawPixmap( PIANO_X, y - ( first_white_key_height - - m_whiteKeySmallHeight ) - - m_whiteKeySmallHeight/2 - 1 - - m_blackKeyHeight, BLACK_KEY_WIDTH, m_blackKeyHeight, *s_blackKeyPm ); + // small font sizes have 1 pixel offset instead of 2 + auto zoomOffset = m_zoomYLevels[m_zoomingYModel.value()] > 1.0f ? 2 : 1; + QString noteString = getNoteString(key); + QRect textRect( + m_whiteKeyWidth - boundingRect.width() - 2, + yb - m_keyLineHeight + zoomOffset, + boundingRect.width(), + boundingRect.height() + ); + p.setPen(pressed ? m_whiteKeyActiveTextShadow : m_whiteKeyInactiveTextShadow); + p.drawText(textRect.adjusted(0, 1, 1, 0), Qt::AlignRight | Qt::AlignHCenter, noteString); + p.setPen(pressed ? m_whiteKeyActiveTextColor : m_whiteKeyInactiveTextColor); + // if (keyCode == Key_C) { p.setPen(textColor()); } + // else { p.setPen(textColorLight()); } + p.drawText(textRect, Qt::AlignRight | Qt::AlignHCenter, noteString); } - // update y-pos - y -= m_whiteKeyBigHeight; - // reset white-counter - white_cnt = 0; - } - else + }; + // lambda for drawing the horizontal grid line + auto drawHorizontalLine = [&]( + const int key, + const int y + ) { - // simple workaround for increasing x if there were - // two white keys (e.g. between E and F) - ++white_cnt; - if( white_cnt > 1 ) - { - y -= m_whiteKeyBigHeight/2; - } - } - - ++key; - } - - - // erase the area below the piano, because there might be keys that - // should be only half-visible - p.fillRect( QRect( 0, key_line_y, - WHITE_KEY_WIDTH, noteEditBottom() - key_line_y ), bgColor ); - - // display note editing info - QFont f = p.font(); - f.setBold( false ); - p.setFont( pointSize<10>( f ) ); - p.setPen( noteModeColor() ); - p.drawText( QRect( 0, key_line_y, - WHITE_KEY_WIDTH, noteEditBottom() - key_line_y ), - Qt::AlignCenter | Qt::TextWordWrap, - m_nemStr.at( m_noteEditMode ) + ":" ); - - // set clipping area, because we are not allowed to paint over - // keyboard... - p.setClipRect( WHITE_KEY_WIDTH, PR_TOP_MARGIN, - width() - WHITE_KEY_WIDTH, - height() - PR_TOP_MARGIN - PR_BOTTOM_MARGIN ); - - // draw the grid - if( hasValidPattern() ) - { - int q, x, tick; - - if( m_zoomingModel.value() > 3 ) - { - // If we're over 100% zoom, we allow all quantization level grids - q = quantization(); - } - else if( quantization() % 3 != 0 ) + if (key % KeysPerOctave == Key_C) { p.setPen(m_beatLineColor); } + else { p.setPen(m_lineColor); } + p.drawLine(m_whiteKeyWidth, y, width(), y); + }; + // correct y offset of the top key + switch (prKeyOrder[topNote]) { - // If we're under 100% zoom, we allow quantization grid up to 1/24 for triplets - // to ensure a dense doesn't fill out the background - q = quantization() < 8 ? 8 : quantization(); - } - else { - // If we're under 100% zoom, we allow quantization grid up to 1/32 for normal notes - q = quantization() < 6 ? 6 : quantization(); - } - - // First we draw the vertical quantization lines - for( tick = m_currentPosition - m_currentPosition % q, x = xCoordOfTick( tick ); - x <= width(); tick += q, x = xCoordOfTick( tick ) ) - { - p.setPen( lineColor() ); - p.drawLine( x, PR_TOP_MARGIN, x, height() - PR_BOTTOM_MARGIN ); + case PR_WHITE_KEY_SMALL: + case PR_WHITE_KEY_BIG: + break; + case PR_BLACK_KEY: + // draw extra white key + drawKey(topKey + 1, grid_line_y - m_keyLineHeight); } - - // Draw horizontal lines - key = m_startKey; - for( int y = key_line_y - 1; y > PR_TOP_MARGIN; - y -= m_keyLineHeight ) + // loop through visible keys + const int lastKey = qMax(0, topKey - m_pianoKeysVisible); + for (int key = topKey; key > lastKey; --key) { - if( static_cast( key % KeysPerOctave ) == Key_C ) + bool whiteKey = Piano::isWhiteKey(key); + if (whiteKey) { - // C note gets accented - p.setPen( beatLineColor() ); + drawKey(key, grid_line_y); + drawHorizontalLine(key, grid_line_y); + grid_line_y += m_keyLineHeight; } else { - p.setPen( lineColor() ); + // draw next white key + drawKey(key - 1, grid_line_y + m_keyLineHeight); + drawHorizontalLine(key - 1, grid_line_y + m_keyLineHeight); + // draw black key over previous and next white key + drawKey(key, grid_line_y); + drawHorizontalLine(key, grid_line_y); + // drew two grid keys so skip ahead properly + grid_line_y += m_keyLineHeight + m_keyLineHeight; + // capture double key draw + --key; } - p.drawLine( WHITE_KEY_WIDTH, y, width(), y ); - ++key; } + // don't draw over keys + p.setClipRect(m_whiteKeyWidth, keyAreaTop(), width(), noteEditBottom() - keyAreaTop()); - // Draw alternating shades on bars - float timeSignature = static_cast( Engine::getSong()->getTimeSigModel().getNumerator() ) - / static_cast( Engine::getSong()->getTimeSigModel().getDenominator() ); + // draw alternating shading on bars + float timeSignature = + static_cast(Engine::getSong()->getTimeSigModel().getNumerator()) / + 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::ticksPerBar(); - + int leftBars = m_currentPosition * zoomFactor / TimePos::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_ppb, ++barCount ) + for (int x = m_whiteKeyWidth, barCount = leftBars; + x < width() + m_currentPosition * zoomFactor / timeSignature; + x += m_ppb, ++barCount) { - if( ( barCount + leftBars ) % 2 != 0 ) + if ((barCount + leftBars) % 2 != 0) { - p.fillRect( x - m_currentPosition * zoomFactor / timeSignature, PR_TOP_MARGIN, m_ppb, - height() - ( PR_BOTTOM_MARGIN + PR_TOP_MARGIN ), backgroundShade() ); + p.fillRect(x - m_currentPosition * zoomFactor / timeSignature, + PR_TOP_MARGIN, + m_ppb, + height() - (PR_BOTTOM_MARGIN + PR_TOP_MARGIN), + m_backgroundShade); } } - // Draw the vertical beat lines + // draw vertical beat lines int ticksPerBeat = DefaultTicksPerBar / Engine::getSong()->getTimeSigModel().getDenominator(); - - for( tick = m_currentPosition - m_currentPosition % ticksPerBeat, - x = xCoordOfTick( tick ); x <= width(); - tick += ticksPerBeat, x = xCoordOfTick( tick ) ) + p.setPen(m_beatLineColor); + for(tick = m_currentPosition - m_currentPosition % ticksPerBeat, + x = xCoordOfTick( tick ); + x <= width(); + tick += ticksPerBeat, x = xCoordOfTick(tick)) { - p.setPen( beatLineColor() ); - p.drawLine( x, PR_TOP_MARGIN, x, height() - PR_BOTTOM_MARGIN ); + p.drawLine(x, PR_TOP_MARGIN, x, noteEditBottom()); } - // Draw the vertical bar lines - for( tick = m_currentPosition - m_currentPosition % MidiTime::ticksPerBar(), - x = xCoordOfTick( tick ); x <= width(); - tick += MidiTime::ticksPerBar(), x = xCoordOfTick( tick ) ) + // draw vertical bar lines + p.setPen(m_barLineColor); + for(tick = m_currentPosition - m_currentPosition % TimePos::ticksPerBar(), + x = xCoordOfTick( tick ); + x <= width(); + tick += TimePos::ticksPerBar(), x = xCoordOfTick(tick)) { - p.setPen( barLineColor() ); - p.drawLine( x, PR_TOP_MARGIN, x, height() - PR_BOTTOM_MARGIN ); + p.drawLine(x, PR_TOP_MARGIN, x, noteEditBottom()); } // draw marked semitones after the grid - for( int i = 0; i < m_markedSemiTones.size(); i++ ) + for(x = 0; x < m_markedSemiTones.size(); ++x) { - const int key_num = m_markedSemiTones.at( i ); - const int y = key_line_y + 5 - - m_keyLineHeight * ( key_num - m_startKey + 1 ); - - if( y > key_line_y ) - { - break; - } - - p.fillRect( WHITE_KEY_WIDTH + 1, y - m_keyLineHeight / 2, width() - 10, m_keyLineHeight + 1, - markedSemitoneColor() ); + const int key_num = m_markedSemiTones.at(x); + const int y = keyAreaBottom() + 5 - m_keyLineHeight * + (key_num - m_startKey + 1); + if(y > keyAreaBottom()) { break; } + p.fillRect(m_whiteKeyWidth + 1, + y - m_keyLineHeight / 2, + width() - 10, + m_keyLineHeight + 1, + m_markedSemitoneColor); } } + // reset clip + p.setClipRect(0, 0, width(), height()); + + // erase the area below the piano, because there might be keys that + // should be only half-visible + p.fillRect( QRect( 0, keyAreaBottom(), + m_whiteKeyWidth, noteEditBottom() - keyAreaBottom()), bgColor); + + // display note editing info + //QFont f = p.font(); + f.setBold( false ); + p.setFont( pointSize<10>( f ) ); + p.setPen(m_noteModeColor); + p.drawText( QRect( 0, keyAreaBottom(), + m_whiteKeyWidth, noteEditBottom() - keyAreaBottom()), + Qt::AlignCenter | Qt::TextWordWrap, + m_nemStr.at( m_noteEditMode ) + ":" ); + + // set clipping area, because we are not allowed to paint over + // keyboard... + p.setClipRect( + m_whiteKeyWidth, + PR_TOP_MARGIN, + width() - m_whiteKeyWidth, + height() - PR_TOP_MARGIN - PR_BOTTOM_MARGIN); + // following code draws all notes in visible area // and the note editing stuff (volume, panning, etc) @@ -3212,15 +3085,17 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) qSwap( sel_key_start, sel_key_end ); } - int y_base = key_line_y - 1; + int y_base = keyAreaBottom() - 1; if( hasValidPattern() ) { - p.setClipRect( WHITE_KEY_WIDTH, PR_TOP_MARGIN, - width() - WHITE_KEY_WIDTH, - height() - PR_TOP_MARGIN ); + p.setClipRect( + m_whiteKeyWidth, + PR_TOP_MARGIN, + width() - m_whiteKeyWidth, + height() - PR_TOP_MARGIN); - const int visible_keys = ( key_line_y-keyAreaTop() ) / - m_keyLineHeight + 2; + const int topKey = qBound(0, m_startKey + m_pianoKeysVisible - 1, NumKeys - 1); + const int bottomKey = topKey - m_pianoKeysVisible; QPolygonF editHandles; @@ -3243,25 +3118,24 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) int pos_ticks = note->pos(); - int note_width = len_ticks * m_ppb / MidiTime::ticksPerBar(); + int note_width = len_ticks * m_ppb / TimePos::ticksPerBar(); const int x = ( pos_ticks - m_currentPosition ) * - m_ppb / MidiTime::ticksPerBar(); + m_ppb / TimePos::ticksPerBar(); // skip this note if not in visible area at all - if( !( x + note_width >= 0 && x <= width() - WHITE_KEY_WIDTH ) ) + if (!(x + note_width >= 0 && x <= width() - m_whiteKeyWidth)) { continue; } // is the note in visible area? - if( key > 0 && key <= visible_keys ) + if (note->key() > bottomKey && note->key() <= topKey) { - // we've done and checked all, let's draw the - // note - drawNoteRect( p, x + WHITE_KEY_WIDTH, - y_base - key * m_keyLineHeight, - note_width, note, ghostNoteColor(), ghostNoteTextColor(), selectedNoteColor(), - ghostNoteOpacity(), ghostNoteBorders(), drawNoteNames ); + // we've done and checked all, let's draw the note + drawNoteRect( + p, x + m_whiteKeyWidth, y_base - key * m_keyLineHeight, note_width, + note, m_ghostNoteColor, m_ghostNoteTextColor, m_selectedNoteColor, + m_ghostNoteOpacity, m_ghostNoteBorders, drawNoteNames); } } @@ -3285,35 +3159,34 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) int pos_ticks = note->pos(); - int note_width = len_ticks * m_ppb / MidiTime::ticksPerBar(); + int note_width = len_ticks * m_ppb / TimePos::ticksPerBar(); const int x = ( pos_ticks - m_currentPosition ) * - m_ppb / MidiTime::ticksPerBar(); + m_ppb / TimePos::ticksPerBar(); // skip this note if not in visible area at all - if( !( x + note_width >= 0 && x <= width() - WHITE_KEY_WIDTH ) ) + if (!(x + note_width >= 0 && x <= width() - m_whiteKeyWidth)) { continue; } // is the note in visible area? - if( key > 0 && key <= visible_keys ) + if (note->key() > bottomKey && note->key() <= topKey) { - // we've done and checked all, let's draw the - // note - drawNoteRect( p, x + WHITE_KEY_WIDTH, - y_base - key * m_keyLineHeight, - note_width, note, noteColor(), noteTextColor(), selectedNoteColor(), - noteOpacity(), noteBorders(), drawNoteNames ); + // we've done and checked all, let's draw the note + drawNoteRect( + p, x + m_whiteKeyWidth, y_base - key * m_keyLineHeight, note_width, + note, m_noteColor, m_noteTextColor, m_selectedNoteColor, + m_noteOpacity, m_noteBorders, drawNoteNames); } // draw note editing stuff int editHandleTop = 0; if( m_noteEditMode == NoteEditVolume ) { - QColor color = barColor().lighter( 30 + ( note->getVolume() * 90 / MaxVolume ) ); + QColor color = m_barColor.lighter(30 + (note->getVolume() * 90 / MaxVolume)); if( note->selected() ) { - color = selectedNoteColor(); + color = m_selectedNoteColor; } p.setPen( QPen( color, NOTE_EDIT_LINE_WIDTH ) ); @@ -3328,10 +3201,10 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) } else if( m_noteEditMode == NoteEditPanning ) { - QColor color = noteColor(); + QColor color = m_noteColor; if( note->selected() ) { - color = selectedNoteColor(); + color = m_selectedNoteColor; } p.setPen( QPen( color, NOTE_EDIT_LINE_WIDTH ) ); @@ -3350,11 +3223,11 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) if( note->hasDetuningInfo() ) { - drawDetuningInfo( p, note, - x + WHITE_KEY_WIDTH, - y_base - key * m_keyLineHeight ); - p.setClipRect(WHITE_KEY_WIDTH, PR_TOP_MARGIN, - width() - WHITE_KEY_WIDTH, + drawDetuningInfo(p, note, x + m_whiteKeyWidth, y_base - key * m_keyLineHeight); + p.setClipRect( + m_whiteKeyWidth, + PR_TOP_MARGIN, + width() - m_whiteKeyWidth, height() - PR_TOP_MARGIN); } } @@ -3373,28 +3246,28 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) int pos_ticks = note->pos(); - int note_width = len_ticks * m_ppb / MidiTime::ticksPerBar(); + int note_width = len_ticks * m_ppb / TimePos::ticksPerBar(); const int x = ( pos_ticks - m_currentPosition ) * - m_ppb / MidiTime::ticksPerBar(); + m_ppb / TimePos::ticksPerBar(); // skip this note if not in visible area at all - if( !( x + note_width >= 0 && x <= width() - WHITE_KEY_WIDTH ) ) + if (!(x + note_width >= 0 && x <= width() - m_whiteKeyWidth)) { continue; } // is the note in visible area? - if( key > 0 && key <= visible_keys ) + if (note->key() > bottomKey && note->key() <= topKey) { // we've done and checked all, let's draw the note - drawNoteRect( p, x + WHITE_KEY_WIDTH, - y_base - key * m_keyLineHeight, - note_width, note, m_stepRecorder.curStepNoteColor(), noteTextColor(), selectedNoteColor(), - noteOpacity(), noteBorders(), drawNoteNames ); + drawNoteRect( + p, x + m_whiteKeyWidth, y_base - key * m_keyLineHeight, note_width, + note, m_stepRecorder.curStepNoteColor(), m_noteTextColor, m_selectedNoteColor, + m_noteOpacity, m_noteBorders, drawNoteNames); } } - p.setPen( QPen( noteColor(), NOTE_EDIT_LINE_WIDTH + 2 ) ); + p.setPen(QPen(m_noteColor, NOTE_EDIT_LINE_WIDTH + 2)); p.drawPoints( editHandles ); } @@ -3405,25 +3278,27 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) p.setFont( pointSize<14>( f ) ); p.setPen( QApplication::palette().color( QPalette::Active, QPalette::BrightText ) ); - p.drawText( WHITE_KEY_WIDTH + 20, PR_TOP_MARGIN + 40, + p.drawText(m_whiteKeyWidth + 20, PR_TOP_MARGIN + 40, tr( "Please open a pattern by double-clicking " "on it!" ) ); } - p.setClipRect( WHITE_KEY_WIDTH, PR_TOP_MARGIN, width() - - WHITE_KEY_WIDTH, height() - PR_TOP_MARGIN - - m_notesEditHeight - PR_BOTTOM_MARGIN ); + p.setClipRect( + m_whiteKeyWidth, + PR_TOP_MARGIN, + width() - m_whiteKeyWidth, + height() - PR_TOP_MARGIN - m_notesEditHeight - PR_BOTTOM_MARGIN); // now draw selection-frame int x = ( ( sel_pos_start - m_currentPosition ) * m_ppb ) / - MidiTime::ticksPerBar(); + TimePos::ticksPerBar(); int w = ( ( ( sel_pos_end - m_currentPosition ) * m_ppb ) / - MidiTime::ticksPerBar() ) - x; + TimePos::ticksPerBar() ) - x; int y = (int) y_base - sel_key_start * m_keyLineHeight; int h = (int) y_base - sel_key_end * m_keyLineHeight - y; - p.setPen( selectedNoteColor() ); + p.setPen(m_selectedNoteColor); p.setBrush( Qt::NoBrush ); - p.drawRect( x + WHITE_KEY_WIDTH, y, w, h ); + p.drawRect(x + m_whiteKeyWidth, y, w, h); // TODO: Get this out of paint event int l = ( hasValidPattern() )? (int) m_pattern->length() : 0; @@ -3436,70 +3311,92 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) } // set line colors - QColor editAreaCol = QColor( lineColor() ); - QColor currentKeyCol = QColor( beatLineColor() ); + QColor editAreaCol = QColor(m_lineColor); + QColor currentKeyCol = QColor(m_beatLineColor); editAreaCol.setAlpha( 64 ); currentKeyCol.setAlpha( 64 ); // horizontal line for the key under the cursor - if( hasValidPattern() ) + if(hasValidPattern() && gui->pianoRoll()->hasFocus()) { int key_num = getKey( mapFromGlobal( QCursor::pos() ).y() ); - p.fillRect( 10, key_line_y + 3 - m_keyLineHeight * + p.fillRect( 10, keyAreaBottom() + 3 - m_keyLineHeight * ( key_num - m_startKey + 1 ), width() - 10, m_keyLineHeight - 7, currentKeyCol ); } // bar to resize note edit area p.setClipRect( 0, 0, width(), height() ); - p.fillRect( QRect( 0, key_line_y, + p.fillRect( QRect( 0, keyAreaBottom(), width()-PR_RIGHT_MARGIN, NOTE_EDIT_RESIZE_BAR ), editAreaCol ); - const QPixmap * cursor = NULL; - // draw current edit-mode-icon below the cursor - switch( m_editMode ) + if (gui->pianoRoll()->hasFocus()) { - case ModeDraw: - if( m_mouseDownRight ) - { - cursor = s_toolErase; - } - else if( m_action == ActionMoveNote ) - { - cursor = s_toolMove; - } - else - { - cursor = s_toolDraw; - } - break; - case ModeErase: cursor = s_toolErase; break; - case ModeSelect: cursor = s_toolSelect; break; - case ModeEditDetuning: cursor = s_toolOpen; break; - } - QPoint mousePosition = mapFromGlobal( QCursor::pos() ); - if( cursor != NULL && mousePosition.y() > keyAreaTop() && mousePosition.x() > noteEditLeft()) - { - p.drawPixmap( mousePosition + QPoint( 8, 8 ), *cursor ); + const QPixmap * cursor = NULL; + // draw current edit-mode-icon below the cursor + switch( m_editMode ) + { + case ModeDraw: + if( m_mouseDownRight ) + { + cursor = s_toolErase; + } + else if( m_action == ActionMoveNote ) + { + cursor = s_toolMove; + } + else + { + cursor = s_toolDraw; + } + break; + case ModeErase: cursor = s_toolErase; break; + case ModeSelect: cursor = s_toolSelect; break; + case ModeEditDetuning: cursor = s_toolOpen; break; + } + QPoint mousePosition = mapFromGlobal( QCursor::pos() ); + if( cursor != NULL && mousePosition.y() > keyAreaTop() && mousePosition.x() > noteEditLeft()) + { + p.drawPixmap( mousePosition + QPoint( 8, 8 ), *cursor ); + } } } +void PianoRoll::updateScrollbars() +{ + m_leftRightScroll->setGeometry( + m_whiteKeyWidth, + height() - SCROLLBAR_SIZE, + width() - m_whiteKeyWidth, + SCROLLBAR_SIZE + ); + m_topBottomScroll->setGeometry( + width() - SCROLLBAR_SIZE, + PR_TOP_MARGIN, + SCROLLBAR_SIZE, + height() - PR_TOP_MARGIN - SCROLLBAR_SIZE + ); + int pianoAreaHeight = keyAreaBottom() - PR_TOP_MARGIN; + int numKeysVisible = pianoAreaHeight / m_keyLineHeight; + m_totalKeysToScroll = qMax(0, NumKeys - numKeysVisible); + m_topBottomScroll->setRange(0, m_totalKeysToScroll); + if (m_startKey > m_totalKeysToScroll) + { + m_startKey = qMax(0, m_totalKeysToScroll); + } + m_topBottomScroll->setValue(m_totalKeysToScroll - m_startKey); +} + // responsible for moving/resizing scrollbars after window-resizing void PianoRoll::resizeEvent(QResizeEvent * re) { - m_leftRightScroll->setGeometry( WHITE_KEY_WIDTH, - height() - - SCROLLBAR_SIZE, - width()-WHITE_KEY_WIDTH, - SCROLLBAR_SIZE ); - updateYScroll(); - - Engine::getSong()->getPlayPos( Song::Mode_PlayPattern - ).m_timeLine->setFixedWidth( width() ); - + updatePositionLineHeight(); + updateScrollbars(); + Engine::getSong()->getPlayPos(Song::Mode_PlayPattern) + .m_timeLine->setFixedWidth(width()); update(); } @@ -3510,17 +3407,17 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) { we->accept(); // handle wheel events for note edit area - for editing note vol/pan with mousewheel - if( we->x() > noteEditLeft() && we->x() < noteEditRight() - && we->y() > noteEditTop() && we->y() < noteEditBottom() ) + if(position(we).x() > noteEditLeft() && position(we).x() < noteEditRight() + && position(we).y() > noteEditTop() && position(we).y() < noteEditBottom()) { if (!hasValidPattern()) {return;} // get values for going through notes int pixel_range = 8; - int x = we->x() - WHITE_KEY_WIDTH; + int x = position(we).x() - m_whiteKeyWidth; int ticks_start = ( x - pixel_range / 2 ) * - MidiTime::ticksPerBar() / m_ppb + m_currentPosition; + TimePos::ticksPerBar() / m_ppb + m_currentPosition; int ticks_end = ( x + pixel_range / 2 ) * - MidiTime::ticksPerBar() / m_ppb + m_currentPosition; + TimePos::ticksPerBar() / m_ppb + m_currentPosition; // When alt is pressed we only edit the note under the cursor bool altPressed = we->modifiers() & Qt::AltModifier; @@ -3535,7 +3432,7 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) } if( nv.size() > 0 ) { - const int step = we->delta() > 0 ? 1 : -1; + const int step = we->angleDelta().y() > 0 ? 1 : -1; if( m_noteEditMode == NoteEditVolume ) { for ( Note * n : nv ) @@ -3552,7 +3449,7 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) { // show the volume hover-text only if all notes have the // same volume - showVolTextFloat( nv[0]->getVolume(), we->pos(), 1000 ); + showVolTextFloat(nv[0]->getVolume(), position(we), 1000); } } else if( m_noteEditMode == NoteEditPanning ) @@ -3571,7 +3468,7 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) { // show the pan hover-text only if all notes have the same // panning - showPanTextFloat( nv[0]->getPanning(), we->pos(), 1000 ); + showPanTextFloat( nv[0]->getPanning(), position( we ), 1000 ); } } update(); @@ -3583,11 +3480,11 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) if( we->modifiers() & Qt::ControlModifier && we->modifiers() & Qt::AltModifier ) { int q = m_quantizeModel.value(); - if( we->delta() > 0 ) + if((we->angleDelta().x() + we->angleDelta().y()) > 0) // alt + scroll becomes horizontal scroll on KDE { q--; } - else if( we->delta() < 0 ) + else if((we->angleDelta().x() + we->angleDelta().y()) < 0) // alt + scroll becomes horizontal scroll on KDE { q++; } @@ -3597,11 +3494,11 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) else if( we->modifiers() & Qt::ControlModifier && we->modifiers() & Qt::ShiftModifier ) { int l = m_noteLenModel.value(); - if( we->delta() > 0 ) + if(we->angleDelta().y() > 0) { l--; } - else if( we->delta() < 0 ) + else if(we->angleDelta().y() < 0) { l++; } @@ -3611,17 +3508,17 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) else if( we->modifiers() & Qt::ControlModifier ) { int z = m_zoomingModel.value(); - if( we->delta() > 0 ) + if(we->angleDelta().y() > 0) { z++; } - else if( we->delta() < 0 ) + else if(we->angleDelta().y() < 0) { z--; } z = qBound( 0, z, m_zoomingModel.size() - 1 ); - int x = (we->x() - WHITE_KEY_WIDTH)* MidiTime::ticksPerBar(); + int x = (position(we).x() - m_whiteKeyWidth) * TimePos::ticksPerBar(); // ticks based on the mouse x-position where the scroll wheel was used int ticks = x / m_ppb; // what would be the ticks in the new zoom level on the very same mouse x @@ -3631,16 +3528,22 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) // update combobox with zooming-factor m_zoomingModel.setValue( z ); } - else if( we->modifiers() & Qt::ShiftModifier - || we->orientation() == Qt::Horizontal ) + + // FIXME: Reconsider if determining orientation is necessary in Qt6. + else if(abs(we->angleDelta().x()) > abs(we->angleDelta().y())) // scrolling is horizontal + { + m_leftRightScroll->setValue(m_leftRightScroll->value() - + we->angleDelta().x() * 2 / 15); + } + else if(we->modifiers() & Qt::ShiftModifier) { - m_leftRightScroll->setValue( m_leftRightScroll->value() - - we->delta() * 2 / 15 ); + m_leftRightScroll->setValue(m_leftRightScroll->value() - + we->angleDelta().y() * 2 / 15); } else { - m_topBottomScroll->setValue( m_topBottomScroll->value() - - we->delta() / 30 ); + m_topBottomScroll->setValue(m_topBottomScroll->value() - + we->angleDelta().y() / 30); } } @@ -3661,27 +3564,28 @@ void PianoRoll::focusOutEvent( QFocusEvent * ) update(); } - - - -int PianoRoll::getKey(int y ) const +void PianoRoll::focusInEvent( QFocusEvent * ev ) { - int key_line_y = keyAreaBottom() - 1; - // pressed key on piano - int key_num = ( key_line_y - y ) / m_keyLineHeight; - key_num += m_startKey; - - // some range-checking-stuff - if( key_num < 0 ) + if ( hasValidPattern() ) { - key_num = 0; + // Assign midi device + m_pattern->instrumentTrack()->autoAssignMidiDevice(true); } + QWidget::focusInEvent(ev); +} + - if( key_num >= KeysPerOctave * NumOctaves ) - { - key_num = KeysPerOctave * NumOctaves - 1; - } +int PianoRoll::getKey(int y) const +{ + // handle case that very top pixel maps to next key above + if (y - keyAreaTop() <= 1) { y = keyAreaTop() + 2; } + int key_num = qBound( + 0, + // add + 1 to stay within the grid lines + ((keyAreaBottom() - y + 1) / m_keyLineHeight) + m_startKey, + NumKeys - 1 + ); return key_num; } @@ -3825,7 +3729,7 @@ void PianoRoll::startRecordNote(const Note & n ) (Engine::getSong()->playMode() == desiredPlayModeForAccompany() || Engine::getSong()->playMode() == Song::Mode_PlayPattern )) { - MidiTime sub; + TimePos sub; if( Engine::getSong()->playMode() == Song::Mode_PlaySong ) { sub = m_pattern->startPosition(); @@ -3899,7 +3803,7 @@ void PianoRoll::horScrolled(int new_pos ) void PianoRoll::verScrolled( int new_pos ) { // revert value - m_startKey = m_totalKeysToScroll - new_pos; + m_startKey = qMax(0, m_totalKeysToScroll - new_pos); update(); } @@ -3969,7 +3873,7 @@ void PianoRoll::selectAll() // returns vector with pointers to all selected notes -NoteVector PianoRoll::getSelectedNotes() +NoteVector PianoRoll::getSelectedNotes() const { NoteVector selectedNotes; @@ -4053,13 +3957,13 @@ void PianoRoll::updateYScroll() int total_pixels = m_octaveHeight * NumOctaves - (height() - PR_TOP_MARGIN - PR_BOTTOM_MARGIN - m_notesEditHeight); - m_totalKeysToScroll = total_pixels * KeysPerOctave / m_octaveHeight; + m_totalKeysToScroll = qMax(0, total_pixels * KeysPerOctave / m_octaveHeight); m_topBottomScroll->setRange(0, m_totalKeysToScroll); if(m_startKey > m_totalKeysToScroll) { - m_startKey = m_totalKeysToScroll; + m_startKey = qMax(0, m_totalKeysToScroll); } m_topBottomScroll->setValue(m_totalKeysToScroll - m_startKey); } @@ -4067,11 +3971,14 @@ void PianoRoll::updateYScroll() void PianoRoll::copyToClipboard( const NoteVector & notes ) const { + // For copyString() and MimeType enum class + using namespace Clipboard; + DataFile dataFile( DataFile::ClipboardData ); QDomElement note_list = dataFile.createElement( "note-list" ); dataFile.content().appendChild( note_list ); - MidiTime start_pos( notes.front()->pos().getBar(), 0 ); + TimePos start_pos( notes.front()->pos().getBar(), 0 ); for( const Note *note : notes ) { Note clip_note( *note ); @@ -4079,10 +3986,7 @@ void PianoRoll::copyToClipboard( const NoteVector & notes ) const clip_note.saveState( dataFile, note_list ); } - QMimeData * clip_content = new QMimeData; - clip_content->setData( Clipboard::mimeType(), dataFile.toString().toUtf8() ); - QApplication::clipboard()->setMimeData( clip_content, - QClipboard::Clipboard ); + copyString( dataFile.toString(), MimeType::Default ); } @@ -4135,14 +4039,15 @@ void PianoRoll::cutSelectedNotes() void PianoRoll::pasteNotes() { + // For getString() and MimeType enum class + using namespace Clipboard; + if( ! hasValidPattern() ) { return; } - QString value = QApplication::clipboard() - ->mimeData( QClipboard::Clipboard ) - ->data( Clipboard::mimeType() ); + QString value = getString( MimeType::Default ); if( ! value.isEmpty() ) { @@ -4183,64 +4088,39 @@ void PianoRoll::pasteNotes() -void PianoRoll::deleteSelectedNotes() +//Return false if no notes are deleted +bool PianoRoll::deleteSelectedNotes() { - if( ! hasValidPattern() ) - { - return; - } + if (!hasValidPattern()) { return false; } - bool update_after_delete = false; + auto selectedNotes = getSelectedNotes(); + if (selectedNotes.empty()) { return false; } m_pattern->addJournalCheckPoint(); - // get note-vector of current pattern - const NoteVector & notes = m_pattern->notes(); - - // will be our iterator in the following loop - NoteVector::ConstIterator it = notes.begin(); - while( it != notes.end() ) - { - Note *note = *it; - if( note->selected() ) - { - // delete this note - m_pattern->removeNote( note ); - update_after_delete = true; - - // start over, make sure we get all the notes - it = notes.begin(); - } - else - { - ++it; - } - } - - if( update_after_delete ) - { - Engine::getSong()->setModified(); - update(); - gui->songEditor()->update(); - } + for (Note* note: selectedNotes) { m_pattern->removeNote( note ); } + Engine::getSong()->setModified(); + update(); + gui->songEditor()->update(); + return true; } -void PianoRoll::autoScroll( const MidiTime & t ) +void PianoRoll::autoScroll( const TimePos & t ) { - const int w = width() - WHITE_KEY_WIDTH; - if( t > m_currentPosition + w * MidiTime::ticksPerBar() / m_ppb ) + const int w = width() - m_whiteKeyWidth; + if( t > m_currentPosition + w * TimePos::ticksPerBar() / m_ppb ) { - m_leftRightScroll->setValue( t.getBar() * MidiTime::ticksPerBar() ); + m_leftRightScroll->setValue( t.getBar() * TimePos::ticksPerBar() ); } else if( t < m_currentPosition ) { - MidiTime t2 = qMax( t - w * MidiTime::ticksPerBar() * - MidiTime::ticksPerBar() / m_ppb, (tick_t) 0 ); - m_leftRightScroll->setValue( t2.getBar() * MidiTime::ticksPerBar() ); + TimePos t2 = qMax( t - w * TimePos::ticksPerBar() * + TimePos::ticksPerBar() / m_ppb, (tick_t) 0 ); + m_leftRightScroll->setValue( t2.getBar() * TimePos::ticksPerBar() ); } m_scrollBack = false; } @@ -4248,7 +4128,7 @@ void PianoRoll::autoScroll( const MidiTime & t ) -void PianoRoll::updatePosition( const MidiTime & t ) +void PianoRoll::updatePosition( const TimePos & t ) { if( ( Engine::getSong()->isPlaying() && Engine::getSong()->playMode() == Song::Mode_PlayPattern @@ -4257,19 +4137,35 @@ void PianoRoll::updatePosition( const MidiTime & t ) { autoScroll( t ); } + const int pos = m_timeLine->pos() * m_ppb / TimePos::ticksPerBar(); + if (pos >= m_currentPosition && pos <= m_currentPosition + width() - m_whiteKeyWidth) + { + m_positionLine->show(); + m_positionLine->move(pos - (m_positionLine->width() - 1) - m_currentPosition + m_whiteKeyWidth, keyAreaTop()); + } + else + { + m_positionLine->hide(); + } +} + + +void PianoRoll::updatePositionLineHeight() +{ + m_positionLine->setFixedHeight(keyAreaBottom() - keyAreaTop()); } -void PianoRoll::updatePositionAccompany( const MidiTime & t ) +void PianoRoll::updatePositionAccompany( const TimePos & t ) { Song * s = Engine::getSong(); if( m_recording && hasValidPattern() && s->playMode() != Song::Mode_PlayPattern ) { - MidiTime pos = t; + TimePos pos = t; if( s->playMode() != Song::Mode_PlayBB ) { pos -= m_pattern->startPosition(); @@ -4283,7 +4179,7 @@ void PianoRoll::updatePositionAccompany( const MidiTime & t ) } -void PianoRoll::updatePositionStepRecording( const MidiTime & t ) +void PianoRoll::updatePositionStepRecording( const TimePos & t ) { if( m_stepRecorder.isRecording() ) { @@ -4300,6 +4196,7 @@ void PianoRoll::zoomingChanged() m_timeLine->setPixelsPerBar( m_ppb ); m_stepRecorderWidget.setPixelsPerBar( m_ppb ); + m_positionLine->zoomChange(m_zoomLevels[m_zoomingModel.value()]); update(); } @@ -4309,9 +4206,9 @@ void PianoRoll::zoomingYChanged() { m_keyLineHeight = m_zoomYLevels[m_zoomingYModel.value()] * DEFAULT_KEY_LINE_HEIGHT; m_octaveHeight = m_keyLineHeight * KeysPerOctave; - m_whiteKeySmallHeight = round(m_keyLineHeight * 1.5); + m_whiteKeySmallHeight = qFloor(m_keyLineHeight * 1.5); m_whiteKeyBigHeight = m_keyLineHeight * 2; - m_blackKeyHeight = round(m_keyLineHeight * 1.3333); + m_blackKeyHeight = m_keyLineHeight; //round(m_keyLineHeight * 1.3333); updateYScroll(); update(); @@ -4329,6 +4226,10 @@ void PianoRoll::noteLengthChanged() update(); } +void PianoRoll::keyChanged() +{ + markSemiTone(stmaMarkCurrentScale, false); +} int PianoRoll::quantization() const { @@ -4344,8 +4245,7 @@ int PianoRoll::quantization() const } } - QString text = m_quantizeModel.currentText(); - return DefaultTicksPerBar / text.right( text.length() - 2 ).toInt(); + return DefaultTicksPerBar / Quantizations[m_quantizeModel.value() - 1]; } @@ -4370,7 +4270,7 @@ void PianoRoll::quantizeNotes() for( Note* n : notes ) { - if( n->length() == MidiTime( 0 ) ) + if( n->length() == TimePos( 0 ) ) { continue; } @@ -4405,7 +4305,7 @@ void PianoRoll::updateSemiToneMarkerMenu() -MidiTime PianoRoll::newNoteLen() const +TimePos PianoRoll::newNoteLen() const { if( m_noteLenModel.value() == 0 ) { @@ -4431,7 +4331,7 @@ Note * PianoRoll::noteUnderMouse() { QPoint pos = mapFromGlobal( QCursor::pos() ); - if( pos.x() <= WHITE_KEY_WIDTH + if (pos.x() <= m_whiteKeyWidth || pos.x() > width() - SCROLLBAR_SIZE || pos.y() < PR_TOP_MARGIN || pos.y() > keyAreaBottom() ) @@ -4440,8 +4340,8 @@ Note * PianoRoll::noteUnderMouse() } int key_num = getKey( pos.y() ); - int pos_ticks = ( pos.x() - WHITE_KEY_WIDTH ) * - MidiTime::ticksPerBar() / m_ppb + m_currentPosition; + int pos_ticks = (pos.x() - m_whiteKeyWidth) * + TimePos::ticksPerBar() / m_ppb + m_currentPosition; // loop through whole note-vector... for( Note* const& note : m_pattern->notes() ) @@ -4531,6 +4431,21 @@ PianoRollWindow::PianoRollWindow() : DropToolBar *timeLineToolBar = addDropToolBarToTop( tr( "Timeline controls" ) ); m_editor->m_timeLine->addToolButtons( timeLineToolBar ); + // -- Note modifier tools + // Toolbar + QToolButton * noteToolsButton = new QToolButton(m_toolBar); + noteToolsButton->setIcon(embed::getIconPixmap("tool")); + noteToolsButton->setPopupMode(QToolButton::InstantPopup); + + // Glue + QAction * glueAction = new QAction(embed::getIconPixmap("glue"), + tr("Glue"), noteToolsButton); + connect(glueAction, SIGNAL(triggered()), m_editor, SLOT(glueNotes())); + glueAction->setShortcut( Qt::SHIFT | Qt::Key_G ); + + noteToolsButton->addAction(glueAction); + + notesActionsToolBar->addWidget(noteToolsButton); addToolBarBreak(); @@ -4542,7 +4457,7 @@ PianoRollWindow::PianoRollWindow() : m_zoomingComboBox = new ComboBox( m_toolBar ); m_zoomingComboBox->setModel( &m_editor->m_zoomingModel ); - m_zoomingComboBox->setFixedSize( 64, 22 ); + m_zoomingComboBox->setFixedSize( 64, ComboBox::DEFAULT_HEIGHT ); m_zoomingComboBox->setToolTip( tr( "Horizontal zooming") ); QLabel * zoom_y_lbl = new QLabel(m_toolBar); @@ -4550,7 +4465,7 @@ PianoRollWindow::PianoRollWindow() : m_zoomingYComboBox = new ComboBox(m_toolBar); m_zoomingYComboBox->setModel(&m_editor->m_zoomingYModel); - m_zoomingYComboBox->setFixedSize(64, 22); + m_zoomingYComboBox->setFixedSize(64, ComboBox::DEFAULT_HEIGHT); m_zoomingYComboBox->setToolTip(tr("Vertical zooming")); // setup quantize-stuff @@ -4559,7 +4474,7 @@ PianoRollWindow::PianoRollWindow() : m_quantizeComboBox = new ComboBox( m_toolBar ); m_quantizeComboBox->setModel( &m_editor->m_quantizeModel ); - m_quantizeComboBox->setFixedSize( 64, 22 ); + m_quantizeComboBox->setFixedSize( 64, ComboBox::DEFAULT_HEIGHT ); m_quantizeComboBox->setToolTip( tr( "Quantization") ); // setup note-len-stuff @@ -4568,16 +4483,22 @@ PianoRollWindow::PianoRollWindow() : m_noteLenComboBox = new ComboBox( m_toolBar ); m_noteLenComboBox->setModel( &m_editor->m_noteLenModel ); - m_noteLenComboBox->setFixedSize( 105, 22 ); + m_noteLenComboBox->setFixedSize( 105, ComboBox::DEFAULT_HEIGHT ); m_noteLenComboBox->setToolTip( tr( "Note length") ); + // setup key-stuff + m_keyComboBox = new ComboBox(m_toolBar); + m_keyComboBox->setModel(&m_editor->m_keyModel); + m_keyComboBox->setFixedSize(72, ComboBox::DEFAULT_HEIGHT); + m_keyComboBox->setToolTip(tr("Key")); + // setup scale-stuff QLabel * scale_lbl = new QLabel( m_toolBar ); scale_lbl->setPixmap( embed::getIconPixmap( "scale" ) ); m_scaleComboBox = new ComboBox( m_toolBar ); m_scaleComboBox->setModel( &m_editor->m_scaleModel ); - m_scaleComboBox->setFixedSize( 105, 22 ); + m_scaleComboBox->setFixedSize( 105, ComboBox::DEFAULT_HEIGHT ); m_scaleComboBox->setToolTip( tr( "Scale") ); // setup chord-stuff @@ -4586,7 +4507,7 @@ PianoRollWindow::PianoRollWindow() : m_chordComboBox = new ComboBox( m_toolBar ); m_chordComboBox->setModel( &m_editor->m_chordModel ); - m_chordComboBox->setFixedSize( 105, 22 ); + m_chordComboBox->setFixedSize( 105, ComboBox::DEFAULT_HEIGHT ); m_chordComboBox->setToolTip( tr( "Chord" ) ); // -- Clear ghost pattern button @@ -4597,27 +4518,61 @@ PianoRollWindow::PianoRollWindow() : connect( m_clearGhostButton, SIGNAL( clicked() ), m_editor, SLOT( clearGhostPattern() ) ); connect( m_editor, SIGNAL( ghostPatternSet( bool ) ), this, SLOT( ghostPatternSet( bool ) ) ); - zoomAndNotesToolBar->addWidget( zoom_lbl ); - zoomAndNotesToolBar->addWidget( m_zoomingComboBox ); - - zoomAndNotesToolBar->addWidget(zoom_y_lbl); - zoomAndNotesToolBar->addWidget(m_zoomingYComboBox); - + // Wrap label icons and comboboxes in a single widget so when + // the window is resized smaller in width it hides both + QWidget * zoom_widget = new QWidget(); + QHBoxLayout * zoom_hbox = new QHBoxLayout(); + zoom_hbox->setContentsMargins(0, 0, 0, 0); + zoom_hbox->addWidget(zoom_lbl); + zoom_hbox->addWidget(m_zoomingComboBox); + zoom_widget->setLayout(zoom_hbox); + zoomAndNotesToolBar->addWidget(zoom_widget); + + QWidget * zoomY_widget = new QWidget(); + QHBoxLayout * zoomY_hbox = new QHBoxLayout(); + zoomY_hbox->setContentsMargins(0, 0, 0, 0); + zoomY_hbox->addWidget(zoom_y_lbl); + zoomY_hbox->addWidget(m_zoomingYComboBox); + zoomY_widget->setLayout(zoomY_hbox); + zoomAndNotesToolBar->addWidget(zoomY_widget); + + QWidget * quantize_widget = new QWidget(); + QHBoxLayout * quantize_hbox = new QHBoxLayout(); + quantize_hbox->setContentsMargins(0, 0, 0, 0); + quantize_hbox->addWidget(quantize_lbl); + quantize_hbox->addWidget(m_quantizeComboBox); + quantize_widget->setLayout(quantize_hbox); zoomAndNotesToolBar->addSeparator(); - zoomAndNotesToolBar->addWidget( quantize_lbl ); - zoomAndNotesToolBar->addWidget( m_quantizeComboBox ); - + zoomAndNotesToolBar->addWidget(quantize_widget); + + QWidget * note_widget = new QWidget(); + QHBoxLayout * note_hbox = new QHBoxLayout(); + note_hbox->setContentsMargins(0, 0, 0, 0); + note_hbox->addWidget(note_len_lbl); + note_hbox->addWidget(m_noteLenComboBox); + note_widget->setLayout(note_hbox); zoomAndNotesToolBar->addSeparator(); - zoomAndNotesToolBar->addWidget( note_len_lbl ); - zoomAndNotesToolBar->addWidget( m_noteLenComboBox ); - + zoomAndNotesToolBar->addWidget(note_widget); + + QWidget * scale_widget = new QWidget(); + QHBoxLayout * scale_hbox = new QHBoxLayout(); + scale_hbox->setContentsMargins(0, 0, 0, 0); + scale_hbox->addWidget(scale_lbl); + // Add the key selection between scale label and key + scale_hbox->addWidget(m_keyComboBox); + scale_hbox->addWidget(m_scaleComboBox); + scale_widget->setLayout(scale_hbox); zoomAndNotesToolBar->addSeparator(); - zoomAndNotesToolBar->addWidget( scale_lbl ); - zoomAndNotesToolBar->addWidget( m_scaleComboBox ); - + zoomAndNotesToolBar->addWidget(scale_widget); + + QWidget * chord_widget = new QWidget(); + QHBoxLayout * chord_hbox = new QHBoxLayout(); + chord_hbox->setContentsMargins(0, 0, 0, 0); + chord_hbox->addWidget(chord_lbl); + chord_hbox->addWidget(m_chordComboBox); + chord_widget->setLayout(chord_hbox); zoomAndNotesToolBar->addSeparator(); - zoomAndNotesToolBar->addWidget( chord_lbl ); - zoomAndNotesToolBar->addWidget( m_chordComboBox ); + zoomAndNotesToolBar->addWidget(chord_widget); zoomAndNotesToolBar->addSeparator(); zoomAndNotesToolBar->addWidget( m_clearGhostButton ); @@ -4792,6 +4747,14 @@ void PianoRollWindow::loadSettings( const QDomElement & de ) m_editor->loadMarkedSemiTones(de.firstChildElement("markedSemiTones")); MainWindow::restoreWidgetState( this, de ); + + // update margins here because we're later in the startup process + // We can't earlier because everything is still starting with the + // WHITE_KEY_WIDTH default + QMargins qm = m_editor->m_stepRecorderWidget.margins(); + qm.setLeft(m_editor->m_whiteKeyWidth); + m_editor->m_stepRecorderWidget.setMargins(qm); + m_editor->m_timeLine->setXOffset(m_editor->m_whiteKeyWidth); } @@ -4804,6 +4767,13 @@ QSize PianoRollWindow::sizeHint() const +bool PianoRollWindow::hasFocus() const +{ + return m_editor->hasFocus(); +} + + + void PianoRollWindow::updateAfterPatternChange() { patternRenamed(); diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 716b2f73493..c20ac7a3b7f 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -24,7 +24,6 @@ #include "SongEditor.h" -#include #include #include #include @@ -32,46 +31,32 @@ #include #include #include +#include +#include +#include "AudioDevice.h" #include "AutomatableSlider.h" #include "ComboBox.h" #include "ConfigManager.h" #include "CPULoadWidget.h" +#include "DeprecationHelper.h" #include "embed.h" #include "GuiApplication.h" #include "LcdSpinBox.h" #include "MainWindow.h" #include "MeterDialog.h" #include "Mixer.h" +#include "Oscilloscope.h" +#include "PianoRoll.h" #include "TextFloat.h" +#include "TimeDisplayWidget.h" #include "TimeLineWidget.h" #include "ToolTip.h" -#include "Oscilloscope.h" -#include "TimeDisplayWidget.h" -#include "AudioDevice.h" -#include "PianoRoll.h" #include "Track.h" -positionLine::positionLine( QWidget * parent ) : - QWidget( parent ) -{ - setFixedWidth( 1 ); - setAttribute( Qt::WA_NoSystemBackground, true ); -} - - - - -void positionLine::paintEvent( QPaintEvent * pe ) -{ - QPainter p( this ); - p.fillRect( rect(), QColor( 255, 255, 255, 153 ) ); -} - const QVector SongEditor::m_zoomLevels = { 0.125f, 0.25f, 0.5f, 1.0f, 2.0f, 4.0f, 8.0f, 16.0f }; - SongEditor::SongEditor( Song * song ) : TrackContainerView( song ), m_song( song ), @@ -85,7 +70,7 @@ SongEditor::SongEditor( Song * song ) : m_scrollPos(), m_mousePos(), m_rubberBandStartTrackview(0), - m_rubberbandStartMidipos(0), + m_rubberbandStartTimePos(0), m_currentZoomingValue(m_zoomingModel->value()), m_trackHeadWidth(ConfigManager::inst()->value("ui", "compacttrackbuttons").toInt()==1 ? DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT + TRACK_OP_WIDTH_COMPACT @@ -99,18 +84,23 @@ SongEditor::SongEditor( Song * song ) : m_song->m_playPos[Song::Mode_PlaySong], m_currentPosition, Song::Mode_PlaySong, this ); - connect( this, SIGNAL( positionChanged( const MidiTime & ) ), + connect( this, SIGNAL( positionChanged( const TimePos & ) ), m_song->m_playPos[Song::Mode_PlaySong].m_timeLine, - SLOT( updatePosition( const MidiTime & ) ) ); - connect( m_timeLine, SIGNAL( positionChanged( const MidiTime & ) ), - this, SLOT( updatePosition( const MidiTime & ) ) ); + SLOT( updatePosition( const TimePos & ) ) ); + connect( m_timeLine, SIGNAL( positionChanged( const TimePos & ) ), + this, SLOT( updatePosition( const TimePos & ) ) ); connect( m_timeLine, SIGNAL( regionSelectedFromPixels( int, int ) ), this, SLOT( selectRegionFromPixels( int, int ) ) ); connect( m_timeLine, SIGNAL( selectionFinished() ), this, SLOT( stopRubberBand() ) ); - m_positionLine = new positionLine( this ); + m_positionLine = new PositionLine(this); static_cast( layout() )->insertWidget( 1, m_timeLine ); + + connect( m_song, SIGNAL( playbackStateChanged() ), + m_positionLine, SLOT( update() ) ); + connect( this, SIGNAL( zoomingValueChanged( double ) ), + m_positionLine, SLOT( zoomChange( double ) ) ); // add some essential widgets to global tool-bar @@ -250,6 +240,8 @@ SongEditor::SongEditor( Song * song ) : m_zoomingModel->findText( "100%" ) ); connect( m_zoomingModel, SIGNAL( dataChanged() ), this, SLOT( zoomingChanged() ) ); + connect( m_zoomingModel, SIGNAL( dataChanged() ), + m_positionLine, SLOT( update() ) ); //Set up snapping model, 2^i for ( int i = 3; i >= -4; i-- ) @@ -302,7 +294,7 @@ float SongEditor::getSnapSize() const { val = val - m_zoomingModel->value() + 3; } - val = max(val, -6); // -6 gives 1/64th bar snapping. Lower values cause crashing. + val = std::max(val, -6); // -6 gives 1/64th bar snapping. Lower values cause crashing. if ( val >= 0 ){ return 1 << val; @@ -316,7 +308,7 @@ QString SongEditor::getSnapSizeString() const { int val = -m_snappingModel->value() + 3; val = val - m_zoomingModel->value() + 3; - val = max(val, -6); // -6 gives 1/64th bar snapping. Lower values cause crashing. + val = std::max(val, -6); // -6 gives 1/64th bar snapping. Lower values cause crashing. if ( val >= 0 ){ int bars = 1 << val; @@ -348,7 +340,7 @@ void SongEditor::setHighQuality( bool hq ) void SongEditor::scrolled( int new_pos ) { update(); - emit positionChanged( m_currentPosition = MidiTime( new_pos, 0 ) ); + emit positionChanged( m_currentPosition = TimePos( new_pos, 0 ) ); } @@ -372,8 +364,8 @@ void SongEditor::selectRegionFromPixels(int xStart, int xEnd) m_currentZoomingValue = zoomingModel()->value(); //calculate the song position where the mouse was clicked - m_rubberbandStartMidipos = MidiTime((xStart - m_trackHeadWidth) - / pixelsPerBar() * MidiTime::ticksPerBar()) + m_rubberbandStartTimePos = TimePos((xStart - m_trackHeadWidth) + / pixelsPerBar() * TimePos::ticksPerBar()) + m_currentPosition; m_rubberBandStartTrackview = 0; } @@ -422,9 +414,9 @@ void SongEditor::updateRubberband() //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()) + //the time position the mouse is hover + TimePos rubberbandTimePos = TimePos((qMin(m_mousePos.x(), width()) - m_trackHeadWidth) + / pixelsPerBar() * TimePos::ticksPerBar()) + m_currentPosition; //are tcos in the rect of selection? @@ -436,9 +428,9 @@ void SongEditor::updateRubberband() 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); + bool isBeetweenRubberbandTimePos = tco->getTrackContentObject()->endPosition() >= qMin(m_rubberbandStartTimePos, rubberbandTimePos) + && tco->getTrackContentObject()->startPosition() <= qMax(m_rubberbandStartTimePos, rubberbandTimePos); + it->setSelected(isBeetweenRubberbandViews && isBeetweenRubberbandTimePos); } } } @@ -485,7 +477,7 @@ void SongEditor::keyPressEvent( QKeyEvent * ke ) } else if( ke->key() == Qt::Key_Left ) { - tick_t t = m_song->currentTick() - MidiTime::ticksPerBar(); + tick_t t = m_song->currentTick() - TimePos::ticksPerBar(); if( t >= 0 ) { m_song->setPlayPos( t, Song::Mode_PlaySong ); @@ -493,7 +485,7 @@ void SongEditor::keyPressEvent( QKeyEvent * ke ) } else if( ke->key() == Qt::Key_Right ) { - tick_t t = m_song->currentTick() + MidiTime::ticksPerBar(); + tick_t t = m_song->currentTick() + TimePos::ticksPerBar(); if( t < MaxSongLength ) { m_song->setPlayPos( t, Song::Mode_PlaySong ); @@ -503,9 +495,8 @@ void SongEditor::keyPressEvent( QKeyEvent * ke ) { m_song->setPlayPos( 0, Song::Mode_PlaySong ); } - else if( ke->key() == Qt::Key_Delete ) + else if( ke->key() == Qt::Key_Delete || ke->key() == Qt::Key_Backspace ) { - QVector tcoViews; QVector so = selectedObjects(); for( QVector::iterator it = so.begin(); it != so.end(); ++it ) @@ -538,18 +529,18 @@ void SongEditor::wheelEvent( QWheelEvent * we ) { int z = m_zoomingModel->value(); - if( we->delta() > 0 ) + if(we->angleDelta().y() > 0) { z++; } - else if( we->delta() < 0 ) + else if(we->angleDelta().y() < 0) { z--; } z = qBound( 0, z, m_zoomingModel->size() - 1 ); - int x = we->x() - m_trackHeadWidth; + int x = position(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 @@ -566,10 +557,17 @@ void SongEditor::wheelEvent( QWheelEvent * we ) // and make sure, all TCO's are resized and relocated realignTracks(); } - else if( we->modifiers() & Qt::ShiftModifier || we->orientation() == Qt::Horizontal ) + + // FIXME: Reconsider if determining orientation is necessary in Qt6. + else if(abs(we->angleDelta().x()) > abs(we->angleDelta().y())) // scrolling is horizontal + { + m_leftRightScroll->setValue(m_leftRightScroll->value() - + we->angleDelta().x() /30); + } + else if(we->modifiers() & Qt::ShiftModifier) { - m_leftRightScroll->setValue( m_leftRightScroll->value() - - we->delta() / 30 ); + m_leftRightScroll->setValue(m_leftRightScroll->value() - + we->angleDelta().y() / 30); } else { @@ -611,10 +609,10 @@ void SongEditor::mousePressEvent(QMouseEvent *me) rubberBand()->setGeometry(QRect(m_origin, QSize())); rubberBand()->show(); - //the trackView(index) and the miditime where the mouse was clicked + //the trackView(index) and the time position where the mouse was clicked m_rubberBandStartTrackview = trackIndexFromSelectionPoint(me->y()); - m_rubberbandStartMidipos = MidiTime((me->x() - m_trackHeadWidth) - / pixelsPerBar() * MidiTime::ticksPerBar()) + m_rubberbandStartTimePos = TimePos((me->x() - m_trackHeadWidth) + / pixelsPerBar() * TimePos::ticksPerBar()) + m_currentPosition; } QWidget::mousePressEvent(me); @@ -769,7 +767,7 @@ static inline void animateScroll( QScrollBar *scrollBar, int newVal, bool smooth -void SongEditor::updatePosition( const MidiTime & t ) +void SongEditor::updatePosition( const TimePos & t ) { int widgetWidth, trackOpWidth; if( ConfigManager::inst()->value( "ui", "compacttrackbuttons" ).toInt() ) @@ -791,7 +789,7 @@ 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::ticksPerBar() / + if( t > m_currentPosition + w * TimePos::ticksPerBar() / pixelsPerBar() ) { animateScroll( m_leftRightScroll, t.getBar(), m_smoothScroll ); @@ -808,7 +806,7 @@ void SongEditor::updatePosition( const MidiTime & t ) if( x >= trackOpWidth + widgetWidth -1 ) { m_positionLine->show(); - m_positionLine->move( x, m_timeLine->height() ); + m_positionLine->move( x-( m_positionLine->width() - 1 ), m_timeLine->height() ); } else { @@ -837,11 +835,11 @@ void SongEditor::zoomingChanged() setPixelsPerBar( pixelsPerBar() ); realignTracks(); updateRubberband(); + + emit zoomingValueChanged( m_zoomLevels[m_zoomingModel->value()] ); } - - void SongEditor::selectAllTcos( bool select ) { QVector so = select ? rubberBand()->selectableObjects() : rubberBand()->selectedObjects(); @@ -958,6 +956,13 @@ SongEditorWindow::SongEditorWindow(Song* song) : DropToolBar *timeLineToolBar = addDropToolBarToTop(tr("Timeline controls")); m_editor->m_timeLine->addToolButtons(timeLineToolBar); + DropToolBar *insertActionsToolBar = addDropToolBarToTop(tr("Bar insert controls")); + m_insertBarAction = new QAction(embed::getIconPixmap("insert_bar"), tr("Insert bar"), this); + m_removeBarAction = new QAction(embed::getIconPixmap("remove_bar"), tr("Remove bar"), this); + insertActionsToolBar->addAction( m_insertBarAction ); + insertActionsToolBar->addAction( m_removeBarAction ); + connect(m_insertBarAction, SIGNAL(triggered()), song, SLOT(insertBar())); + connect(m_removeBarAction, SIGNAL(triggered()), song, SLOT(removeBar())); DropToolBar *zoomToolBar = addDropToolBarToTop(tr("Zoom controls")); @@ -966,7 +971,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : //Set up zooming-stuff m_zoomingComboBox = new ComboBox( m_toolBar ); - m_zoomingComboBox->setFixedSize( 80, 22 ); + m_zoomingComboBox->setFixedSize( 80, ComboBox::DEFAULT_HEIGHT ); m_zoomingComboBox->move( 580, 4 ); m_zoomingComboBox->setModel(m_editor->m_zoomingModel); m_zoomingComboBox->setToolTip(tr("Horizontal zooming")); @@ -981,7 +986,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : //Set up quantization/snapping selector m_snappingComboBox = new ComboBox( m_toolBar ); - m_snappingComboBox->setFixedSize( 80, 22 ); + m_snappingComboBox->setFixedSize( 80, ComboBox::DEFAULT_HEIGHT ); m_snappingComboBox->setModel(m_editor->m_snappingModel); m_snappingComboBox->setToolTip(tr("Clip snapping size")); connect(m_editor->snappingModel(), SIGNAL(dataChanged()), this, SLOT(updateSnapLabel())); diff --git a/src/gui/widgets/ComboBox.cpp b/src/gui/widgets/ComboBox.cpp index c796bfa74c8..4ef43bee74e 100644 --- a/src/gui/widgets/ComboBox.cpp +++ b/src/gui/widgets/ComboBox.cpp @@ -51,6 +51,8 @@ ComboBox::ComboBox( QWidget * _parent, const QString & _name ) : m_menu( this ), m_pressed( false ) { + setFixedHeight( ComboBox::DEFAULT_HEIGHT ); + if( s_background == NULL ) { s_background = new QPixmap( embed::getIconPixmap( "combobox_bg" ) ); @@ -192,7 +194,7 @@ void ComboBox::paintEvent( QPaintEvent * _pe ) // Border QStyleOptionFrame opt; opt.initFrom( this ); - opt.state = 0; + opt.state = QStyle::StateFlag::State_None; style()->drawPrimitive( QStyle::PE_Frame, &opt, &p, this ); @@ -230,7 +232,7 @@ void ComboBox::wheelEvent( QWheelEvent* event ) { if( model() ) { - model()->setInitValue( model()->value() + ( ( event->delta() < 0 ) ? 1 : -1 ) ); + model()->setInitValue(model()->value() + ((event->angleDelta().y() < 0) ? 1 : -1)); update(); event->accept(); } diff --git a/src/gui/widgets/ControlLayout.cpp b/src/gui/widgets/ControlLayout.cpp index ce2e9e4ef9b..aa265b14e5b 100644 --- a/src/gui/widgets/ControlLayout.cpp +++ b/src/gui/widgets/ControlLayout.cpp @@ -177,6 +177,11 @@ QLayoutItem *ControlLayout::takeAt(int index) return (itr == m_itemMap.end()) ? nullptr : m_itemMap.take(itr.key()); } +void ControlLayout::removeFocusFromSearchBar() +{ + m_searchBar->clearFocus(); +} + Qt::Orientations ControlLayout::expandingDirections() const { return Qt::Orientations(); diff --git a/src/gui/widgets/Controls.cpp b/src/gui/widgets/Controls.cpp index 15b4e0d282a..98aaf0e0eee 100644 --- a/src/gui/widgets/Controls.cpp +++ b/src/gui/widgets/Controls.cpp @@ -78,7 +78,7 @@ ComboControl::ComboControl(QWidget *parent) : m_combo(new ComboBox(nullptr)), m_label(new QLabel(m_widget)) { - m_combo->setFixedSize(64, 22); + m_combo->setFixedSize(64, ComboBox::DEFAULT_HEIGHT); QVBoxLayout* vbox = new QVBoxLayout(m_widget); vbox->addWidget(m_combo); vbox->addWidget(m_label); diff --git a/src/gui/widgets/CustomTextKnob.cpp b/src/gui/widgets/CustomTextKnob.cpp new file mode 100644 index 00000000000..149b3494be6 --- /dev/null +++ b/src/gui/widgets/CustomTextKnob.cpp @@ -0,0 +1,14 @@ +#include "CustomTextKnob.h" + +CustomTextKnob::CustomTextKnob( knobTypes _knob_num, QWidget * _parent, const QString & _name, const QString & _value_text ) : + Knob( _knob_num, _parent, _name ), + m_value_text( _value_text ) {} + +CustomTextKnob::CustomTextKnob( QWidget * _parent, const QString & _name, const QString & _value_text ) : //!< default ctor + Knob( _parent, _name ), + m_value_text( _value_text ) {} + +QString CustomTextKnob::displayValue() const +{ + return m_description.trimmed() + m_value_text; +} diff --git a/src/gui/widgets/EffectRackView.cpp b/src/gui/widgets/EffectRackView.cpp index 6af490a42a8..c0761e7f8f0 100644 --- a/src/gui/widgets/EffectRackView.cpp +++ b/src/gui/widgets/EffectRackView.cpp @@ -211,7 +211,7 @@ void EffectRackView::update() } } - w->setFixedSize( 210 + 2*EffectViewMargin, m_lastY ); + w->setFixedSize( EffectView::DEFAULT_WIDTH + 2*EffectViewMargin, m_lastY); QWidget::update(); } diff --git a/src/gui/widgets/EffectView.cpp b/src/gui/widgets/EffectView.cpp index a159eedf956..936a786d0c7 100644 --- a/src/gui/widgets/EffectView.cpp +++ b/src/gui/widgets/EffectView.cpp @@ -49,7 +49,7 @@ EffectView::EffectView( Effect * _model, QWidget * _parent ) : m_subWindow( NULL ), m_controlView( NULL ) { - setFixedSize( 210, 60 ); + setFixedSize( EffectView::DEFAULT_WIDTH, 60 ); // Disable effects that are of type "DummyEffect" bool isEnabled = !dynamic_cast( effect() ); @@ -62,21 +62,21 @@ EffectView::EffectView( Effect * _model, QWidget * _parent ) : m_wetDry = new Knob( knobBright_26, this ); m_wetDry->setLabel( tr( "W/D" ) ); - m_wetDry->move( 27, 5 ); + m_wetDry->move( 40 - m_wetDry->width() / 2, 5 ); m_wetDry->setEnabled( isEnabled ); m_wetDry->setHintText( tr( "Wet Level:" ), "" ); m_autoQuit = new TempoSyncKnob( knobBright_26, this ); m_autoQuit->setLabel( tr( "DECAY" ) ); - m_autoQuit->move( 60, 5 ); + m_autoQuit->move( 78 - m_autoQuit->width() / 2, 5 ); m_autoQuit->setEnabled( isEnabled && !effect()->m_autoQuitDisabled ); m_autoQuit->setHintText( tr( "Time:" ), "ms" ); m_gate = new Knob( knobBright_26, this ); m_gate->setLabel( tr( "GATE" ) ); - m_gate->move( 93, 5 ); + m_gate->move( 116 - m_gate->width() / 2, 5 ); m_gate->setEnabled( isEnabled && !effect()->m_autoQuitDisabled ); m_gate->setHintText( tr( "Gate:" ), "" ); @@ -89,7 +89,7 @@ EffectView::EffectView( Effect * _model, QWidget * _parent ) : this ); QFont f = ctls_btn->font(); ctls_btn->setFont( pointSize<8>( f ) ); - ctls_btn->setGeometry( 140, 14, 50, 20 ); + ctls_btn->setGeometry( 150, 14, 50, 20 ); connect( ctls_btn, SIGNAL( clicked() ), this, SLOT( editControls() ) ); @@ -219,10 +219,12 @@ void EffectView::paintEvent( QPaintEvent * ) f.setBold( true ); p.setFont( f ); + QString elidedText = p.fontMetrics().elidedText( model()->displayName(), Qt::ElideRight, width() - 22 ); + p.setPen( palette().shadow().color() ); - p.drawText( 6, 55, model()->displayName() ); + p.drawText( 6, 55, elidedText ); p.setPen( palette().text().color() ); - p.drawText( 5, 54, model()->displayName() ); + p.drawText( 5, 54, elidedText ); } diff --git a/src/gui/widgets/FadeButton.cpp b/src/gui/widgets/FadeButton.cpp index 43f8061441a..c40569c2181 100644 --- a/src/gui/widgets/FadeButton.cpp +++ b/src/gui/widgets/FadeButton.cpp @@ -110,20 +110,20 @@ void FadeButton::paintEvent(QPaintEvent * _pe) { QColor col = m_normalColor; - if(!m_stateTimer.isNull() && m_stateTimer.elapsed() < FadeDuration) + if(m_stateTimer.isValid() && m_stateTimer.elapsed() < FadeDuration) { // The first part of the fade, when a note is triggered. col = fadeToColor(m_activatedColor, m_holdColor, m_stateTimer, FadeDuration); QTimer::singleShot(20, this, SLOT(update())); } - else if (!m_stateTimer.isNull() + else if (m_stateTimer.isValid() && m_stateTimer.elapsed() >= FadeDuration && activeNotes > 0) { // The fade is done, but at least one note is still held. col = m_holdColor; } - else if (!m_releaseTimer.isNull() && m_releaseTimer.elapsed() < FadeDuration) + else if (m_releaseTimer.isValid() && m_releaseTimer.elapsed() < FadeDuration) { // Last note just ended. Fade to default color. col = fadeToColor(m_holdColor, m_normalColor, m_releaseTimer, FadeDuration); @@ -149,7 +149,7 @@ void FadeButton::paintEvent(QPaintEvent * _pe) } -QColor FadeButton::fadeToColor(QColor startCol, QColor endCol, QTime timer, float duration) +QColor FadeButton::fadeToColor(QColor startCol, QColor endCol, QElapsedTimer timer, float duration) { QColor col; diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 4317066ab65..089964ec75e 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -72,7 +72,6 @@ Fader::Fader( FloatModel * _model, const QString & _name, QWidget * _parent ) : m_persistentPeak_R( 0.0 ), m_fMinPeak( 0.01f ), m_fMaxPeak( 1.1 ), - m_displayConversion( true ), m_levelsDisplayedInDBFS(false), m_moveStartPoint( -1 ), m_startValue( 0 ), @@ -102,6 +101,8 @@ Fader::Fader( FloatModel * _model, const QString & _name, QWidget * _parent ) : m_knob = s_knob; init(_model, _name); + + m_conversionFactor = 100.0; } @@ -114,7 +115,6 @@ Fader::Fader( FloatModel * model, const QString & name, QWidget * parent, QPixma m_persistentPeak_R( 0.0 ), m_fMinPeak( 0.01f ), m_fMaxPeak( 1.1 ), - m_displayConversion( false ), m_levelsDisplayedInDBFS(false), m_moveStartPoint( -1 ), m_startValue( 0 ), @@ -217,26 +217,13 @@ void Fader::mouseDoubleClickEvent( QMouseEvent* mouseEvent ) bool ok; float newValue; // TODO: dbV handling - if( m_displayConversion ) - { - newValue = QInputDialog::getDouble( this, tr( "Set value" ), - tr( "Please enter a new value between %1 and %2:" ). - arg( model()->minValue() * 100 ). - arg( model()->maxValue() * 100 ), - model()->getRoundedValue() * 100, - model()->minValue() * 100, - model()->maxValue() * 100, model()->getDigitCount(), &ok ) * 0.01f; - } - else - { - newValue = QInputDialog::getDouble( this, tr( "Set value" ), - tr( "Please enter a new value between %1 and %2:" ). - arg( model()->minValue() ). - arg( model()->maxValue() ), - model()->getRoundedValue(), - model()->minValue(), - model()->maxValue(), model()->getDigitCount(), &ok ); - } + newValue = QInputDialog::getDouble( this, tr( "Set value" ), + tr( "Please enter a new value between %1 and %2:" ). + arg( model()->minValue() * m_conversionFactor ). + arg( model()->maxValue() * m_conversionFactor ), + model()->getRoundedValue() * m_conversionFactor, + model()->minValue() * m_conversionFactor, + model()->maxValue() * m_conversionFactor, model()->getDigitCount(), &ok ) / m_conversionFactor; if( ok ) { @@ -265,7 +252,7 @@ void Fader::wheelEvent ( QWheelEvent *ev ) { ev->accept(); - if ( ev->delta() > 0 ) + if (ev->angleDelta().y() > 0) { model()->incValue( 1 ); } @@ -282,7 +269,7 @@ void Fader::wheelEvent ( QWheelEvent *ev ) /// /// Set peak value (0.0 .. 1.0) /// -void Fader::setPeak( float fPeak, float &targetPeak, float &persistentPeak, QTime &lastPeakTime ) +void Fader::setPeak( float fPeak, float &targetPeak, float &persistentPeak, QElapsedTimer &lastPeakTimer ) { if( fPeak < m_fMinPeak ) { @@ -299,12 +286,12 @@ void Fader::setPeak( float fPeak, float &targetPeak, float &persistentPeak, QTim if( targetPeak >= persistentPeak ) { persistentPeak = targetPeak; - lastPeakTime.restart(); + lastPeakTimer.restart(); } update(); } - if( persistentPeak > 0 && lastPeakTime.elapsed() > 1500 ) + if( persistentPeak > 0 && lastPeakTimer.elapsed() > 1500 ) { persistentPeak = qMax( 0, persistentPeak-0.05 ); update(); @@ -315,14 +302,14 @@ void Fader::setPeak( float fPeak, float &targetPeak, float &persistentPeak, QTim void Fader::setPeak_L( float fPeak ) { - setPeak( fPeak, m_fPeakValue_L, m_persistentPeak_L, m_lastPeakTime_L ); + setPeak( fPeak, m_fPeakValue_L, m_persistentPeak_L, m_lastPeakTimer_L ); } void Fader::setPeak_R( float fPeak ) { - setPeak( fPeak, m_fPeakValue_R, m_persistentPeak_R, m_lastPeakTime_R ); + setPeak( fPeak, m_fPeakValue_R, m_persistentPeak_R, m_lastPeakTimer_R ); } @@ -330,14 +317,14 @@ void Fader::setPeak_R( float fPeak ) // update tooltip showing value and adjust position while changing fader value void Fader::updateTextFloat() { - if( ConfigManager::inst()->value( "app", "displaydbfs" ).toInt() && m_displayConversion ) + if( ConfigManager::inst()->value( "app", "displaydbfs" ).toInt() && m_conversionFactor == 100.0 ) { s_textFloat->setText( QString("Volume: %1 dBFS"). arg( ampToDbfs( model()->value() ), 3, 'f', 2 ) ); } else { - s_textFloat->setText( m_description + " " + QString("%1 ").arg( m_displayConversion ? model()->value() * 100 : model()->value() ) + " " + m_unit ); + s_textFloat->setText( m_description + " " + QString("%1 ").arg( model()->value() * m_conversionFactor ) + " " + m_unit ); } s_textFloat->moveGlobal( this, QPoint( width() - ( *m_knob ).width() - 5, knobPosY() - 46 ) ); } diff --git a/src/gui/widgets/FxLine.cpp b/src/gui/widgets/FxLine.cpp index 3314301fd77..254e4068d94 100644 --- a/src/gui/widgets/FxLine.cpp +++ b/src/gui/widgets/FxLine.cpp @@ -25,6 +25,8 @@ #include "FxLine.h" +#include + #include #include "CaptionMenu.h" @@ -120,6 +122,8 @@ FxLine::FxLine( QWidget * _parent, FxMixerView * _mv, int _channelIndex ) : proxyWidget->setPos( 8, 145 ); connect( m_renameLineEdit, SIGNAL( editingFinished() ), this, SLOT( renameFinished() ) ); + connect( &Engine::fxMixer()->effectChannel( m_channelIndex )->m_muteModel, SIGNAL( dataChanged() ), this, SLOT( update() ) ); + } @@ -144,10 +148,11 @@ void FxLine::setChannelIndex( int index ) - void FxLine::drawFxLine( QPainter* p, const FxLine *fxLine, bool isActive, bool sendToThis, bool receiveFromThis ) { - QString name = Engine::fxMixer()->effectChannel( m_channelIndex )->m_name; + auto channel = Engine::fxMixer()->effectChannel( m_channelIndex ); + bool muted = channel->m_muteModel.value(); + QString name = channel->m_name; QString elidedName = elideName( name ); if( !m_inRename && m_renameLineEdit->text() != elidedName ) { @@ -156,8 +161,16 @@ void FxLine::drawFxLine( QPainter* p, const FxLine *fxLine, bool isActive, bool int width = fxLine->rect().width(); int height = fxLine->rect().height(); - - p->fillRect( fxLine->rect(), isActive ? fxLine->backgroundActive() : p->background() ); + + if( channel->m_hasColor && !muted ) + { + p->fillRect( fxLine->rect(), channel->m_color.darker( isActive ? 120 : 150 ) ); + } + else + { + p->fillRect( fxLine->rect(), + isActive ? fxLine->backgroundActive().color() : p->background().color() ); + } // inner border p->setPen( isActive ? fxLine->strokeInnerActive() : fxLine->strokeInnerInactive() ); @@ -224,7 +237,7 @@ void FxLine::mouseDoubleClickEvent( QMouseEvent * ) void FxLine::contextMenuEvent( QContextMenuEvent * ) { QPointer contextMenu = new CaptionMenu( Engine::fxMixer()->effectChannel( m_channelIndex )->m_name, this ); - if( m_channelIndex != 0 ) // no move-options in master + if( m_channelIndex != 0 ) // no move-options in master { contextMenu->addAction( tr( "Move &left" ), this, SLOT( moveChannelLeft() ) ); contextMenu->addAction( tr( "Move &right" ), this, SLOT( moveChannelRight() ) ); @@ -238,6 +251,10 @@ void FxLine::contextMenuEvent( QContextMenuEvent * ) contextMenu->addSeparator(); } contextMenu->addAction( embed::getIconPixmap( "cancel" ), tr( "Remove &unused channels" ), this, SLOT( removeUnusedChannels() ) ); + contextMenu->addSeparator(); + contextMenu->addAction( embed::getIconPixmap( "colorize" ), tr( "Set channel color" ), this, SLOT( changeColor() ) ); + contextMenu->addAction( embed::getIconPixmap( "colorize" ), tr( "Remove channel color" ), this, SLOT( resetColor() ) ); + contextMenu->addAction( embed::getIconPixmap( "colorize" ), tr( "Pick random channel color" ), this, SLOT( randomColor() ) ); contextMenu->exec( QCursor::pos() ); delete contextMenu; } @@ -395,3 +412,31 @@ void FxLine::setStrokeInnerInactive( const QColor & c ) { m_strokeInnerInactive = c; } + + +// Ask user for a color, and set it as the mixer line color +void FxLine::changeColor() +{ + auto channel = Engine::fxMixer()->effectChannel( m_channelIndex ); + auto new_color = ColorChooser(this).withPalette(ColorChooser::Palette::Mixer)->getColor(channel->m_color); + if(!new_color.isValid()) { return; } + channel->setColor (new_color); + update(); +} + + +// Disable the usage of color on this mixer line +void FxLine::resetColor() +{ + Engine::fxMixer()->effectChannel( m_channelIndex )->m_hasColor = false; + update(); +} + + +// Pick a random color from the mixer palette and set it as our color +void FxLine::randomColor() +{ + auto channel = Engine::fxMixer()->effectChannel( m_channelIndex ); + channel->setColor (ColorChooser::getPalette(ColorChooser::Palette::Mixer)[rand() % 48]); + update(); +} diff --git a/src/gui/widgets/FxLineLcdSpinBox.cpp b/src/gui/widgets/FxLineLcdSpinBox.cpp index bfe4a9637f9..5edf50c6c3e 100644 --- a/src/gui/widgets/FxLineLcdSpinBox.cpp +++ b/src/gui/widgets/FxLineLcdSpinBox.cpp @@ -27,7 +27,7 @@ #include "CaptionMenu.h" #include "FxMixerView.h" #include "GuiApplication.h" -#include "Track.h" +#include "TrackView.h" void FxLineLcdSpinBox::setTrackView(TrackView * tv) { diff --git a/src/gui/widgets/InstrumentMidiIOView.cpp b/src/gui/widgets/InstrumentMidiIOView.cpp index 56047d5e677..db8ae709bd1 100644 --- a/src/gui/widgets/InstrumentMidiIOView.cpp +++ b/src/gui/widgets/InstrumentMidiIOView.cpp @@ -53,18 +53,22 @@ InstrumentMidiIOView::InstrumentMidiIOView( QWidget* parent ) : QHBoxLayout* midiInputLayout = new QHBoxLayout( m_midiInputGroupBox ); midiInputLayout->setContentsMargins( 8, 18, 8, 8 ); - midiInputLayout->setSpacing( 6 ); + midiInputLayout->setSpacing( 4 ); m_inputChannelSpinBox = new LcdSpinBox( 2, m_midiInputGroupBox ); m_inputChannelSpinBox->addTextForValue( 0, "--" ); - m_inputChannelSpinBox->setLabel( tr( "CHANNEL" ) ); + /*: This string must be be short, its width must be less than + * width of LCD spin-box of two digits */ + m_inputChannelSpinBox->setLabel( tr( "CHAN" ) ); m_inputChannelSpinBox->setEnabled( false ); midiInputLayout->addWidget( m_inputChannelSpinBox ); m_fixedInputVelocitySpinBox = new LcdSpinBox( 3, m_midiInputGroupBox ); m_fixedInputVelocitySpinBox->setDisplayOffset( 1 ); m_fixedInputVelocitySpinBox->addTextForValue( 0, "---" ); - m_fixedInputVelocitySpinBox->setLabel( tr( "VELOCITY" ) ); + /*: This string must be be short, its width must be less than + * width of LCD spin-box of three digits */ + m_fixedInputVelocitySpinBox->setLabel( tr( "VELOC" ) ); m_fixedInputVelocitySpinBox->setEnabled( false ); midiInputLayout->addWidget( m_fixedInputVelocitySpinBox ); midiInputLayout->addStretch(); @@ -81,35 +85,41 @@ InstrumentMidiIOView::InstrumentMidiIOView( QWidget* parent ) : QHBoxLayout* midiOutputLayout = new QHBoxLayout( m_midiOutputGroupBox ); midiOutputLayout->setContentsMargins( 8, 18, 8, 8 ); - midiOutputLayout->setSpacing( 6 ); + midiOutputLayout->setSpacing( 4 ); m_outputChannelSpinBox = new LcdSpinBox( 2, m_midiOutputGroupBox ); - m_outputChannelSpinBox->setLabel( tr( "CHANNEL" ) ); - m_outputChannelSpinBox->setEnabled( false ); + m_outputChannelSpinBox->addTextForValue( 0, "--" ); + /*: This string must be be short, its width must be less than + * width of LCD spin-box of two digits */ + m_outputChannelSpinBox->setLabel( tr( "CHAN" ) ); midiOutputLayout->addWidget( m_outputChannelSpinBox ); m_fixedOutputVelocitySpinBox = new LcdSpinBox( 3, m_midiOutputGroupBox ); m_fixedOutputVelocitySpinBox->setDisplayOffset( 1 ); m_fixedOutputVelocitySpinBox->addTextForValue( 0, "---" ); - m_fixedOutputVelocitySpinBox->setLabel( tr( "VELOCITY" ) ); + /*: This string must be be short, its width must be less than + * width of LCD spin-box of three digits */ + m_fixedOutputVelocitySpinBox->setLabel( tr( "VELOC" ) ); m_fixedOutputVelocitySpinBox->setEnabled( false ); midiOutputLayout->addWidget( m_fixedOutputVelocitySpinBox ); m_outputProgramSpinBox = new LcdSpinBox( 3, m_midiOutputGroupBox ); - m_outputProgramSpinBox->setLabel( tr( "PROGRAM" ) ); + /*: This string must be be short, its width must be less than the + * width of LCD spin-box of three digits */ + m_outputProgramSpinBox->setLabel( tr( "PROG" ) ); m_outputProgramSpinBox->setEnabled( false ); midiOutputLayout->addWidget( m_outputProgramSpinBox ); m_fixedOutputNoteSpinBox = new LcdSpinBox( 3, m_midiOutputGroupBox ); m_fixedOutputNoteSpinBox->setDisplayOffset( 1 ); m_fixedOutputNoteSpinBox->addTextForValue( 0, "---" ); + /*: This string must be be short, its width must be less than + * width of LCD spin-box of three digits */ m_fixedOutputNoteSpinBox->setLabel( tr( "NOTE" ) ); m_fixedOutputNoteSpinBox->setEnabled( false ); midiOutputLayout->addWidget( m_fixedOutputNoteSpinBox ); midiOutputLayout->addStretch(); - connect( m_midiOutputGroupBox->ledButton(), SIGNAL( toggled( bool ) ), - m_outputChannelSpinBox, SLOT( setEnabled( bool ) ) ); connect( m_midiOutputGroupBox->ledButton(), SIGNAL( toggled( bool ) ), m_fixedOutputVelocitySpinBox, SLOT( setEnabled( bool ) ) ); connect( m_midiOutputGroupBox->ledButton(), SIGNAL( toggled( bool ) ), @@ -213,6 +223,7 @@ InstrumentMiscView::InstrumentMiscView(InstrumentTrack *it, QWidget *parent) : QHBoxLayout* masterPitchLayout = new QHBoxLayout( m_pitchGroupBox ); masterPitchLayout->setContentsMargins( 8, 18, 8, 8 ); QLabel *tlabel = new QLabel(tr( "Enables the use of master pitch" ) ); + tlabel->setFont( pointSize<8>( tlabel->font() ) ); m_pitchGroupBox->setModel( &it->m_useMasterPitchModel ); masterPitchLayout->addWidget( tlabel ); layout->addStretch(); diff --git a/src/gui/widgets/InstrumentSoundShapingView.cpp b/src/gui/widgets/InstrumentSoundShapingView.cpp index a6c6fbd56cf..24a52fad235 100644 --- a/src/gui/widgets/InstrumentSoundShapingView.cpp +++ b/src/gui/widgets/InstrumentSoundShapingView.cpp @@ -62,7 +62,7 @@ InstrumentSoundShapingView::InstrumentSoundShapingView( QWidget * _parent ) : { m_envLfoViews[i] = new EnvelopeAndLfoView( m_targetsTabWidget ); m_targetsTabWidget->addTab( m_envLfoViews[i], - tr( InstrumentSoundShaping::targetNames[i][0].toUtf8().constData() ), + tr( InstrumentSoundShaping::targetNames[i][0] ), NULL ); } @@ -74,7 +74,7 @@ InstrumentSoundShapingView::InstrumentSoundShapingView( QWidget * _parent ) : m_filterComboBox = new ComboBox( m_filterGroupBox ); - m_filterComboBox->setGeometry( 14, 22, 120, 22 ); + m_filterComboBox->setGeometry( 14, 22, 120, ComboBox::DEFAULT_HEIGHT ); m_filterComboBox->setFont( pointSize<8>( m_filterComboBox->font() ) ); diff --git a/src/gui/widgets/Knob.cpp b/src/gui/widgets/Knob.cpp index 167c3ecf883..362207653be 100644 --- a/src/gui/widgets/Knob.cpp +++ b/src/gui/widgets/Knob.cpp @@ -22,6 +22,7 @@ * */ +#include #include #include #include @@ -38,6 +39,7 @@ #include "CaptionMenu.h" #include "ConfigManager.h" #include "ControllerConnection.h" +#include "DeprecationHelper.h" #include "embed.h" #include "gui_templates.h" #include "GuiApplication.h" @@ -45,6 +47,7 @@ #include "MainWindow.h" #include "ProjectJournal.h" #include "Song.h" +#include "stdshims.h" #include "StringPairDrag.h" #include "TextFloat.h" @@ -57,7 +60,6 @@ Knob::Knob( knobTypes _knob_num, QWidget * _parent, const QString & _name ) : QWidget( _parent ), FloatModelView( new FloatModel( 0, 0, 0, 1, NULL, _name, true ), this ), m_label( "" ), - m_knobPixmap( NULL ), m_volumeKnob( false ), m_volumeRatio( 100.0, 0.0, 1000000.0 ), m_buttonPressed( false ), @@ -104,10 +106,16 @@ void Knob::initUi( const QString & _name ) case knobSmall_17: case knobBright_26: case knobDark_28: - setlineColor(QApplication::palette().color( QPalette::Active, QPalette::WindowText )); + m_lineActiveColor = QApplication::palette().color(QPalette::Active, QPalette::WindowText); + m_arcActiveColor = QColor(QApplication::palette().color( + QPalette::Active, QPalette::WindowText)); + m_arcActiveColor.setAlpha(70); break; case knobVintage_32: - setlineColor(QApplication::palette().color( QPalette::Active, QPalette::Shadow )); + m_lineActiveColor = QApplication::palette().color(QPalette::Active, QPalette::Shadow); + m_arcActiveColor = QColor(QApplication::palette().color( + QPalette::Active, QPalette::Shadow)); + m_arcActiveColor.setAlpha(70); break; default: break; @@ -143,8 +151,11 @@ void Knob::onKnobNumUpdated() } // If knobFilename is still empty here we should get the fallback pixmap of size 1x1 - m_knobPixmap = new QPixmap( embed::getIconPixmap( knobFilename.toUtf8().constData() ) ); - + m_knobPixmap = make_unique(QPixmap(embed::getIconPixmap(knobFilename.toUtf8().constData()))); + if (!this->isEnabled()) + { + convertPixmapToGrayScale(*m_knobPixmap.get()); + } setFixedSize( m_knobPixmap->width(), m_knobPixmap->height() ); } } @@ -152,25 +163,14 @@ void Knob::onKnobNumUpdated() -Knob::~Knob() -{ - if( m_knobPixmap ) - { - delete m_knobPixmap; - } -} - - - - void Knob::setLabel( const QString & txt ) { m_label = txt; if( m_knobPixmap ) { - setFixedSize( qMax( m_knobPixmap->width(), - QFontMetrics( pointSizeF( font(), 6.5) ).width( m_label ) ), - m_knobPixmap->height() + 10 ); + setFixedSize(qMax( m_knobPixmap->width(), + horizontalAdvance(QFontMetrics(pointSizeF(font(), 6.5)), m_label)), + m_knobPixmap->height() + 10); } update(); } @@ -307,35 +307,6 @@ void Knob::setOuterColor( const QColor & c ) -QColor Knob::lineColor() const -{ - return m_lineColor; -} - - - -void Knob::setlineColor( const QColor & c ) -{ - m_lineColor = c; -} - - - -QColor Knob::arcColor() const -{ - return m_arcColor; -} - - - -void Knob::setarcColor( const QColor & c ) -{ - m_arcColor = c; -} - - - - QColor Knob::textColor() const { return m_textColor; @@ -382,6 +353,10 @@ bool Knob::updateAngle() void Knob::drawKnob( QPainter * _p ) { + bool enabled = this->isEnabled(); + QColor currentArcColor = enabled ? m_arcActiveColor : m_arcInactiveColor; + QColor currentLineColor = enabled ? m_lineActiveColor : m_lineInactiveColor; + if( updateAngle() == false && !m_cache.isNull() ) { _p->drawImage( 0, 0, m_cache ); @@ -440,33 +415,24 @@ void Knob::drawKnob( QPainter * _p ) const int arcLineWidth = 2; const int arcRectSize = m_knobPixmap->width() - arcLineWidth; - QColor col; - if( m_knobNum == knobVintage_32 ) - { col = QApplication::palette().color( QPalette::Active, QPalette::Shadow ); } - else - { col = QApplication::palette().color( QPalette::Active, QPalette::WindowText ); } - col.setAlpha( 70 ); - - p.setPen( QPen( col, 2 ) ); + p.setPen(QPen(currentArcColor, 2)); p.drawArc( mid.x() - arcRectSize/2, 1, arcRectSize, arcRectSize, 315*16, 16*m_totalAngle ); + p.setPen(QPen(currentLineColor, 2)); switch( m_knobNum ) { case knobSmall_17: { - p.setPen( QPen( lineColor(), 2 ) ); p.drawLine( calculateLine( mid, radius-2 ) ); break; } case knobBright_26: { - p.setPen( QPen( lineColor(), 2 ) ); p.drawLine( calculateLine( mid, radius-5 ) ); break; } case knobDark_28: { - p.setPen( QPen( lineColor(), 2 ) ); const float rb = qMax( ( radius - 10 ) / 3.0, 0.0 ); const float re = qMax( ( radius - 4 ), 0.0 ); @@ -477,7 +443,6 @@ void Knob::drawKnob( QPainter * _p ) } case knobVintage_32: { - p.setPen( QPen( lineColor(), 2 ) ); p.drawLine( calculateLine( mid, radius-2, 2 ) ); break; } @@ -496,8 +461,8 @@ float Knob::getValue( const QPoint & _p ) { float value; - // arcane mathemagicks for calculating knob movement - value = ( ( _p.y() + _p.y() * qMin( qAbs( _p.y() / 2.5f ), 6.0f ) ) ) / 12.0f; + // knob value increase is linear to mouse movement + value = .4f * _p.y(); // if shift pressed we want slower movement if( gui->mainWindow()->isShiftPressed() ) @@ -585,13 +550,11 @@ void Knob::mousePressEvent( QMouseEvent * _me ) } const QPoint & p = _me->pos(); - m_origMousePos = p; - m_mouseOffset = QPoint(0, 0); + m_lastMousePos = p; m_leftOver = 0.0f; emit sliderPressed(); - QApplication::setOverrideCursor( Qt::BlankCursor ); s_textFloat->setText( displayValue() ); s_textFloat->moveGlobal( this, QPoint( width() + 2, 0 ) ); @@ -616,12 +579,13 @@ void Knob::mousePressEvent( QMouseEvent * _me ) void Knob::mouseMoveEvent( QMouseEvent * _me ) { - if( m_buttonPressed && _me->pos() != m_origMousePos ) + if( m_buttonPressed && _me->pos() != m_lastMousePos ) { - m_mouseOffset = _me->pos() - m_origMousePos; - setPosition( m_mouseOffset ); + // knob position is changed depending on last mouse position + setPosition( _me->pos() - m_lastMousePos ); emit sliderMoved( model()->value() ); - QCursor::setPos( mapToGlobal( m_origMousePos ) ); + // original position for next time is current position + m_lastMousePos = _me->pos(); } s_textFloat->setText( displayValue() ); } @@ -683,19 +647,20 @@ void Knob::paintEvent( QPaintEvent * _me ) p.fontMetrics().width( m_label ) / 2 + 1, height() - 1, m_label );*/ p.setPen( textColor() ); - p.drawText( width() / 2 - - p.fontMetrics().width( m_label ) / 2, - height() - 2, m_label ); + p.drawText(width() / 2 - + horizontalAdvance(p.fontMetrics(), m_label) / 2, + height() - 2, m_label); } } -void Knob::wheelEvent( QWheelEvent * _we ) +void Knob::wheelEvent(QWheelEvent * we) { - _we->accept(); - const int inc = ( _we->delta() > 0 ) ? 1 : -1; + we->accept(); + const float stepMult = model()->range() / 2000 / model()->step(); + const int inc = ((we->angleDelta().y() > 0 ) ? 1 : -1) * ((stepMult < 1 ) ? 1 : stepMult); model()->incValue( inc ); @@ -839,3 +804,35 @@ void Knob::doConnections() this, SLOT( update() ) ); } } + + +void Knob::changeEvent(QEvent * ev) +{ + if (ev->type() == QEvent::EnabledChange) + { + onKnobNumUpdated(); + if (!m_label.isEmpty()) + { + setLabel(m_label); + } + m_cache = QImage(); + update(); + } +} + + +void convertPixmapToGrayScale(QPixmap& pixMap) +{ + QImage temp = pixMap.toImage().convertToFormat(QImage::Format_ARGB32); + for (int i = 0; i < temp.height(); ++i) + { + for (int j = 0; j < temp.width(); ++j) + { + const auto pix = temp.pixelColor(i, j); + const auto gscale = 0.2126 * pix.redF() + 0.7152 * pix.greenF() + 0.0722 * pix.blueF(); + const auto pixGray = QColor::fromRgbF(gscale, gscale, gscale, pix.alphaF()); + temp.setPixelColor(i, j, pixGray); + } + } + pixMap.convertFromImage(temp); +} diff --git a/src/gui/widgets/LcdSpinBox.cpp b/src/gui/widgets/LcdSpinBox.cpp index 8b30a38ca14..6aacc01dd5a 100644 --- a/src/gui/widgets/LcdSpinBox.cpp +++ b/src/gui/widgets/LcdSpinBox.cpp @@ -23,6 +23,7 @@ * */ +#include #include #include #include @@ -40,8 +41,9 @@ LcdSpinBox::LcdSpinBox( int numDigits, QWidget* parent, const QString& name ) : LcdWidget( numDigits, parent, name ), IntModelView( new IntModel( 0, 0, 0, NULL, name, true ), this ), + m_remainder( 0.f ), m_mouseMoving( false ), - m_origMousePos(), + m_lastMousePos(), m_displayOffset( 0 ) { } @@ -50,10 +52,11 @@ LcdSpinBox::LcdSpinBox( int numDigits, QWidget* parent, const QString& name ) : LcdSpinBox::LcdSpinBox( int numDigits, const QString& style, QWidget* parent, const QString& name ) : - LcdWidget( numDigits, parent, name ), + LcdWidget( numDigits, style, parent, name ), IntModelView( new IntModel( 0, 0, 0, NULL, name, true ), this ), + m_remainder( 0.f ), m_mouseMoving( false ), - m_origMousePos(), + m_lastMousePos(), m_displayOffset( 0 ) { } @@ -90,8 +93,7 @@ void LcdSpinBox::mousePressEvent( QMouseEvent* event ) event->y() < cellHeight() + 2 ) { m_mouseMoving = true; - m_origMousePos = event->globalPos(); - QApplication::setOverrideCursor( Qt::BlankCursor ); + m_lastMousePos = event->globalPos(); AutomatableModel *thisModel = model(); if( thisModel ) @@ -113,15 +115,20 @@ void LcdSpinBox::mouseMoveEvent( QMouseEvent* event ) { if( m_mouseMoving ) { - int dy = event->globalY() - m_origMousePos.y(); - if( event->modifiers() & Qt::ShiftModifier ) - dy = qBound( -4, dy/4, 4 ); - if( dy > 1 || dy < -1 ) + int dy = event->globalY() - m_lastMousePos.y(); + if( dy ) { - model()->setInitValue( model()->value() - - dy / 2 * model()->step() ); + float fdy = static_cast(dy); + if( event->modifiers() & Qt::ShiftModifier ) { + fdy = qBound( -4.f, fdy/4.f, 4.f ); + } + float floatValNotRounded = + model()->value() + m_remainder - fdy / 2.f * model()->step(); + float floatValRounded = roundf( floatValNotRounded ); + m_remainder = floatValNotRounded - floatValRounded; + model()->setInitValue( floatValRounded ); emit manualChange(); - QCursor::setPos( m_origMousePos ); + m_lastMousePos = event->globalPos(); } } } @@ -134,10 +141,7 @@ void LcdSpinBox::mouseReleaseEvent( QMouseEvent* ) if( m_mouseMoving ) { model()->restoreJournallingState(); - - QCursor::setPos( m_origMousePos ); QApplication::restoreOverrideCursor(); - m_mouseMoving = false; } } @@ -145,11 +149,10 @@ void LcdSpinBox::mouseReleaseEvent( QMouseEvent* ) -void LcdSpinBox::wheelEvent( QWheelEvent * _we ) +void LcdSpinBox::wheelEvent(QWheelEvent * we) { - _we->accept(); - model()->setInitValue( model()->value() + - ( ( _we->delta() > 0 ) ? 1 : -1 ) * model()->step() ); + we->accept(); + model()->setInitValue(model()->value() + ((we->angleDelta().y() > 0) ? 1 : -1) * model()->step()); emit manualChange(); } @@ -179,5 +182,3 @@ void LcdSpinBox::enterValue() } } - - diff --git a/src/gui/widgets/LcdWidget.cpp b/src/gui/widgets/LcdWidget.cpp index e34e1eb47b3..63e3b6ac0c5 100644 --- a/src/gui/widgets/LcdWidget.cpp +++ b/src/gui/widgets/LcdWidget.cpp @@ -32,6 +32,7 @@ #include #include "LcdWidget.h" +#include "DeprecationHelper.h" #include "embed.h" #include "gui_templates.h" #include "MainWindow.h" @@ -199,13 +200,13 @@ void LcdWidget::paintEvent( QPaintEvent* ) { p.setFont( pointSizeF( p.font(), 6.5 ) ); p.setPen( textShadowColor() ); - p.drawText( width() / 2 - - p.fontMetrics().width( m_label ) / 2 + 1, - height(), m_label ); + p.drawText(width() / 2 - + horizontalAdvance(p.fontMetrics(), m_label) / 2 + 1, + height(), m_label); p.setPen( textColor() ); - p.drawText( width() / 2 - - p.fontMetrics().width( m_label ) / 2, - height() - 1, m_label ); + p.drawText(width() / 2 - + horizontalAdvance(p.fontMetrics(), m_label) / 2, + height() - 1, m_label); } } @@ -240,10 +241,10 @@ void LcdWidget::updateSize() m_cellHeight + (2*margin) ); } else { - setFixedSize( qMax( + setFixedSize(qMax( m_cellWidth * m_numDigits + 2*(margin+m_marginWidth), - QFontMetrics( pointSizeF( font(), 6.5 ) ).width( m_label ) ), - m_cellHeight + (2*margin) + 9 ); + horizontalAdvance(QFontMetrics(pointSizeF(font(), 6.5)), m_label)), + m_cellHeight + (2*margin) + 9); } update(); diff --git a/src/gui/widgets/LedCheckbox.cpp b/src/gui/widgets/LedCheckbox.cpp index bdb537744f7..1ce64f1a85e 100644 --- a/src/gui/widgets/LedCheckbox.cpp +++ b/src/gui/widgets/LedCheckbox.cpp @@ -27,6 +27,7 @@ #include #include "LedCheckbox.h" +#include "DeprecationHelper.h" #include "embed.h" #include "gui_templates.h" @@ -120,7 +121,9 @@ void LedCheckBox::initUi( LedColors _color ) void LedCheckBox::onTextUpdated() { - setFixedSize( m_ledOffPixmap->width() + 5 + QFontMetrics( font() ).width( text() ), m_ledOffPixmap->height() ); + setFixedSize(m_ledOffPixmap->width() + 5 + horizontalAdvance(QFontMetrics(font()), + text()), + m_ledOffPixmap->height()); } diff --git a/src/gui/widgets/LinkedModelGroupViews.cpp b/src/gui/widgets/LinkedModelGroupViews.cpp index 21d40efcc1e..b9e007ff9d1 100644 --- a/src/gui/widgets/LinkedModelGroupViews.cpp +++ b/src/gui/widgets/LinkedModelGroupViews.cpp @@ -42,6 +42,11 @@ LinkedModelGroupView::LinkedModelGroupView(QWidget* parent, m_colNum(colNum), m_layout(new ControlLayout(this)) { + // This is required to remove the focus of the line edit + // when e.g. another spin box is being clicked. + // Removing the focus is wanted because in many cases, the user wants to + // quickly play notes on the virtual keyboard. + setFocusPolicy( Qt::StrongFocus ); } @@ -142,6 +147,14 @@ void LinkedModelGroupView::removeControl(const QString& key) } + + +void LinkedModelGroupView::removeFocusFromSearchBar() +{ + m_layout->removeFocusFromSearchBar(); +} + + /* LinkedModelGroupsViewBase */ diff --git a/src/gui/widgets/Oscilloscope.cpp b/src/gui/widgets/Oscilloscope.cpp index 1b1e18365d3..d999555437c 100644 --- a/src/gui/widgets/Oscilloscope.cpp +++ b/src/gui/widgets/Oscilloscope.cpp @@ -44,7 +44,6 @@ Oscilloscope::Oscilloscope( QWidget * _p ) : m_points( new QPointF[Engine::mixer()->framesPerPeriod()] ), m_active( false ), m_normalColor(71, 253, 133), - m_warningColor(255, 192, 64), m_clippingColor(255, 64, 64) { setFixedSize( m_background.width(), m_background.height() ); @@ -121,16 +120,6 @@ void Oscilloscope::setNormalColor(QColor const & normalColor) m_normalColor = normalColor; } -QColor const & Oscilloscope::warningColor() const -{ - return m_warningColor; -} - -void Oscilloscope::setWarningColor(QColor const & warningColor) -{ - m_warningColor = warningColor; -} - QColor const & Oscilloscope::clippingColor() const { return m_clippingColor; @@ -205,14 +194,10 @@ void Oscilloscope::mousePressEvent( QMouseEvent * _me ) QColor const & Oscilloscope::determineLineColor(float level) const { - if( level < 0.9f ) + if( level <= 1.0f ) { return normalColor(); } - else if( level <= 1.0f ) - { - return warningColor(); - } else { return clippingColor(); diff --git a/src/gui/widgets/PositionLine.cpp b/src/gui/widgets/PositionLine.cpp new file mode 100644 index 00000000000..ef003c5ebad --- /dev/null +++ b/src/gui/widgets/PositionLine.cpp @@ -0,0 +1,98 @@ +/* + * PositionLine.cpp + * + * Copyright (c) 2004-2014 Tobias Doerffel + * + * 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. + * + */ + +#include "PositionLine.h" + +#include + +#include "GuiApplication.h" +#include "Song.h" + + +PositionLine::PositionLine(QWidget* parent) : + QWidget(parent), + m_hasTailGradient(false), + m_lineColor(0, 0, 0, 0) +{ + resize(8, height()); + + setAttribute(Qt::WA_NoSystemBackground, true); + setAttribute(Qt::WA_TransparentForMouseEvents); +} + +void PositionLine::paintEvent(QPaintEvent* pe) +{ + QPainter p(this); + QColor c = QColor(m_lineColor); + + // If width is 1, we don't need a gradient + if (width() == 1) + { + c.setAlpha(153); + p.fillRect(rect(), c); + } + // If width > 1, we need the gradient + else + { + // Create the gradient trail behind the line + QLinearGradient gradient(rect().bottomLeft(), rect().bottomRight()); + qreal w = (width() - 1.0) / width(); + + // If gradient is enabled, we're in focus and we're playing, enable gradient + if (m_hasTailGradient && + Engine::getSong()->isPlaying() && + (Engine::getSong()->playMode() == Song::Mode_PlaySong || + Engine::getSong()->playMode() == Song::Mode_PlayPattern)) + { + c.setAlpha(60); + gradient.setColorAt(w, c); + } + else + { + c.setAlpha(0); + gradient.setColorAt(w, c); + } + + // Fill in the remaining parts + c.setAlpha(0); + gradient.setColorAt(0, c); + c.setAlpha(153); + gradient.setColorAt(1, c); + + // Fill line + p.fillRect(rect(), gradient); + } +} + +// NOTE: the move() implementation fixes a bug where the position line would appear +// in an unexpected location when positioned at the start of the track +void PositionLine::zoomChange(double zoom) +{ + int playHeadPos = x() + width() - 1; + + resize(8.0 * zoom, height()); + move(playHeadPos - width() + 1, y()); + + update(); +} \ No newline at end of file diff --git a/src/gui/widgets/StepRecorderWidget.cpp b/src/gui/widgets/StepRecorderWidget.cpp index a546c2a2cdc..65deb0d0a8b 100644 --- a/src/gui/widgets/StepRecorderWidget.cpp +++ b/src/gui/widgets/StepRecorderWidget.cpp @@ -53,22 +53,35 @@ void StepRecorderWidget::setPixelsPerBar(int ppb) m_ppb = ppb; } -void StepRecorderWidget::setCurrentPosition(MidiTime currentPosition) +void StepRecorderWidget::setCurrentPosition(TimePos currentPosition) { m_currentPosition = currentPosition; } +void StepRecorderWidget::setMargins(const QMargins &qm) +{ + m_left = qm.left(); + m_right = qm.right(); + m_top = qm.top(); + m_bottom = qm.bottom(); +} + +QMargins StepRecorderWidget::margins() +{ + return QMargins(m_left, m_top, m_right, m_bottom); +} + void StepRecorderWidget::setBottomMargin(const int marginBottom) { m_marginBottom = marginBottom; } -void StepRecorderWidget::setStartPosition(MidiTime pos) +void StepRecorderWidget::setStartPosition(TimePos pos) { m_curStepStartPos = pos; } -void StepRecorderWidget::setEndPosition(MidiTime pos) +void StepRecorderWidget::setEndPosition(TimePos pos) { m_curStepEndPos = pos; emit positionChanged(m_curStepEndPos); @@ -80,7 +93,7 @@ void StepRecorderWidget::showHint() embed::getIconPixmap("hint")); } -void StepRecorderWidget::setStepsLength(MidiTime stepsLength) +void StepRecorderWidget::setStepsLength(TimePos stepsLength) { m_stepsLength = stepsLength; } @@ -96,7 +109,7 @@ void StepRecorderWidget::paintEvent(QPaintEvent * pe) //draw steps ruler painter.setPen(m_colorLineEnd); - MidiTime curPos = m_curStepEndPos; + TimePos curPos = m_curStepEndPos; int x = xCoordOfTick(curPos); while(x <= m_right) { @@ -125,7 +138,7 @@ void StepRecorderWidget::paintEvent(QPaintEvent * pe) int StepRecorderWidget::xCoordOfTick(int tick) { - return m_marginLeft + ((tick - m_currentPosition) * m_ppb / MidiTime::ticksPerBar()); + return m_marginLeft + ((tick - m_currentPosition) * m_ppb / TimePos::ticksPerBar()); } @@ -138,7 +151,7 @@ void StepRecorderWidget::drawVerLine(QPainter* painter, int x, const QColor& col } } -void StepRecorderWidget::drawVerLine(QPainter* painter, const MidiTime& pos, const QColor& color, int top, int bottom) +void StepRecorderWidget::drawVerLine(QPainter* painter, const TimePos& pos, const QColor& color, int top, int bottom) { drawVerLine(painter, xCoordOfTick(pos), color, top, bottom); } diff --git a/src/gui/widgets/TabWidget.cpp b/src/gui/widgets/TabWidget.cpp index 22d32261210..07889c331f5 100644 --- a/src/gui/widgets/TabWidget.cpp +++ b/src/gui/widgets/TabWidget.cpp @@ -31,8 +31,9 @@ #include #include -#include "gui_templates.h" +#include "DeprecationHelper.h" #include "embed.h" +#include "gui_templates.h" TabWidget::TabWidget(const QString & caption, QWidget * parent, bool usePixmap, bool resizable) : @@ -76,7 +77,7 @@ void TabWidget::addTab( QWidget * w, const QString & name, const char *pixmap, i } // Tab's width when it is a text tab. This isn't correct for artwork tabs, but it's fixed later during the PaintEvent - int tab_width = fontMetrics().width( name ) + 10; + int tab_width = horizontalAdvance(fontMetrics(), name) + 10; // Register new tab widgetDesc d = { w, pixmap, name, tab_width }; @@ -125,7 +126,7 @@ int TabWidget::findTabAtPos( const QPoint *pos ) if( pos->y() > 1 && pos->y() < m_tabbarHeight - 1 ) { - int cx = ( ( m_caption == "" ) ? 4 : 14 ) + fontMetrics().width( m_caption ); + int cx = ((m_caption == "") ? 4 : 14) + horizontalAdvance(fontMetrics(), m_caption); for( widgetStack::iterator it = m_widgets.begin(); it != m_widgets.end(); ++it ) { @@ -232,7 +233,7 @@ void TabWidget::paintEvent( QPaintEvent * pe ) } // Calculate the tabs' x (tabs are painted next to the caption) - int tab_x_offset = m_caption.isEmpty() ? 4 : 14 + fontMetrics().width( m_caption ); + int tab_x_offset = m_caption.isEmpty() ? 4 : 14 + horizontalAdvance(fontMetrics(), m_caption); // Compute tabs' width depending on the number of tabs (only applicable for artwork tabs) widgetStack::iterator first = m_widgets.begin(); @@ -288,13 +289,13 @@ void TabWidget::paintEvent( QPaintEvent * pe ) // Switch between tabs with mouse wheel void TabWidget::wheelEvent( QWheelEvent * we ) { - if( we->y() > m_tabheight ) + if(position(we).y() > m_tabheight) { return; } we->accept(); - int dir = ( we->delta() < 0 ) ? 1 : -1; + int dir = (we->angleDelta().y() < 0) ? 1 : -1; int tab = m_activeTab; while( tab > -1 && static_cast( tab ) < m_widgets.count() ) { diff --git a/src/gui/widgets/TrackContentWidget.cpp b/src/gui/widgets/TrackContentWidget.cpp new file mode 100644 index 00000000000..7064b1e7540 --- /dev/null +++ b/src/gui/widgets/TrackContentWidget.cpp @@ -0,0 +1,710 @@ +/* + * TrackContentWidget.cpp - implementation of TrackContentWidget class + * + * Copyright (c) 2004-2014 Tobias Doerffel + * + * 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. + * + */ + +#include "TrackContentWidget.h" + +#include +#include +#include +#include + +#include "AutomationPattern.h" +#include "BBEditor.h" +#include "BBTrackContainer.h" +#include "Clipboard.h" +#include "DataFile.h" +#include "Engine.h" +#include "GuiApplication.h" +#include "Song.h" +#include "SongEditor.h" +#include "StringPairDrag.h" +#include "TrackContainerView.h" +#include "TrackContentObjectView.h" +#include "TrackView.h" + + +/*! Alternate between a darker and a lighter background color every 4 bars + */ +const int BARS_PER_GROUP = 4; + + +/*! \brief Create a new trackContentWidget + * + * Creates a new track content widget for the given track. + * The content widget comprises the 'grip bar' and the 'tools' button + * for the track's context menu. + * + * \param parent The parent track. + */ +TrackContentWidget::TrackContentWidget( TrackView * parent ) : + QWidget( parent ), + m_trackView( parent ), + m_darkerColor( Qt::SolidPattern ), + m_lighterColor( Qt::SolidPattern ), + m_gridColor( Qt::SolidPattern ), + m_embossColor( Qt::SolidPattern ) +{ + setAcceptDrops( true ); + + connect( parent->trackContainerView(), + SIGNAL( positionChanged( const TimePos & ) ), + this, SLOT( changePosition( const TimePos & ) ) ); + + setStyle( QApplication::style() ); + + updateBackground(); +} + + + + +/*! \brief Destroy this trackContentWidget + * + * Destroys the trackContentWidget. + */ +TrackContentWidget::~TrackContentWidget() +{ +} + + + + +void TrackContentWidget::updateBackground() +{ + const TrackContainerView * tcv = m_trackView->trackContainerView(); + + // Assume even-pixels-per-bar. Makes sense, should be like this anyways + int ppb = static_cast( tcv->pixelsPerBar() ); + + int w = ppb * BARS_PER_GROUP; + int h = height(); + m_background = QPixmap( w * 2, height() ); + QPainter pmp( &m_background ); + + pmp.fillRect( 0, 0, w, h, darkerColor() ); + pmp.fillRect( w, 0, w , h, lighterColor() ); + + // draw lines + // vertical lines + pmp.setPen( QPen( gridColor(), 1 ) ); + 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 += ppb ) + { + pmp.drawLine( QLineF( x, 0.0, x, h ) ); + } + + // horizontal line + pmp.setPen( QPen( gridColor(), 1 ) ); + pmp.drawLine( 0, h-1, w*2, h-1 ); + + pmp.end(); + + // Force redraw + update(); +} + + + + +/*! \brief Adds a trackContentObjectView to this widget. + * + * Adds a(nother) trackContentObjectView to our list of views. We also + * check that our position is up-to-date. + * + * \param tcov The trackContentObjectView to add. + */ +void TrackContentWidget::addTCOView( TrackContentObjectView * tcov ) +{ + TrackContentObject * tco = tcov->getTrackContentObject(); + + m_tcoViews.push_back( tcov ); + + tco->saveJournallingState( false ); + changePosition(); + tco->restoreJournallingState(); +} + + + + +/*! \brief Removes the given trackContentObjectView to this widget. + * + * Removes the given trackContentObjectView from our list of views. + * + * \param tcov The trackContentObjectView to add. + */ +void TrackContentWidget::removeTCOView( TrackContentObjectView * tcov ) +{ + tcoViewVector::iterator it = std::find( m_tcoViews.begin(), + m_tcoViews.end(), + tcov ); + if( it != m_tcoViews.end() ) + { + m_tcoViews.erase( it ); + Engine::getSong()->setModified(); + } +} + + + + +/*! \brief Update ourselves by updating all the tCOViews attached. + * + */ +void TrackContentWidget::update() +{ + for( tcoViewVector::iterator it = m_tcoViews.begin(); + it != m_tcoViews.end(); ++it ) + { + ( *it )->setFixedHeight( height() - 1 ); + ( *it )->update(); + } + QWidget::update(); +} + + + + +// resposible for moving track-content-widgets to appropriate position after +// change of visible viewport +/*! \brief Move the trackContentWidget to a new place in time + * + * \param newPos The MIDI time to move to. + */ +void TrackContentWidget::changePosition( const TimePos & newPos ) +{ + if( m_trackView->trackContainerView() == gui->getBBEditor()->trackContainerView() ) + { + const int curBB = Engine::getBBTrackContainer()->currentBB(); + setUpdatesEnabled( false ); + + // first show TCO for current BB... + for( tcoViewVector::iterator it = m_tcoViews.begin(); + it != m_tcoViews.end(); ++it ) + { + if( ( *it )->getTrackContentObject()-> + startPosition().getBar() == curBB ) + { + ( *it )->move( 0, ( *it )->y() ); + ( *it )->raise(); + ( *it )->show(); + } + else + { + ( *it )->lower(); + } + } + // ...then hide others to avoid flickering + for( tcoViewVector::iterator it = m_tcoViews.begin(); + it != m_tcoViews.end(); ++it ) + { + if( ( *it )->getTrackContentObject()-> + startPosition().getBar() != curBB ) + { + ( *it )->hide(); + } + } + setUpdatesEnabled( true ); + return; + } + + TimePos pos = newPos; + if( pos < 0 ) + { + pos = m_trackView->trackContainerView()->currentPosition(); + } + + const int begin = pos; + const int end = endPosition( pos ); + const float ppb = m_trackView->trackContainerView()->pixelsPerBar(); + + setUpdatesEnabled( false ); + for( tcoViewVector::iterator it = m_tcoViews.begin(); + it != m_tcoViews.end(); ++it ) + { + TrackContentObjectView * tcov = *it; + TrackContentObject * tco = tcov->getTrackContentObject(); + + tco->changeLength( tco->length() ); + + const int ts = tco->startPosition(); + const int te = tco->endPosition()-3; + if( ( ts >= begin && ts <= end ) || + ( te >= begin && te <= end ) || + ( ts <= begin && te >= end ) ) + { + tcov->move( static_cast( ( ts - begin ) * ppb / + TimePos::ticksPerBar() ), + tcov->y() ); + if( !tcov->isVisible() ) + { + tcov->show(); + } + } + else + { + tcov->move( -tcov->width()-10, tcov->y() ); + } + } + setUpdatesEnabled( true ); + + // redraw background +// update(); +} + + + + +/*! \brief Return the position of the trackContentWidget in bars. + * + * \param mouseX the mouse's current X position in pixels. + */ +TimePos TrackContentWidget::getPosition( int mouseX ) +{ + TrackContainerView * tv = m_trackView->trackContainerView(); + return TimePos( tv->currentPosition() + + mouseX * + TimePos::ticksPerBar() / + static_cast( tv->pixelsPerBar() ) ); +} + + + + +/*! \brief Respond to a drag enter event on the trackContentWidget + * + * \param dee the Drag Enter Event to respond to + */ +void TrackContentWidget::dragEnterEvent( QDragEnterEvent * dee ) +{ + TimePos tcoPos = getPosition( dee->pos().x() ); + if( canPasteSelection( tcoPos, dee ) == false ) + { + dee->ignore(); + } + else + { + StringPairDrag::processDragEnterEvent( dee, "tco_" + + QString::number( getTrack()->type() ) ); + } +} + + + + +/*! \brief Returns whether a selection of TCOs can be pasted into this + * + * \param tcoPos the position of the TCO slot being pasted on + * \param de the DropEvent generated + */ +bool TrackContentWidget::canPasteSelection( TimePos tcoPos, const QDropEvent* de ) +{ + const QMimeData * mimeData = de->mimeData(); + + // If the source of the DropEvent is the current instance of LMMS we don't allow pasting in the same bar + // if it's another instance of LMMS we allow it + return de->source() + ? canPasteSelection( tcoPos, mimeData ) + : canPasteSelection( tcoPos, mimeData, true ); +} + +// Overloaded method to make it possible to call this method without a Drag&Drop event +bool TrackContentWidget::canPasteSelection( TimePos tcoPos, const QMimeData* md , bool allowSameBar ) +{ + // For decodeKey() and decodeValue() + using namespace Clipboard; + + Track * t = getTrack(); + QString type = decodeKey( md ); + QString value = decodeValue( md ); + + // We can only paste into tracks of the same type + if( type != ( "tco_" + QString::number( t->type() ) ) || + m_trackView->trackContainerView()->fixedTCOs() == true ) + { + return false; + } + + // value contains XML needed to reconstruct TCOs and place them + DataFile dataFile( value.toUtf8() ); + + // Extract the metadata and which TCO was grabbed + QDomElement metadata = dataFile.content().firstChildElement( "copyMetadata" ); + QDomAttr tcoPosAttr = metadata.attributeNode( "grabbedTCOPos" ); + TimePos grabbedTCOPos = tcoPosAttr.value().toInt(); + TimePos grabbedTCOBar = TimePos( grabbedTCOPos.getBar(), 0 ); + + // Extract the track index that was originally clicked + QDomAttr tiAttr = metadata.attributeNode( "initialTrackIndex" ); + const int initialTrackIndex = tiAttr.value().toInt(); + + // Get the current track's index + const TrackContainer::TrackList tracks = t->trackContainer()->tracks(); + const int currentTrackIndex = tracks.indexOf( t ); + + // Don't paste if we're on the same bar and allowSameBar is false + auto sourceTrackContainerId = metadata.attributeNode( "trackContainerId" ).value().toUInt(); + if( !allowSameBar && sourceTrackContainerId == t->trackContainer()->id() && + tcoPos == grabbedTCOBar && currentTrackIndex == initialTrackIndex ) + { + return false; + } + + // Extract the tco data + QDomElement tcoParent = dataFile.content().firstChildElement( "tcos" ); + QDomNodeList tcoNodes = tcoParent.childNodes(); + + // Determine if all the TCOs will land on a valid track + for( int i = 0; i < tcoNodes.length(); i++ ) + { + QDomElement tcoElement = tcoNodes.item( i ).toElement(); + int trackIndex = tcoElement.attributeNode( "trackIndex" ).value().toInt(); + int finalTrackIndex = trackIndex + currentTrackIndex - initialTrackIndex; + + // Track must be in TrackContainer's tracks + if( finalTrackIndex < 0 || finalTrackIndex >= tracks.size() ) + { + return false; + } + + // Track must be of the same type + auto startTrackType = tcoElement.attributeNode("trackType").value().toInt(); + Track * endTrack = tracks.at( finalTrackIndex ); + if( startTrackType != endTrack->type() ) + { + return false; + } + } + + return true; +} + +/*! \brief Pastes a selection of TCOs onto the track + * + * \param tcoPos the position of the TCO slot being pasted on + * \param de the DropEvent generated + */ +bool TrackContentWidget::pasteSelection( TimePos tcoPos, QDropEvent * de ) +{ + const QMimeData * mimeData = de->mimeData(); + + if( canPasteSelection( tcoPos, de ) == false ) + { + return false; + } + + // We set skipSafetyCheck to true because we already called canPasteSelection + return pasteSelection( tcoPos, mimeData, true ); +} + +// Overloaded method so we can call it without a Drag&Drop event +bool TrackContentWidget::pasteSelection( TimePos tcoPos, const QMimeData * md, bool skipSafetyCheck ) +{ + // For decodeKey() and decodeValue() + using namespace Clipboard; + + // When canPasteSelection was already called before, skipSafetyCheck will skip this + if( !skipSafetyCheck && canPasteSelection( tcoPos, md ) == false ) + { + return false; + } + + QString type = decodeKey( md ); + QString value = decodeValue( md ); + + getTrack()->addJournalCheckPoint(); + + // value contains XML needed to reconstruct TCOs and place them + DataFile dataFile( value.toUtf8() ); + + // Extract the tco data + QDomElement tcoParent = dataFile.content().firstChildElement( "tcos" ); + QDomNodeList tcoNodes = tcoParent.childNodes(); + + // Extract the track index that was originally clicked + QDomElement metadata = dataFile.content().firstChildElement( "copyMetadata" ); + QDomAttr tiAttr = metadata.attributeNode( "initialTrackIndex" ); + int initialTrackIndex = tiAttr.value().toInt(); + QDomAttr tcoPosAttr = metadata.attributeNode( "grabbedTCOPos" ); + TimePos grabbedTCOPos = tcoPosAttr.value().toInt(); + + // 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() ); + + bool wasSelection = m_trackView->trackContainerView()->rubberBand()->selectedObjects().count(); + + // Unselect the old group + const QVector so = + m_trackView->trackContainerView()->selectedObjects(); + for( QVector::const_iterator it = so.begin(); + it != so.end(); ++it ) + { + ( *it )->setSelected( false ); + } + + + // TODO -- Need to draw the hovericon either way, or ghost the TCOs + // onto their final position. + + float snapSize = gui->songEditor()->m_editor->getSnapSize(); + // All patterns should be offset the same amount as the grabbed pattern + TimePos offset = TimePos(tcoPos - grabbedTCOPos); + // Users expect clips to "fall" backwards, so bias the offset + offset = offset - TimePos::ticksPerBar() * snapSize / 2; + // The offset is quantized (rather than the positions) to preserve fine adjustments + offset = offset.quantize(snapSize); + + // Get the leftmost TCO and fix the offset if it reaches below bar 0 + TimePos leftmostPos = grabbedTCOPos; + for(int i = 0; i < tcoNodes.length(); ++i) + { + QDomElement outerTCOElement = tcoNodes.item(i).toElement(); + QDomElement tcoElement = outerTCOElement.firstChildElement(); + + TimePos pos = tcoElement.attributeNode("pos").value().toInt(); + + if(pos < leftmostPos) { leftmostPos = pos; } + } + // Fix offset if it sets the left most TCO to a negative position + offset = std::max(offset.getTicks(), -leftmostPos.getTicks()); + + for( int i = 0; isongEditor()->m_editor->getSnapSize(); + if (offset == 0) { pos += shift; } + + TrackContentObject * tco = t->createTCO( pos ); + tco->restoreState( tcoElement ); + tco->movePosition(pos); // Because we restored the state, we need to move the TCO again. + if( wasSelection ) + { + tco->selectViewOnCreate( true ); + } + } + + AutomationPattern::resolveAllIDs(); + + return true; +} + + +/*! \brief Respond to a drop event on the trackContentWidget + * + * \param de the Drop Event to respond to + */ +void TrackContentWidget::dropEvent( QDropEvent * de ) +{ + TimePos tcoPos = TimePos( getPosition( de->pos().x() ) ); + if( pasteSelection( tcoPos, de ) == true ) + { + de->accept(); + } +} + + + + +/*! \brief Respond to a mouse press on the trackContentWidget + * + * \param me the mouse press event to respond to + */ +void TrackContentWidget::mousePressEvent( QMouseEvent * me ) +{ + if( m_trackView->trackContainerView()->allowRubberband() == true ) + { + QWidget::mousePressEvent( me ); + } + else if( me->modifiers() & Qt::ShiftModifier ) + { + QWidget::mousePressEvent( me ); + } + else if( me->button() == Qt::LeftButton && + !m_trackView->trackContainerView()->fixedTCOs() ) + { + QVector so = m_trackView->trackContainerView()->rubberBand()->selectedObjects(); + for( int i = 0; i < so.count(); ++i ) + { + so.at( i )->setSelected( false); + } + getTrack()->addJournalCheckPoint(); + const TimePos pos = getPosition( me->x() ).getBar() * + TimePos::ticksPerBar(); + getTrack()->createTCO(pos); + } +} + + + + +/*! \brief Repaint the trackContentWidget on command + * + * \param pe the Paint Event to respond to + */ +void TrackContentWidget::paintEvent( QPaintEvent * pe ) +{ + // Assume even-pixels-per-bar. Makes sense, should be like this anyways + const TrackContainerView * tcv = m_trackView->trackContainerView(); + 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().getBar() * ppb, 0 ) ); + } +} + + + + +/*! \brief Updates the background tile pixmap on size changes. + * + * \param resizeEvent the resize event to pass to base class + */ +void TrackContentWidget::resizeEvent( QResizeEvent * resizeEvent ) +{ + // Update backgroud + updateBackground(); + // Force redraw + QWidget::resizeEvent( resizeEvent ); +} + + + + +/*! \brief Return the track shown by the trackContentWidget + * + */ +Track * TrackContentWidget::getTrack() +{ + return m_trackView->getTrack(); +} + + + + +/*! \brief Return the end position of the trackContentWidget in Bars. + * + * \param posStart the starting position of the Widget (from getPosition()) + */ +TimePos TrackContentWidget::endPosition( const TimePos & posStart ) +{ + const float ppb = m_trackView->trackContainerView()->pixelsPerBar(); + const int w = width(); + return posStart + static_cast( w * TimePos::ticksPerBar() / ppb ); +} + +void TrackContentWidget::contextMenuEvent( QContextMenuEvent * cme ) +{ + // For hasFormat(), MimeType enum class and getMimeData() + using namespace Clipboard; + + if( cme->modifiers() ) + { + return; + } + + // If we don't have TCO data in the clipboard there's no need to create this menu + // since "paste" is the only action at the moment. + if( ! hasFormat( MimeType::StringPair ) ) + { + return; + } + + QMenu contextMenu( this ); + QAction *pasteA = contextMenu.addAction( embed::getIconPixmap( "edit_paste" ), + tr( "Paste" ), [this, cme](){ contextMenuAction( cme, Paste ); } ); + // If we can't paste in the current TCW for some reason, disable the action so the user knows + pasteA->setEnabled( canPasteSelection( getPosition( cme->x() ), getMimeData() ) ? true : false ); + + contextMenu.exec( QCursor::pos() ); +} + +void TrackContentWidget::contextMenuAction( QContextMenuEvent * cme, ContextMenuAction action ) +{ + // For getMimeData() + using namespace Clipboard; + + switch( action ) + { + case Paste: + // Paste the selection on the TimePos of the context menu event + TimePos tcoPos = getPosition( cme->x() ); + + pasteSelection( tcoPos, getMimeData() ); + break; + } +} + + + +// qproperty access methods +//! \brief CSS theming qproperty access method +QBrush TrackContentWidget::darkerColor() const +{ return m_darkerColor; } + +//! \brief CSS theming qproperty access method +QBrush TrackContentWidget::lighterColor() const +{ return m_lighterColor; } + +//! \brief CSS theming qproperty access method +QBrush TrackContentWidget::gridColor() const +{ return m_gridColor; } + +//! \brief CSS theming qproperty access method +QBrush TrackContentWidget::embossColor() const +{ return m_embossColor; } + +//! \brief CSS theming qproperty access method +void TrackContentWidget::setDarkerColor( const QBrush & c ) +{ m_darkerColor = c; } + +//! \brief CSS theming qproperty access method +void TrackContentWidget::setLighterColor( const QBrush & c ) +{ m_lighterColor = c; } + +//! \brief CSS theming qproperty access method +void TrackContentWidget::setGridColor( const QBrush & c ) +{ m_gridColor = c; } + +//! \brief CSS theming qproperty access method +void TrackContentWidget::setEmbossColor( const QBrush & c ) +{ m_embossColor = c; } + diff --git a/src/gui/widgets/TrackOperationsWidget.cpp b/src/gui/widgets/TrackOperationsWidget.cpp new file mode 100644 index 00000000000..8588aeb5a5d --- /dev/null +++ b/src/gui/widgets/TrackOperationsWidget.cpp @@ -0,0 +1,353 @@ +/* + * TrackOperationsWidget.cpp - implementation of TrackOperationsWidget class + * + * Copyright (c) 2004-2014 Tobias Doerffel + * + * 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. + * + */ + +#include "TrackOperationsWidget.h" + +#include +#include +#include +#include + +#include "AutomationPattern.h" +#include "AutomationTrack.h" +#include "ColorChooser.h" +#include "ConfigManager.h" +#include "DataFile.h" +#include "embed.h" +#include "Engine.h" +#include "gui_templates.h" +#include "InstrumentTrack.h" +#include "PixmapButton.h" +#include "Song.h" +#include "StringPairDrag.h" +#include "ToolTip.h" +#include "Track.h" +#include "TrackContainerView.h" +#include "TrackView.h" + +/*! \brief Create a new trackOperationsWidget + * + * The trackOperationsWidget is the grip and the mute button of a track. + * + * \param parent the trackView to contain this widget + */ +TrackOperationsWidget::TrackOperationsWidget( TrackView * parent ) : + QWidget( parent ), /*!< The parent widget */ + m_trackView( parent ) /*!< The parent track view */ +{ + ToolTip::add( this, tr( "Press <%1> while clicking on move-grip " + "to begin a new drag'n'drop action." ).arg(UI_CTRL_KEY) ); + + QMenu * toMenu = new QMenu( this ); + toMenu->setFont( pointSize<9>( toMenu->font() ) ); + connect( toMenu, SIGNAL( aboutToShow() ), this, SLOT( updateMenu() ) ); + + + setObjectName( "automationEnabled" ); + + + m_trackOps = new QPushButton( this ); + m_trackOps->move( 12, 1 ); + m_trackOps->setFocusPolicy( Qt::NoFocus ); + m_trackOps->setMenu( toMenu ); + ToolTip::add( m_trackOps, tr( "Actions" ) ); + + + m_muteBtn = new PixmapButton( this, tr( "Mute" ) ); + m_muteBtn->setActiveGraphic( embed::getIconPixmap( "led_off" ) ); + m_muteBtn->setInactiveGraphic( embed::getIconPixmap( "led_green" ) ); + m_muteBtn->setCheckable( true ); + + m_soloBtn = new PixmapButton( this, tr( "Solo" ) ); + m_soloBtn->setActiveGraphic( embed::getIconPixmap( "led_red" ) ); + m_soloBtn->setInactiveGraphic( embed::getIconPixmap( "led_off" ) ); + m_soloBtn->setCheckable( true ); + + if( ConfigManager::inst()->value( "ui", + "compacttrackbuttons" ).toInt() ) + { + m_muteBtn->move( 46, 0 ); + m_soloBtn->move( 46, 16 ); + } + else + { + m_muteBtn->move( 46, 8 ); + m_soloBtn->move( 62, 8 ); + } + + m_muteBtn->show(); + ToolTip::add( m_muteBtn, tr( "Mute" ) ); + + m_soloBtn->show(); + ToolTip::add( m_soloBtn, tr( "Solo" ) ); + + connect( this, SIGNAL( trackRemovalScheduled( TrackView * ) ), + m_trackView->trackContainerView(), + SLOT( deleteTrackView( TrackView * ) ), + Qt::QueuedConnection ); + + connect( m_trackView->getTrack()->getMutedModel(), SIGNAL( dataChanged() ), + this, SLOT( update() ) ); + +} + + + + +/*! \brief Destroy an existing trackOperationsWidget + * + */ +TrackOperationsWidget::~TrackOperationsWidget() +{ +} + + + + +/*! \brief Respond to trackOperationsWidget mouse events + * + * If it's the left mouse button, and Ctrl is held down, and we're + * not a Beat+Bassline Editor track, then start a new drag event to + * copy this track. + * + * Otherwise, ignore all other events. + * + * \param me The mouse event to respond to. + */ +void TrackOperationsWidget::mousePressEvent( QMouseEvent * me ) +{ + if( me->button() == Qt::LeftButton && + me->modifiers() & Qt::ControlModifier && + m_trackView->getTrack()->type() != Track::BBTrack ) + { + DataFile dataFile( DataFile::DragNDropData ); + m_trackView->getTrack()->saveState( dataFile, dataFile.content() ); + new StringPairDrag( QString( "track_%1" ).arg( + m_trackView->getTrack()->type() ), + dataFile.toString(), m_trackView->getTrackSettingsWidget()->grab(), + this ); + } + else if( me->button() == Qt::LeftButton ) + { + // track-widget (parent-widget) initiates track-move + me->ignore(); + } +} + + + + +/*! \brief Repaint the trackOperationsWidget + * + * If we're not moving, and in the Beat+Bassline Editor, then turn + * automation on or off depending on its previous state and show + * ourselves. + * + * Otherwise, hide ourselves. + * + * \todo Flesh this out a bit - is it correct? + * \param pe The paint event to respond to + */ +void TrackOperationsWidget::paintEvent( QPaintEvent * pe ) +{ + QPainter p( this ); + + p.fillRect( rect(), palette().brush(QPalette::Background) ); + + if( m_trackView->getTrack()->useColor() && ! m_trackView->getTrack()->getMutedModel()->value() ) + { + QRect coloredRect( 0, 0, 10, m_trackView->getTrack()->getHeight() ); + + p.fillRect( coloredRect, m_trackView->getTrack()->color() ); + } + + if( m_trackView->isMovingTrack() == false ) + { + p.drawPixmap( 2, 2, embed::getIconPixmap("track_op_grip")); + } + else + { + p.drawPixmap( 2, 2, embed::getIconPixmap("track_op_grip_c")); + } +} + + + + +/*! \brief Clone this track + * + */ +void TrackOperationsWidget::cloneTrack() +{ + TrackContainerView *tcView = m_trackView->trackContainerView(); + + Track *newTrack = m_trackView->getTrack()->clone(); + TrackView *newTrackView = tcView->createTrackView( newTrack ); + + int index = tcView->trackViews().indexOf( m_trackView ); + int i = tcView->trackViews().size(); + while ( i != index + 1 ) + { + tcView->moveTrackView( newTrackView, i - 1 ); + i--; + } +} + + +/*! \brief Clear this track - clears all TCOs from the track */ +void TrackOperationsWidget::clearTrack() +{ + Track * t = m_trackView->getTrack(); + t->addJournalCheckPoint(); + t->lock(); + t->deleteTCOs(); + t->unlock(); +} + + + +/*! \brief Remove this track from the track list + * + */ +void TrackOperationsWidget::removeTrack() +{ + emit trackRemovalScheduled( m_trackView ); +} + +void TrackOperationsWidget::changeTrackColor() +{ + QColor new_color = ColorChooser( this ).withPalette( ColorChooser::Palette::Track )-> \ + getColor( m_trackView->getTrack()->color() ); + + if( ! new_color.isValid() ) + { return; } + + emit colorChanged( new_color ); + + Engine::getSong()->setModified(); + update(); +} + +void TrackOperationsWidget::resetTrackColor() +{ + emit colorReset(); + Engine::getSong()->setModified(); + update(); +} + +void TrackOperationsWidget::randomTrackColor() +{ + QColor buffer = ColorChooser::getPalette( ColorChooser::Palette::Track )[ rand() % 48 ]; + + emit colorChanged( buffer ); + Engine::getSong()->setModified(); + update(); +} + +void TrackOperationsWidget::useTrackColor() +{ + emit colorParented(); + Engine::getSong()->setModified(); +} + + +/*! \brief Update the trackOperationsWidget context menu + * + * For all track types, we have the Clone and Remove options. + * For instrument-tracks we also offer the MIDI-control-menu + * For automation tracks, extra options: turn on/off recording + * on all TCOs (same should be added for sample tracks when + * sampletrack recording is implemented) + */ +void TrackOperationsWidget::updateMenu() +{ + QMenu * toMenu = m_trackOps->menu(); + toMenu->clear(); + toMenu->addAction( embed::getIconPixmap( "edit_copy", 16, 16 ), + tr( "Clone this track" ), + this, SLOT( cloneTrack() ) ); + toMenu->addAction( embed::getIconPixmap( "cancel", 16, 16 ), + tr( "Remove this track" ), + this, SLOT( removeTrack() ) ); + + if( ! m_trackView->trackContainerView()->fixedTCOs() ) + { + toMenu->addAction( tr( "Clear this track" ), this, SLOT( clearTrack() ) ); + } + if (QMenu *fxMenu = m_trackView->createFxMenu(tr("FX %1: %2"), tr("Assign to new FX Channel"))) + { + toMenu->addMenu(fxMenu); + } + + if (InstrumentTrackView * trackView = dynamic_cast(m_trackView)) + { + toMenu->addSeparator(); + toMenu->addMenu(trackView->midiMenu()); + } + if( dynamic_cast( m_trackView ) ) + { + toMenu->addAction( tr( "Turn all recording on" ), this, SLOT( recordingOn() ) ); + toMenu->addAction( tr( "Turn all recording off" ), this, SLOT( recordingOff() ) ); + } + + toMenu->addSeparator(); + toMenu->addAction( embed::getIconPixmap( "colorize" ), + tr( "Change color" ), this, SLOT( changeTrackColor() ) ); + toMenu->addAction( embed::getIconPixmap( "colorize" ), + tr( "Reset color to default" ), this, SLOT( resetTrackColor() ) ); + toMenu->addAction( embed::getIconPixmap( "colorize" ), + tr( "Set random color" ), this, SLOT( randomTrackColor() ) ); + toMenu->addSeparator(); + toMenu->addAction( embed::getIconPixmap( "colorize" ), + tr( "Clear clip colors" ), this, SLOT( useTrackColor() ) ); +} + + +void TrackOperationsWidget::toggleRecording( bool on ) +{ + AutomationTrackView * atv = dynamic_cast( m_trackView ); + if( atv ) + { + for( TrackContentObject * tco : atv->getTrack()->getTCOs() ) + { + AutomationPattern * ap = dynamic_cast( tco ); + if( ap ) { ap->setRecording( on ); } + } + atv->update(); + } +} + + + +void TrackOperationsWidget::recordingOn() +{ + toggleRecording( true ); +} + + +void TrackOperationsWidget::recordingOff() +{ + toggleRecording( false ); +} + diff --git a/src/lmmsconfig.h.in b/src/lmmsconfig.h.in index 3ea9d749c0c..86882d22e25 100644 --- a/src/lmmsconfig.h.in +++ b/src/lmmsconfig.h.in @@ -13,6 +13,8 @@ #cmakedefine LMMS_HAVE_FLUIDSYNTH #cmakedefine LMMS_HAVE_JACK #cmakedefine LMMS_HAVE_WEAKJACK +#cmakedefine LMMS_HAVE_LV2 +#cmakedefine LMMS_HAVE_SUIL #cmakedefine LMMS_HAVE_MP3LAME #cmakedefine LMMS_HAVE_OGGVORBIS #cmakedefine LMMS_HAVE_OSS diff --git a/src/tracks/AutomationTrack.cpp b/src/tracks/AutomationTrack.cpp index 430f54a5692..dfb0df480fb 100644 --- a/src/tracks/AutomationTrack.cpp +++ b/src/tracks/AutomationTrack.cpp @@ -40,7 +40,7 @@ AutomationTrack::AutomationTrack( TrackContainer* tc, bool _hidden ) : setName( tr( "Automation track" ) ); } -bool AutomationTrack::play( const MidiTime & time_start, const fpp_t _frames, +bool AutomationTrack::play( const TimePos & time_start, const fpp_t _frames, const f_cnt_t _frame_base, int _tco_num ) { return false; @@ -57,9 +57,11 @@ TrackView * AutomationTrack::createView( TrackContainerView* tcv ) -TrackContentObject * AutomationTrack::createTCO( const MidiTime & ) +TrackContentObject* AutomationTrack::createTCO(const TimePos & pos) { - return new AutomationPattern( this ); + AutomationPattern* p = new AutomationPattern(this); + p->movePosition(pos); + return p; } @@ -117,11 +119,11 @@ void AutomationTrackView::dropEvent( QDropEvent * _de ) journallingObject( val.toInt() ) ); if( mod != NULL ) { - MidiTime pos = MidiTime( trackContainerView()-> + TimePos pos = TimePos( trackContainerView()-> currentPosition() + ( _de->pos().x() - getTrackContentWidget()->x() ) * - MidiTime::ticksPerBar() / + TimePos::ticksPerBar() / static_cast( trackContainerView()->pixelsPerBar() ) ) .toAbsoluteBar(); @@ -133,7 +135,6 @@ void AutomationTrackView::dropEvent( QDropEvent * _de ) TrackContentObject * tco = getTrack()->createTCO( pos ); AutomationPattern * pat = dynamic_cast( tco ); pat->addObject( mod ); - pat->movePosition( pos ); } } diff --git a/src/tracks/BBTrack.cpp b/src/tracks/BBTrack.cpp index a779e2ea49b..1460d5eef79 100644 --- a/src/tracks/BBTrack.cpp +++ b/src/tracks/BBTrack.cpp @@ -23,7 +23,7 @@ */ #include "BBTrack.h" -#include +#include #include #include @@ -32,8 +32,8 @@ #include "embed.h" #include "Engine.h" #include "gui_templates.h" -#include "MainWindow.h" #include "GuiApplication.h" +#include "MainWindow.h" #include "Mixer.h" #include "RenameDialog.h" #include "Song.h" @@ -47,15 +47,13 @@ BBTrack::infoMap BBTrack::s_infoMap; BBTCO::BBTCO( Track * _track ) : - TrackContentObject( _track ), - m_color( 128, 128, 128 ), - m_useStyleColor( true ) + TrackContentObject( _track ) { bar_t t = Engine::getBBTrackContainer()->lengthOfBB( bbTrackIndex() ); if( t > 0 ) { saveJournallingState( false ); - changeLength( MidiTime( t, 0 ) ); + changeLength( TimePos( t, 0 ) ); restoreJournallingState(); } setAutoResize( false ); @@ -74,15 +72,9 @@ void BBTCO::saveSettings( QDomDocument & doc, QDomElement & element ) } element.setAttribute( "len", length() ); element.setAttribute( "muted", isMuted() ); - element.setAttribute( "color", color() ); - - if( m_useStyleColor ) + if( usesCustomClipColor() ) { - element.setAttribute( "usestyle", 1 ); - } - else - { - element.setAttribute( "usestyle", 0 ); + element.setAttribute( "color", color().name() ); } } @@ -101,33 +93,21 @@ void BBTCO::loadSettings( const QDomElement & element ) { toggleMute(); } - - if( element.hasAttribute( "color" ) ) - { - setColor( QColor( element.attribute( "color" ).toUInt() ) ); - } - if( element.hasAttribute( "usestyle" ) ) + // for colors saved in 1.3-onwards + if( element.hasAttribute( "color" ) && !element.hasAttribute( "usestyle" ) ) { - if( element.attribute( "usestyle" ).toUInt() == 1 ) - { - m_useStyleColor = true; - } - else - { - m_useStyleColor = false; - } + useCustomClipColor( true ); + setColor( element.attribute( "color" ) ); } + + // for colors saved before 1.3 else { - if( m_color.rgb() == qRgb( 128, 182, 175 ) || m_color.rgb() == qRgb( 64, 128, 255 ) ) // old or older default color - { - m_useStyleColor = true; - } - else - { - m_useStyleColor = false; - } + if( element.hasAttribute( "color" ) ) + { setColor( QColor( element.attribute( "color" ).toUInt() ) ); } + + // usestyle attribute is no longer used } } @@ -153,7 +133,8 @@ BBTCOView::BBTCOView( TrackContentObject * _tco, TrackView * _tv ) : m_bbTCO( dynamic_cast( _tco ) ), m_paintPixmap() { - connect( _tco->getTrack(), SIGNAL( dataChanged() ), this, SLOT( update() ) ); + connect( _tco->getTrack(), SIGNAL( dataChanged() ), + this, SLOT( update() ) ); setStyle( QApplication::style() ); } @@ -173,10 +154,6 @@ void BBTCOView::constructContextMenu( QMenu * _cm ) _cm->addAction( embed::getIconPixmap( "edit_rename" ), tr( "Change name" ), this, SLOT( changeName() ) ); - _cm->addAction( embed::getIconPixmap( "colorize" ), - tr( "Change color" ), this, SLOT( changeColor() ) ); - _cm->addAction( embed::getIconPixmap( "colorize" ), - tr( "Reset color to default" ), this, SLOT( resetColor() ) ); } @@ -210,13 +187,7 @@ void BBTCOView::paintEvent( QPaintEvent * ) QPainter p( &m_paintPixmap ); QLinearGradient lingrad( 0, 0, 0, height() ); - QColor c; - bool muted = m_bbTCO->getTrack()->isMuted() || m_bbTCO->isMuted(); - - // state: selected, muted, default, user selected - c = isSelected() ? selectedColor() : ( muted ? mutedBackgroundColor() - : ( m_bbTCO->m_useStyleColor ? painter.background().color() - : m_bbTCO->colorObj() ) ); + QColor c = getColorForDisplay( painter.background().color() ); lingrad.setColorAt( 0, c.lighter( 130 ) ); lingrad.setColorAt( 1, c.lighter( 70 ) ); @@ -238,7 +209,7 @@ void BBTCOView::paintEvent( QPaintEvent * ) p.setPen( c.darker( 200 ) ); bar_t t = Engine::getBBTrackContainer()->lengthOfBB( m_bbTCO->bbTrackIndex() ); - if( m_bbTCO->length() > MidiTime::ticksPerBar() && t > 0 ) + if( m_bbTCO->length() > TimePos::ticksPerBar() && t > 0 ) { for( int x = static_cast( t * pixelsPerBar() ); x < width() - 2; @@ -290,10 +261,7 @@ void BBTCOView::openInBBEditor() -void BBTCOView::resetName() -{ - m_bbTCO->setName( m_bbTCO->getTrack()->name() ); -} +void BBTCOView::resetName() { m_bbTCO->setName(""); } @@ -308,63 +276,6 @@ void BBTCOView::changeName() - -void BBTCOView::changeColor() -{ - QColor new_color = QColorDialog::getColor( m_bbTCO->m_color ); - if( ! new_color.isValid() ) - { - return; - } - if( isSelected() ) - { - QVector selected = - gui->songEditor()->m_editor->selectedObjects(); - for( QVector::iterator it = - selected.begin(); - it != selected.end(); ++it ) - { - BBTCOView * bb_tcov = dynamic_cast( *it ); - if( bb_tcov ) - { - bb_tcov->setColor( new_color ); - } - } - } - else - { - setColor( new_color ); - } -} - - -/** \brief Makes the BB pattern use the colour defined in the stylesheet */ -void BBTCOView::resetColor() -{ - if( ! m_bbTCO->m_useStyleColor ) - { - m_bbTCO->m_useStyleColor = true; - Engine::getSong()->setModified(); - update(); - } - BBTrack::clearLastTCOColor(); -} - - - -void BBTCOView::setColor( QColor new_color ) -{ - if( new_color.rgb() != m_bbTCO->color() ) - { - m_bbTCO->setColor( new_color ); - m_bbTCO->m_useStyleColor = false; - Engine::getSong()->setModified(); - update(); - } - BBTrack::setLastTCOColor( new_color ); -} - - void BBTCOView::update() { ToolTip::add(this, m_bbTCO->name()); @@ -374,8 +285,6 @@ void BBTCOView::update() -QColor * BBTrack::s_lastTCOColor = NULL; - BBTrack::BBTrack( TrackContainer* tc ) : Track( Track::BBTrack, tc ) { @@ -423,7 +332,7 @@ BBTrack::~BBTrack() // play _frames frames of given TCO within starting with _start -bool BBTrack::play( const MidiTime & _start, const fpp_t _frames, +bool BBTrack::play( const TimePos & _start, const fpp_t _frames, const f_cnt_t _offset, int _tco_num ) { if( isMuted() ) @@ -444,8 +353,8 @@ bool BBTrack::play( const MidiTime & _start, const fpp_t _frames, return false; } - MidiTime lastPosition; - MidiTime lastLen; + TimePos lastPosition; + TimePos lastLen; for( tcoVector::iterator it = tcos.begin(); it != tcos.end(); ++it ) { if( !( *it )->isMuted() && @@ -474,14 +383,10 @@ TrackView * BBTrack::createView( TrackContainerView* tcv ) -TrackContentObject * BBTrack::createTCO( const MidiTime & _pos ) +TrackContentObject* BBTrack::createTCO(const TimePos & pos) { - BBTCO * bbtco = new BBTCO( this ); - if( s_lastTCOColor ) - { - bbtco->setColor( *s_lastTCOColor ); - bbtco->setUseStyleColor( false ); - } + BBTCO* bbtco = new BBTCO(this); + bbtco->movePosition(pos); return bbtco; } @@ -528,8 +433,8 @@ void BBTrack::loadTrackSpecificSettings( const QDomElement & _this ) for( TrackContainer::TrackList::iterator it = tl.begin(); it != tl.end(); ++it ) { - ( *it )->getTCO( src )->copy(); - ( *it )->getTCO( dst )->paste(); + TrackContentObject::copyStateTo( ( *it )->getTCO( src ), + ( *it )->getTCO( dst ) ); } setName( tr( "Clone of %1" ).arg( _this.parentNode().toElement().attribute( "name" ) ) ); diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index f8cded6d7cf..15dd17c8bb5 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -22,9 +22,9 @@ * Boston, MA 02110-1301 USA. * */ +#include "InstrumentTrack.h" #include -#include #include #include #include @@ -37,12 +37,12 @@ #include #include "FileDialog.h" -#include "InstrumentTrack.h" #include "AutomationPattern.h" #include "BBTrack.h" #include "CaptionMenu.h" #include "ConfigManager.h" #include "ControllerConnection.h" +#include "DataFile.h" #include "EffectChain.h" #include "EffectRackView.h" #include "embed.h" @@ -74,17 +74,12 @@ #include "StringPairDrag.h" #include "TrackContainerView.h" #include "TrackLabelButton.h" +#include "MidiCCRackView.h" -const char * volume_help = QT_TRANSLATE_NOOP( "InstrumentTrack", - "With this knob you can set " - "the volume of the opened " - "channel."); - const int INSTRUMENT_WIDTH = 254; const int INSTRUMENT_HEIGHT = INSTRUMENT_WIDTH; const int PIANO_HEIGHT = 80; -const int INSTRUMENT_WINDOW_CACHE_SIZE = 8; // #### IT: @@ -97,6 +92,7 @@ InstrumentTrack::InstrumentTrack( TrackContainer* tc ) : m_sustainPedalPressed( false ), m_silentBuffersProcessed( false ), m_previewMode( false ), + m_hasAutoMidiDev( false ), m_baseNoteModel( 0, 0, KeysPerOctave * NumOctaves - 1, this, tr( "Base note" ) ), m_volumeModel( DefaultVolume, MinVolume, MaxVolume, 0.1f, this, tr( "Volume" ) ), @@ -125,6 +121,21 @@ InstrumentTrack::InstrumentTrack( TrackContainer* tc ) : } + // Initialize the m_midiCCEnabled variable, but it's actually going to be connected + // to a LedButton + m_midiCCEnable = std::make_unique(false, nullptr, tr("Enable/Disable MIDI CC")); + + // Initialize the MIDI CC controller models and connect them to the method that processes + // the midi cc events + for (int i = 0; i < MidiControllerCount; ++i) + { + m_midiCCModel[i] = std::make_unique(0.0f, 0.0f, 127.0f, 1.0f, + nullptr, tr("CC Controller %1").arg(i)); + + connect(m_midiCCModel[i].get(), &FloatModel::dataChanged, + this, [this, i]{ processCCEvent(i); }, Qt::DirectConnection); + } + setName( tr( "Default preset" ) ); connect( &m_baseNoteModel, SIGNAL( dataChanged() ), @@ -149,6 +160,13 @@ int InstrumentTrack::baseNote() const InstrumentTrack::~InstrumentTrack() { + // De-assign midi device + if (m_hasAutoMidiDev) + { + autoAssignMidiDevice(false); + s_autoAssignedTrack = NULL; + } + // kill all running notes and the iph silenceAllNotes( true ); @@ -241,9 +259,27 @@ MidiEvent InstrumentTrack::applyMasterKey( const MidiEvent& event ) -void InstrumentTrack::processInEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset ) +void InstrumentTrack::processCCEvent(int controller) { - if( Engine::getSong()->isExporting() ) + // Does nothing if the LED is disabled + if (!m_midiCCEnable->value()) { return; } + + uint8_t channel = static_cast(midiPort()->realOutputChannel()); + uint16_t cc = static_cast(controller); + uint16_t value = static_cast(m_midiCCModel[controller]->value()); + + // Process the MIDI CC event as an input event but with source set to Internal + // so we can know LMMS generated the event, not a controller, and can process it during + // the project export + processInEvent(MidiEvent(MidiControlChange, channel, cc, value, nullptr, MidiEvent::Source::Internal)); +} + + + + +void InstrumentTrack::processInEvent( const MidiEvent& event, const TimePos& time, f_cnt_t offset ) +{ + if (Engine::getSong()->isExporting() && event.source() == MidiEvent::Source::External) { return; } @@ -264,7 +300,7 @@ void InstrumentTrack::processInEvent( const MidiEvent& event, const MidiTime& ti NotePlayHandlePool.construct( this, offset, typeInfo::max() / 2, - Note( MidiTime(), MidiTime(), event.key(), event.volume( midiPort()->baseVelocity() ) ), + Note( TimePos(), TimePos(), event.key(), event.volume( midiPort()->baseVelocity() ) ), nullptr, event.channel(), NotePlayHandle::OriginMidiInput ); m_notes[event.key()] = nph; @@ -329,7 +365,7 @@ void InstrumentTrack::processInEvent( const MidiEvent& event, const MidiTime& ti nph->OriginMidiInput) { nph->setLength( - MidiTime( static_cast( + TimePos( static_cast( nph->totalFramesPlayed() / Engine::framesPerTick() ) ) ); midiNoteOff( *nph ); @@ -372,9 +408,11 @@ void InstrumentTrack::processInEvent( const MidiEvent& event, const MidiTime& ti break; } - if( eventHandled == false && instrument()->handleMidiEvent( event, time, offset ) == false ) + // If the event wasn't handled, check if there's a loaded instrument and if so send the + // event to it. If it returns false means the instrument didn't handle the event, so we trigger a warning. + if (eventHandled == false && !(instrument() && instrument()->handleMidiEvent(event, time, offset))) { - qWarning( "InstrumentTrack: unhandled MIDI event %d", event.type() ); + qWarning("InstrumentTrack: unhandled MIDI event %d", event.type()); } } @@ -382,7 +420,7 @@ void InstrumentTrack::processInEvent( const MidiEvent& event, const MidiTime& ti -void InstrumentTrack::processOutEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset ) +void InstrumentTrack::processOutEvent( const MidiEvent& event, const TimePos& time, f_cnt_t offset ) { // do nothing if we do not have an instrument instance (e.g. when loading settings) if( m_instrument == NULL ) @@ -393,6 +431,12 @@ void InstrumentTrack::processOutEvent( const MidiEvent& event, const MidiTime& t const MidiEvent transposedEvent = applyMasterKey( event ); const int key = transposedEvent.key(); + // If we have a selected output midi channel between 1-16, we will use that channel to handle the midi event. + // But if our selected midi output channel is 0 ("--"), we will use the event channel instead. + const auto handleEventOutputChannel = midiPort()->outputChannel() == 0 + ? event.channel() + : midiPort()->realOutputChannel(); + switch( event.type() ) { case MidiNoteOn: @@ -403,10 +447,10 @@ void InstrumentTrack::processOutEvent( const MidiEvent& event, const MidiTime& t { if( m_runningMidiNotes[key] > 0 ) { - m_instrument->handleMidiEvent( MidiEvent( MidiNoteOff, midiPort()->realOutputChannel(), key, 0 ), time, offset ); + m_instrument->handleMidiEvent( MidiEvent( MidiNoteOff, handleEventOutputChannel, key, 0 ), time, offset ); } ++m_runningMidiNotes[key]; - m_instrument->handleMidiEvent( MidiEvent( MidiNoteOn, midiPort()->realOutputChannel(), key, event.velocity() ), time, offset ); + m_instrument->handleMidiEvent( MidiEvent( MidiNoteOn, handleEventOutputChannel, key, event.velocity() ), time, offset ); } m_midiNotesMutex.unlock(); @@ -419,7 +463,7 @@ void InstrumentTrack::processOutEvent( const MidiEvent& event, const MidiTime& t if( key >= 0 && key < NumKeys && --m_runningMidiNotes[key] <= 0 ) { - m_instrument->handleMidiEvent( MidiEvent( MidiNoteOff, midiPort()->realOutputChannel(), key, 0 ), time, offset ); + m_instrument->handleMidiEvent( MidiEvent( MidiNoteOff, handleEventOutputChannel, key, 0 ), time, offset ); } m_midiNotesMutex.unlock(); emit endNote(); @@ -521,17 +565,6 @@ void InstrumentTrack::deleteNotePluginData( NotePlayHandle* n ) void InstrumentTrack::setName( const QString & _new_name ) { - // when changing name of track, also change name of those patterns, - // which have the same name as the instrument-track - for( int i = 0; i < numOfTCOs(); ++i ) - { - Pattern* p = dynamic_cast( getTCO( i ) ); - if( ( p != NULL && p->name() == name() ) || p->name() == "" ) - { - p->setName( _new_name ); - } - } - Track::setName( _new_name ); m_midiPort.setName( name() ); m_audioPort.setName( name() ); @@ -610,7 +643,7 @@ void InstrumentTrack::removeMidiPortNode( DataFile & _dataFile ) -bool InstrumentTrack::play( const MidiTime & _start, const fpp_t _frames, +bool InstrumentTrack::play( const TimePos & _start, const fpp_t _frames, const f_cnt_t _offset, int _tco_num ) { if( ! m_instrument || ! tryLock() ) @@ -640,7 +673,7 @@ bool InstrumentTrack::play( const MidiTime & _start, const fpp_t _frames, for( NotePlayHandleList::Iterator it = m_processHandles.begin(); it != m_processHandles.end(); ++it ) { - ( *it )->processMidiTime( _start ); + ( *it )->processTimePos( _start ); } if ( tcos.size() == 0 ) @@ -662,7 +695,7 @@ bool InstrumentTrack::play( const MidiTime & _start, const fpp_t _frames, { continue; } - MidiTime cur_start = _start; + TimePos cur_start = _start; if( _tco_num < 0 ) { cur_start -= p->startPosition(); @@ -715,9 +748,11 @@ bool InstrumentTrack::play( const MidiTime & _start, const fpp_t _frames, -TrackContentObject * InstrumentTrack::createTCO( const MidiTime & ) +TrackContentObject* InstrumentTrack::createTCO(const TimePos & pos) { - return new Pattern( this ); + Pattern* p = new Pattern(this); + p->movePosition(pos); + return p; } @@ -742,6 +777,15 @@ void InstrumentTrack::saveTrackSpecificSettings( QDomDocument& doc, QDomElement m_baseNoteModel.saveSettings( doc, thisElement, "basenote" ); m_useMasterPitchModel.saveSettings( doc, thisElement, "usemasterpitch"); + // Save MIDI CC stuff + m_midiCCEnable->saveSettings(doc, thisElement, "enablecc"); + QDomElement midiCC = doc.createElement("midicontrollers"); + thisElement.appendChild(midiCC); + for (int i = 0; i < MidiControllerCount; ++i) + { + m_midiCCModel[i]->saveSettings(doc, midiCC, "cc" + QString::number(i)); + } + if( m_instrument != NULL ) { QDomElement i = doc.createElement( "instrument" ); @@ -760,7 +804,13 @@ void InstrumentTrack::saveTrackSpecificSettings( QDomDocument& doc, QDomElement if (Engine::getSong()->isSavingProject() && !Engine::getSong()->getSaveOptions().discardMIDIConnections.value()) { + // Don't save auto assigned midi device connection + bool hasAuto = m_hasAutoMidiDev; + autoAssignMidiDevice(false); + m_midiPort.saveState( doc, thisElement ); + + autoAssignMidiDevice(hasAuto); } m_audioPort.effects()->saveState( doc, thisElement ); @@ -794,6 +844,10 @@ void InstrumentTrack::loadTrackSpecificSettings( const QDomElement & thisElement // clear effect-chain just in case we load an old preset without FX-data m_audioPort.effects()->clear(); + // We set MIDI CC enable to false so the knobs don't trigger MIDI CC events while + // they are being loaded. After all knobs are loaded we load the right value of m_midiCCEnable. + m_midiCCEnable->setValue(false); + QDomNode node = thisElement.firstChild(); while( !node.isNull() ) { @@ -838,6 +892,13 @@ void InstrumentTrack::loadTrackSpecificSettings( const QDomElement & thisElement emit instrumentChanged(); } } + else if (node.nodeName() == "midicontrollers") + { + for (int i = 0; i < MidiControllerCount; ++i) + { + m_midiCCModel[i]->loadSettings(node.toElement(), "cc" + QString::number(i)); + } + } // compat code - if node-name doesn't match any known // one, we assume that it is an instrument-plugin // which we'll try to load @@ -858,6 +919,10 @@ void InstrumentTrack::loadTrackSpecificSettings( const QDomElement & thisElement } node = node.nextSibling(); } + + // Load the right value of m_midiCCEnable + m_midiCCEnable->loadSettings(thisElement, "enablecc"); + updatePitchRange(); unlock(); } @@ -908,12 +973,41 @@ Instrument * InstrumentTrack::loadInstrument(const QString & _plugin_name, +InstrumentTrack *InstrumentTrack::s_autoAssignedTrack = NULL; +/*! \brief Automatically assign a midi controller to this track, based on the midiautoassign setting + * + * \param assign set to true to connect the midi device, set to false to disconnect + */ +void InstrumentTrack::autoAssignMidiDevice(bool assign) +{ + if (assign) + { + if (s_autoAssignedTrack) + { + s_autoAssignedTrack->autoAssignMidiDevice(false); + } + s_autoAssignedTrack = this; + } -// #### ITV: + const QString &device = ConfigManager::inst()->value("midi", "midiautoassign"); + if ( Engine::mixer()->midiClient()->isRaw() && device != "none" ) + { + m_midiPort.setReadable( assign ); + return; + } + + // Check if the device exists + if ( Engine::mixer()->midiClient()->readablePorts().indexOf(device) >= 0 ) + { + m_midiPort.subscribeReadablePort(device, assign); + m_hasAutoMidiDev = assign; + } +} -QQueue InstrumentTrackView::s_windowCache; + +// #### ITV: @@ -937,6 +1031,9 @@ InstrumentTrackView::InstrumentTrackView( InstrumentTrack * _it, TrackContainerV connect( _it, SIGNAL( nameChanged() ), m_tlb, SLOT( update() ) ); + connect(ConfigManager::inst(), SIGNAL(valueChanged(QString, QString, QString)), + this, SLOT(handleConfigChange(QString, QString, QString))); + // creation of widgets for track-settings-widget int widgetWidth; if( ConfigManager::inst()->value( "ui", @@ -961,7 +1058,7 @@ InstrumentTrackView::InstrumentTrackView( InstrumentTrack * _it, TrackContainerV m_panningKnob = new Knob( knobSmall_17, getTrackSettingsWidget(), tr( "Panning" ) ); m_panningKnob->setModel( &_it->m_panningModel ); - m_panningKnob->setHintText( tr( "Panning:" ), "%" ); + m_panningKnob->setHintText(tr("Panning:"), "%"); m_panningKnob->move( widgetWidth-24, 2 ); m_panningKnob->setLabel( tr( "PAN" ) ); m_panningKnob->show(); @@ -1001,6 +1098,11 @@ InstrumentTrackView::InstrumentTrackView( InstrumentTrack * _it, TrackContainerV m_midiInputAction->setText( tr( "Input" ) ); m_midiOutputAction->setText( tr( "Output" ) ); + QAction *midiRackAction = m_midiMenu->addAction(tr("Open/Close MIDI CC Rack")); + midiRackAction->setIcon(embed::getIconPixmap("midi_cc_rack")); + connect(midiRackAction, SIGNAL(triggered()), + this, SLOT(toggleMidiCCRack())); + m_activityIndicator = new FadeButton( QApplication::palette().color( QPalette::Active, QPalette::Background), QApplication::palette().color( QPalette::Active, @@ -1028,7 +1130,8 @@ InstrumentTrackView::InstrumentTrackView( InstrumentTrack * _it, TrackContainerV InstrumentTrackView::~InstrumentTrackView() { - freeInstrumentTrackWindow(); + delete m_window; + m_window = nullptr; delete model()->m_midiPort.m_readablePortsMenu; delete model()->m_midiPort.m_writablePortsMenu; @@ -1037,6 +1140,29 @@ InstrumentTrackView::~InstrumentTrackView() +void InstrumentTrackView::toggleMidiCCRack() +{ + // Lazy creation: midiCCRackView is only created when accessed the first time. + // this->model() returns pointer to the InstrumentTrack who owns this InstrumentTrackView. + if (!m_midiCCRackView) + { + m_midiCCRackView = std::unique_ptr(new MidiCCRackView(this->model())); + } + + if (m_midiCCRackView->parentWidget()->isVisible()) + { + m_midiCCRackView->parentWidget()->hide(); + } + else + { + m_midiCCRackView->parentWidget()->show(); + m_midiCCRackView->show(); + } +} + + + + InstrumentTrackWindow * InstrumentTrackView::topLevelInstrumentTrackWindow() { InstrumentTrackWindow * w = NULL; @@ -1060,8 +1186,10 @@ InstrumentTrackWindow * InstrumentTrackView::topLevelInstrumentTrackWindow() void InstrumentTrackView::createFxLine() { int channelIndex = gui->fxMixerView()->addNewChannel(); + auto channel = Engine::fxMixer()->effectChannel(channelIndex); - Engine::fxMixer()->effectChannel( channelIndex )->m_name = getTrack()->name(); + channel->m_name = getTrack()->name(); + if (getTrack()->useColor()) { channel->setColor (getTrack()->color()); } assignFxLine(channelIndex); } @@ -1079,92 +1207,26 @@ void InstrumentTrackView::assignFxLine(int channelIndex) -// TODO: Add windows to free list on freeInstrumentTrackWindow. -// But, don't NULL m_window or disconnect signals. This will allow windows -// that are being show/hidden frequently to stay connected. -void InstrumentTrackView::freeInstrumentTrackWindow() +InstrumentTrackWindow * InstrumentTrackView::getInstrumentTrackWindow() { - if( m_window != NULL ) + if (!m_window) { - m_lastPos = m_window->parentWidget()->pos(); - - if( ConfigManager::inst()->value( "ui", - "oneinstrumenttrackwindow" ).toInt() || - s_windowCache.count() < INSTRUMENT_WINDOW_CACHE_SIZE ) - { - model()->setHook( NULL ); - m_window->setInstrumentTrackView( NULL ); - m_window->parentWidget()->hide(); - //m_window->setModel( - // engine::dummyTrackContainer()-> - // dummyInstrumentTrack() ); - m_window->updateInstrumentView(); - s_windowCache << m_window; - } - else - { - delete m_window; - } - - m_window = NULL; + m_window = new InstrumentTrackWindow(this); } -} - - - -void InstrumentTrackView::cleanupWindowCache() -{ - while( !s_windowCache.isEmpty() ) - { - delete s_windowCache.dequeue(); - } + return m_window; } - - - -InstrumentTrackWindow * InstrumentTrackView::getInstrumentTrackWindow() +void InstrumentTrackView::handleConfigChange(QString cls, QString attr, QString value) { - if( m_window != NULL ) + // When one instrument track window mode is turned on, + // close windows except last opened one. + if (cls == "ui" && attr == "oneinstrumenttrackwindow" && value.toInt()) { + m_tlb->setChecked(m_window && m_window == topLevelInstrumentTrackWindow()); } - else if( !s_windowCache.isEmpty() ) - { - m_window = s_windowCache.dequeue(); - - m_window->setInstrumentTrackView( this ); - m_window->setModel( model() ); - m_window->updateInstrumentView(); - model()->setHook( m_window ); - - if( ConfigManager::inst()-> - value( "ui", "oneinstrumenttrackwindow" ).toInt() ) - { - s_windowCache << m_window; - } - else if( m_lastPos.x() > 0 || m_lastPos.y() > 0 ) - { - m_window->parentWidget()->move( m_lastPos ); - } - } - else - { - m_window = new InstrumentTrackWindow( this ); - if( ConfigManager::inst()-> - value( "ui", "oneinstrumenttrackwindow" ).toInt() ) - { - // first time, an InstrumentTrackWindow is opened - s_windowCache << m_window; - } - } - - return m_window; } - - - void InstrumentTrackView::dragEnterEvent( QDragEnterEvent * _dee ) { InstrumentTrackWindow::dragEnterEventGeneric( _dee ); @@ -1188,12 +1250,15 @@ void InstrumentTrackView::dropEvent( QDropEvent * _de ) void InstrumentTrackView::toggleInstrumentWindow( bool _on ) { - getInstrumentTrackWindow()->toggleVisibility( _on ); - - if( !_on ) + if (_on && ConfigManager::inst()->value("ui", "oneinstrumenttrackwindow").toInt()) { - freeInstrumentTrackWindow(); + if (topLevelInstrumentTrackWindow()) + { + topLevelInstrumentTrackWindow()->m_itv->m_tlb->setChecked(false); + } } + + getInstrumentTrackWindow()->toggleVisibility( _on ); } @@ -1470,9 +1535,7 @@ InstrumentTrackWindow::InstrumentTrackWindow( InstrumentTrackView * _itv ) : m_tabWidget->addTab( m_miscView, tr( "Miscellaneous" ), "misc_tab", 5 ); adjustTabSize(m_ssView); adjustTabSize(instrumentFunctions); - adjustTabSize(m_effectView); - // stupid bugfix, no one knows why - m_effectView->resize(INSTRUMENT_WIDTH - 4, INSTRUMENT_HEIGHT - 4 - 1); + m_effectView->resize(EffectRackView::DEFAULT_WIDTH, INSTRUMENT_HEIGHT - 4 - 1); adjustTabSize(m_midiView); adjustTabSize(m_miscView); @@ -1482,20 +1545,20 @@ InstrumentTrackWindow::InstrumentTrackWindow( InstrumentTrackView * _itv ) : m_pianoView->setMaximumHeight( PIANO_HEIGHT ); vlayout->addWidget( generalSettingsWidget ); - vlayout->addWidget( m_tabWidget, 1 ); + // Use QWidgetItem explicitly to make the size hint change on instrument changes + // QLayout::addWidget() uses QWidgetItemV2 with size hint caching + vlayout->insertItem(1, new QWidgetItem(m_tabWidget)); vlayout->addWidget( m_pianoView ); setModel( _itv->model() ); - updateInstrumentView(); - - resize( sizeHint() ); - QMdiSubWindow* subWin = gui->mainWindow()->addWindowedWidget( this ); Qt::WindowFlags flags = subWin->windowFlags(); flags |= Qt::MSWindowsFixedSizeDialogHint; flags &= ~Qt::WindowMaximizeButtonHint; subWin->setWindowFlags( flags ); + updateInstrumentView(); + // Hide the Size and Maximize options from the system menu // since the dialog size is fixed. QMenu * systemMenu = subWin->systemMenu(); @@ -1512,11 +1575,9 @@ InstrumentTrackWindow::InstrumentTrackWindow( InstrumentTrackView * _itv ) : InstrumentTrackWindow::~InstrumentTrackWindow() { - InstrumentTrackView::s_windowCache.removeAll( this ); - delete m_instrumentView; - if( gui->mainWindow()->workspace() ) + if (parentWidget()) { parentWidget()->hide(); parentWidget()->deleteLater(); @@ -1656,6 +1717,15 @@ void InstrumentTrackWindow::updateInstrumentView() adjustTabSize(m_instrumentView); m_pianoView->setVisible(m_track->m_instrument->hasNoteInput()); + // adjust window size + layout()->invalidate(); + resize(sizeHint()); + if (parentWidget()) + { + parentWidget()->resize(parentWidget()->sizeHint()); + } + update(); + m_instrumentView->update(); } } diff --git a/src/tracks/Pattern.cpp b/src/tracks/Pattern.cpp index 125e84a1f57..ded78ffa8c6 100644 --- a/src/tracks/Pattern.cpp +++ b/src/tracks/Pattern.cpp @@ -24,23 +24,23 @@ */ #include "Pattern.h" +#include #include #include #include #include #include +#include -#include "InstrumentTrack.h" -#include "gui_templates.h" +#include "AudioSampleRecorder.h" +#include "BBTrackContainer.h" +#include "DeprecationHelper.h" #include "embed.h" +#include "gui_templates.h" #include "GuiApplication.h" +#include "InstrumentTrack.h" #include "PianoRoll.h" #include "RenameDialog.h" -#include "SampleBuffer.h" -#include "AudioSampleRecorder.h" -#include "BBTrackContainer.h" -#include "StringPairDrag.h" -#include "MainWindow.h" #include @@ -56,9 +56,8 @@ Pattern::Pattern( InstrumentTrack * _instrument_track ) : TrackContentObject( _instrument_track ), m_instrumentTrack( _instrument_track ), m_patternType( BeatPattern ), - m_steps( MidiTime::stepsPerBar() ) + m_steps( TimePos::stepsPerBar() ) { - setName( _instrument_track->name() ); if( _instrument_track->trackContainer() == Engine::getBBTrackContainer() ) { @@ -161,7 +160,7 @@ void Pattern::updateLength() return; } - tick_t max_length = MidiTime::ticksPerBar(); + tick_t max_length = TimePos::ticksPerBar(); for( NoteVector::ConstIterator it = m_notes.begin(); it != m_notes.end(); ++it ) @@ -172,17 +171,17 @@ void Pattern::updateLength() ( *it )->endPos() ); } } - changeLength( MidiTime( max_length ).nextFullBar() * - MidiTime::ticksPerBar() ); + changeLength( TimePos( max_length ).nextFullBar() * + TimePos::ticksPerBar() ); updateBBTrack(); } -MidiTime Pattern::beatPatternLength() const +TimePos Pattern::beatPatternLength() const { - tick_t max_length = MidiTime::ticksPerBar(); + tick_t max_length = TimePos::ticksPerBar(); for( NoteVector::ConstIterator it = m_notes.begin(); it != m_notes.end(); ++it ) @@ -194,13 +193,13 @@ MidiTime Pattern::beatPatternLength() const } } - if( m_steps != MidiTime::stepsPerBar() ) + if( m_steps != TimePos::stepsPerBar() ) { - max_length = m_steps * MidiTime::ticksPerBar() / - MidiTime::stepsPerBar(); + max_length = m_steps * TimePos::ticksPerBar() / + TimePos::stepsPerBar(); } - return MidiTime( max_length ).nextFullBar() * MidiTime::ticksPerBar(); + return TimePos( max_length ).nextFullBar() * TimePos::ticksPerBar(); } @@ -259,7 +258,7 @@ Note * Pattern::noteAtStep( int _step ) for( NoteVector::Iterator it = m_notes.begin(); it != m_notes.end(); ++it ) { - if( ( *it )->pos() == MidiTime::stepPosition( _step ) + if( ( *it )->pos() == TimePos::stepPosition( _step ) && ( *it )->length() < 0 ) { return *it; @@ -298,8 +297,8 @@ void Pattern::clearNotes() Note * Pattern::addStepNote( int step ) { - return addNote( Note( MidiTime( -DefaultTicksPerBar ), - MidiTime::stepPosition( step ) ), false ); + return addNote( Note( TimePos( -DefaultTicksPerBar ), + TimePos::stepPosition( step ) ), false ); } @@ -359,6 +358,11 @@ void Pattern::saveSettings( QDomDocument & _doc, QDomElement & _this ) { _this.setAttribute( "type", m_patternType ); _this.setAttribute( "name", name() ); + + if( usesCustomClipColor() ) + { + _this.setAttribute( "color", color().name() ); + } // as the target of copied/dragged pattern is always an existing // pattern, we must not store actual position, instead we store -1 // which tells loadSettings() not to mess around with position @@ -390,6 +394,13 @@ void Pattern::loadSettings( const QDomElement & _this ) m_patternType = static_cast( _this.attribute( "type" ).toInt() ); setName( _this.attribute( "name" ) ); + + if( _this.hasAttribute( "color" ) ) + { + useCustomClipColor( true ); + setColor( _this.attribute( "color" ) ); + } + if( _this.attribute( "pos" ).toInt() >= 0 ) { movePosition( _this.attribute( "pos" ).toInt() ); @@ -417,7 +428,7 @@ void Pattern::loadSettings( const QDomElement & _this ) m_steps = _this.attribute( "steps" ).toInt(); if( m_steps == 0 ) { - m_steps = MidiTime::stepsPerBar(); + m_steps = TimePos::stepsPerBar(); } checkType(); @@ -466,7 +477,7 @@ void Pattern::clear() void Pattern::addSteps() { - m_steps += MidiTime::stepsPerBar(); + m_steps += TimePos::stepsPerBar(); updateLength(); emit dataChanged(); } @@ -497,7 +508,7 @@ void Pattern::cloneSteps() void Pattern::removeSteps() { - int n = MidiTime::stepsPerBar(); + int n = TimePos::stepsPerBar(); if( n < m_steps ) { for( int i = m_steps - n; i < m_steps; ++i ) @@ -555,19 +566,19 @@ bool Pattern::empty() void Pattern::changeTimeSignature() { - MidiTime last_pos = MidiTime::ticksPerBar() - 1; + TimePos last_pos = TimePos::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::ticksPerBar() / - MidiTime::stepsPerBar(); + last_pos = ( *cit )->pos()+TimePos::ticksPerBar() / + TimePos::stepsPerBar(); } } - last_pos = last_pos.nextFullBar() * MidiTime::ticksPerBar(); - m_steps = qMax( MidiTime::stepsPerBar(), - last_pos.getBar() * MidiTime::stepsPerBar() ); + last_pos = last_pos.nextFullBar() * TimePos::ticksPerBar(); + m_steps = qMax( TimePos::stepsPerBar(), + last_pos.getBar() * TimePos::stepsPerBar() ); updateLength(); } @@ -649,10 +660,7 @@ void PatternView::setGhostInPianoRoll() -void PatternView::resetName() -{ - m_pat->setName( m_pat->m_instrumentTrack->name() ); -} +void PatternView::resetName() { m_pat->setName(""); } @@ -782,16 +790,16 @@ void PatternView::mouseDoubleClickEvent(QMouseEvent *_me) -void PatternView::wheelEvent( QWheelEvent * _we ) +void PatternView::wheelEvent(QWheelEvent * we) { - if( m_pat->m_patternType == Pattern::BeatPattern && - ( fixedTCOs() || pixelsPerBar() >= 96 ) && - _we->y() > height() - s_stepBtnOff->height() ) + if(m_pat->m_patternType == Pattern::BeatPattern && + (fixedTCOs() || pixelsPerBar() >= 96) && + position(we).y() > height() - s_stepBtnOff->height()) { // get the step number that was wheeled on and // do calculations in floats to prevent rounding errors... - float tmp = ( ( float(_we->x()) - TCO_BORDER_WIDTH ) * - float( m_pat -> m_steps ) ) / float(width() - TCO_BORDER_WIDTH*2); + float tmp = ((float(position(we).x()) - TCO_BORDER_WIDTH) * + float(m_pat -> m_steps)) / float(width() - TCO_BORDER_WIDTH*2); int step = int( tmp ); @@ -801,7 +809,7 @@ void PatternView::wheelEvent( QWheelEvent * _we ) } Note * n = m_pat->noteAtStep( step ); - if( !n && _we->delta() > 0 ) + if(!n && we->angleDelta().y() > 0) { n = m_pat->addStepNote( step ); n->setVolume( 0 ); @@ -810,7 +818,7 @@ void PatternView::wheelEvent( QWheelEvent * _we ) { int vol = n->getVolume(); - if( _we->delta() > 0 ) + if(we->angleDelta().y() > 0) { n->setVolume( qMin( 100, vol + 5 ) ); } @@ -826,11 +834,11 @@ void PatternView::wheelEvent( QWheelEvent * _we ) gui->pianoRoll()->update(); } } - _we->accept(); + we->accept(); } else { - TrackContentObjectView::wheelEvent( _we ); + TrackContentObjectView::wheelEvent(we); } } @@ -859,14 +867,20 @@ void PatternView::paintEvent( QPaintEvent * ) QPainter p( &m_paintPixmap ); + QColor c; bool const muted = m_pat->getTrack()->isMuted() || m_pat->isMuted(); bool current = gui->pianoRoll()->currentPattern() == m_pat; bool beatPattern = m_pat->m_patternType == Pattern::BeatPattern; - - // state: selected, normal, beat pattern, muted - QColor c = isSelected() ? selectedColor() : ( ( !muted && !beatPattern ) - ? painter.background().color() : ( beatPattern - ? BBPatternBackground() : mutedBackgroundColor() ) ); + + if( beatPattern ) + { + // Do not paint BBTCOs how we paint pattern TCOs + c = BBPatternBackground(); + } + else + { + c = getColorForDisplay( painter.background().color() ); + } // invert the gradient for the background in the B&B editor QLinearGradient lingrad( 0, 0, 0, height() ); @@ -887,8 +901,8 @@ void PatternView::paintEvent( QPaintEvent * ) // Check whether we will paint a text box and compute its potential height // This is needed so we can paint the notes underneath it. - bool const isDefaultName = m_pat->name() == m_pat->instrumentTrack()->name(); - bool const drawTextBox = !beatPattern && !isDefaultName; + bool const drawName = !m_pat->name().isEmpty(); + bool const drawTextBox = !beatPattern && drawName; // TODO Warning! This might cause problems if TrackContentObjectView::paintTextLabel changes int textBoxHeight = 0; @@ -909,7 +923,7 @@ void PatternView::paintEvent( QPaintEvent * ) // 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 float tickLength = barLength / TimePos::ticksPerBar(); const int x_base = TCO_BORDER_WIDTH; @@ -979,7 +993,8 @@ void PatternView::paintEvent( QPaintEvent * ) // set colour based on mute status QColor noteFillColor = muted ? getMutedNoteFillColor() : getNoteFillColor(); - QColor noteBorderColor = muted ? getMutedNoteBorderColor() : getNoteBorderColor(); + QColor noteBorderColor = muted ? getMutedNoteBorderColor() + : ( m_pat->hasColor() ? c.lighter( 200 ) : getNoteBorderColor() ); bool const drawAsLines = height() < 64; if (drawAsLines) @@ -1123,7 +1138,7 @@ void PatternView::paintEvent( QPaintEvent * ) // outer border p.setPen( current ? c.lighter( 130 ) : c.darker( 300 ) ); - p.drawRect( rect() ); + p.drawRect( 0, 0, rect().right(), rect().bottom() ); } // draw the 'muted' pixmap only if the pattern was manually muted diff --git a/src/tracks/SampleTrack.cpp b/src/tracks/SampleTrack.cpp index f377e35cfa3..613d8f173ac 100644 --- a/src/tracks/SampleTrack.cpp +++ b/src/tracks/SampleTrack.cpp @@ -24,6 +24,7 @@ */ #include "SampleTrack.h" +#include #include #include #include @@ -34,23 +35,24 @@ #include #include +#include "BBTrack.h" +#include "EffectRackView.h" +#include "embed.h" +#include "FxMixerView.h" #include "gui_templates.h" #include "GuiApplication.h" -#include "Song.h" -#include "embed.h" -#include "ToolTip.h" -#include "BBTrack.h" +#include "Knob.h" +#include "MainWindow.h" +#include "Mixer.h" +#include "PathUtil.h" #include "SamplePlayHandle.h" #include "SampleRecordHandle.h" +#include "Song.h" #include "SongEditor.h" #include "StringPairDrag.h" -#include "TimeLineWidget.h" -#include "Knob.h" -#include "MainWindow.h" -#include "Mixer.h" -#include "EffectRackView.h" -#include "FxMixerView.h" #include "TabWidget.h" +#include "TimeLineWidget.h" +#include "ToolTip.h" #include "TrackLabelButton.h" SampleTCO::SampleTCO( Track * _track ) : @@ -122,7 +124,7 @@ SampleTCO::~SampleTCO() -void SampleTCO::changeLength( const MidiTime & _length ) +void SampleTCO::changeLength( const TimePos & _length ) { TrackContentObject::changeLength( qMax( static_cast( _length ), 1 ) ); } @@ -230,7 +232,7 @@ void SampleTCO::updateLength() -MidiTime SampleTCO::sampleLength() const +TimePos SampleTCO::sampleLength() const { return (int)( m_sampleBuffer->frames() / Engine::framesPerTick() ); } @@ -274,7 +276,15 @@ void SampleTCO::saveSettings( QDomDocument & _doc, QDomElement & _this ) _this.setAttribute( "data", m_sampleBuffer->toBase64( s ) ); } - _this.setAttribute ("sample_rate", m_sampleBuffer->sampleRate()); + _this.setAttribute( "sample_rate", m_sampleBuffer->sampleRate()); + if( usesCustomClipColor() ) + { + _this.setAttribute( "color", color().name() ); + } + if (m_sampleBuffer->reversed()) + { + _this.setAttribute("reversed", "true"); + } // TODO: start- and end-frame } @@ -296,8 +306,20 @@ void SampleTCO::loadSettings( const QDomElement & _this ) setMuted( _this.attribute( "muted" ).toInt() ); setStartTimeOffset( _this.attribute( "off" ).toInt() ); - if (_this.hasAttribute("sample_rate")) { - m_sampleBuffer->setSampleRate(_this.attribute("sample_rate").toInt()); + if ( _this.hasAttribute( "sample_rate" ) ) { + m_sampleBuffer->setSampleRate( _this.attribute( "sample_rate" ).toInt() ); + } + + if( _this.hasAttribute( "color" ) ) + { + useCustomClipColor( true ); + setColor( _this.attribute( "color" ) ); + } + + if(_this.hasAttribute("reversed")) + { + m_sampleBuffer->setReversed(true); + emit wasReversed(); // tell SampleTCOView to update the view } } @@ -321,8 +343,9 @@ SampleTCOView::SampleTCOView( SampleTCO * _tco, TrackView * _tv ) : updateSample(); // track future changes of SampleTCO - connect( m_tco, SIGNAL( sampleChanged() ), - this, SLOT( updateSample() ) ); + connect(m_tco, SIGNAL(sampleChanged()), this, SLOT(updateSample())); + + connect(m_tco, SIGNAL(wasReversed()), this, SLOT(update())); setStyle( QApplication::style() ); } @@ -333,7 +356,7 @@ void SampleTCOView::updateSample() // set tooltip to filename so that user can see what sample this // sample-tco contains ToolTip::add( this, ( m_tco->m_sampleBuffer->audioFile() != "" ) ? - m_tco->m_sampleBuffer->audioFile() : + PathUtil::toAbsolute(m_tco->m_sampleBuffer->audioFile()) : tr( "Double-click to open sample" ) ); } @@ -342,32 +365,75 @@ void SampleTCOView::updateSample() void SampleTCOView::contextMenuEvent( QContextMenuEvent * _cme ) { + // Depending on whether we right-clicked a selection or an individual TCO we will have + // different labels for the actions. + bool individualTCO = getClickedTCOs().size() <= 1; + if( _cme->modifiers() ) { return; } QMenu contextMenu( this ); + if( fixedTCOs() == false ) { - contextMenu.addAction( embed::getIconPixmap( "cancel" ), - tr( "Delete (middle mousebutton)" ), - this, SLOT( remove() ) ); + contextMenu.addAction( + embed::getIconPixmap( "cancel" ), + individualTCO + ? tr("Delete (middle mousebutton)") + : tr("Delete selection (middle mousebutton)"), + [this](){ contextMenuAction( Remove ); } ); + contextMenu.addSeparator(); - contextMenu.addAction( embed::getIconPixmap( "edit_cut" ), - tr( "Cut" ), this, SLOT( cut() ) ); + + contextMenu.addAction( + embed::getIconPixmap( "edit_cut" ), + individualTCO + ? tr("Cut") + : tr("Cut selection"), + [this](){ contextMenuAction( Cut ); } ); } - contextMenu.addAction( embed::getIconPixmap( "edit_copy" ), - tr( "Copy" ), m_tco, SLOT( copy() ) ); - contextMenu.addAction( embed::getIconPixmap( "edit_paste" ), - tr( "Paste" ), m_tco, SLOT( paste() ) ); + + contextMenu.addAction( + embed::getIconPixmap( "edit_copy" ), + individualTCO + ? tr("Copy") + : tr("Copy selection"), + [this](){ contextMenuAction( Copy ); } ); + + contextMenu.addAction( + embed::getIconPixmap( "edit_paste" ), + tr( "Paste" ), + [this](){ contextMenuAction( Paste ); } ); + contextMenu.addSeparator(); - contextMenu.addAction( embed::getIconPixmap( "muted" ), - tr( "Mute/unmute (<%1> + middle click)" ).arg(UI_CTRL_KEY), - m_tco, SLOT( toggleMute() ) ); + + contextMenu.addAction( + embed::getIconPixmap( "muted" ), + (individualTCO + ? tr("Mute/unmute (<%1> + middle click)") + : tr("Mute/unmute selection (<%1> + middle click)")).arg(UI_CTRL_KEY), + [this](){ contextMenuAction( Mute ); } ); + /*contextMenu.addAction( embed::getIconPixmap( "record" ), tr( "Set/clear record" ), m_tco, SLOT( toggleRecord() ) );*/ + + contextMenu.addAction( + embed::getIconPixmap("flip_x"), + tr("Reverse sample"), + this, + SLOT(reverseSample()) + ); + + contextMenu.addSeparator(); + + contextMenu.addAction( embed::getIconPixmap( "colorize" ), + tr( "Set clip color" ), this, SLOT( changeClipColor() ) ); + contextMenu.addAction( embed::getIconPixmap( "colorize" ), + tr( "Use track color" ), this, SLOT( useTrackColor() ) ); + constructContextMenu( &contextMenu ); contextMenu.exec( QCursor::pos() ); @@ -496,13 +562,9 @@ void SampleTCOView::paintEvent( QPaintEvent * pe ) QPainter p( &m_paintPixmap ); QLinearGradient lingrad( 0, 0, 0, height() ); - QColor c; + QColor c = getColorForDisplay( painter.background().color() ); bool muted = m_tco->getTrack()->isMuted() || m_tco->isMuted(); - // state: selected, muted, normal - c = isSelected() ? selectedColor() : ( muted ? mutedBackgroundColor() - : painter.background().color() ); - lingrad.setColorAt( 1, c.darker( 300 ) ); lingrad.setColorAt( 0, c ); @@ -535,20 +597,19 @@ void SampleTCOView::paintEvent( QPaintEvent * pe ) 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()); - QString filename = fileInfo.fileName(); - paintTextLabel(filename, p); + QString name = PathUtil::cleanName(m_tco->m_sampleBuffer->audioFile()); + paintTextLabel(name, p); // disable antialiasing for borders, since its not needed p.setRenderHint( QPainter::Antialiasing, false ); // inner border - p.setPen( c.lighter( 160 ) ); + p.setPen( c.lighter( 135 ) ); p.drawRect( 1, 1, rect().right() - TCO_BORDER_WIDTH, rect().bottom() - TCO_BORDER_WIDTH ); // outer border - p.setPen( c.darker( 300 ) ); + p.setPen( c.darker( 200 ) ); p.drawRect( 0, 0, rect().right(), rect().bottom() ); // draw the 'muted' pixmap only if the pattern was manualy muted @@ -583,6 +644,16 @@ void SampleTCOView::paintEvent( QPaintEvent * pe ) +void SampleTCOView::reverseSample() +{ + m_tco->sampleBuffer()->setReversed(!m_tco->sampleBuffer()->reversed()); + Engine::getSong()->setModified(); + update(); +} + + + + SampleTrack::SampleTrack(TrackContainer* tc) : @@ -611,7 +682,7 @@ SampleTrack::~SampleTrack() -bool SampleTrack::play( const MidiTime & _start, const fpp_t _frames, +bool SampleTrack::play( const TimePos & _start, const fpp_t _frames, const f_cnt_t _offset, int _tco_num ) { m_audioPort.effects()->startRunning(); @@ -646,7 +717,7 @@ bool SampleTrack::play( const MidiTime & _start, const fpp_t _frames, if( _start >= sTco->startPosition() && _start < sTco->endPosition() ) { - if( sTco->isPlaying() == false && _start > sTco->startPosition() + sTco->startTimeOffset() ) + if( sTco->isPlaying() == false && _start >= (sTco->startPosition() + sTco->startTimeOffset()) ) { auto bufferFramesPerTick = Engine::framesPerTick (sTco->sampleBuffer ()->sampleRate ()); f_cnt_t sampleStart = bufferFramesPerTick * ( _start - sTco->startPosition() - sTco->startTimeOffset() ); @@ -718,7 +789,7 @@ TrackView * SampleTrack::createView( TrackContainerView* tcv ) -TrackContentObject * SampleTrack::createTCO(const MidiTime & pos) +TrackContentObject * SampleTrack::createTCO(const TimePos & pos) { SampleTCO * sTco = new SampleTCO(this); sTco->movePosition(pos); @@ -843,8 +914,6 @@ SampleTrackView::SampleTrackView( SampleTrack * _t, TrackContainerView* tcv ) : m_activityIndicator->setGeometry(settingsWidgetWidth - 2 * 24 - 11, 2, 8, 28); m_activityIndicator->show(); connect(_t, SIGNAL(playingChanged()), this, SLOT(updateIndicator())); - connect(Engine::getSong(), SIGNAL(stopped()), - this, SLOT(stopPlaying())); setModel( _t ); @@ -955,10 +1024,10 @@ void SampleTrackView::dropEvent(QDropEvent *de) ? trackHeadWidth : de->pos().x(); - MidiTime tcoPos = trackContainerView()->fixedTCOs() - ? MidiTime(0) - : MidiTime(((xPos - trackHeadWidth) / trackContainerView()->pixelsPerBar() - * MidiTime::ticksPerBar()) + trackContainerView()->currentPosition() + TimePos tcoPos = trackContainerView()->fixedTCOs() + ? TimePos(0) + : TimePos(((xPos - trackHeadWidth) / trackContainerView()->pixelsPerBar() + * TimePos::ticksPerBar()) + trackContainerView()->currentPosition() ).quantize(1.0); SampleTCO * sTco = static_cast(getTrack()->createTCO(tcoPos)); @@ -1060,7 +1129,7 @@ SampleTrackWindow::SampleTrackWindow(SampleTrackView * tv) : generalSettingsLayout->addLayout(basicControlsLayout); m_effectRack = new EffectRackView(tv->model()->audioPort()->effects()); - m_effectRack->setFixedSize(240, 242); + m_effectRack->setFixedSize(EffectRackView::DEFAULT_WIDTH, 242); vlayout->addWidget(generalSettingsWidget); vlayout->addWidget(m_effectRack); @@ -1129,8 +1198,10 @@ void SampleTrackWindow::modelChanged() void SampleTrackView::createFxLine() { int channelIndex = gui->fxMixerView()->addNewChannel(); + auto channel = Engine::fxMixer()->effectChannel(channelIndex); - Engine::fxMixer()->effectChannel(channelIndex)->m_name = getTrack()->name(); + channel->m_name = getTrack()->name(); + if (getTrack()->useColor()) { channel->setColor (getTrack()->color()); } assignFxLine(channelIndex); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b3830d8fc61..094ee974384 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,12 +4,17 @@ INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/include") INCLUDE_DIRECTORIES("${CMAKE_BINARY_DIR}") INCLUDE_DIRECTORIES("${CMAKE_BINARY_DIR}/src") -SET(CMAKE_CXX_STANDARD 11) +SET(CMAKE_CXX_STANDARD 14) FIND_PACKAGE(Qt5Test) SET(CMAKE_AUTOMOC ON) +# FIXME: remove this once we export include directories for LMMS +IF(LMMS_BUILD_APPLE) +INCLUDE_DIRECTORIES("/usr/local/include") +ENDIF() + ADD_EXECUTABLE(tests EXCLUDE_FROM_ALL main.cpp diff --git a/tests/src/core/ProjectVersionTest.cpp b/tests/src/core/ProjectVersionTest.cpp index 7c99727397f..e52088f6f8c 100644 --- a/tests/src/core/ProjectVersionTest.cpp +++ b/tests/src/core/ProjectVersionTest.cpp @@ -39,9 +39,39 @@ private slots: QVERIFY(ProjectVersion("1.1.0", ProjectVersion::Minor) == "1.1.5"); QVERIFY( ! ( ProjectVersion("3.1.0", ProjectVersion::Minor) < "2.2.5" ) ); QVERIFY( ! ( ProjectVersion("2.5.0", ProjectVersion::Release) < "2.2.5" ) ); + //A pre-release version has lower precedence than a normal version QVERIFY(ProjectVersion("1.1.0") > "1.1.0-alpha"); + //But higher precedence than the previous version + QVERIFY(ProjectVersion("1.1.0-alpha") > "1.0.0"); + //Identifiers with letters or hyphens are compare lexically in ASCII sort order QVERIFY(ProjectVersion("1.1.0-alpha") < "1.1.0-beta"); QVERIFY(ProjectVersion("1.2.0-rc1") < "1.2.0-rc2"); + //Build metadata MUST be ignored when determining version precedence + QVERIFY(ProjectVersion("1.2.2") == "1.2.2+metadata"); + QVERIFY(ProjectVersion("1.0.0-alpha") < "1.0.0-alpha.1"); + QVERIFY(ProjectVersion("1.0.0-alpha.1") < "1.0.0-alpha.beta"); + QVERIFY(ProjectVersion("1.0.0-alpha.beta") < "1.0.0-beta"); + QVERIFY(ProjectVersion("1.0.0-beta.2") < "1.0.0-beta.11"); + //Test workaround for old, nonstandard version numbers + QVERIFY(ProjectVersion("1.2.2.42") == "1.2.3-42"); + QVERIFY(ProjectVersion("1.2.2.42") > "1.2.2.21"); + //Ensure that newer versions of the same format aren't upgraded + //in order to discourage use of incorrect versioning + QVERIFY(ProjectVersion("1.2.3.42") == "1.2.3"); + //CompareVersion "All" should compare every identifier + QVERIFY( + ProjectVersion("1.0.0-a.b.c.d.e.f.g.h.i.j.k.l", ProjectVersion::All) + < "1.0.0-a.b.c.d.e.f.g.h.i.j.k.m" + ); + //Prerelease identifiers may contain hyphens + QVERIFY(ProjectVersion("1.0.0-Alpha-1.2") > "1.0.0-Alpha-1.1"); + //We shouldn't crash on invalid versions + QVERIFY(ProjectVersion("1-invalid") == "1.0.0-invalid"); + QVERIFY(ProjectVersion("") == "0.0.0"); + //Numeric identifiers are smaller than non-numeric identiiers + QVERIFY(ProjectVersion("1.0.0-alpha") > "1.0.0-1"); + //An identifier of the form "-x" is non-numeric, not negative + QVERIFY(ProjectVersion("1.0.0-alpha.-1") > "1.0.0-alpha.1"); } } ProjectVersionTests; diff --git a/tests/src/core/RelativePathsTest.cpp b/tests/src/core/RelativePathsTest.cpp index 6a75483776a..3f1712e1b5a 100644 --- a/tests/src/core/RelativePathsTest.cpp +++ b/tests/src/core/RelativePathsTest.cpp @@ -26,6 +26,7 @@ #include "ConfigManager.h" #include "SampleBuffer.h" +#include "PathUtil.h" #include @@ -33,18 +34,35 @@ class RelativePathsTest : QTestSuite { Q_OBJECT private slots: - void RelativePathComparisonTests() + void PathUtilComparisonTests() { QFileInfo fi(ConfigManager::inst()->factorySamplesDir() + "/drums/kick01.ogg"); QVERIFY(fi.exists()); QString absPath = fi.absoluteFilePath(); - QString relPath = "drums/kick01.ogg"; + QString oldRelPath = "drums/kick01.ogg"; + QString relPath = PathUtil::basePrefix(PathUtil::Base::FactorySample) + "drums/kick01.ogg"; QString fuzPath = absPath; fuzPath.replace(relPath, "drums/.///kick01.ogg"); - QCOMPARE(SampleBuffer::tryToMakeRelative(absPath), relPath); - QCOMPARE(SampleBuffer::tryToMakeAbsolute(relPath), absPath); - QCOMPARE(SampleBuffer::tryToMakeRelative(fuzPath), relPath); + + //Test nicely formatted paths + QCOMPARE(PathUtil::toShortestRelative(absPath), relPath); + QCOMPARE(PathUtil::toAbsolute(relPath), absPath); + + //Test upgrading old paths + QCOMPARE(PathUtil::toShortestRelative(oldRelPath), relPath); + QCOMPARE(PathUtil::toAbsolute(oldRelPath), absPath); + + //Test weird but valid paths + QCOMPARE(PathUtil::toShortestRelative(fuzPath), relPath); + QCOMPARE(PathUtil::toAbsolute(fuzPath), absPath); + + //Empty paths should stay empty + QString empty = QString(""); + QCOMPARE(PathUtil::stripPrefix(""), empty); + QCOMPARE(PathUtil::cleanName(""), empty); + QCOMPARE(PathUtil::toAbsolute(""), empty); + QCOMPARE(PathUtil::toShortestRelative(""), empty); } } RelativePathTests; diff --git a/tests/src/tracks/AutomationTrackTest.cpp b/tests/src/tracks/AutomationTrackTest.cpp index 291ae293ef1..f86bfe44d2b 100644 --- a/tests/src/tracks/AutomationTrackTest.cpp +++ b/tests/src/tracks/AutomationTrackTest.cpp @@ -141,20 +141,20 @@ private slots: dynamic_cast(Track::create(Track::InstrumentTrack, song)); Pattern* notePattern = dynamic_cast(instrumentTrack->createTCO(0)); - notePattern->changeLength(MidiTime(4, 0)); - Note* note = notePattern->addNote(Note(MidiTime(4, 0)), false); + notePattern->changeLength(TimePos(4, 0)); + Note* note = notePattern->addNote(Note(TimePos(4, 0)), false); note->createDetuning(); DetuningHelper* dh = note->detuning(); auto pattern = dh->automationPattern(); pattern->setProgressionType( AutomationPattern::LinearProgression ); - pattern->putValue(MidiTime(0, 0), 0.0); - pattern->putValue(MidiTime(4, 0), 1.0); + pattern->putValue(TimePos(0, 0), 0.0); + pattern->putValue(TimePos(4, 0), 1.0); - QCOMPARE(pattern->valueAt(MidiTime(0, 0)), 0.0f); - QCOMPARE(pattern->valueAt(MidiTime(1, 0)), 0.25f); - QCOMPARE(pattern->valueAt(MidiTime(2, 0)), 0.5f); - QCOMPARE(pattern->valueAt(MidiTime(4, 0)), 1.0f); + QCOMPARE(pattern->valueAt(TimePos(0, 0)), 0.0f); + QCOMPARE(pattern->valueAt(TimePos(1, 0)), 0.25f); + QCOMPARE(pattern->valueAt(TimePos(2, 0)), 0.5f); + QCOMPARE(pattern->valueAt(TimePos(4, 0)), 1.0f); } void testBBTrack() @@ -186,12 +186,12 @@ private slots: QVERIFY(! bbContainer->automatedValuesAt(5, bbTrack2.index()).size()); BBTCO tco(&bbTrack); - tco.changeLength(MidiTime::ticksPerBar() * 2); + tco.changeLength(TimePos::ticksPerBar() * 2); tco.movePosition(0); QCOMPARE(song->automatedValuesAt(0)[&model], 0.0f); QCOMPARE(song->automatedValuesAt(5)[&model], 0.5f); - QCOMPARE(song->automatedValuesAt(MidiTime::ticksPerBar() + 5)[&model], 0.5f); + QCOMPARE(song->automatedValuesAt(TimePos::ticksPerBar() + 5)[&model], 0.5f); } void testGlobalAutomation()