diff --git a/.github/workflows/build-checks.yml b/.github/workflows/build-checks.yml index fb8bd2cfbda..5843ea0abd6 100644 --- a/.github/workflows/build-checks.yml +++ b/.github/workflows/build-checks.yml @@ -17,44 +17,7 @@ jobs: - name: Check out repository uses: actions/checkout@v2 - name: Install build dependencies - run: | - sudo apt-get update && sudo apt-get install -y --no-install-recommends \ - libavformat-dev \ - libchromaprint-dev \ - libebur128-dev \ - libfftw3-dev \ - libflac-dev \ - libid3tag0-dev \ - liblilv-dev \ - libmad0-dev \ - libmodplug-dev \ - libmp3lame-dev \ - libopus-dev \ - libopusfile-dev \ - libportmidi-dev \ - libprotobuf-dev \ - libqt5opengl5-dev \ - libqt5sql5-sqlite \ - libqt5svg5-dev \ - libqt5x11extras5-dev \ - librubberband-dev \ - libshout-idjc-dev \ - libsndfile1-dev \ - libsoundtouch-dev \ - libsqlite3-dev \ - libtag1-dev \ - libupower-glib-dev \ - libusb-1.0-0-dev \ - libwavpack-dev \ - portaudio19-dev \ - protobuf-compiler \ - qt5-default \ - qtdeclarative5-dev \ - qtscript5-dev \ - qt5keychain-dev \ - clazy \ - clang-tidy \ - cmake + run: tools/debian_buildenv.sh setup - name: Create build directory run: mkdir build - name: Configure (clazy) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ef9513853f9..e3d13fb25ad 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,7 +21,6 @@ jobs: -DMODPLUG=ON -DWAVPACK=ON -DINSTALL_USER_UDEV_RULES=OFF - cmake_generator: Unix Makefiles ctest_args: compiler_cache: ccache compiler_cache_path: ~/.ccache @@ -41,7 +40,6 @@ jobs: -DMACOS_BUNDLE=ON -DMODPLUG=OFF -DWAVPACK=OFF - cmake_generator: Unix Makefiles # TODO: Fix this broken test on macOS ctest_args: --exclude-regex DirectoryDAOTest.relocateDirectory cpack_generator: DragNDrop @@ -70,7 +68,6 @@ jobs: -DWAVPACK=ON cc: cl cxx: cl - cmake_generator: Ninja # TODO: Fix these broken tests on Windows ctest_args: --exclude-regex '^AutoDJProcessorTest.*$' cpack_generator: WIX @@ -163,7 +160,7 @@ jobs: # Studio on Windows comes with its own CMake version anyway. if: runner.os == 'macOS' with: - # This should always match the mininum required version in + # This should always match the minimum required version in # our CMakeLists.txt cmake-version: '3.16.x' @@ -244,12 +241,10 @@ jobs: - name: "Configure" run: >- - cmake - -G "${{ matrix.cmake_generator }}" + cmake ${{ matrix.cmake_args }} ${{ env.CMAKE_ARGS_EXTRA }} -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_PREFIX_PATH="${{ env.CMAKE_PREFIX_PATH }}" - -DDEBUG_ASSERTIONS_FATAL=ON - -DQt5_DIR=${{ env.QT_PATH }} ${{ matrix.cmake_args }} ${{ env.CMAKE_ARGS_EXTRA }} + -DDEBUG_ASSERTIONS_FATAL=OFF -DBATTERY=ON -DBROADCAST=ON -DDOWNLOAD_MANUAL=ON @@ -356,7 +351,7 @@ jobs: run: > if [[ "${GITHUB_REF}" =~ ^refs/tags/.* ]]; then - export DEPLOY_PATH='releases/mixxx-{git_describe}/mixxx-{git_describe}-{package_slug}{ext}'; + export DEPLOY_PATH='releases/{git_describe}/mixxx-{git_describe}-{package_slug}{ext}'; else export DEPLOY_PATH='snapshots/{git_branch}/mixxx-{git_describe}-{package_slug}{ext}'; fi; @@ -427,7 +422,7 @@ jobs: run: > if [[ "${GITHUB_REF}" =~ ^refs/tags/.* ]]; then - export DEPLOY_PATH='releases/mixxx-{git_describe}/manifest.json'; + export DEPLOY_PATH='releases/{git_describe}/manifest.json'; else export DEPLOY_PATH='snapshots/{git_branch}/manifest.json'; fi; diff --git a/.gitignore b/.gitignore index adf91b83592..a494144787b 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,7 @@ compile_commands.json /buildenv # CMake build configurations, generated by tools/windows_buildenv.bat -/CMakeSettings.json +/CMakeSettings*.json # Build and distribution directories for various build configurations /build diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b7ac991bf2..85249678445 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ * Add Random Track Control to AutoDJ [#3076](https://github.com/mixxxdj/mixxx/pull/3076) * Add support for saving loops as hotcues [#2194](https://github.com/mixxxdj/mixxx/pull/2194) [lp:1367159](https://bugs.launchpad.net/mixxx/+bug/1367159) -## [2.3.0](https://launchpad.net/mixxx/+milestone/2.3.0) (Unreleased) +## [2.3.0](https://launchpad.net/mixxx/+milestone/2.3.0) ### Hotcues ### * Add hotcue colors and custom labels by right clicking hotcue buttons or right clicking hotcues on overview waveforms [#2016](https://github.com/mixxxdj/mixxx/pull/2016) [#2520](https://github.com/mixxxdj/mixxx/pull/2520) [#2238](https://github.com/mixxxdj/mixxx/pull/2238) [#2560](https://github.com/mixxxdj/mixxx/pull/2560) [#2557](https://github.com/mixxxdj/mixxx/pull/2557) [#2362](https://github.com/mixxxdj/mixxx/pull/2362) * Mouse hover cues on overview waveform to show time remaining until the cue [#2238](https://github.com/mixxxdj/mixxx/pull/2238) @@ -18,7 +18,7 @@ * Add hotcue color find-and-replace tool [#2547](https://github.com/mixxxdj/mixxx/pull/2547) ### Importing From Other DJ Software ### -* Import cue points, track colors, and playlists from Serato file tags & database [#2480](https://github.com/mixxxdj/mixxx/pull/2480) [#2526](https://github.com/mixxxdj/mixxx/pull/2526) [#2499](https://github.com/mixxxdj/mixxx/pull/2499) [#2495](https://github.com/mixxxdj/mixxx/pull/2495) [#2673](https://github.com/mixxxdj/mixxx/pull/2673) +* Import cue points, track colors, and playlists from Serato file tags & database [#2480](https://github.com/mixxxdj/mixxx/pull/2480) [#2526](https://github.com/mixxxdj/mixxx/pull/2526) [#2499](https://github.com/mixxxdj/mixxx/pull/2499) [#2495](https://github.com/mixxxdj/mixxx/pull/2495) [#2673](https://github.com/mixxxdj/mixxx/pull/2673) [#3885](https://github.com/mixxxdj/mixxx/pull/3885) * Note: Mixxx does not yet support multiple loops per track. We are [working on this for Mixxx 2.4](https://github.com/mixxxdj/mixxx/pull/2194). In Mixxx 2.3, if you import a track with multiple loops from Serato, Mixxx will use the first loop cue as the single loop Mixxx currently supports. The imported loops are still stored in Mixxx's database and are treated as hotcues in Mixxx 2.3. If you do not delete these hotcues, they will be usable as loops in Mixxx 2.4. Serato keeps loops and hotcues in separate lists, but Mixxx does not, so loops from Serato are imported starting as hotcue 9. * Import cue points, track colors, and playlists from Rekordbox USB drives [#2119](https://github.com/mixxxdj/mixxx/pull/2119) [#2555](https://github.com/mixxxdj/mixxx/pull/2555) [#2543](https://github.com/mixxxdj/mixxx/pull/2543) [#2779](https://github.com/mixxxdj/mixxx/pull/2779) * Note: The first Rekordbox memory cue is imported for the main cue button in Mixxx and the remaining Rekordbox memory cues are imported as Mixxx hotcues, starting with the next hotcue number after the last hotcue from Rekordbox. @@ -30,12 +30,13 @@ * Use intro & outro cues in AutoDJ transitions [#2103](https://github.com/mixxxdj/mixxx/pull/2103) ### Deck cloning ### -* Add deck cloning (also known as "instant doubles" in other DJ software) by dragging and dropping between decks [#1892](https://github.com/mixxxdj/mixxx/pull/1892) +* Add deck cloning (also known as "instant doubles" in other DJ software) by dragging and dropping between decks [#1892](https://github.com/mixxxdj/mixxx/pull/1892) and samplers [#3200](https://github.com/mixxxdj/mixxx/pull/3200) * Clone decks by double pressing the load button on a controller (with option to disable this) [#2024](https://github.com/mixxxdj/mixxx/pull/2024) [#2042](https://github.com/mixxxdj/mixxx/pull/2042) ### Skins & GUI ### * Aesthetically revamped LateNight skin [#2298](https://github.com/mixxxdj/mixxx/pull/2298) [#2342](https://github.com/mixxxdj/mixxx/pull/2342) * Right click overview waveform to show time remaining until that point [#2238](https://github.com/mixxxdj/mixxx/pull/2238) +* Show track info dialog when double clicking track labels in decks [#2990](https://github.com/mixxxdj/mixxx/pull/2990) * Show track context menu when right clicking text in decks [#2612](https://github.com/mixxxdj/mixxx/pull/2612) [#2675](https://github.com/mixxxdj/mixxx/pull/2675) [#2684](https://github.com/mixxxdj/mixxx/pull/2684) [#2696](https://github.com/mixxxdj/mixxx/pull/2696) * Add laptop battery widget to skins [#2283](https://github.com/mixxxdj/mixxx/pull/2283) [#2277](https://github.com/mixxxdj/mixxx/pull/2277) [#2250](https://github.com/mixxxdj/mixxx/pull/2250) [#2228](https://github.com/mixxxdj/mixxx/pull/2228) [#2221](https://github.com/mixxxdj/mixxx/pull/2221) [#2163](https://github.com/mixxxdj/mixxx/pull/2163) [#2160](https://github.com/mixxxdj/mixxx/pull/2160) [#2147](https://github.com/mixxxdj/mixxx/pull/2147) [#2281](https://github.com/mixxxdj/mixxx/pull/2281) [#2319](https://github.com/mixxxdj/mixxx/pull/2319) [#2287](https://github.com/mixxxdj/mixxx/pull/2287) * Show when passthrough mode is active on overview waveforms [#2575](https://github.com/mixxxdj/mixxx/pull/2575) [#2616](https://github.com/mixxxdj/mixxx/pull/2616) @@ -46,6 +47,9 @@ * AutoDJ: Make "enable" shortcut work after startup [#3242](https://github.com/mixxxdj/mixxx/pull/3242) * Add rate range indicator [#3693](https://github.com/mixxxdj/mixxx/pull/3693) * Allow menubar to be styled [#3372](https://github.com/mixxxdj/mixxx/pull/3372) [#3788](https://github.com/mixxxdj/mixxx/pull/3788) +* Add Donate button to About dialog [#3838](https://github.com/mixxxdj/mixxx/pull/3838) [#3846](https://github.com/mixxxdj/mixxx/pull/3846) +* Add Scrollable Skin Widget [#3890](https://github.com/mixxxdj/mixxx/pull/3890) +* Fix minor visual issues in Skins [#3958](https://github.com/mixxxdj/mixxx/pull/3958/) [#3954](https://github.com/mixxxdj/mixxx/pull/3954/) [#3941](https://github.com/mixxxdj/mixxx/pull/3941/) [#3938](https://github.com/mixxxdj/mixxx/pull/3938/) [#3936](https://github.com/mixxxdj/mixxx/pull/3936/) [#3886](https://github.com/mixxxdj/mixxx/pull/3886/) [#3927](https://github.com/mixxxdj/mixxx/pull/3927/) [#3844](https://github.com/mixxxdj/mixxx/pull/3844/) [#3933](https://github.com/mixxxdj/mixxx/pull/3933/) [#3835](https://github.com/mixxxdj/mixxx/pull/3835/) [#3902](https://github.com/mixxxdj/mixxx/pull/3902) [#3931](https://github.com/mixxxdj/mixxx/pull/3931) ### Music Feature Analysis ### * Multithreaded analysis for much faster batch analysis on multicore CPUs [#1624](https://github.com/mixxxdj/mixxx/pull/1624) [#2142](https://github.com/mixxxdj/mixxx/pull/2142) [lp:1641153](https://bugs.launchpad.net/mixxx/+bug/1641153) @@ -53,6 +57,7 @@ * Note: Users who have not manually corrected keys are advised to clear all keys in their library by pressing Ctrl + A in the library, right clicking, going to Reset -> Key, then reanalyzing their library. This will freeze the GUI while Mixxx clears the keys; this is a known problem that we will not be able to fix for 2.3. Wait until it is finished and you will be able to reanalyze tracks for better key detection results. * Remove VAMP plugin support and use Queen Mary DSP library directly. vamp-plugin-sdk and vamp-hostsdk are no longer required dependencies. [#926](https://github.com/mixxxdj/mixxx/pull/926) * Improvements BPM detection on non-const beatgrids [#3626](https://github.com/mixxxdj/mixxx/pull/3626) +* Fix const beatgrid placement [#3965](https://github.com/mixxxdj/mixxx/pull/3965) [#3973](https://github.com/mixxxdj/mixxx/pull/3973) ### Music Library ### * Add support for searching for empty fields (for example `crate:""`) [lp:1788086](https://bugs.launchpad.net/mixxx/+bug/1788086) @@ -65,12 +70,17 @@ * Fix caching of duplicate tracks that reference the same file [#3027](https://github.com/mixxxdj/mixxx/pull/3027) * Use 6 instead of only 4 compatible musical keys (major/minor) [#3205](https://github.com/mixxxdj/mixxx/pull/3205) * Fix possible crash when trying to refocus the tracks table while another Mixxx window has focus [#3201](https://github.com/mixxxdj/mixxx/pull/3201) +* Don't create new tags in file when exporting metadata to it [#3898](https://github.com/mixxxdj/mixxx/pull/3898) +* Fix playlist files beginning with non-english characters not being loaded [#3916](https://github.com/mixxxdj/mixxx/pull/3916) +* Enable sorting in "Hidden Tracks" and "Missing Tracks" views [#3828](https://github.com/mixxxdj/mixxx/pull/3828) [lp:1828555](https://bugs.launchpad.net/mixxx/+bug/1828555/) [lp:1924616](https://bugs.launchpad.net/mixxx/+bug/1924616/) +* Fix track table being empty after start [#3935](https://github.com/mixxxdj/mixxx/pull/3935/) [lp:1930546](https://bugs.launchpad.net/mixxx/+bug/1930546/) [lp:1924843](https://bugs.launchpad.net/mixxx/+bug/1924843/) ### Audio Codecs ### * Add FFmpeg audio decoder, bringing support for ALAC files [#1356](https://github.com/mixxxdj/mixxx/pull/1356) * Include LAME MP3 encoder with Mixxx now that the MP3 patent has expired [lp:1294128](https://bugs.launchpad.net/mixxx/+bug/1294128) [buildserver:#37](https://github.com/mixxxdj/buildserver/pull/37) [buildserver:9e8bcee](https://github.com/mixxxdj/buildserver/commit/9e8bcee771731920ae82f3e076d43f0fb51e5027) * Add Opus streaming and recording support. [lp:1338413](https://bugs.launchpad.net/mixxx/+bug/1338413) * Remove support for SoundSource plugins because the code was not well-maintained and could lead to crashes [lp:1792747](https://bugs.launchpad.net/mixxx/+bug/1792747) +* Add HE-AAC encoding capabilities for recording and broadcasting [#3615](https://github.com/mixxxdj/mixxx/pull/3615) ### Audio Engine ### * Fix loss of precision when dealing with floating-point sample positions while setting loop out position and seeking using vinyl control [#3126](https://github.com/mixxxdj/mixxx/pull/3126) [#3127](https://github.com/mixxxdj/mixxx/pull/3127) @@ -78,6 +88,8 @@ * Fix possible memory corruption using JACK on Linux [#3160](https://github.com/mixxxdj/mixxx/pull/3160) * Fix changing of vinyl lead-in time [lp:1915483](https://bugs.launchpad.net/mixxx/+bug/1915483) [#3781](https://github.com/mixxxdj/mixxx/pull/3781) * Fix tempo change of non-const beatgrid track on audible deck when cueing another track [#3772](https://github.com/mixxxdj/mixxx/pull/3772) +* Fix crash when changing effect unit routing [#3882](https://github.com/mixxxdj/mixxx/pull/3882) [lp:1775497](https://bugs.launchpad.net/mixxx/+bug/1775497) +* Make microphone ducking use strength knob the same way in automatic & manual mode [#2750](https://github.com/mixxxdj/mixxx/pull/2750) ### Controllers ### * Improve workflow for configuring controller mappings and editing mappings [#2569](https://github.com/mixxxdj/mixxx/pull/2569) [#3278](https://github.com/mixxxdj/mixxx/pull/3278) [#3667](https://github.com/mixxxdj/mixxx/pull/3667) @@ -90,11 +102,11 @@ * Add controller mapping for Numark iDJ Live II [#2818](https://github.com/mixxxdj/mixxx/pull/2818) * Add controller mapping for Hercules DJControl Inpulse 200 [#2542](https://github.com/mixxxdj/mixxx/pull/2542) * Add controller mapping for Hercules DJControl Jogvision [#2370](https://github.com/mixxxdj/mixxx/pull/2370) -* Add controller mapping for Pioneer DDJ-200 [#3185](https://github.com/mixxxdj/mixxx/pull/3185) [#3193](https://github.com/mixxxdj/mixxx/pull/3193) [#3479](https://github.com/mixxxdj/mixxx/pull/3742) +* Add controller mapping for Pioneer DDJ-200 [#3185](https://github.com/mixxxdj/mixxx/pull/3185) [#3193](https://github.com/mixxxdj/mixxx/pull/3193) [#3479](https://github.com/mixxxdj/mixxx/pull/3742) [#3793](https://github.com/mixxxdj/mixxx/pull/3793) [#3949](https://github.com/mixxxdj/mixxx/pull/3949) * Add controller mapping for Pioneer DDJ-400 [#3479](https://github.com/mixxxdj/mixxx/pull/3479) * Add controller mapping for ION Discover DJ Pro [#2893](https://github.com/mixxxdj/mixxx/pull/2893) * Add controller mapping for Native Instrument Traktor Kontrol S3 [#3031](https://github.com/mixxxdj/mixxx/pull/3031) -* Add controller mapping for Behringer BCR2000 [#3342](https://github.com/mixxxdj/mixxx/pull/3342) +* Add controller mapping for Behringer BCR2000 [#3342](https://github.com/mixxxdj/mixxx/pull/3342) [#3943](https://github.com/mixxxdj/mixxx/pull/3943) * Add controller mapping for Behringer DDM4000 [#3542](https://github.com/mixxxdj/mixxx/pull/3542) * Update controller mapping for Allen & Heath Xone K2 to add intro/outro cues [#2236](https://github.com/mixxxdj/mixxx/pull/2236) * Update controller mapping for Hercules P32 for more accurate headmix control [#3537](https://github.com/mixxxdj/mixxx/pull/3537) @@ -111,6 +123,9 @@ * Add macOS codesigning and notarization to fix startup warnings [#3281](https://github.com/mixxxdj/mixxx/pull/3281) * Don't trash user configuration if an error occurs when writing [#3192](https://github.com/mixxxdj/mixxx/pull/3192) * Enable CUE sheet recording by default [#3374](https://github.com/mixxxdj/mixxx/pull/3374) +* Fix crash when double clicking GLSL waveforms with right mouse button [#3904](https://github.com/mixxxdj/mixxx/pull/3904) +* Derive Mixxx version from `git describe` [#3824](https://github.com/mixxxdj/mixxx/pull/3824) [#3841](https://github.com/mixxxdj/mixxx/pull/3841) [#3848](https://github.com/mixxxdj/mixxx/pull/3848) +* Improve tapping the bpm of a deck [#3790](https://github.com/mixxxdj/mixxx/pull/3790) [lp:1882776](https://bugs.launchpad.net/mixxx/+bug/1882776) * And countless other small fixes and improvements (too many to list them all!) ## [2.2.4](https://launchpad.net/mixxx/+milestone/2.2.4) (2020-06-27) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6fae9997815..d7c5faa55cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,39 @@ if(POLICY CMP0071) cmake_policy(SET CMP0071 NEW) endif() +# Check if any relevant env vars were set from the build env scripts +if(DEFINED ENV{X_VCPKG_APPLOCAL_DEPS_INSTALL} AND NOT DEFINED X_VCPKG_APPLOCAL_DEPS_INSTALL) + set(X_VCPKG_APPLOCAL_DEPS_INSTALL "$ENV{X_VCPKG_APPLOCAL_DEPS_INSTALL}" CACHE BOOL "") +endif() + +if(DEFINED ENV{VCPKG_DEFAULT_TRIPLET} AND NOT DEFINED VCPKG_TARGET_TRIPLET) + set(VCPKG_TARGET_TRIPLET "$ENV{VCPKG_DEFAULT_TRIPLET}" CACHE STRING "") +endif() + +if(DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE) + set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "") +endif() + +# Set a default build type if none was specified +# See https://blog.kitware.com/cmake-and-the-default-build-type/ for details. +set(default_build_type "RelWithDebInfo") +if(EXISTS "${CMAKE_SOURCE_DIR}/.git" AND NOT WIN32) + # On Windows, Debug builds are linked to unoptimized libs + # generating unusable slow Mixxx builds. + set(default_build_type "Debug") +endif() + +if(NOT CMAKE_CONFIGURATION_TYPES) + if(NOT CMAKE_BUILD_TYPE) + message(STATUS "Setting CMAKE_BUILD_TYPE to '${default_build_type}' as none was specified.") + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "RelWithDebInfo") + elseif(NOT CMAKE_BUILD_TYPE MATCHES "^(Debug|Release|RelWithDebInfo)$") + message(FATAL_ERROR "CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} is not supported, use one of Debug, Release or RelWithDebInfo.") + endif() +endif() + project(mixxx VERSION 2.4.0) # Work around missing version suffixes support https://gitlab.kitware.com/cmake/cmake/-/issues/16716 set(MIXXX_VERSION_PRERELEASE "alpha-pre") # set to "alpha-pre" "beta" or "" @@ -101,6 +134,7 @@ endif() # set(OPTIMIZE "portable" CACHE STRING "Optimization and Tuning (set to off, portable, native, legacy)") +set_property(CACHE OPTIMIZE PROPERTY STRINGS "off" "portable" "native" "legacy") string(TOLOWER "${OPTIMIZE}" OPTIMIZE) message(STATUS "Optimization level: ${OPTIMIZE}") @@ -181,10 +215,11 @@ if(MSVC) string(REPLACE "/INCREMENTAL" "/INCREMENTAL:NO" CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}") endif() # Note: CMAKE_INTERPROCEDURAL_OPTIMIZATION sets the /GL and /LTCG flags for us - elseif(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel") - # Settings for MinSizeRel builds elseif(CMAKE_BUILD_TYPE STREQUAL "Release") - # Settings for Release builds + # Reduce the size of the binary in Release builds + # Do not use /OPT:ICF because it has no effect. + # https://github.com/mixxxdj/mixxx/pull/3660#pullrequestreview-600137258 + add_link_options(/OPT:REF) endif() if(OPTIMIZE STREQUAL "portable") @@ -668,8 +703,8 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL src/mixer/sampler.cpp src/mixer/samplerbank.cpp src/coreservices.cpp - src/mixxx.cpp src/mixxxapplication.cpp + src/mixxxmainwindow.cpp src/musicbrainz/chromaprinter.cpp src/musicbrainz/crc.cpp src/musicbrainz/gzip.cpp @@ -736,9 +771,15 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL src/skin/qml/asyncimageprovider.cpp src/skin/qml/qmlcontrolproxy.cpp src/skin/qml/qmlconfigproxy.cpp + src/skin/qml/qmleffectmanifestparametersmodel.cpp + src/skin/qml/qmleffectsmanagerproxy.cpp + src/skin/qml/qmleffectslotproxy.cpp + src/skin/qml/qmllibraryproxy.cpp + src/skin/qml/qmllibrarytracklistmodel.cpp src/skin/qml/qmlplayermanagerproxy.cpp src/skin/qml/qmlplayerproxy.cpp src/skin/qml/qmlskin.cpp + src/skin/qml/qmlvisibleeffectsmodel.cpp src/skin/qml/qmlwaveformoverview.cpp src/skin/legacy/skincontext.cpp src/skin/legacy/tooltips.cpp @@ -978,6 +1019,12 @@ if(UNIX AND NOT APPLE) set(MIXXX_SETTINGS_PATH ".mixxx/") endif() +# QML Debugging +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + target_compile_definitions(mixxx-lib PRIVATE QT_QML_DEBUG) + message(STATUS "Enabling QML Debugging! This poses a security risk as Mixxx will open a TCP port for debugging") +endif() + # Disable warnings in generated source files set_property( SOURCE src/library/rekordbox/rekordbox_anlz.cpp @@ -1430,6 +1477,7 @@ add_executable(mixxx-test src/test/beatgridtest.cpp src/test/beatmaptest.cpp src/test/beatstranslatetest.cpp + src/test/bpmtest.cpp src/test/bpmcontrol_test.cpp src/test/broadcastprofile_test.cpp src/test/broadcastsettings_test.cpp @@ -1463,6 +1511,7 @@ add_executable(mixxx-test src/test/enginemicrophonetest.cpp src/test/enginesynctest.cpp src/test/fileinfo_test.cpp + src/test/frametest.cpp src/test/globaltrackcache_test.cpp src/test/hotcuecontrol_test.cpp src/test/imageutils_test.cpp @@ -1861,6 +1910,7 @@ if(KEYFINDER) -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH= -DCMAKE_PREFIX_PATH:PATH="${CMAKE_PREFIX_PATH}" + -DCMAKE_INSTALL_LIBDIR=${CMAKE_INSTALL_LIBDIR} -DBUILD_TESTING=OFF BUILD_COMMAND ${CMAKE_COMMAND} --build . BUILD_BYPRODUCTS /${KeyFinder_LIBRARY} @@ -2355,13 +2405,7 @@ find_package(MP4) find_package(MP4v2) # It is enabled by default on Linux only, because other targets have other # solutions. It requires MP4 or MP4v2. -# Note, we use if() here, because the following line does not work with cmake 3.16.3 -# default_option(FAAD "FAAD AAC audio file decoder support" "UNIX;NOT APPLE;(MP4_FOUND OR MP4v2_FOUND)") -if (UNIX AND NOT APPLE AND (MP4_FOUND OR MP4v2_FOUND)) - option(FAAD "FAAD AAC audio file decoder support" ON) -else() - option(FAAD "FAAD AAC audio file decoder support" OFF) -endif() +default_option(FAAD "FAAD AAC audio file decoder support" "UNIX;NOT APPLE;MP4_FOUND OR MP4v2_FOUND") if(FAAD) if(NOT MP4_FOUND AND NOT MP4v2_FOUND) message(FATAL_ERROR "FAAD AAC audio support requires libmp4 or libmp4v2 with development headers.") @@ -2623,12 +2667,9 @@ if(MODPLUG) endif() # QtKeychain -find_package(Qt5Keychain QUIET) option(QTKEYCHAIN "Secure credentials storage support for Live Broadcasting profiles" ON) if(QTKEYCHAIN) - if(NOT Qt5Keychain_FOUND) - message(FATAL_ERROR "Secure credential storage support requires the Qt5::Keychain component.") - endif() + find_package(Qt5Keychain REQUIRED) target_compile_definitions(mixxx-lib PUBLIC __QTKEYCHAIN__) target_link_libraries(mixxx-lib PRIVATE ${QTKEYCHAIN_LIBRARIES}) target_include_directories(mixxx-lib SYSTEM PUBLIC ${QTKEYCHAIN_INCLUDE_DIRS}) @@ -2655,11 +2696,17 @@ if(HID) find_library(AppKit_LIBRARY AppKit REQUIRED) target_link_libraries(mixxx-hidapi PUBLIC ${AppKit_LIBRARY}) elseif(UNIX) - if(NOT LibUSB_FOUND) - message(FATAL_ERROR "USB HID controller support on Unix with statically linked libhidapi-libusb requires libusb 1.0 and its development headers.") + if(CMAKE_SYSTEM_NAME STREQUAL Linux) + find_library(libudev_LIBRARY udev REQUIRED) + target_sources(mixxx-hidapi PRIVATE lib/hidapi/linux/hid.c) + target_link_libraries(mixxx-hidapi PRIVATE ${libudev_LIBRARY}) + else() + if(NOT LibUSB_FOUND) + message(FATAL_ERROR "USB HID controller support on Unix with statically linked libhidapi-libusb requires libusb 1.0 and its development headers.") + endif() + target_sources(mixxx-hidapi PRIVATE lib/hidapi/libusb/hid.c) + target_link_libraries(mixxx-hidapi PRIVATE LibUSB::LibUSB) endif() - target_sources(mixxx-hidapi PRIVATE lib/hidapi/libusb/hid.c) - target_link_libraries(mixxx-hidapi PRIVATE LibUSB::LibUSB) else() message(FATAL_ERROR "USB HID controller support only possible on Windows/Mac OS/Linux/BSD.") endif() @@ -2667,9 +2714,16 @@ if(HID) else() message(STATUS "Linking libhidapi dynamically") if(NOT HIDAPI_FOUND) - message(FATAL_ERROR "USB HID controller support requires libhidapi-libusb and its development headers.") + message(FATAL_ERROR "USB HID controller support requires hidapi and its development headers.") + endif() + # hidapi has two backends on Linux, one using the kernel's hidraw API and one using libusb. + # libusb obviously does not support Bluetooth HID devices, so use the hidraw backend. The + # libusb backend is the default, so hidraw needs to be selected explicitly at link time. + if(CMAKE_SYSTEM_NAME STREQUAL Linux) + target_link_libraries(mixxx-lib PRIVATE hidapi::hidraw) + else() + target_link_libraries(mixxx-lib PRIVATE hidapi::hidapi) endif() - target_link_libraries(mixxx-lib PRIVATE hidapi::hidapi) endif() target_sources(mixxx-lib PRIVATE src/controllers/hid/hidcontroller.cpp diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000000..f9a639a6c2f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,86 @@ +# Mixxx Contribution Guidelines # +Thank you for contributing to [Mixxx](https://mixxx.org/)! Your work helps DJs all over the world! We are global, all volunteer team that works by consensus and we are excited to have you join us. This document specifies technical aspects of our workflow. For social aspects please refer to [CODE_OF_CONDUCT.md](https://github.com/mixxxdj/mixxx/blob/master/CODE_OF_CONDUCT.md) in this repository. We encourage you to introduce yourself on our [Zulip chat](https://mixxx.zulipchat.com/) before starting to contribute code to Mixxx. + +Table of Contents +1. [Orientation](#Orientation) + 1. [Git Repositories](#Git-Repositories) +2. [Git Workflow](#Git-Workflow) + 1. [All Contributors](#All-Contributors) + 2. [Core Team](#Core-Team) + +## Orientation ## +We have lots more helpful information for users and developers on the [Mixxx wiki](https://mixxx.org/wiki/doku.php/start), including [build instructions](https://mixxx.org/wiki/doku.php/start#compile_mixxx_from_source_code). + +### Git Repositories ### +This repository contains the Mixxx source code, skins, controller mappings, and some helpful scripts. We have a few other Git repositories too: +* [mixxxdj/website](https://github.com/mixxxdj/website): content for the main [mixxx.org](https://mixxx.org/) website which is generated with the [Cactus static site generator](https://github.com/eudicots/Cactus) +* [mixxxdj/manual](https://github.com/mixxxdj/manual): content for the Mixxx manual, which uses [Sphinx](https://www.sphinx-doc.org/) +* [mixxxdj/buildserver](https://github.com/mixxxdj/buildserver): scripts for generating our prebuilt dependencies for macOS and Windows + +All of these are automatically built and deployed by our [Jenkins build servers](https://builds.renegadetech.mixxx.org/) whenever a change is committed. You are welcome to open a pull request in any of these repositories. + +## Git Workflow ## +### All Contributors ### +* Each feature/bug fix should be done on its own Git branch so they can be reviewed and merged independently. Refer to [Using Git](https://mixxx.org/wiki/doku.php/using_git) for how to do this. Please ask for help on [Zulip](https://mixxx.zulipchat.com/) if you have questions about using Git after reading that page. +* Commits should be as small as they can while still building. The smaller the commit, the easier it is to review. It also makes it easier to revert if it is later identified as the source of a bug. If you have lots of changes that you need to commit, a [GUI Git client](https://git-scm.com/downloads/guis) can be helpful for picking out specific changes for multiple small commits. +* Every commit should build. This is important so [git bisect](https://git-scm.com/book/en/v2/Git-Tools-Debugging-with-Git#_binary_search) works. +* Commit messages should succinctly describe what is changed in that commit and why. Lines should wrap at 72 characters so they show fully in GitHub and other Git tools. For example, this is a good commit message: + + ``` + DlgPrefEffects: add QListWidget to set order of chains + + This order will soon be used by new ControlObjects to load them + from controllers. + ``` + + This is not a good commit message: + + ``` + address comments from PR review + ``` + + Neither is this: + + ``` + fix a bug with quantize while the deck is playing and master sync is enabled and an effect unit is on the deck while the user is turning an EQ knob + ``` + + Refer to [How to Write a Git Commit Message](https://chris.beams.io/posts/git-commit/) for more details. + +* Install [pre-commit](https://pre-commit.com/#install) to automatically ensure that your commits comply with our code style for both C++ and JavaScript. Note this is currently not working on Windows. This saves time reviewing so we don't have to point out nitpicky style issues. Once you have pre-commit installed on your computer, set it up in your local Git repository: + + ``` + cd /path/to/your/git/repo + pre-commit install + pre-commit install -t pre-push + ``` + + If you have a problems with a particular hook, you can use the SKIP environment variable to disable hooks: + + ``` + SKIP=clang-format,end-of-file-fixer git commit + ``` + + This can also be used to separate logic changes and autoformatting into two subsequent commits. Using the SKIP environment variable is preferable to using `git commit --no-verify` (which also disables the checks) because it won't prevent catching other, unrelated issues. + +* Generally, prefer merging to rebasing. Do not rebase unless you have discussed that with whoever is reviewing the pull request. When you rebase a branch with an open pull request, prior review comments made inline in the code on GitHub lose their connection to that spot in the code. If you want to correct minor mistakes with a rebase or `git commit --amend` within a few minutes of pushing commits, that is okay as long as no one has started reviewing those commits yet. +* If you are helping with someone else's pull request that is not yet merged, open a pull request targeted at their fork. Leave a comment on the upstream pull request (which targets mixxxdj/mixxx) with a link to your pull request so other Mixxx contributors are aware of your changes. +* Low risk bug fixes should be targeted at the stable branch (currently 2.2). However, bug fixes for the stable branches must have a direct impact on users. If you spot a minor bug reading the code or only want to clean up the code, target that at the master or beta branch. +* Controller mappings should be targeted at the stable branch unless they use features that are new in the beta or master branch. +* If you are making changes to the GUI with a pull request, please post before and after screenshots of the changes. +* Please help review other people's pull requests. When others review your pull requests, please return the favor. The continued progress of Mixxx depends on all of us working together. Even if you are not familiar with the area of the code being changed in a pull request, you can be helpful by building the branch, verifying that it works as described, and commenting with feedback about the user experience design. +* If you demonstrate good coding skills, help review pull requests, contribute major features, and show a commitment to Mixxx over time, we may invite you to the core team. + +### Core Team ### +Mixxx core team members are contributors who have write access to the [upstream mixxxdj repositories](https://github.com/mixxxdj/) on GitHub, access to the Jenkins web interface for the build servers, and access to the private Zulip stream for the core team. + +* Enable [two-factor authentication (2FA)](https://help.github.com/en/github/authenticating-to-github/securing-your-account-with-two-factor-authentication-2fa) for your GitHub account. +* _Never_ force push to an upstream repository (mixxxdj). If you encounter an error from Git saying you would need to force push, stop what you are doing and discuss the situation on Zulip. +* Only push directly to an upstream repository (mixxxdj) for trivial, uncontroversial changes like fixing a typo. +* All non-trivial contributions should be made with a pull request, just like any other contributor who does not have write access. Do not merge your own pull requests. +* You may merge someone else's pull request as the only reviewer if no other contributors have expressed concerns about the changes or said they want to review the code. Please do not merge pull requests immediately; allow at least a day or two for others to comment. Remember we are all volunteers and cannot respond to everything immediately. +* If there is disagreement about changes in a pull request, do not merge it until a consensus has been reached. +* Check CI to ensure builds work and tests pass before merging. If CI timed out, either manually restart it or build the branch and run the tests locally before merging. +* When you merge a pull request to a stable branch, merge the stable branch to the beta branch afterwards. If you merge a pull request to a beta branch, merge the beta branch to master afterwards. When backporting, cherry-pick or rebase rather than merge. +* Default to open; only post in the private Zulip stream for discussions that have a reason to be private. Most of the time, post to a public Zulip stream so anyone can participate in the discussion. +* When Mixxx participates in Google Summer of Code, you may volunteer as a mentor if you like. diff --git a/LICENSE b/LICENSE index 518e705c7be..bd06d53fe42 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Mixxx version 2.3, Digital DJ'ing software. +Mixxx version 2.4, Digital DJ'ing software. Copyright (C) 2001-2021 Mixxx Development Team Mixxx is free software; you can redistribute it and/or modify diff --git a/README.md b/README.md index 1f610eedf3c..5a27fbba2a5 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![Packaging status](https://repology.org/badge/tiny-repos/mixxx.svg)](https://repology.org/metapackage/mixxx/versions) [![Zulip chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://mixxx.zulipchat.com) [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://mixxx.org/donate) +[![Build](https://github.com/mixxxdj/mixxx/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/mixxxdj/mixxx/actions/workflows/build.yml) [Mixxx] is Free DJ software that gives you everything you need to perform live DJ mixes. Mixxx works on GNU/Linux, Windows, and macOS. @@ -26,20 +27,20 @@ bug list][easybugs] and get started! ## Building Mixxx -First, open a terminal (on Windows, use "x64 Native Tools command prompt for -VS2019"), download the mixxx source code and navigate to it: +First, open a terminal (on Windows, use "x64 Native Tools Command Prompt for +VS 2019"), download the mixxx source code and navigate to it: $ git clone https://github.com/mixxxdj/mixxx.git $ cd mixxx -Fetch the required dependencies (on Windows, macOS and Debian/Ubuntu, you can -do that by running `tools\windows_buildenv.bat`, `source -tools/macos_buildenv.sh setup` or `source tools/debian_buildenv.sh setup` -respectively), then run: +Fetch the required dependencies and set up the build environment (on Windows, +macOS and Debian/Ubuntu, you can do that by running +`tools\windows_buildenv.bat`, `source tools/macos_buildenv.sh setup` or `source +tools/debian_buildenv.sh setup` respectively), then run: $ mkdir build $ cd build - $ cmake .. # Use `cmake -G Ninja ..` on Windows + $ cmake .. $ cmake --build . There should now be a `mixxx` executable in the current directory that you can diff --git a/cmake/ctest-to-junit.xsl b/cmake/ctest-to-junit.xsl index 8bd53978b6a..ad4869944f0 100644 --- a/cmake/ctest-to-junit.xsl +++ b/cmake/ctest-to-junit.xsl @@ -4,7 +4,7 @@ This XSLT stylesheet is taken from the jenkins-ctest-plugin by Version One, Inc. and Ryan Pavlik and is subject to the terms of the MIT License. -It was taken from this GitHub repositiory: +It was taken from this GitHub repository: https://github.com/rpavlik/jenkins-ctest-plugin Includes modifications by Jan Holthuis to add support for skipped/errored diff --git a/cmake/modules/DefaultOption.cmake b/cmake/modules/DefaultOption.cmake index c9c0b6d134e..160cafc2420 100644 --- a/cmake/modules/DefaultOption.cmake +++ b/cmake/modules/DefaultOption.cmake @@ -33,7 +33,10 @@ set a default and the value may be overridden by the user. macro(DEFAULT_OPTION option doc depends) set(${option}_DEFAULT_ON 1) foreach(d ${depends}) - string(REGEX REPLACE " +" ";" DEFAULT_OPTION_DEP "${d}") + # if() takes the condition as a list of arguments. Parentheses need to be separated as well. + string(REPLACE "(" " ( " DEFAULT_OPTION_DEP "${d}") + string(REPLACE ")" " ) " DEFAULT_OPTION_DEP "${DEFAULT_OPTION_DEP}") + string(REGEX REPLACE " +" ";" DEFAULT_OPTION_DEP "${DEFAULT_OPTION_DEP}") if(${DEFAULT_OPTION_DEP}) else() set(${option}_DEFAULT_ON 0) diff --git a/cmake/modules/Findhidapi.cmake b/cmake/modules/Findhidapi.cmake index b4a7b282dd7..b74a53fedcf 100644 --- a/cmake/modules/Findhidapi.cmake +++ b/cmake/modules/Findhidapi.cmake @@ -62,6 +62,15 @@ find_library(hidapi_LIBRARY ) mark_as_advanced(hidapi_LIBRARY) +if(CMAKE_SYSTEM_NAME STREQUAL Linux) + find_library(hidapi-hidraw_LIBRARY + NAMES hidapi-hidraw + PATHS ${PC_hidapi_LIBRARY_DIRS} + DOC "hidap-hidraw library" + ) + mark_as_advanced(hidapi-hidraw_LIBRARY) +endif() + include(FindPackageHandleStandardArgs) find_package_handle_standard_args( hidapi @@ -98,5 +107,14 @@ if(hidapi_FOUND) INTERFACE_COMPILE_OPTIONS "${PC_hidapi_CFLAGS_OTHER}" INTERFACE_INCLUDE_DIRECTORIES "${hidapi_INCLUDE_DIR}" ) + if(CMAKE_SYSTEM_NAME STREQUAL Linux) + add_library(hidapi::hidraw UNKNOWN IMPORTED) + set_target_properties(hidapi::hidraw + PROPERTIES + IMPORTED_LOCATION "${hidapi-hidraw_LIBRARY}" + INTERFACE_COMPILE_OPTIONS "${PC_hidapi_CFLAGS_OTHER}" + INTERFACE_INCLUDE_DIRECTORIES "${hidapi_INCLUDE_DIR}" + ) + endif() endif() endif() diff --git a/packaging/CPackDebInstall.cmake b/packaging/CPackDebInstall.cmake index 16e99ecb72d..a3198e1dd51 100644 --- a/packaging/CPackDebInstall.cmake +++ b/packaging/CPackDebInstall.cmake @@ -23,7 +23,7 @@ if(NOT CPACK_DEBIAN_DEBCHANGE) endif() # We create a temporary debian folder that the debhelper below run as usual. -# The final debian folder is created indipendently by cpack +# The final debian folder is created independently by cpack message( NOTICE "Creating temporary debian folder for debhelper" ) file(COPY ${CPACK_DEBIAN_SOURCE_DIR}/packaging/debian DESTINATION ${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}) @@ -69,7 +69,7 @@ function(run_dh DH_COMMAND) WORKING_DIRECTORY ${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME} RESULT_VARIABLE CPACK_DEBIAN_DH_RET) if(NOT CPACK_DEBIAN_DH_RET EQUAL "0") - message(FATAL_ERROR "${DH_COMMAND} retuned exit code ${CPACK_DEBIAN_DH_RET}") + message(FATAL_ERROR "${DH_COMMAND} returned exit code ${CPACK_DEBIAN_DH_RET}") endif() endfunction() diff --git a/packaging/CPackDebUploadPPA.cmake b/packaging/CPackDebUploadPPA.cmake index daaa59a8126..23eb1e53ede 100644 --- a/packaging/CPackDebUploadPPA.cmake +++ b/packaging/CPackDebUploadPPA.cmake @@ -117,7 +117,7 @@ foreach(RELEASE ${CPACK_DEBIAN_DISTRIBUTION_RELEASES}) WORKING_DIRECTORY ${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME} RESULT_VARIABLE CPACK_DEBIAN_DEBUILD_RET) if(NOT CPACK_DEBIAN_DEBUILD_RET EQUAL "0") - message(FATAL_ERROR "${CPACK_DEBIAN_DEBUILD} retuned exit code ${CPACK_DEBIAN_DEBUILD_RET}") + message(FATAL_ERROR "${CPACK_DEBIAN_DEBUILD} returned exit code ${CPACK_DEBIAN_DEBUILD_RET}") endif() endif() if (BUILD_MACHINE_RELEASE STREQUAL RELEASE AND DEB_BUILD) diff --git a/packaging/macos/entitlements.plist b/packaging/macos/entitlements.plist index 126ccd7564d..7193269b745 100644 --- a/packaging/macos/entitlements.plist +++ b/packaging/macos/entitlements.plist @@ -30,7 +30,7 @@ com.apple.security.files.user-selected.read-write - + com.apple.security.files.bookmarks.app-scope diff --git a/packaging/windows/build_environment b/packaging/windows/build_environment index f0914804cae..f31ffb8a0dc 100644 --- a/packaging/windows/build_environment +++ b/packaging/windows/build_environment @@ -1 +1 @@ -mixxx-dependencies-2.3-x64-windows-3d70970e752542db9901e4aa2656f215699dc102 +mixxx-deps-2.3-x64-windows-049b5ad diff --git a/res/Mixxx-Keyboard-Shortcuts.pdf b/res/Mixxx-Keyboard-Shortcuts.pdf index d6491d378d2..51986d9b47b 100644 Binary files a/res/Mixxx-Keyboard-Shortcuts.pdf and b/res/Mixxx-Keyboard-Shortcuts.pdf differ diff --git a/res/controllers/Behringer-Extension-scripts.js b/res/controllers/Behringer-Extension-scripts.js index a6d7c8aa9b1..5dc9e38b1ae 100644 --- a/res/controllers/Behringer-Extension-scripts.js +++ b/res/controllers/Behringer-Extension-scripts.js @@ -478,8 +478,8 @@ var loopSize = engine.getValue(group, "beatloop_size"); var beatjumpSize = engine.getValue(group, "beatjump_size"); engine.setValue(group, "beatjump_size", loopSize); - script.triggerControl(group, "beatloop_activate"); script.triggerControl(group, "beatjump_backward"); + script.triggerControl(group, "beatloop_activate"); engine.setValue(group, "beatjump_size", beatjumpSize); } else { script.triggerControl(group, "reloop_toggle"); diff --git a/res/controllers/Hercules_DJControl_Inpulse_200.midi.xml b/res/controllers/Hercules_DJControl_Inpulse_200.midi.xml index 90b0d317c61..79ac80305f8 100644 --- a/res/controllers/Hercules_DJControl_Inpulse_200.midi.xml +++ b/res/controllers/Hercules_DJControl_Inpulse_200.midi.xml @@ -1303,7 +1303,7 @@ 0x07 0x05 - + [AutoDJ] enabled diff --git a/res/controllers/Hercules_DJControl_Jogvision.midi.xml b/res/controllers/Hercules_DJControl_Jogvision.midi.xml index 75e456d4a07..1f7aa166a8d 100644 --- a/res/controllers/Hercules_DJControl_Jogvision.midi.xml +++ b/res/controllers/Hercules_DJControl_Jogvision.midi.xml @@ -1721,7 +1721,7 @@ [Master] maximize_library - VIEW buton LED + VIEW button LED 0.5 1 0x90 diff --git a/res/controllers/Numark-N4-scripts.js b/res/controllers/Numark-N4-scripts.js index fcf8a427f6f..9967cbf3038 100644 --- a/res/controllers/Numark-N4-scripts.js +++ b/res/controllers/Numark-N4-scripts.js @@ -24,7 +24,7 @@ NumarkN4.cueReverseRoll=true; // enables the ability to do a reverse roll while NumarkN4.hotcuePageIndexBehavior=true; // possible ranges (0.0..3.0 where 0.06=6%) -NumarkN4.rateRanges = [0, // default (gets set via script later; don't modifify) +NumarkN4.rateRanges = [0, // default (gets set via script later; don't modify) 0.06, // one semitone 0.24, // for maximum freedom ]; diff --git a/res/controllers/Pioneer-DDJ-200-scripts.js b/res/controllers/Pioneer-DDJ-200-scripts.js index 5cfc7274597..e1f03a234a2 100644 --- a/res/controllers/Pioneer-DDJ-200-scripts.js +++ b/res/controllers/Pioneer-DDJ-200-scripts.js @@ -31,7 +31,7 @@ DDJ200.init = function() { DDJ200.switchPlayLED(d, ch); }); - // run switchSyncLED after sync toogle to set LEDs accordingly + // run switchSyncLED after sync toggle to set LEDs accordingly engine.makeConnection(vgroup, "sync_enabled", function(ch, vgroup) { var vDeckNo = script.deckFromGroup(vgroup); var d = (vDeckNo % 2) ? 0 : 1; diff --git a/res/controllers/Pioneer-DDJ-400.midi.xml b/res/controllers/Pioneer-DDJ-400.midi.xml index a2cc1d28eba..d1abe4e38b1 100644 --- a/res/controllers/Pioneer-DDJ-400.midi.xml +++ b/res/controllers/Pioneer-DDJ-400.midi.xml @@ -206,7 +206,7 @@ - JOG DIAL PLATTER (DECK1) - touch - enabe (on touch) / disable (on release) Scraching/Pitch + JOG DIAL PLATTER (DECK1) - touch - enable (on touch) / disable (on release) Scratching/Pitch bend [Channel1] @@ -218,7 +218,7 @@ - JOG DIAL PLATTER +SHIFT (DECK1) - touch - enabe (on touch) / disable (on release) highspeed + JOG DIAL PLATTER +SHIFT (DECK1) - touch - enable (on touch) / disable (on release) highspeed Pitch bend [Channel1] @@ -271,7 +271,7 @@ - JOG DIAL PLATTER (DECK2) - touch - enabe (on touch) / disable (on release) Scraching/Pitch + JOG DIAL PLATTER (DECK2) - touch - enable (on touch) / disable (on release) Scratching/Pitch bend [Channel2] @@ -283,7 +283,7 @@ - JOG DIAL PLATTER +SHIFT (DECK2) - touch - enabe (on touch) / disable (on release) highspeed + JOG DIAL PLATTER +SHIFT (DECK2) - touch - enable (on touch) / disable (on release) highspeed Pitch bend [Channel2] diff --git a/res/controllers/Traktor-Kontrol-S2-MK3-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK3-hid-scripts.js index c98765289da..6507bf3548e 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK3-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK3-hid-scripts.js @@ -187,7 +187,7 @@ TraktorS2MK3.registerInputPackets = function () { this.registerInputScaler(messageLong, "[Master]", "crossfader", 0x05, 0xFFFF, this.parameterHandler); /* do NOT map the "master" button because it also drives the analog output gain. - Disabling this mapping is the only way to have independant controls for the + Disabling this mapping is the only way to have independent controls for the digital master gain and the output level - the latter usually needs to be set at 100%. */ diff --git a/res/controllers/Traktor-Kontrol-S3-hid-scripts.js b/res/controllers/Traktor-Kontrol-S3-hid-scripts.js index 140b1d612ef..2cd16782952 100644 --- a/res/controllers/Traktor-Kontrol-S3-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S3-hid-scripts.js @@ -2073,7 +2073,7 @@ TraktorS3.Controller.prototype.lightDeck = function(group, sendPackets) { deck.colorOutput(0, "!PreviewTrack"); deck.colorOutput(0, "!LibraryFocus"); deck.colorOutput(0, "!MaximizeLibrary"); - deck.colorOutput(TraktorS3.JogDefaultOn, "!jogButton"); + deck.colorOutput(deck.jogToggled, "!jogButton"); if (group === "[Channel4]") { this.basicOutput(0, "[Master]", "!extButton"); } diff --git a/res/images/templates/ic_template_keyboard_mapping_sheet.svg b/res/images/templates/ic_template_keyboard_mapping_sheet.svg index ef8d1a5172c..5f39a761916 100644 --- a/res/images/templates/ic_template_keyboard_mapping_sheet.svg +++ b/res/images/templates/ic_template_keyboard_mapping_sheet.svg @@ -1,22 +1,22 @@ Mixxx Keyboard mapping sheet templateimage/svg+xml @@ -7901,13 +8010,13 @@ id="g32437" style="fill:#ffffff;fill-opacity:1"> - - - - - - - -Mixxx default keyboard mapping sheet *www.mixxx.org - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Mixxx default keyboard mapping - - - - - - - - - - - - - - - - - - - - -rate - smallrate + smalltemp - smalltemp + smallloopin   loopout   reloop/ exit   QuickEffectsync tap  loopin   loopout   reloop/ exit   QuickEffect    4-barloop  loop÷ 2   loopx 2   headphone   headphone   4-barloop  loop÷ 2   loopx 2   back rev  play cue set  cue cue go  xFader small  xFader small  fwd  back rev  play cue set  fwd  cue cue go  talkover  hot 1 clear  hot 2 clear  hot 3 clear  hot 4 clear  lowkill  lowkill  toggleshuffleskipfade Deck 1Deck 2hot 1 clear  hot 2 clear  hot 3 clear  hot 4 clear  rate - smallrate + smalltemp - smalltemp + smallsync tap  load 1eject 1  load 2 eject 2  AutoDJLibrary±§ + + + + + + + +Mixxx default keyboard mapping sheet *www.mixxx.org + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mixxx default keyboard mapping + + + + + + + + + + + + + + + + + + + + +rate - smallrate + smalltemp - smalltemp + smallloopin   loopout   reloop/ exit   QuickEffectsync tap  loopin   loopout   reloop/ exit   QuickEffect    4-barloop  loop÷ 2   loopx 2   headphone   headphone   4-barloop  loop÷ 2   loopx 2   back rev  play cue set  cue cue go  xFader small  xFader small  fwd  back rev  play cue set  fwd  cue cue go  talkover  hot 1 clear  hot 2 clear  hot 3 clear  hot 4 clear  lowkill  lowkill  toggleshuffleskipfade Deck 1Deck 2hot 1 clear  hot 2 clear  hot 3 clear  hot 4 clear  rate - smallrate + smalltemp - smalltemp + smallsync tap  load 1eject 1  load 2 eject 2  ±§AutoDJLibrarymaximize library * for en-us keyboard layout * for en-us keyboard layout- select the rectangle in layer 'res > doc_file_boundary'- select the rectangle in layer 'res' > 'doc_file_boundary'- delete layers 'res' and 'links' 'setup_export'- delete layers 'res', 'links' 'setup_export'defined by the rectangle in layer 'doc_file_frame',defined by the rectangle in layer 'res' > 'doc_file_boundary', + + + Add source_synchronized_ms column to library table + + + + ALTER TABLE library ADD COLUMN source_synchronized_ms INTEGER DEFAULT NULL; + + + + + Fix 0/NULL issue after upgrade to schema version 37. + + + UPDATE library SET source_synchronized_ms=NULL WHERE source_synchronized_ms=0; + + diff --git a/res/skins/Deere/icon/ic_broadcast_4_32px.svg b/res/skins/Deere/icon/ic_broadcast_4_32px.svg new file mode 100644 index 00000000000..78965e1488d --- /dev/null +++ b/res/skins/Deere/icon/ic_broadcast_4_32px.svg @@ -0,0 +1,3 @@ + + + diff --git a/res/skins/Deere/tool_bar.xml b/res/skins/Deere/tool_bar.xml index c102bd7f423..207059f3a3e 100644 --- a/res/skins/Deere/tool_bar.xml +++ b/res/skins/Deere/tool_bar.xml @@ -342,6 +342,7 @@ icon/ic_broadcast_1_32px.svg icon/ic_broadcast_2_32px.svg icon/ic_broadcast_3_32px.svg + icon/ic_broadcast_4_32px.svg [Shoutcast],enabled [Shoutcast],status diff --git a/res/skins/LateNight/fx/unit_parameters_hidden.xml b/res/skins/LateNight/fx/unit_parameters_hidden.xml index dc92a339730..9fe21ee27b8 100644 --- a/res/skins/LateNight/fx/unit_parameters_hidden.xml +++ b/res/skins/LateNight/fx/unit_parameters_hidden.xml @@ -18,7 +18,7 @@ horizontal - + + When a track is loaded the bg gets darker for better contrast --> #19191a #001b23 rgba(15, 15, 15, 20) @@ -249,7 +249,7 @@ blue white 0f,0f @@ -392,7 +392,7 @@ diff --git a/res/skins/LateNight/style.qss b/res/skins/LateNight/style.qss index 3584169bbe1..b3eb4f37b65 100644 --- a/res/skins/LateNight/style.qss +++ b/res/skins/LateNight/style.qss @@ -717,7 +717,7 @@ WEffectSelector { -/************** Skin setttings ************************************************/ +/************** Skin settings *************************************************/ #SkinSettings { qproperty-layoutAlignment: 'AlignLeft | AlignTop'; diff --git a/res/skins/LateNight/style_classic.qss b/res/skins/LateNight/style_classic.qss index bab8b194d51..523680812f4 100644 --- a/res/skins/LateNight/style_classic.qss +++ b/res/skins/LateNight/style_classic.qss @@ -1181,7 +1181,10 @@ WBeatSpinBox, #spinBoxTransition, #FxAssignButtons WPushButton[displayValue="1"], #GuiToggleButton[displayValue="1"], #GuiToggleButton[displayValue="2"], -#BroadcastButton[displayValue="1"], /* connecting: yellow */ +#BroadcastButton[displayValue="1"], +#BroadcastButton[displayValue="2"], +#BroadcastButton[displayValue="3"], +#BroadcastButton[displayValue="4"], #RecDuration[highlight="1"], #RecDuration[highlight="2"], #SkinSettingsToggle[displayValue="1"], @@ -1274,6 +1277,7 @@ WPushButton#FxAssignButton1[displayValue="1"], #BroadcastButton[displayValue="1"], #BroadcastButton[displayValue="2"], #BroadcastButton[displayValue="3"], +#BroadcastButton[displayValue="4"], #SkinSettingsToggle[displayValue="1"], #LibraryFeatureControls QPushButton:pressed, QPushButton#pushButtonAutoDJ:checked, @@ -1449,7 +1453,8 @@ QPushButton#pushButtonRepeatPlaylist:checked { background-color: #888; } -#BroadcastButton[displayValue="3"] { +#BroadcastButton[displayValue="3"], +#BroadcastButton[displayValue="4"] { /* pink */ background-color: #f856e7; } @@ -1888,7 +1893,8 @@ WPushButton#SamplerExpand[displayValue="0"], } #BroadcastButton[displayValue="1"], #BroadcastButton[displayValue="2"], - #BroadcastButton[displayValue="3"] { + #BroadcastButton[displayValue="3"], + #BroadcastButton[displayValue="4"] { image: url(skin:/classic/buttons/btn__broadcast_on.svg) no-repeat left top; } diff --git a/res/skins/LateNight/style_palemoon.qss b/res/skins/LateNight/style_palemoon.qss index c08796ddcad..a03b1b8e315 100644 --- a/res/skins/LateNight/style_palemoon.qss +++ b/res/skins/LateNight/style_palemoon.qss @@ -351,7 +351,7 @@ WSearchLineEdit { border-radius: 1px; } -/* Disbled for now since the hover effect is stuck as soon as the +/* Disabled for now since the hover effect is stuck as soon as the track menu is opened. #TitleText[highlight="1"]:hover, #TitleTextSmall[highlight="1"]:hover, #ArtistText[highlight="1"]:hover, #ArtistTextSmall[highlight="1"]:hover { @@ -1371,6 +1371,7 @@ WEffectSelector QAbstractScrollArea, #BroadcastButton[displayValue="1"], /* connecting */ #BroadcastButton[displayValue="2"], /* broadcasting */ #BroadcastButton[displayValue="3"], /* failure */ +#BroadcastButton[displayValue="4"], /* warning */ #RecDuration[highlight="1"], /* initializing */ #RecDuration[highlight="2"], /* recording */ #SkinSettingsToggle[displayValue="1"], @@ -1457,6 +1458,7 @@ WEffectSelector:!editable, #BroadcastButton[displayValue="1"], #BroadcastButton[displayValue="2"], #BroadcastButton[displayValue="3"], + #BroadcastButton[displayValue="4"], #SkinSettingsToggle[displayValue="1"], #LibraryFeatureControls QPushButton:pressed QPushButton#pushButtonAutoDJ:checked, @@ -1603,7 +1605,7 @@ WBeatSpinBox::down-button { WPushButton#MicAuxAdd { background-color: #1e1e20; } - /* brigth buttons in dimmed containers + /* bright buttons in dimmed containers #BeatgridControls WPushButton[displayValue="0"], */ #CueDeleteButton, #SplitCue[displayValue="0"], @@ -1640,6 +1642,7 @@ WPushButton#Reverse[pressed="true"], #MicDucking[value="2"], #VinylButton[displayValue="1"], #PassthroughButton[displayValue="1"], +#BroadcastButton[displayValue="4"], /* warning */ QPushButton#pushButtonAutoDJ:checked, QPushButton#pushButtonAnalyze:checked { background-color: #b24c12; @@ -1776,7 +1779,7 @@ WPushButton#FxSuperLinkInvertButton[displayValue="0"] { /* Yellow */ #RecFeedback[displayValue="1"], /* initialize recording */ -#BroadcastButton[displayValue="1"] /* connecting */ { +#BroadcastButton[displayValue="1"] { /* connecting */ background-color: #d09300; } @@ -2392,7 +2395,8 @@ WPushButton#PlayDeck[value="0"] { } #BroadcastButton[displayValue="1"], #BroadcastButton[displayValue="2"], - #BroadcastButton[displayValue="3"] { + #BroadcastButton[displayValue="3"], + #BroadcastButton[displayValue="4"] { image: url(skin:/palemoon/buttons/btn__broadcast_on.svg) no-repeat left top; } diff --git a/res/skins/QMLDemo/AuxiliaryUnit.qml b/res/skins/QMLDemo/AuxiliaryUnit.qml index a433cfab3f2..62eb11118f6 100644 --- a/res/skins/QMLDemo/AuxiliaryUnit.qml +++ b/res/skins/QMLDemo/AuxiliaryUnit.qml @@ -35,7 +35,7 @@ Row { anchors.centerIn: parent width: 48 height: width - arcStart: 0 + arcStart: Knob.ArcStart.Minimum group: root.group key: "pregain" color: Theme.gainKnobColor diff --git a/res/skins/QMLDemo/ComboBox.qml b/res/skins/QMLDemo/ComboBox.qml index db2e97e0dc6..d5d5e82ae5e 100644 --- a/res/skins/QMLDemo/ComboBox.qml +++ b/res/skins/QMLDemo/ComboBox.qml @@ -12,9 +12,10 @@ ComboBox { delegate: ItemDelegate { width: parent.width highlighted: root.highlightedIndex === index + text: root.textAt(index) contentItem: Text { - text: modelData + text: parent.text color: Theme.deckTextColor elide: Text.ElideRight verticalAlignment: Text.AlignVCenter diff --git a/res/skins/QMLDemo/Deck.qml b/res/skins/QMLDemo/Deck.qml index 0d10bc96ee9..d3661dc5d63 100644 --- a/res/skins/QMLDemo/Deck.qml +++ b/res/skins/QMLDemo/Deck.qml @@ -13,6 +13,27 @@ Item { property bool minimized: false property var deckPlayer: Mixxx.PlayerManager.getPlayer(group) + Drag.active: dragArea.drag.active + Drag.dragType: Drag.Automatic + Drag.supportedActions: Qt.CopyAction + Drag.mimeData: { + let data = { + "mixxx/player": group + }; + const trackLocationUrl = deckPlayer.trackLocationUrl; + if (trackLocationUrl) + data["text/uri-list"] = trackLocationUrl; + + return data; + } + + MouseArea { + id: dragArea + + anchors.fill: root + drag.target: root + } + Skin.SectionBackground { anchors.fill: parent } @@ -344,16 +365,12 @@ Item { } - Skin.ControlButton { + Skin.SyncButton { id: syncButton anchors.right: parent.right anchors.top: parent.top - text: "Sync" group: root.group - key: "sync_enabled" - toggleable: true - activeColor: Theme.deckActiveColor } FadeBehavior on visible { diff --git a/res/skins/QMLDemo/EffectRow.qml b/res/skins/QMLDemo/EffectRow.qml index b57f926d28f..16c8d55f0ca 100644 --- a/res/skins/QMLDemo/EffectRow.qml +++ b/res/skins/QMLDemo/EffectRow.qml @@ -2,25 +2,43 @@ import "." as Skin import QtQuick 2.12 import QtQuick.Controls 2.12 -Row { +Item { id: root - height: 60 + width: positioner.width + height: positioner.height - Skin.EffectUnit { - id: effectUnit1 + Row { + id: positioner + + Skin.EffectUnit { + id: effectUnit1 + + width: root.width / 2 + unitNumber: 1 + } + + Skin.EffectUnit { + id: effectUnit2 + + width: root.width / 2 + unitNumber: 2 + } - width: root.width / 2 - height: root.height - unitNumber: 1 } - Skin.EffectUnit { - id: effectUnit2 + Skin.SectionBackground { + anchors.top: parent.top + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.right: parent.horizontalCenter + } - width: root.width / 2 - height: root.height - unitNumber: 2 + Skin.SectionBackground { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.horizontalCenter + anchors.right: parent.right } } diff --git a/res/skins/QMLDemo/EffectSlot.qml b/res/skins/QMLDemo/EffectSlot.qml new file mode 100644 index 00000000000..f3004d376ba --- /dev/null +++ b/res/skins/QMLDemo/EffectSlot.qml @@ -0,0 +1,199 @@ +import "." as Skin +import Mixxx 0.1 as Mixxx +import QtQuick 2.12 +import "Theme" + +Item { + id: root + + property Mixxx.EffectSlotProxy slot: Mixxx.EffectsManager.getEffectSlot(1, unitNumber, effectNumber) + property int unitNumber // required + property int effectNumber // required + property bool expanded: false + readonly property string group: slot.group + property real maxSelectorWidth: 300 + + height: 50 + + Item { + id: selector + + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom + width: Math.min(root.width, root.maxSelectorWidth) + + Skin.ControlButton { + id: effectEnableButton + + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.margins: 5 + width: 40 + group: root.group + key: "enabled" + toggleable: true + text: "ON" + activeColor: Theme.effectColor + } + + Skin.ComboBox { + id: effectSelector + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: effectEnableButton.right + anchors.right: effectMetaKnob.left + anchors.margins: 5 + textRole: "display" + model: Mixxx.EffectsManager.visibleEffectsModel + onActivated: { + const effectId = model.get(index).effectId; + if (root.slot.effectId != effectId) + root.slot.effectId = effectId; + + } + Component.onCompleted: root.slot.onEffectIdChanged() + + Connections { + function onEffectIdChanged() { + const rowCount = effectSelector.model.rowCount(); + // TODO: Consider using an additional QHash in the + // model and provide a more efficient lookup method + for (let i = 0; i < rowCount; i++) { + if (effectSelector.model.get(i).effectId === target.effectId) { + effectSelector.currentIndex = i; + break; + } + } + } + + target: root.slot + } + + } + + Skin.ControlMiniKnob { + id: effectMetaKnob + + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.margins: 5 + arcStart: Knob.ArcStart.Minimum + width: 40 + group: root.group + key: "meta" + color: Theme.effectColor + } + + } + + ListView { + id: parametersView + + visible: root.expanded + anchors.leftMargin: 10 + anchors.top: parent.top + anchors.left: selector.right + anchors.right: parent.right + anchors.bottom: parent.bottom + clip: true + spacing: 5 + model: root.slot.parametersModel + orientation: ListView.Horizontal + + delegate: Item { + id: parameter + + property int number: index + 1 + // TODO: Use null coalescing when we switch to Qt >= 5.15 + property string label: shortName ? shortName : name + property string key: controlKey + property bool isButton: controlHint > 0 && controlHint == 6 + property bool isKnob: controlHint > 0 && controlHint < 6 + + width: 50 + height: 50 + + EmbeddedText { + anchors.fill: parent + verticalAlignment: Text.AlignBottom + text: parameter.label + font.bold: false + } + + Skin.ControlMiniKnob { + id: parameterKnob + + width: 30 + height: 30 + anchors.centerIn: parent + arcStart: 0 + group: root.group + key: parameter.key + color: Theme.effectColor + visible: parameter.isKnob + + Mixxx.ControlProxy { + id: parameterLoadedControl + + property bool loaded: value != 0 + + group: root.group + key: parameter.key + "_loaded" + } + + } + + Skin.ControlButton { + id: buttonParameterButton + + height: 22 + width: parent.width + anchors.centerIn: parent + group: root.group + key: parameter.key + activeColor: Theme.effectColor + visible: parameter.isButton + toggleable: true + text: "ON" + + Mixxx.ControlProxy { + id: buttonParameterLoadedControl + + property bool loaded: value != 0 + + group: root.group + key: parameter.key + "_loaded" + } + + } + + } + + populate: Transition { + NumberAnimation { + property: "opacity" + from: 0 + to: 1 + duration: 200 + } + + NumberAnimation { + property: "scale" + from: 0 + to: 1 + duration: 200 + } + + } + + Skin.FadeBehavior on opacity { + fadeTarget: parametersView + } + + } + +} diff --git a/res/skins/QMLDemo/EffectUnit.qml b/res/skins/QMLDemo/EffectUnit.qml index 02b89d26d2a..4cab128f49c 100644 --- a/res/skins/QMLDemo/EffectUnit.qml +++ b/res/skins/QMLDemo/EffectUnit.qml @@ -1,75 +1,119 @@ import "." as Skin +import Mixxx 0.1 as Mixxx import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.12 import "Theme" Item { + id: root + property int unitNumber // required - Skin.SectionBackground { - anchors.fill: parent - } + implicitHeight: effectContainer.height - RowLayout { + Item { + id: effectContainer + + anchors.margins: 5 anchors.left: parent.left anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.right: effectSuperKnobFrame.left - anchors.rightMargin: 5 + anchors.right: effectUnitControlsFrame.left + height: 60 + + EffectSlot { + id: effect1 + + anchors.top: parent.top + anchors.left: parent.left + width: parent.width / 3 + unitNumber: root.unitNumber + effectNumber: 1 + expanded: false + } - Repeater { - model: 3 + EffectSlot { + id: effect2 - Item { - id: effect - - property string group: "[EffectRack1_EffectUnit" + unitNumber + "_Effect" + (index + 1) + "]" - - height: 50 - Layout.fillWidth: true - - Skin.ControlButton { - id: effectEnableButton - - anchors.left: parent.left - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.margins: 5 - width: 40 - group: effect.group - key: "enabled" - toggleable: true - text: "ON" - activeColor: Theme.effectColor - } + anchors.top: parent.top + anchors.left: effect1.right + width: parent.width / 3 + unitNumber: root.unitNumber + effectNumber: 2 + expanded: false + } - Skin.ComboBox { - id: effectSelector + EffectSlot { + id: effect3 - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.left: effectEnableButton.right - anchors.right: effectMetaKnob.left - anchors.margins: 5 - // TODO: Add a way to retrieve effect names here - model: ["---", "Effect 1", "Effect 2", "Effect 3", "Effect 4"] - } + anchors.top: parent.top + anchors.left: effect2.right + width: parent.width / 3 + unitNumber: root.unitNumber + effectNumber: 3 + expanded: false + } - Skin.ControlMiniKnob { - id: effectMetaKnob - - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.margins: 5 - arcStart: 0 - width: 40 - group: effect.group - key: "meta" - color: Theme.effectColor - } + states: State { + when: expandButton.checked + name: "expanded" + + AnchorChanges { + target: effect1 + anchors.left: effectContainer.left + } + + AnchorChanges { + target: effect2 + anchors.left: effectContainer.left + anchors.top: effect1.bottom + } + + AnchorChanges { + target: effect3 + anchors.left: effectContainer.left + anchors.top: effect2.bottom + } + + PropertyChanges { + target: effect1 + width: parent.width + expanded: true + } + + PropertyChanges { + target: effect2 + width: parent.width + expanded: true + } + + PropertyChanges { + target: effect3 + width: parent.width + expanded: true + } + + PropertyChanges { + target: effectContainer + height: 160 + } + + PropertyChanges { + target: superKnob + visible: true + } + + PropertyChanges { + target: dryWetKnob + visible: true + } + + } + transitions: Transition { + AnchorAnimation { + targets: [effect1, effect2, effect3] + duration: 150 } } @@ -77,26 +121,90 @@ Item { } Rectangle { - id: effectSuperKnobFrame + id: effectUnitControlsFrame anchors.margins: 5 anchors.right: parent.right anchors.top: parent.top anchors.bottom: parent.bottom - width: height + width: effectUnitControls.width color: Theme.knobBackgroundColor radius: 5 - Skin.ControlKnob { - id: effectSuperKnob + Column { + id: effectUnitControls + + anchors.top: parent.top + anchors.right: parent.right + padding: 5 + spacing: 10 + + Item { + width: 40 + height: width + + Skin.Button { + id: expandButton + + anchors.fill: parent + activeColor: Theme.effectUnitColor + text: "▼" + checkable: true + } + + } + + Skin.ControlKnob { + id: superKnob + + height: 40 + width: height + arcStart: Knob.ArcStart.Minimum + group: "[EffectRack1_EffectUnit" + unitNumber + "]" + key: "super1" + color: Theme.effectUnitColor + visible: false + + Skin.FadeBehavior on visible { + fadeTarget: superKnob + } + + } + + Skin.ControlKnob { + id: dryWetKnob + + height: 40 + width: height + arcStart: Knob.ArcStart.Minimum + group: "[EffectRack1_EffectUnit" + unitNumber + "]" + key: "mix" + color: Theme.effectUnitColor + visible: false + + Skin.FadeBehavior on visible { + fadeTarget: dryWetKnob + } + + } + + add: Transition { + NumberAnimation { + property: "opacity" + from: 0 + to: 1 + duration: 150 + } + + NumberAnimation { + property: "scale" + from: 0 + to: 1 + duration: 150 + } + + } - anchors.centerIn: parent - width: 48 - height: 48 - arcStart: 0 - group: "[EffectRack1_EffectUnit" + unitNumber + "]" - key: "super1" - color: Theme.effectUnitColor } } diff --git a/res/skins/QMLDemo/Knob.qml b/res/skins/QMLDemo/Knob.qml index e139dfd2848..8405716bb08 100644 --- a/res/skins/QMLDemo/Knob.qml +++ b/res/skins/QMLDemo/Knob.qml @@ -6,6 +6,8 @@ MixxxControls.Knob { id: root property color color // required + property url shadowSource: Theme.imgKnobShadow + property url backgroundSource: Theme.imgKnob implicitWidth: background.width implicitHeight: implicitWidth @@ -24,7 +26,7 @@ MixxxControls.Knob { anchors.right: parent.right height: width * 7 / 6 fillMode: Image.PreserveAspectFit - source: Theme.imgKnobShadow + source: root.shadowSource } background: Image { @@ -34,12 +36,10 @@ MixxxControls.Knob { anchors.left: parent.left anchors.right: parent.right height: width - source: Theme.imgKnob + source: root.backgroundSource } foreground: Item { - id: inidicator - anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right @@ -47,8 +47,8 @@ MixxxControls.Knob { Rectangle { anchors.horizontalCenter: parent.horizontalCenter - width: root.width / 30 - height: 10 + width: 2 + height: root.width / 5 y: height color: root.color } diff --git a/res/skins/QMLDemo/Library.qml b/res/skins/QMLDemo/Library.qml index f8437c5813f..1fe9921102d 100644 --- a/res/skins/QMLDemo/Library.qml +++ b/res/skins/QMLDemo/Library.qml @@ -1,5 +1,5 @@ import "." as Skin -import Qt.labs.qmlmodels 1.0 +import Mixxx 0.1 as Mixxx import QtQuick 2.12 import QtQuick.Controls 1.4 import "Theme" @@ -9,12 +9,81 @@ Item { color: Theme.deckBackgroundColor anchors.fill: parent - Text { - text: "Library Placeholder" - font.family: Theme.fontFamily - font.pixelSize: Theme.textFontPixelSize - color: Theme.deckTextColor - anchors.centerIn: parent + TreeView { + id: sidebar + + anchors.top: parent.top + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.margins: 10 + width: 250 + model: Mixxx.Library.getSidebarModel() + + TableViewColumn { + title: "Icon" + role: "iconName" + width: 50 + + delegate: Image { + fillMode: Image.PreserveAspectFit + source: styleData.value ? "qrc:///images/library/ic_library_" + styleData.value + ".svg" : "" + } + + } + + TableViewColumn { + title: "Title" + role: "display" + } + + } + + ListView { + anchors.top: parent.top + anchors.left: sidebar.right + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: 10 + clip: true + model: Mixxx.Library.model + + delegate: Item { + id: itemDelegate + + implicitWidth: 300 + implicitHeight: 30 + + Text { + anchors.fill: parent + text: artist + " - " + title + color: Theme.deckTextColor + } + + Image { + id: dragItem + + Drag.active: dragArea.drag.active + Drag.dragType: Drag.Automatic + Drag.supportedActions: Qt.CopyAction + Drag.mimeData: { + "text/uri-list": fileUrl, + "text/plain": fileUrl + } + anchors.fill: parent + } + + MouseArea { + id: dragArea + + anchors.fill: parent + drag.target: dragItem + onPressed: parent.grabToImage((result) => { + dragItem.Drag.imageSource = result.url; + }) + } + + } + } } diff --git a/res/skins/QMLDemo/MicrophoneUnit.qml b/res/skins/QMLDemo/MicrophoneUnit.qml index aef83afb799..5a610fc86cc 100644 --- a/res/skins/QMLDemo/MicrophoneUnit.qml +++ b/res/skins/QMLDemo/MicrophoneUnit.qml @@ -35,7 +35,7 @@ Row { anchors.centerIn: parent width: 48 height: width - arcStart: 0 + arcStart: Knob.ArcStart.Minimum group: root.group key: "pregain" color: Theme.gainKnobColor diff --git a/res/skins/QMLDemo/MiniKnob.qml b/res/skins/QMLDemo/MiniKnob.qml index b55bbc411bf..7fce622df66 100644 --- a/res/skins/QMLDemo/MiniKnob.qml +++ b/res/skins/QMLDemo/MiniKnob.qml @@ -1,56 +1,9 @@ -import Mixxx.Controls 0.1 as MixxxControls -import QtQuick 2.12 +import "." as Skin import "Theme" -MixxxControls.Knob { +Skin.Knob { id: root - property color color // required - - implicitWidth: background.width - implicitHeight: implicitWidth - arc: true - arcRadius: width * 0.45 - arcOffsetY: width * 0.01 - arcColor: root.color - arcWidth: 2 - angle: 116 - - Image { - id: shadow - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - height: width * 7 / 6 - fillMode: Image.PreserveAspectFit - source: Theme.imgKnobMiniShadow - } - - background: Image { - id: background - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - height: width - source: Theme.imgKnobMini - } - - foreground: Item { - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - height: width - - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - width: root.width / 30 - height: 10 - y: height - color: root.color - } - - } - + shadowSource: Theme.imgKnobMiniShadow + backgroundSource: Theme.imgKnobMini } diff --git a/res/skins/QMLDemo/Mixxx/Controls/Knob.qml b/res/skins/QMLDemo/Mixxx/Controls/Knob.qml index 303ef760774..aa986b02ecc 100644 --- a/res/skins/QMLDemo/Mixxx/Controls/Knob.qml +++ b/res/skins/QMLDemo/Mixxx/Controls/Knob.qml @@ -6,6 +6,12 @@ import QtQuick.Shapes 1.12 Item { id: root + enum ArcStart { + Minimum, + Center, + Maximum + } + property real value: min property alias background: background.data property alias foreground: foreground.data @@ -14,8 +20,18 @@ Item { property real wheelStepSize: (root.max - root.min) / 10 property real angle: 130 property bool arc: false + property int arcStart: Knob.Center property real arcRadius: width / 2 - property real arcStart: (max - min) / 2 + readonly property real arcStartValue: { + switch (arcStart) { + case Knob.ArcStart.Minimum: + return min; + case Knob.ArcStart.Maximum: + return max; + default: + return valueCenter; + } + } property real arcOffsetX: 0 property real arcOffsetY: 0 property alias arcColor: arcPath.strokeColor @@ -56,8 +72,8 @@ Item { fillColor: "transparent" PathAngleArc { - startAngle: root.angleFrom(root.arcStart - root.valueCenter) - 90 - sweepAngle: root.angleFrom(root.value - root.arcStart) + startAngle: root.angleFrom(root.arcStartValue - root.valueCenter) - 90 + sweepAngle: root.angleFrom(root.value - root.arcStartValue) radiusX: root.arcRadius radiusY: root.arcRadius centerX: root.width / 2 + root.arcOffsetX diff --git a/res/skins/QMLDemo/Mixxx/PlayerDropArea.qml b/res/skins/QMLDemo/Mixxx/PlayerDropArea.qml index 53a81a93161..af6e85bd79b 100644 --- a/res/skins/QMLDemo/Mixxx/PlayerDropArea.qml +++ b/res/skins/QMLDemo/Mixxx/PlayerDropArea.qml @@ -7,10 +7,23 @@ DropArea { property var player: Mixxx.PlayerManager.getPlayer(group) onDropped: { + if (drop.formats.includes("mixxx/player")) { + const sourceGroup = drop.getDataAsString("mixxx/player"); + // Prevent dropping a deck onto itself + if (sourceGroup != this.group) + return ; + + console.log("Drag from group " + sourceGroup); + player.cloneFromGroup(sourceGroup); + drop.accepted = true; + return ; + } if (drop.hasUrls) { let url = drop.urls[0]; console.log("Dropped URL '" + url + "' on deck " + group); player.loadTrackFromLocationUrl(url); + drop.accepted = true; + return ; } } } diff --git a/res/skins/QMLDemo/Sampler.qml b/res/skins/QMLDemo/Sampler.qml index ca56973c389..7d4460ed372 100644 --- a/res/skins/QMLDemo/Sampler.qml +++ b/res/skins/QMLDemo/Sampler.qml @@ -21,6 +21,26 @@ Rectangle { return Qt.darker(root.deckPlayer.color, 2); } implicitHeight: gainKnob.height + 10 + Drag.active: dragArea.drag.active + Drag.dragType: Drag.Automatic + Drag.supportedActions: Qt.CopyAction + Drag.mimeData: { + let data = { + "mixxx/player": group + }; + const trackLocationUrl = deckPlayer.trackLocationUrl; + if (trackLocationUrl) + data["text/uri-list"] = trackLocationUrl; + + return data; + } + + MouseArea { + id: dragArea + + anchors.fill: root + drag.target: root + } Skin.SectionBackground { anchors.fill: parent diff --git a/res/skins/QMLDemo/SyncButton.qml b/res/skins/QMLDemo/SyncButton.qml new file mode 100644 index 00000000000..b3aec256dd0 --- /dev/null +++ b/res/skins/QMLDemo/SyncButton.qml @@ -0,0 +1,70 @@ +import "." as Skin +import Mixxx 0.1 as Mixxx +import "Theme" + +Skin.Button { + id: root + + enum SyncMode { + Off, + Follower, + ImplicitLeader, + ExplicitLeader + } + + property string group // required + property alias mode: modeControl.value + + function toggleSync() { + enabledControl.value = !enabledControl.value; + } + + function toggleLeader() { + leaderControl.value = !leaderControl.value; + } + + activeColor: { + switch (mode) { + case SyncButton.SyncMode.ImplicitLeader: + return Theme.yellow; + case SyncButton.SyncMode.ExplicitLeader: + return Theme.red; + default: + return Theme.deckActiveColor; + } + } + text: { + switch (mode) { + case SyncButton.SyncMode.ImplicitLeader: + case SyncButton.SyncMode.ExplicitLeader: + return "Leader"; + default: + return "Sync"; + } + } + highlight: enabledControl.value + onClicked: toggleSync() + onPressAndHold: toggleLeader() + + Mixxx.ControlProxy { + id: enabledControl + + group: root.group + key: "sync_enabled" + } + + Mixxx.ControlProxy { + id: modeControl + + group: root.group + key: "sync_mode" + } + + Mixxx.ControlProxy { + id: leaderControl + + group: root.group + key: "sync_master" + } + +} diff --git a/res/skins/Tango (64 Samplers)/skin.xml b/res/skins/Tango (64 Samplers)/skin.xml index 97737e1cd3a..9312221172d 100644 --- a/res/skins/Tango (64 Samplers)/skin.xml +++ b/res/skins/Tango (64 Samplers)/skin.xml @@ -68,7 +68,7 @@ 0 1 0 - 0 + 1 1 0 diff --git a/res/skins/Tango/skin.xml b/res/skins/Tango/skin.xml index 911a5886250..fbdf04e53f0 100644 --- a/res/skins/Tango/skin.xml +++ b/res/skins/Tango/skin.xml @@ -68,7 +68,7 @@ 0 1 0 - 0 + 1 1 0 diff --git a/res/skins/default-menu-styles-linux.qss b/res/skins/default-menu-styles-linux.qss index e014dbe17e2..961cfb51abe 100644 --- a/res/skins/default-menu-styles-linux.qss +++ b/res/skins/default-menu-styles-linux.qss @@ -12,7 +12,7 @@ but we now have space for the checkbox */ margin: 0em 0em 0em 1.3em; } - /* Checkbox preceeding menu items */ + /* Checkbox preceding menu items */ #MainMenu QMenu::indicator { /*width: 1em;*/ /*height: 1em;*/ diff --git a/res/skins/default-menu-styles-windows.qss b/res/skins/default-menu-styles-windows.qss index d3d84a3d638..f70f8cfb5d2 100644 --- a/res/skins/default-menu-styles-windows.qss +++ b/res/skins/default-menu-styles-windows.qss @@ -12,7 +12,7 @@ but we now have space for the checkbox */ margin: 0em 0em 0em 1.2em; } - /* Checkbox preceeding menu items */ + /* Checkbox preceding menu items */ #MainMenu QMenu::indicator { /*width: 1em;*/ /*height: 1em;*/ diff --git a/res/skins/default.qss b/res/skins/default.qss index e7090c3cf69..2d32985e916 100644 --- a/res/skins/default.qss +++ b/res/skins/default.qss @@ -91,7 +91,7 @@ WOverview #PassthroughLabel { /* Lay out all context menus and the track table header with relative sizes, adjusting to the system-chosen font (size). Same is done for the Played checkedbox and the BPM lock icon in the library above. -Appearantly, the mainmenubar needs special treatment -- see default-menu-styles-linux7windows.qss */ +Apparently, the mainmenubar needs special treatment -- see default-menu-styles-linux7windows.qss */ QToolTip, #MainMenu QMenu, WLibrarySidebar QMenu, diff --git a/res/translations/mixxx.ts b/res/translations/mixxx.ts index f8025f49eaa..c6eeb644a68 100644 --- a/res/translations/mixxx.ts +++ b/res/translations/mixxx.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3442,12 +3442,12 @@ - + Official Website - + Donate @@ -5568,37 +5568,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6892,17 +6892,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8771,33 +8771,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10179,27 +10177,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock - + Lock @@ -10353,47 +10351,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14229,22 +14227,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14252,52 +14250,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14307,17 +14305,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14325,52 +14323,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14571,4 +14569,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + diff --git a/res/translations/mixxx_ar.qm b/res/translations/mixxx_ar.qm index 113bfe40a54..0b0ee5166a5 100644 Binary files a/res/translations/mixxx_ar.qm and b/res/translations/mixxx_ar.qm differ diff --git a/res/translations/mixxx_ar.ts b/res/translations/mixxx_ar.ts index 68e45f95545..1df78de1e7b 100644 --- a/res/translations/mixxx_ar.ts +++ b/res/translations/mixxx_ar.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. لا يمكنك تحميل المقطع @@ -403,12 +403,12 @@ BroadcastManager - + Action failed محاولة فاشلة - + Please enable at least one connection to use Live Broadcasting. برجاء تشغيل وصله واحده علي الاقل لاستخدام البث المباشر @@ -3442,12 +3442,12 @@ - + Official Website - + Donate @@ -5568,37 +5568,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6892,17 +6892,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8771,33 +8771,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10179,27 +10177,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock فك القفل - + Lock أقفِل @@ -10353,47 +10351,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14169,22 +14167,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14192,52 +14190,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14247,17 +14245,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14265,52 +14263,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14511,4 +14509,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_ast.qm b/res/translations/mixxx_ast.qm index 297aeb1344c..db050260a94 100644 Binary files a/res/translations/mixxx_ast.qm and b/res/translations/mixxx_ast.qm differ diff --git a/res/translations/mixxx_ast.ts b/res/translations/mixxx_ast.ts index 3bb3803cbf6..75375632e8c 100644 --- a/res/translations/mixxx_ast.ts +++ b/res/translations/mixxx_ast.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Nun se pudo cargar la pista. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? Codificador - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Desbloquiar - + Lock Bloquiar @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Escueyi'l direutoriu de biblioteca de música - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_bg.qm b/res/translations/mixxx_bg.qm index 1b72a061fef..adb6eff5f79 100644 Binary files a/res/translations/mixxx_bg.qm and b/res/translations/mixxx_bg.qm differ diff --git a/res/translations/mixxx_bg.ts b/res/translations/mixxx_bg.ts index ba7549e2c7e..e9d7841912f 100644 --- a/res/translations/mixxx_bg.ts +++ b/res/translations/mixxx_bg.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Песента не може да бъде заредена. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed Неуспешно действие - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ Програмисти от стари версии - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information Информация - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8771,33 +8771,31 @@ Do you want to scan your library for cover files now? Кодек - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10179,27 +10177,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Отключване - + Lock Заключване @@ -10353,47 +10351,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. Моля проверете Интернет връзката си и дали името и паролата ви са верни. @@ -14169,22 +14167,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14192,52 +14190,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14247,17 +14245,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14265,52 +14263,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Изберете папка за музикалната библиотека - + controllers - + Cannot open database Не може да се отвори базата данни - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14514,4 +14512,12 @@ Mixxx се нуждае от QT с поддръжка за SQLite. Молже п + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_br.qm b/res/translations/mixxx_br.qm index 5e765d58a37..3ead64e99e0 100644 Binary files a/res/translations/mixxx_br.qm and b/res/translations/mixxx_br.qm differ diff --git a/res/translations/mixxx_br.ts b/res/translations/mixxx_br.ts index 94d6b969e72..a10ca713b67 100644 --- a/res/translations/mixxx_br.ts +++ b/res/translations/mixxx_br.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock - + Lock @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_bs.qm b/res/translations/mixxx_bs.qm index 4008a4d8f88..8836db8aaaf 100644 Binary files a/res/translations/mixxx_bs.qm and b/res/translations/mixxx_bs.qm differ diff --git a/res/translations/mixxx_bs.ts b/res/translations/mixxx_bs.ts index c7f9a6c53be..9dc5f2608dc 100644 --- a/res/translations/mixxx_bs.ts +++ b/res/translations/mixxx_bs.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Nije u mogućnosti pustiti pjesmu. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Otključaj - + Lock Zaključaj @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_ca.qm b/res/translations/mixxx_ca.qm index e68febd9dc6..1995e4f1700 100644 Binary files a/res/translations/mixxx_ca.qm and b/res/translations/mixxx_ca.qm differ diff --git a/res/translations/mixxx_ca.ts b/res/translations/mixxx_ca.ts index 15ee6f4221c..6f626314fc5 100644 --- a/res/translations/mixxx_ca.ts +++ b/res/translations/mixxx_ca.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. No s'ha pogut carregar la pista. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed La acció ha fallat - + Please enable at least one connection to use Live Broadcasting. Si us plau, activa almenys una font per a utilitzar la retransmissió en directe. @@ -3442,12 +3442,12 @@ Antics Contribuidors - + Official Website - + Donate @@ -5623,37 +5623,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. La mida mínima de l'aparenca és més gran que la resolució de la vostra pantalla - + Allow screensaver to run Permet que s'activi l'estalvi de pantalla - + Prevent screensaver from running Evita que s'activi l'estalvi de pantalla - + Prevent screensaver while playing Evita l'estalvi de pantalla mentre reprodueix - + This skin does not support color schemes Aquesta aparença no suporta els esquemes de colors - + Information Informació - + Mixxx must be restarted before the new locale setting will take effect. Reinicieu el Mixxx per aplicar els canvis de llengua. @@ -6949,17 +6949,17 @@ El valor desitjat és aproximat i assumeix que els pre-guanys i el volum de sort RGB - + OpenGL not available OpenGL no està disponible - + dropped frames fotogrames descartats - + Cached waveforms occupy %1 MiB on disk. La memòria cau dels gràfics d'ona ocupa %1 MiB en disc. @@ -8842,39 +8842,31 @@ Voleu escanejar ara la biblioteca cercant les caràtules? Codificador - + Mixxx Needs Access to: %1 El Mixxx necessita accés a: %1 - - Due to Mac Sandboxing, we need your permission to access this file: - -%1 - -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - Degut a l'execució en "Sandbox" en els Mac, necessitem el vostre permis per a accedir a aquest fitxer: + + Your permission is required to access the following location: %1 -Un cop feu clic a Accepta, podreu veure el selector de fitxers. Per a donar permisos a Mixxx, hey de seleccionar '%2' per a seguir. Si no voleu donar-li permissos, feu clic a Cancel·la al selector de fitxers. Demanem disculpes per aquest inconvenient. - -Per descartar aquesta acció, premeu Cancel·la. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. Heu seleccionat el fitxer equivocat. Per permetre acccés al Mixxx, heu de seleccionar l'arxiu '%1'. Si no voleu continuar, premeu Cancel·la - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10282,27 +10274,27 @@ Tot a la dreta: Al final del període SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Historial - + Unlock Permet els canvis - + Lock Bloca els canvis @@ -10456,47 +10448,47 @@ Tot a la dreta: Al final del període Memòria cau de xarxa excedida - + Connection error Error de connexió - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> Una de les fonts de retransmissió en directe ha provocat aquest error:<br><b>Error amb la font '%1':</b><br> - + Connection message Missatge de connexió - + <b>Message from Live Broadcasting connection '%1':</b><br> <b>Missatge de la font de retransmissió en directe '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. S'ha perdut la connexió al servidor d'emissió i han fallat %1 dels reintent de reconnexió. - + Lost connection to streaming server. S'ha perdut la connexió al servidor d'emissió. - + Please check your connection to the Internet. Per favor, comproveu la connexió cap a internet. - + Can't connect to streaming server No s'ha pogut connectar al servidor d'emissió - + Please check your connection to the Internet and verify that your username and password are correct. Per favor, comproveu la connexió cap a Internet i verifiqueu que el nom d'usuari i la contrasenya són correctes. @@ -14274,22 +14266,22 @@ Ho pots utilitzar per canviar només la senyal processada amb EQs i efectes de f WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) (GLSL ES) - + (GL ES) (GL ES) @@ -14297,52 +14289,52 @@ Ho pots utilitzar per canviar només la senyal processada amb EQs i efectes de f main - + Starts Mixxx in full-screen mode Inicia el Mixxx el el mode de pantalla sencera - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. Directori inicial on el Mixxx cerca els fixers de recursos, com les configuracions MIDI. Permet utilitzar una ubicació diferent a la de per defecte. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14352,17 +14344,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14370,52 +14362,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks reproductors - + library - + Choose music library directory Seleccioneu la carpeta de la biblioteca de música. - + controllers - + Cannot open database No es pot obrir la base de dades - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14619,4 +14611,12 @@ Feu click a Acceptar per sortir. Sense accés a la xarxa + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_ca_ES.qm b/res/translations/mixxx_ca_ES.qm index ba6f285ac53..4ca69fb3688 100644 Binary files a/res/translations/mixxx_ca_ES.qm and b/res/translations/mixxx_ca_ES.qm differ diff --git a/res/translations/mixxx_ca_ES.ts b/res/translations/mixxx_ca_ES.ts index 84e2e68c196..a7f00bc3db0 100644 --- a/res/translations/mixxx_ca_ES.ts +++ b/res/translations/mixxx_ca_ES.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. No s'ha pogut carregar la pista. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed La acció ha fallat - + Please enable at least one connection to use Live Broadcasting. Si us plau, activa almenys una font per a utilitzar la retransmissió en directe. @@ -3442,12 +3442,12 @@ Antics contribuidors - + Official Website - + Donate @@ -5594,37 +5594,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. La mida mínima de l'aparenca és més gran que la resolució de la vostra pantalla - + Allow screensaver to run Permet que s'activi l'estalvi de pantalla - + Prevent screensaver from running Evita que s'activi l'estalvi de pantalla - + Prevent screensaver while playing Evita l'estalvi de pantalla mentre reprodueix - + This skin does not support color schemes Aquesta aparença no suporta els esquemes de colors - + Information Informació - + Mixxx must be restarted before the new locale setting will take effect. Reinicieu el Mixxx per aplicar els canvis de llengua. @@ -6920,17 +6920,17 @@ El valor desitjat és aproximat i assumeix que els pre-guanys i el volum de sort RGB - + OpenGL not available OpenGL no està disponible - + dropped frames fotogrames descartats - + Cached waveforms occupy %1 MiB on disk. La memòria cau dels gràfics d'ona ocupa %1 MiB en disc. @@ -8808,39 +8808,31 @@ Voleu escanejar ara la biblioteca cercant les caràtules? Codificador - + Mixxx Needs Access to: %1 El Mixxx necessita accés a: %1 - - Due to Mac Sandboxing, we need your permission to access this file: - -%1 - -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - Degut a l'execució en "Sandbox" en els Mac, necessitem el vostre permis per a accedir a aquest fitxer: + + Your permission is required to access the following location: %1 -Un cop feu clic a Accepta, podreu veure el selector de fitxers. Per a donar permisos a Mixxx, hey de seleccionar '%2' per a seguir. Si no voleu donar-li permissos, feu clic a Cancel·la al selector de fitxers. Demanem disculpes per aquest inconvenient. - -Per descartar aquesta acció, premeu Cancel·la. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. Heu seleccionat el fitxer equivocat. Per permetre acccés al Mixxx, heu de seleccionar l'arxiu '%1'. Si no voleu continuar, premeu Cancel·la - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10248,27 +10240,27 @@ Tot a la dreta: Al final del període SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Historial - + Unlock Permet els canvis - + Lock Bloca els canvis @@ -10422,47 +10414,47 @@ Tot a la dreta: Al final del període Memòria cau de xarxa excedida - + Connection error Error de connexió - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> Una de les fonts de retransmissió en directe ha provocat aquest error:<br><b>Error amb la font '%1':</b><br> - + Connection message Missatge de connexió - + <b>Message from Live Broadcasting connection '%1':</b><br> <b>Missatge de la font de retransmissió en directe '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. S'ha perdut la connexió al servidor d'emissió i han fallat %1 dels reintent de reconnexió. - + Lost connection to streaming server. S'ha perdut la connexió al servidor d'emissió. - + Please check your connection to the Internet. Per favor, comproveu la connexió cap a internet. - + Can't connect to streaming server No s'ha pogut connectar al servidor d'emissió - + Please check your connection to the Internet and verify that your username and password are correct. Per favor, comproveu la connexió cap a Internet i verifiqueu que el nom d'usuari i la contrasenya són correctes. @@ -14240,22 +14232,22 @@ Ho pots utilitzar per canviar només la senyal processada amb EQs i efectes de f WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14263,52 +14255,52 @@ Ho pots utilitzar per canviar només la senyal processada amb EQs i efectes de f main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14318,17 +14310,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14336,52 +14328,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Seleccioneu la carpeta de la biblioteca de música. - + controllers - + Cannot open database No es pot obrir la base de dades - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14585,4 +14577,12 @@ Feu click a Acceptar per sortir. Sense accés a la xarxa + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_cs.qm b/res/translations/mixxx_cs.qm index 1e86320e821..9e1cea9c841 100644 Binary files a/res/translations/mixxx_cs.qm and b/res/translations/mixxx_cs.qm differ diff --git a/res/translations/mixxx_cs.ts b/res/translations/mixxx_cs.ts index 935767037a9..f64d340a687 100644 --- a/res/translations/mixxx_cs.ts +++ b/res/translations/mixxx_cs.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Nepodařilo se nahrát skladbu. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Činnost se nezdařila - + Please enable at least one connection to use Live Broadcasting. Povolte, prosím, alespoň jedno spojení pro použití živého vysílání @@ -3442,12 +3442,12 @@ Přispěvatelé v minulosti - + Official Website - + Donate @@ -5595,37 +5595,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. Nejmenší velikost vybraného vzhledu je větší než rozlišení vaší obrazovky. - + Allow screensaver to run Povolit běh spořiče obrazovky - + Prevent screensaver from running Zabránit spořiči obrazovky v běhu - + Prevent screensaver while playing Zabránit spořiči obrazovky v běhu během přehrávání - + This skin does not support color schemes Tento vzhled nepodporuje barevná schémata - + Information Informace - + Mixxx must be restarted before the new locale setting will take effect. Předtím než se změny projeví, bude se muset Mixxx spustit znovu. @@ -6923,17 +6923,17 @@ Kompenzace pro přizpůsobení načasování mikrofonu. RGB - + OpenGL not available OpenGL není dostupné - + dropped frames upuštěné snímky - + Cached waveforms occupy %1 MiB on disk. Průběhové křivky uložené do vyrovnávací paměti zabírají %1 MiB místa na disku. @@ -8813,39 +8813,31 @@ Chcete nyní kvůli souborům s obaly prohledat knihovnu? Kodér - + Mixxx Needs Access to: %1 Mixxx potřebuje přístup k: %1 - - Due to Mac Sandboxing, we need your permission to access this file: - -%1 - -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - Kvůli Mac OS X-Sandbox jsou pro tyto soubory potřeba vaše přístupová oprávnění: + + Your permission is required to access the following location: %1 -Po klepnutí na OK uvidíte výběr souborů. Pro udělení přístupových oprávnění Mixxxu a pokračování, musíte vybrat '%2'. Když Mixxxu žádná přístupová oprávnění poskytnout nechcete, klepněte na výběr souborů a na Zrušit. Omlouváme se za tuto nepříjemnost. - -Pro zrušení této činnosti, stiskněte Zrušit v souborovém dialogu. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. Vybral jste nesprávný soubor. Pro poskytnutí přístupového oprávnění Mixxxu, vyberte soubor '%1'. Pokud nechcete pokračovat, klepněte na Zrušit. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10234,27 +10226,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Historie - + Unlock Odemknout - + Lock Zamknout @@ -10408,47 +10400,47 @@ Fully right: end of the effect period Přetečení vyrovnávací paměti sítě - + Connection error Chyba spojení - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message Zpráva o spojení - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. Ztraceno spojení s vysílacím serverem a %1 pokus o opětovné připojení se nezdařil - + Lost connection to streaming server. Ztraceno spojení s vysílacím serverem. - + Please check your connection to the Internet. Zkontrolujte, prosím, vaše připojení k internetu. - + Can't connect to streaming server Nelze vytvořit spojení s vysílacím serverem - + Please check your connection to the Internet and verify that your username and password are correct. Zkontrolujte, prosím, vaše připojení k internetu a ověřte, jestli je správně zadáno uživatelské jméno a heslo. @@ -14224,22 +14216,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) (GLSL ES) - + (GL ES) (GL ES) @@ -14247,52 +14239,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14302,17 +14294,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14320,52 +14312,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks Přehrávače - + library - + Choose music library directory Vybrat adresář s hudební knihovnou - + controllers - + Cannot open database Nelze otevřít databázi - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14569,4 +14561,12 @@ Stiskněte OK pro ukončení. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_da.qm b/res/translations/mixxx_da.qm index faf99104906..addb7d7ec3d 100644 Binary files a/res/translations/mixxx_da.qm and b/res/translations/mixxx_da.qm differ diff --git a/res/translations/mixxx_da.ts b/res/translations/mixxx_da.ts index a78e6ac7603..de35b6e40c1 100644 --- a/res/translations/mixxx_da.ts +++ b/res/translations/mixxx_da.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Kunne ikke læse spor. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed Handlingen fejlede - + Please enable at least one connection to use Live Broadcasting. Mindst en forbindelse skal være aktiv for sende live @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Lås op - + Lock Lås @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_de-DE.qm b/res/translations/mixxx_de-DE.qm index f8d8bdb7577..e17ec93a072 100644 Binary files a/res/translations/mixxx_de-DE.qm and b/res/translations/mixxx_de-DE.qm differ diff --git a/res/translations/mixxx_de.qm b/res/translations/mixxx_de.qm index e0c06e91d09..dc8e10c4eba 100644 Binary files a/res/translations/mixxx_de.qm and b/res/translations/mixxx_de.qm differ diff --git a/res/translations/mixxx_de.ts b/res/translations/mixxx_de.ts index 04f501882d3..7478105aa16 100644 --- a/res/translations/mixxx_de.ts +++ b/res/translations/mixxx_de.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Track konnte nicht geladen werden. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Aktion fehlgeschlagen - + Please enable at least one connection to use Live Broadcasting. Bitte aktivieren Sie mindestens eine Verbindung, um Liveübertragung zu verwenden. @@ -3442,12 +3442,12 @@ Frühere Mitwirkende - + Official Website Offizielle Webseite - + Donate @@ -5630,37 +5630,37 @@ Sie können jederzeit Tracks auf dem Bildschirm ziehen und ablegen, um ein Deck DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. Die minimale Größe des ausgewählten Skins ist größer als Ihre Bildschirmauflösung. - + Allow screensaver to run Bildschirmschoner erlauben - + Prevent screensaver from running Bildschirmschoner unterdrücken - + Prevent screensaver while playing Bildschirmschoner während der Wiedergabe unterdrücken - + This skin does not support color schemes Dieses Skin unterstützt keine Farbschemen - + Information Information - + Mixxx must be restarted before the new locale setting will take effect. Mixxx muss neu gestartet werden, damit die neuen Spracheinstellungen wirksam werden. @@ -6957,17 +6957,17 @@ Die Ziel-Lautheit ist ungefähr und nimmt an das Track-Vorverstärkung und Maste RGB - + OpenGL not available OpenGL nicht verfügbar - + dropped frames ausgelassene Einzelbilder - + Cached waveforms occupy %1 MiB on disk. Zwischengespeicherte Wellenformen belegen %1 MiB auf der Festplatte. @@ -8852,39 +8852,31 @@ Willst du deine Bibliothek jetzt nach Cover-Dateien scannen? Kodierer - + Mixxx Needs Access to: %1 Mixxx benötigt Zugriff auf: %1 - - Due to Mac Sandboxing, we need your permission to access this file: - -%1 - -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - Aufgrund der macOS-Sandboxing benötigen wir Ihre Erlaubnis, um auf diese Datei zuzugreifen: + + Your permission is required to access the following location: %1 -Nach einem Klick auf OK sehen Sie eine Dateiauswahl. Um Mixxx Zugriffsberechtigung zu erteilen und fortzufahren, müssen Sie '%2' auswählen. Wenn Sie Mixxx keinen Zugriff gewähren wollen, klicken Sie in der Dateiauswahl auf Abbrechen. Wir entschuldigen uns für diese Unannehmlichkeit. - -Um diese Aktion abzubrechen, drücken Sie Abbrechen im Datei-Dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. Sie haben die falsche Datei ausgewählt. Um Mixxx Zugriff zu gewähren, wählen Sie die Datei '%1'. Wenn Sie nicht fortfahren möchten, klicken Sie auf Abbrechen. - + Upgrading old Mixxx settings Aktualisieren alter Mixxx-Einstellungen - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10296,27 +10288,27 @@ Ganz rechts: Ende der Effektperiode SetlogFeature - + Join with previous (below) Mit vorherigem verbinden (darunter) - + Finish current and start new Aktuelles beenden und neu beginnen - + History Verlauf - + Unlock Entsperren - + Lock Sperren @@ -10470,47 +10462,47 @@ Ganz rechts: Ende der Effektperiode Netzwerk-Zwischenspeicher-Überlauf - + Connection error Verbindungsfehler - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> Eine der Liveübertragung-Verbindungen hat diesen Fehler ausgelöst:<br><b>Fehler bei Verbindung '%1':</b><br> - + Connection message Verbindungsnachricht - + <b>Message from Live Broadcasting connection '%1':</b><br> <b>Nachricht von Liveübertragung-Verbindung '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. Verbindung zum Streaming-Server verloren, und %1 Versuche erneut zu verbinden sind fehlgeschlagen. - + Lost connection to streaming server. Verbindung zum Streaming-Server verloren. - + Please check your connection to the Internet. Bitte überprüfen Sie die Verbindung zum Internet. - + Can't connect to streaming server Verbindung zum Streaming-Server kann nicht hergestellt werden - + Please check your connection to the Internet and verify that your username and password are correct. Bitte überprüfen Sie die Internetverbindung und vergewissern sich, dass Ihr Benutzername und Kennwort richtig sind. @@ -14288,22 +14280,22 @@ Verwenden Sie diese Option, um nur das verarbeitete (Wet) Signal mit EQ- und Fil WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) (GLSL ES) - + (GL ES) (GL ES) @@ -14311,52 +14303,52 @@ Verwenden Sie diese Option, um nur das verarbeitete (Wet) Signal mit EQ- und Fil main - + Starts Mixxx in full-screen mode Startet Mixxx im Vollbild-Modus - + Use a custom locale for loading translations. (e.g 'fr') Verwenden Sie ein benutzerdefiniertes Gebietsschema für das Laden von Übersetzungen (z.B. 'de') - + Top-level directory where Mixxx should look for settings. Default is: Übergeordnetes Verzeichnis, in dem Mixxx nach Einstellungen suchen soll. Standard ist: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. Übergeordnetes Verzeichnis, in dem Mixxx nach seinen Ressourcendateien wie z. B. MIDI-Mappings suchen soll, wobei der Standard-Installationsort überschrieben wird. - + Path the timeline is written to Pfad, in den die Zeitleiste geschrieben wird - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads Lässt Mixxx alle Controller-Daten, die es empfängt und Skript-Funktionen die es lädt anzeigen/protokollieren - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. Aktiviert den Entwicklermodus. Enthält zusätzliche Protokollinformationen, Statistiken zur Leistung und ein Menü für Entwicklerwerkzeuge. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. Aktiviert den Safe-Modus. Deaktiviert OpenGL-Wellenformen und rotierende Vinyl-Widgets. Versuchen Sie diese Option, wenn Mixxx beim Starten abstürzt. - + [auto|always|never] Use colors on the console output. [auto|always|never] Farbige Konsolenausgabe verwenden. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14371,17 +14363,17 @@ debug - Wie oben + Debug-/Entwicklermeldungen trace - Wie oben + Profiling-Meldungen - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. Legt die Protokollierungsstufe fest, mit welcher der Protokollpuffer in mixxx.log geschrieben wird. LEVEL ist einer der oben unter --logLevel definierten Werte. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. Bricht (SIGINT) Mixxx ab, wenn ein DEBUG_ASSERT zu false ausgewertet wird. Unter einem Debugger können Sie danach fortfahren. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. Lädt die angegebene(n) Musikdatei(en) beim Start. Jede angegebene Datei wird in das nächste virtuelle Deck geladen. @@ -14389,52 +14381,52 @@ trace - Wie oben + Profiling-Meldungen mixxx::CoreServices - + fonts Schriftarten - + database Datenbank - + effects Effekte - + audio interface Audio-Interface - + decks Decks - + library Bibliothek - + Choose music library directory Verzeichnis für die Musikbibliothek auswählen - + controllers Controller - + Cannot open database Kann Datenbank nicht öffnen - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14638,4 +14630,12 @@ Zum Beenden OK drücken. Kein Netzwerkzugriff + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_de_DE.ts b/res/translations/mixxx_de_DE.ts index cc283f1c82f..55c4658052c 100644 --- a/res/translations/mixxx_de_DE.ts +++ b/res/translations/mixxx_de_DE.ts @@ -261,7 +261,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Titel konnte nicht geladen werden. @@ -402,12 +402,12 @@ BroadcastManager - + Action failed Aktion fehlgeschlagen - + Please enable at least one connection to use Live Broadcasting. Aktiviere mindestens eine Verbindung um die Live-Übertragung zu benutzen. @@ -3441,12 +3441,12 @@ Frühere Beitragende - + Official Website - + Donate @@ -5567,37 +5567,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6891,17 +6891,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8770,33 +8770,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10178,27 +10176,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock - + Lock Sperren @@ -10352,47 +10350,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14168,22 +14166,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14191,52 +14189,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14246,17 +14244,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14264,52 +14262,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14510,4 +14508,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_el.qm b/res/translations/mixxx_el.qm index c869d9678ae..40a551bd1af 100644 Binary files a/res/translations/mixxx_el.qm and b/res/translations/mixxx_el.qm differ diff --git a/res/translations/mixxx_el.ts b/res/translations/mixxx_el.ts index dd4e1cd51ac..d361a678506 100644 --- a/res/translations/mixxx_el.ts +++ b/res/translations/mixxx_el.ts @@ -83,7 +83,7 @@ Add to Auto DJ Queue (replace) - + Προσθήκη στη λίστα του Αυτόματου DJ (Αντικατάσταση) @@ -185,7 +185,7 @@ Add to Auto DJ Queue (replace) - + Προσθήκη στη λίστα του Αυτόματου DJ (Αντικατάσταση) @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. H φόρτωση του κομματιού απέτυχε. @@ -302,7 +302,7 @@ Color - + Χρώμα @@ -377,7 +377,7 @@ Samplerate - + Ρυθμός δειγματοληψίας @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Αποτυχία ενέργειας - + Please enable at least one connection to use Live Broadcasting. Παρακαλούμε ενεργοποιήστε τουλάχιστον μία σύνδεση για τη λειτουργία Ζωντανής Μετάδοσης. @@ -418,12 +418,12 @@ Can't use secure password storage: keychain access failed. - + Δεν μπορεί να χρησιμοποιηθεί η αποθήκη κωδικών: Σφάλμα κατά την πρόσβαση στο Keychain Secure password retrieval unsuccessful: keychain access failed. - + Δεν μπορεί να ανακτηθεί ο ασφαλής κωδικός: Σφάλμα κατά την πρόσβαση στο Keychain @@ -670,17 +670,17 @@ The file '%1' could not be found. - + Το αρχείο '%1' δεν βρέθηκε The file '%1' could not be loaded. - + Το αρχείο '%1' δεν ήταν δυνατόν να φορτωθεί. The file '%1' is empty and could not be loaded. - + Το αρχείο '%1' είναι άδειο και δεν ήταν δυνατόν να φορτωθεί. @@ -688,12 +688,12 @@ Remove Color - + Αφαίρεση χρώματος Add Color - + Προσθήκη χρώματος @@ -704,12 +704,12 @@ Remove Palette - + Αφαίρεση παλέττας Color - + Χρώμα @@ -2721,7 +2721,7 @@ Add to Auto DJ Queue (replace) - + Προσθήκη στη λίστα του Αυτόματου DJ (Αντικατάσταση) @@ -3443,12 +3443,12 @@ - + Official Website - + Donate @@ -4351,7 +4351,7 @@ Two source connections to the same server can't have the same mountpoint. Password storage - + Αποθήκη κωδικών @@ -4361,7 +4361,7 @@ Two source connections to the same server can't have the same mountpoint. Secure storage (OS keychain) - + Ασφαλής αποθήκη (Keychain λειτουργικού συστήματος) @@ -4522,7 +4522,7 @@ Two source connections to the same server can't have the same mountpoint. Color - + Χρώμα @@ -5570,37 +5570,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information Πληροφορίες - + Mixxx must be restarted before the new locale setting will take effect. @@ -6894,17 +6894,17 @@ The loudness target is approximate and assumes track pregain and master output l RGB - + OpenGL not available Η OpenGL δεν είναι διαθέσιμη - + dropped frames απορριφθέντα καρέ - + Cached waveforms occupy %1 MiB on disk. @@ -8773,33 +8773,31 @@ Do you want to scan your library for cover files now? Κωδικοποιητής - + Mixxx Needs Access to: %1 Το Mixxx χρειάζεται πρόσβαση σε: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10181,27 +10179,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Ιστορικό - + Unlock Ξεκλείδωμα - + Lock Κλείδωμα @@ -10355,47 +10353,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. Ελέγξτε την σύνδεσή σας στο Internet και επιβεβαιώστε οτι το όνομα χρήστη και ο κωδικός είναι σωστά. @@ -13830,7 +13828,7 @@ Use this to change only the effected (wet) signal with EQ and filter effects. Add to Auto DJ Queue (replace) - + Προσθήκη στη λίστα του Αυτόματου DJ (Αντικατάσταση) @@ -14171,22 +14169,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14194,52 +14192,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14249,17 +14247,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14267,52 +14265,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Επιλογή καταλόγου μουσικής συλλογής - + controllers - + Cannot open database Αδυναμία ανοίγματος της βάσης δεδομένων - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14516,4 +14514,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_el_GR.qm b/res/translations/mixxx_el_GR.qm index 52d830f917c..f4d5498b85c 100644 Binary files a/res/translations/mixxx_el_GR.qm and b/res/translations/mixxx_el_GR.qm differ diff --git a/res/translations/mixxx_el_GR.ts b/res/translations/mixxx_el_GR.ts index 9535e505d21..d492306d933 100644 --- a/res/translations/mixxx_el_GR.ts +++ b/res/translations/mixxx_el_GR.ts @@ -264,7 +264,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Αδύνατο να φόρτωθεί το συγκεκριμένο κομμάτι. @@ -405,12 +405,12 @@ BroadcastManager - + Action failed Αυτή η ενέργεια απέτυχε - + Please enable at least one connection to use Live Broadcasting. Πρέπει να ενεργοποιήσεις τουλάχιστον μια σύνδεση για την επίτευξη Ζωντανης Μετάδοσης. @@ -3445,12 +3445,12 @@ - + Official Website - + Donate @@ -5571,37 +5571,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6895,17 +6895,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8774,33 +8774,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10182,27 +10180,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Ξεκλείδωμα - + Lock Κλείδωμα @@ -10356,47 +10354,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14173,22 +14171,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14196,52 +14194,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14251,17 +14249,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14269,52 +14267,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14515,4 +14513,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_en_GB.qm b/res/translations/mixxx_en_GB.qm index fd84502d447..46ad7d18800 100644 Binary files a/res/translations/mixxx_en_GB.qm and b/res/translations/mixxx_en_GB.qm differ diff --git a/res/translations/mixxx_en_GB.ts b/res/translations/mixxx_en_GB.ts index d39b0d9e5f2..55a2229927c 100644 --- a/res/translations/mixxx_en_GB.ts +++ b/res/translations/mixxx_en_GB.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Couldn't load track. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Action failed - + Please enable at least one connection to use Live Broadcasting. Please enable at least one connection to use Live Broadcasting. @@ -3442,12 +3442,12 @@ Past Contributors - + Official Website - + Donate @@ -5626,37 +5626,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run Allow screensaver to run - + Prevent screensaver from running Prevent screensaver from running - + Prevent screensaver while playing Prevent screensaver while playing - + This skin does not support color schemes This skin does not support color schemes - + Information Information - + Mixxx must be restarted before the new locale setting will take effect. Mixxx must be restarted before the new locale setting will take effect. @@ -6952,17 +6952,17 @@ The loudness target is approximate and assumes track pregain and master output l RGB - + OpenGL not available OpenGL not available - + dropped frames dropped frames - + Cached waveforms occupy %1 MiB on disk. Cached waveforms occupy %1 MiB on disk. @@ -8845,39 +8845,31 @@ Do you want to scan your library for cover files now? Encoder - + Mixxx Needs Access to: %1 Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: - -%1 - -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10285,27 +10277,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History History - + Unlock Unlock - + Lock Lock @@ -10459,47 +10451,47 @@ Fully right: end of the effect period Network cache overflow - + Connection error Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. Lost connection to streaming server. - + Please check your connection to the Internet. Please check your connection to the Internet. - + Can't connect to streaming server Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. Please check your connection to the Internet and verify that your username and password are correct. @@ -14277,22 +14269,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) (GLSL ES) - + (GL ES) (GL ES) @@ -14300,52 +14292,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14355,17 +14347,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14373,52 +14365,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Choose music library directory - + controllers - + Cannot open database Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14622,4 +14614,12 @@ Click OK to exit. No network access + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + No effect loaded. + + \ No newline at end of file diff --git a/res/translations/mixxx_eo.qm b/res/translations/mixxx_eo.qm index f0fe70671cc..b05b0b38ac6 100644 Binary files a/res/translations/mixxx_eo.qm and b/res/translations/mixxx_eo.qm differ diff --git a/res/translations/mixxx_eo.ts b/res/translations/mixxx_eo.ts index 72f7a3cde6a..896585455e3 100644 --- a/res/translations/mixxx_eo.ts +++ b/res/translations/mixxx_eo.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Oni ne povis ŝargi la kanton. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Malŝlosi - + Lock Ŝlosi @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_es.qm b/res/translations/mixxx_es.qm index 9d5f0b25c3d..7519022f1a0 100644 Binary files a/res/translations/mixxx_es.qm and b/res/translations/mixxx_es.qm differ diff --git a/res/translations/mixxx_es.ts b/res/translations/mixxx_es.ts index 6f2ad712c73..6f00d67a5d1 100644 --- a/res/translations/mixxx_es.ts +++ b/res/translations/mixxx_es.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. No se ha podido cargar la pista. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Acción fallida - + Please enable at least one connection to use Live Broadcasting. Por favor, activa almenos una fuente de emisión en vivo. @@ -3442,12 +3442,12 @@ Contribuyentes anteriores - + Official Website - + Donate @@ -5590,37 +5590,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. El tamaño mínimo de la apariencia seleccionada es mas grande que la resolucion de su pantalla. - + Allow screensaver to run Permite el salvapantallas - + Prevent screensaver from running Evita que se active el salvapantallas - + Prevent screensaver while playing Evita el salvapantallas mientras reproduce - + This skin does not support color schemes Este skin no soporta esquemas de color - + Information Información - + Mixxx must be restarted before the new locale setting will take effect. Mixxx debe reiniciarse para que los cambios en la configuración regional surtan efecto. @@ -6916,17 +6916,17 @@ Este volumen de referencia es aproximado y asume que la ganancia y el nivel de s RGB - + OpenGL not available OpenGL no disponible - + dropped frames fotogramas perdidos - + Cached waveforms occupy %1 MiB on disk. Formas de onda almacenadas en caché ocupan %1 MiB en el disco. @@ -8804,39 +8804,31 @@ Do you want to scan your library for cover files now? Codificador - + Mixxx Needs Access to: %1 Mixxx Necesita Acceder a: %1 - - Due to Mac Sandboxing, we need your permission to access this file: - -%1 - -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - Debido al Sandboxing de Mac, necesitamos tu permiso para acceder a este fichero: + + Your permission is required to access the following location: %1 -Una vez pulse Aceptar, verá un selector de archivos. Debes seleccionar '%2' para darle permiso a Mixxx. Si no desea permitir el acceso, pulse en cancelar. Lamentamos este inconveniente. - -Para abortar esta acción, pulse Cancelar en el selector de archivos. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. Usted ha seleccionado un archivo equivocado. Para permitir acceso a Mixxx, por favor seleccione el archivo '%1'. Si no quiere continuar, presione Cancelar. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10244,27 +10236,27 @@ Todo a la derecha: final del período SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Historial - + Unlock Desbloquear - + Lock Bloquear @@ -10418,47 +10410,47 @@ Todo a la derecha: final del período Caché de red excedido - + Connection error Error de connexión - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> Una de las fuentes de emisión en vivo ha lanzado este error:<br><b>Error con la fuente '%1':</b><br> - + Connection message Mensaje de conexión - + <b>Message from Live Broadcasting connection '%1':</b><br> <b>Mensaje de la fuente de emisión en vivo '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. Se ha perdido la conexión al servidor de emisión y han fallado %1 intentos de reconexión. - + Lost connection to streaming server. Se ha perdido la conexión al servidor de emisión - + Please check your connection to the Internet. Comprueba tu conexión a internet. - + Can't connect to streaming server No se puede conectar al servidor de emisión - + Please check your connection to the Internet and verify that your username and password are correct. Comprobe a súa conexión a internet e verifique que o seu nome de usuario e contrasinal son correctos. @@ -14234,22 +14226,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) (GLSL ES) - + (GL ES) (GL ES) @@ -14257,52 +14249,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14312,17 +14304,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14330,52 +14322,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Elija el directorio de la biblioteca de la música - + controllers - + Cannot open database No se puede abrir la base de datos - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14579,4 +14571,12 @@ Pulse Aceptar para salir. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_es_ES.qm b/res/translations/mixxx_es_ES.qm index e664bcf3af8..1e8c281352e 100644 Binary files a/res/translations/mixxx_es_ES.qm and b/res/translations/mixxx_es_ES.qm differ diff --git a/res/translations/mixxx_es_ES.ts b/res/translations/mixxx_es_ES.ts index 6890b206e70..1cc4432bfc2 100644 --- a/res/translations/mixxx_es_ES.ts +++ b/res/translations/mixxx_es_ES.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. No se ha podido cargar la pista. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Acción fallida - + Please enable at least one connection to use Live Broadcasting. Por favor, activa almenos una fuente de emisión en vivo. @@ -3442,12 +3442,12 @@ Antiguos colaboradores - + Official Website Official Website - + Donate @@ -5631,37 +5631,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. El tamaño mínimo de la apariencia seleccionada es mas grande que la resolucion de su pantalla. - + Allow screensaver to run Permite el salvapantallas - + Prevent screensaver from running Evita que se active el salvapantallas - + Prevent screensaver while playing Evita el salvapantallas mientras reproduce - + This skin does not support color schemes Este skin no soporta esquemas de color - + Information Información - + Mixxx must be restarted before the new locale setting will take effect. Mixxx debe reiniciarse para que los cambios en la configuración regional surtan efecto. @@ -6958,17 +6958,17 @@ Este volumen de referencia es aproximado y asume que la ganancia y el nivel de s RGB - + OpenGL not available OpenGL no disponible - + dropped frames fotogramas perdidos - + Cached waveforms occupy %1 MiB on disk. Formas de onda almacenadas en caché ocupan %1 MiB en el disco. @@ -8853,39 +8853,31 @@ Do you want to scan your library for cover files now? Codificador - + Mixxx Needs Access to: %1 Mixxx Necesita Acceder a: %1 - - Due to Mac Sandboxing, we need your permission to access this file: - -%1 - -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - Debido al Sandboxing de Mac, necesitamos tu permiso para acceder a este fichero: + + Your permission is required to access the following location: %1 -Una vez pulse Aceptar, verá un selector de archivos. Debes seleccionar '%2' para darle permiso a Mixxx. Si no desea permitir el acceso, pulse en cancelar. Lamentamos este inconveniente. - -Para abortar esta acción, pulse Cancelar en el selector de archivos. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. Usted ha seleccionado un archivo equivocado. Para permitir acceso a Mixxx, por favor seleccione el archivo '%1'. Si no quiere continuar, presione Cancelar. - + Upgrading old Mixxx settings Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10297,27 +10289,27 @@ Todo a la derecha: final del período SetlogFeature - + Join with previous (below) Join with previous (below) - + Finish current and start new Finish current and start new - + History Historial - + Unlock Desbloquear - + Lock Bloquear @@ -10471,47 +10463,47 @@ Todo a la derecha: final del período Caché de red excedido - + Connection error Error de connexión - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> Una de las fuentes de emisión en vivo ha lanzado este error:<br><b>Error con la fuente '%1':</b><br> - + Connection message Mensaje de conexión - + <b>Message from Live Broadcasting connection '%1':</b><br> <b>Mensaje de la fuente de emisión en vivo '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. Se ha perdido la conexión al servidor de emisión y han fallado %1 intentos de reconexión. - + Lost connection to streaming server. Se ha perdido la conexión al servidor de emisión - + Please check your connection to the Internet. Comprueba tu conexión a internet. - + Can't connect to streaming server No se puede conectar al servidor de emisión - + Please check your connection to the Internet and verify that your username and password are correct. Comprobe a súa conexión a internet e verifique que o seu nome de usuario e contrasinal son correctos. @@ -14289,22 +14281,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) (GLSL ES) - + (GL ES) (GL ES) @@ -14312,52 +14304,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14372,17 +14364,17 @@ debug - Above + Debug/Developer messages trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14390,52 +14382,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts fonts - + database database - + effects efectos - + audio interface audio interface - + decks decks - + library library - + Choose music library directory Elija el directorio de la biblioteca de la música - + controllers controllers - + Cannot open database No se puede abrir la base de datos - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14639,4 +14631,12 @@ Pulse Aceptar para salir. No network access + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_es_MX.qm b/res/translations/mixxx_es_MX.qm index 65c3608e8e1..757b25b04e3 100644 Binary files a/res/translations/mixxx_es_MX.qm and b/res/translations/mixxx_es_MX.qm differ diff --git a/res/translations/mixxx_es_MX.ts b/res/translations/mixxx_es_MX.ts index 680a7aafa82..cf699fd7c55 100644 --- a/res/translations/mixxx_es_MX.ts +++ b/res/translations/mixxx_es_MX.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. No se puede cargar la pista @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Acción fallida - + Please enable at least one connection to use Live Broadcasting. Por favor habilite al menos una conexión para usar el Broadcasting en vivo @@ -3443,12 +3443,12 @@ M3U Playlist (*.m3u);;M3U8 Playlist (*.m3u8);;PLS Playlist (*.pls);;Text CSV (*. - + Official Website - + Donate @@ -5569,37 +5569,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6893,17 +6893,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8772,33 +8772,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10180,27 +10178,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock - + Lock Bloquear @@ -10354,47 +10352,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14170,22 +14168,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14193,52 +14191,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14248,17 +14246,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14266,52 +14264,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14512,4 +14510,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_et.qm b/res/translations/mixxx_et.qm index 6bcf73520ae..30bfbe7e50c 100644 Binary files a/res/translations/mixxx_et.qm and b/res/translations/mixxx_et.qm differ diff --git a/res/translations/mixxx_et.ts b/res/translations/mixxx_et.ts index 24181b0f3ef..1caa05f0491 100644 --- a/res/translations/mixxx_et.ts +++ b/res/translations/mixxx_et.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Ei suuda lugu laadida. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information Info - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? Kodeerija - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Ajalugu - + Unlock Võta lukust lahti - + Lock Lukus @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database Ei suuda avada andmebaasi - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_eu.qm b/res/translations/mixxx_eu.qm index 963456b29ca..680e31c34c6 100644 Binary files a/res/translations/mixxx_eu.qm and b/res/translations/mixxx_eu.qm differ diff --git a/res/translations/mixxx_eu.ts b/res/translations/mixxx_eu.ts index 7c93dbf74bd..c2e32a9d88d 100644 --- a/res/translations/mixxx_eu.ts +++ b/res/translations/mixxx_eu.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Ezin izan da pista kargatu @@ -401,12 +401,12 @@ BroadcastManager - + Action failed Ekintzak huts egin du - + Please enable at least one connection to use Live Broadcasting. Mesedez, gutxienez konexio bat erabil ezazu Zuzeneko Emanaldia erabiltzeko. @@ -3440,12 +3440,12 @@ Lehengo - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information Informazioa - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8770,33 +8770,31 @@ Do you want to scan your library for cover files now? Kodetzailea - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10178,27 +10176,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Historia - + Unlock Desblokeatu - + Lock Blokeatu @@ -10352,47 +10350,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14168,22 +14166,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14191,52 +14189,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14246,17 +14244,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14264,52 +14262,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Aukeratu musika liburutegiaren direktorioa - + controllers - + Cannot open database Ezin da datu-basea ireki - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14510,4 +14508,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_fa.qm b/res/translations/mixxx_fa.qm index 769d2ef9f44..8da8c1eae9e 100644 Binary files a/res/translations/mixxx_fa.qm and b/res/translations/mixxx_fa.qm differ diff --git a/res/translations/mixxx_fa.ts b/res/translations/mixxx_fa.ts index ff45c4b0c99..7c7e3b0d9f4 100644 --- a/res/translations/mixxx_fa.ts +++ b/res/translations/mixxx_fa.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. بارگزاری قطعه امکان‌پذیر نیست. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed عمل ناموفق - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information اطلاعات - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History پیشینه - + Unlock بازکردن قفل - + Lock قفل @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_fi.qm b/res/translations/mixxx_fi.qm index 272e4b49557..bdde62c2a65 100644 Binary files a/res/translations/mixxx_fi.qm and b/res/translations/mixxx_fi.qm differ diff --git a/res/translations/mixxx_fi.ts b/res/translations/mixxx_fi.ts index 25cb1dc7469..7d023baba93 100644 --- a/res/translations/mixxx_fi.ts +++ b/res/translations/mixxx_fi.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Kappaletta ei voitu ladata. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ Aikaisemmat avustajat - + Official Website - + Donate @@ -5567,37 +5567,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information Tietoja - + Mixxx must be restarted before the new locale setting will take effect. @@ -6891,17 +6891,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available OpenGL ei ole käytettävissä - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8772,33 +8772,31 @@ Do you want to scan your library for cover files now? Pakkaaja - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10180,27 +10178,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Soittohistoria - + Unlock Poista lukitus - + Lock Lukitse @@ -10354,47 +10352,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. Tarkista verkkoyhteytesi tila ja että käyttäjätunnuksesi ja salasanasi ovat oikein. @@ -14170,22 +14168,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14193,52 +14191,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14248,17 +14246,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14266,52 +14264,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Valitse musiikkikokoelman sijainti - + controllers - + Cannot open database Tietokantaa ei voida avata - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14515,4 +14513,12 @@ Valitse OK poistuaksesi. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_fr.qm b/res/translations/mixxx_fr.qm index d7f89dae440..92a7c6feb46 100644 Binary files a/res/translations/mixxx_fr.qm and b/res/translations/mixxx_fr.qm differ diff --git a/res/translations/mixxx_fr.ts b/res/translations/mixxx_fr.ts index cf2da212195..d334383472c 100644 --- a/res/translations/mixxx_fr.ts +++ b/res/translations/mixxx_fr.ts @@ -263,7 +263,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Impossible de charger la piste. @@ -404,12 +404,12 @@ BroadcastManager - + Action failed Échec de l'action - + Please enable at least one connection to use Live Broadcasting. Merci d'activer au moins une connexion pour utiliser la transmission en direct @@ -3444,14 +3444,14 @@ Ajouter la piste à la file Auto DJ (fin) Anciens contributeurs - + Official Website Site Internet officiel - + Donate - + Donation @@ -5633,37 +5633,37 @@ Vous pouvez toujours glisser-déposer des pistes sur l'écran pour cloner u DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. La taille minimale du thème sélectionné est plus grande que la résolution de votre écran. - + Allow screensaver to run Autoriser l'économiseur d'écran - + Prevent screensaver from running Interdire l'économiseur d'écran - + Prevent screensaver while playing Interdire l'économiseur d'écran pendant la lecture - + This skin does not support color schemes Ce thème n'accepte pas les modèles de couleurs - + Information Information - + Mixxx must be restarted before the new locale setting will take effect. Mixxx doit être redémarré avant que les nouveaux réglages locaux prennent effet. @@ -6960,17 +6960,17 @@ Le niveau sonore visé est approximatif et suppose que les gains d'entrée RVB - + OpenGL not available OpenGL non disponible - + dropped frames images sautées - + Cached waveforms occupy %1 MiB on disk. La forme d'onde en cache occupe %1 MiB sur le disque. @@ -8855,39 +8855,31 @@ Désirez-vous rechercher maintenant les pochettes dans votre bibliothèque?Encodeur - + Mixxx Needs Access to: %1 Mixxx necessite l'accès à: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - Dû au Sandboxing de Mac, nous avons besoin de votre permission pour accéder à ce fichier: - -%1 - -Après avoir cliqué sur OK, vous verrez un sélecteur de fichier. Pour donner la permission à Mixxx, vous devez sélectionner '%2' afin de procéder. Si vous ne désirez pas donner cet accès à Mixxx, cliquez sur Annuler dans le sélecteur de fichier. Nous nous excusons de ce désagrément. - -Pour annuler cette opération, appuyez sur Annuler dans le dialogue du fichier. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. Vous avez sélectionné le mauvais fichier. Pour permettre l'accès à Mixxx, veuillez sélectionner le fichier '%1'. Si vous désirez ne pas continuer, appuyez sur Annuler. - + Upgrading old Mixxx settings Mise à niveau des anciens paramètres de Mixxx - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10298,27 +10290,27 @@ Complètement à droite: fin de la période d'effet SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Historique - + Unlock Déverrouiller - + Lock Verrouiller @@ -10472,47 +10464,47 @@ Complètement à droite: fin de la période d'effet Débordement de cache réseau - + Connection error Erreur de connexion - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> Une des connexions de diffusion en direct a généré cette erreur:<br><b>Erreur avec la connexion '%1':</b><br> - + Connection message Message de connexion - + <b>Message from Live Broadcasting connection '%1':</b><br> <b>Message de la connexion de diffusion en direct '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. Connexion au serveur de streaming perdue et %1 essais de reconnexion ont échoué. - + Lost connection to streaming server. Connexion au serveur de streaming perdue. - + Please check your connection to the Internet. Veuillez vérifier votre connexion Internet. - + Can't connect to streaming server Connexion impossible au serveur de streaming - + Please check your connection to the Internet and verify that your username and password are correct. Veuillez vérifier votre connection Internet et que votre identifiant et mot de passe soit correct. @@ -10640,7 +10632,7 @@ Complètement à droite: fin de la période d'effet Double-click - + Double-cliquer @@ -11300,7 +11292,7 @@ Complètement à droite: fin de la période d'effet Opens separate artwork viewer. - + Ouvre une visionneuse de pochette d'album distincte. @@ -12422,12 +12414,12 @@ Utiliser ceci pour modifier uniquement le signal affecté (traité) avec EQ et l Opens the track properties editor - + Ouvre l'éditeur de propriétés de piste Opens the track context menu. - + Ouvre le menu contextuel de la piste. @@ -14290,22 +14282,22 @@ Utiliser ceci pour modifier uniquement le signal affecté (traité) avec EQ et l WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) (GLSL ES) - + (GL ES) (GL ES) @@ -14313,52 +14305,52 @@ Utiliser ceci pour modifier uniquement le signal affecté (traité) avec EQ et l main - + Starts Mixxx in full-screen mode Démarre Mixxx en mode plein écran - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. Répertoire de niveau supérieur dans lequel Mixxx doit rechercher ses fichiers de ressources, tels que les mappages MIDI, en remplaçant l'emplacement d'installation par défaut. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14368,17 +14360,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14386,52 +14378,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects effets - + audio interface interface audio - + decks platines - + library - + Choose music library directory Choisissez le répertoire de la bibliothèque musicale - + controllers - + Cannot open database Ne peux ouvrir la base de données - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14634,4 +14626,12 @@ Cliquez sur OK pour sortir. Pas d'accès au réseau + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_fr_FR.qm b/res/translations/mixxx_fr_FR.qm index cb3f83511af..346da98b9bc 100644 Binary files a/res/translations/mixxx_fr_FR.qm and b/res/translations/mixxx_fr_FR.qm differ diff --git a/res/translations/mixxx_fr_FR.ts b/res/translations/mixxx_fr_FR.ts index 4f279729d8c..ac5117b910b 100644 --- a/res/translations/mixxx_fr_FR.ts +++ b/res/translations/mixxx_fr_FR.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Impossible de charger la piste. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed Action échouée - + Please enable at least one connection to use Live Broadcasting. Veuillez activer au moins une connexion pour utiliser la diffusion en direct. @@ -3441,12 +3441,12 @@ Anciens contributeurs - + Official Website - + Donate @@ -5567,37 +5567,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6891,17 +6891,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8770,33 +8770,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10178,27 +10176,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock - + Lock Verroullier @@ -10352,47 +10350,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14168,22 +14166,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14191,52 +14189,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14246,17 +14244,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14264,52 +14262,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14510,4 +14508,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_ga.qm b/res/translations/mixxx_ga.qm index 0f79104ef52..35dbb81ea43 100644 Binary files a/res/translations/mixxx_ga.qm and b/res/translations/mixxx_ga.qm differ diff --git a/res/translations/mixxx_ga.ts b/res/translations/mixxx_ga.ts index 762a0294a0e..dda294293f0 100644 --- a/res/translations/mixxx_ga.ts +++ b/res/translations/mixxx_ga.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock - + Lock @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_gl.qm b/res/translations/mixxx_gl.qm index 6a3e3b697c0..9373e74d493 100644 Binary files a/res/translations/mixxx_gl.qm and b/res/translations/mixxx_gl.qm differ diff --git a/res/translations/mixxx_gl.ts b/res/translations/mixxx_gl.ts index 643c619cf15..ef60223f219 100644 --- a/res/translations/mixxx_gl.ts +++ b/res/translations/mixxx_gl.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Non foi posíbel cargar a pista. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3442,12 +3442,12 @@ Colaboradores anteriores - + Official Website - + Donate @@ -5570,37 +5570,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. O tamaño mínimo do tema seleccionado é maior que a resolución da súa pantalla. - + Allow screensaver to run Permitir que se execute o protector de pantallas - + Prevent screensaver from running Impide que se execute o protector de pantallas - + Prevent screensaver while playing Impide que se execute o protector de pantallas durante a reprodución - + This skin does not support color schemes Este tema non admite esquemas de cor - + Information Información - + Mixxx must be restarted before the new locale setting will take effect. @@ -6896,17 +6896,17 @@ O obxectivo de sonoridade é aproximado e asume que a ganancia e o nivel de saí RGB - + OpenGL not available OpenGL non dispoñíbel - + dropped frames cadros desbotados - + Cached waveforms occupy %1 MiB on disk. As formas de onda almacenadas na caché ocupan %1 MiB no disco. @@ -8779,33 +8779,31 @@ Do you want to scan your library for cover files now? Codificador - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10187,27 +10185,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Historial - + Unlock Desbloquear - + Lock Bloquear @@ -10361,47 +10359,47 @@ Fully right: end of the effect period Desbordamento da caché de rede - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. Perdeuse a conexión co servidor de fluxo e fallaron ½1 intentos de reconexión. - + Lost connection to streaming server. Perdeuse a conexión co servidor de fluxo - + Please check your connection to the Internet. Comprobe a súa conexión a internet. - + Can't connect to streaming server Non é posíbel conectar co servidor de fluxo - + Please check your connection to the Internet and verify that your username and password are correct. Comprobe a súa conexión a internet e verifique que o seu nome de usuario e contrasinal son correctos. @@ -14177,22 +14175,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14200,52 +14198,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14255,17 +14253,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14273,52 +14271,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Escolla o directorio da fonoteca - + controllers - + Cannot open database Non é posíbel abrir a base de datos - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14519,4 +14517,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + Non hai ningún efecto cargado + + \ No newline at end of file diff --git a/res/translations/mixxx_he.qm b/res/translations/mixxx_he.qm index 4c8051afc50..68287a3a2ae 100644 Binary files a/res/translations/mixxx_he.qm and b/res/translations/mixxx_he.qm differ diff --git a/res/translations/mixxx_he.ts b/res/translations/mixxx_he.ts index 431e7b244c2..27900fc4344 100644 --- a/res/translations/mixxx_he.ts +++ b/res/translations/mixxx_he.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. לא ניתן לטעון את הרצועה. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed פעולה נכשלה - + Please enable at least one connection to use Live Broadcasting. הפעל לפחות חיבור אחד לשימוש בשידור חי. @@ -3441,12 +3441,12 @@ - + Official Website - + Donate @@ -5567,37 +5567,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information פרטים - + Mixxx must be restarted before the new locale setting will take effect. @@ -6891,17 +6891,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8770,33 +8770,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10178,27 +10176,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock שחרור נעילה - + Lock נעל @@ -10352,47 +10350,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14168,22 +14166,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14191,52 +14189,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14246,17 +14244,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14264,52 +14262,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14510,4 +14508,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_he_IL.qm b/res/translations/mixxx_he_IL.qm index 05ad4575c73..1f048922676 100644 Binary files a/res/translations/mixxx_he_IL.qm and b/res/translations/mixxx_he_IL.qm differ diff --git a/res/translations/mixxx_he_IL.ts b/res/translations/mixxx_he_IL.ts index c27d46bb4b8..e8421283fd9 100644 --- a/res/translations/mixxx_he_IL.ts +++ b/res/translations/mixxx_he_IL.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. לא הצליח לטעון רצועה @@ -403,12 +403,12 @@ BroadcastManager - + Action failed הפעולה כשלה - + Please enable at least one connection to use Live Broadcasting. אנא אפשרו חיבור אחד לפחות על מנת להשתמש בשידור החי. @@ -3442,12 +3442,12 @@ - + Official Website - + Donate @@ -5568,37 +5568,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6892,17 +6892,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8771,33 +8771,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10179,27 +10177,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock - + Lock נעלו @@ -10353,47 +10351,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14169,22 +14167,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14192,52 +14190,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14247,17 +14245,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14265,52 +14263,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14511,4 +14509,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_hi_IN.qm b/res/translations/mixxx_hi_IN.qm index 0916b8f115f..6629ca4bc51 100644 Binary files a/res/translations/mixxx_hi_IN.qm and b/res/translations/mixxx_hi_IN.qm differ diff --git a/res/translations/mixxx_hi_IN.ts b/res/translations/mixxx_hi_IN.ts index 5ff6963d4c0..b3403a9c374 100644 --- a/res/translations/mixxx_hi_IN.ts +++ b/res/translations/mixxx_hi_IN.ts @@ -261,7 +261,7 @@ BaseTrackPlayerImpl - + Couldn't load track. ट्रैक लोड नहीं हो सका @@ -402,12 +402,12 @@ BroadcastManager - + Action failed क्रिया: विफल रही - + Please enable at least one connection to use Live Broadcasting. लाइव प्रसारण का उपयोग करने के लिए कृपया कम से कम एक कनेक्शन सक्षम करें। @@ -3441,12 +3441,12 @@ - + Official Website - + Donate @@ -5567,37 +5567,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6891,17 +6891,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8770,33 +8770,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10178,27 +10176,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock - + Lock लॉक @@ -10352,47 +10350,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14168,22 +14166,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14191,52 +14189,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14246,17 +14244,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14264,52 +14262,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14510,4 +14508,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_hr.qm b/res/translations/mixxx_hr.qm index 2d2b6f06344..935146ee73a 100644 Binary files a/res/translations/mixxx_hr.qm and b/res/translations/mixxx_hr.qm differ diff --git a/res/translations/mixxx_hr.ts b/res/translations/mixxx_hr.ts index 700a7d4c667..3ac26c9edf7 100644 --- a/res/translations/mixxx_hr.ts +++ b/res/translations/mixxx_hr.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Ne može učitati pjesmu @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Akcija nije uspjela - + Please enable at least one connection to use Live Broadcasting. Omogućite barem jednu vezu kako biste koristili Strujanje Uživo @@ -3442,12 +3442,12 @@ - + Official Website - + Donate @@ -5568,37 +5568,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6892,17 +6892,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8771,33 +8771,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10179,27 +10177,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Otključaj - + Lock Zaključaj @@ -10353,47 +10351,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14169,22 +14167,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14192,52 +14190,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14247,17 +14245,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14265,52 +14263,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14511,4 +14509,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_hu.qm b/res/translations/mixxx_hu.qm index ec35f60ce6b..f60af41ad8c 100644 Binary files a/res/translations/mixxx_hu.qm and b/res/translations/mixxx_hu.qm differ diff --git a/res/translations/mixxx_hu.ts b/res/translations/mixxx_hu.ts index 22b4de292c7..ff335b6ed31 100644 --- a/res/translations/mixxx_hu.ts +++ b/res/translations/mixxx_hu.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Nem lehet a számot betölteni. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Az akció nem sikerült - + Please enable at least one connection to use Live Broadcasting. Engedélyezz legalább egy kapcsolatot az élő sugárzás használatához. @@ -3442,12 +3442,12 @@ - + Official Website - + Donate @@ -5587,37 +5587,37 @@ Fogd-és-vidd módszerrel mindig másolhatsz lejátszókat. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. A kiválasztott kinézet mérete nagyobb, mint a képernyőd felbontása. - + Allow screensaver to run Képernyővédő engedése - + Prevent screensaver from running Képernyővédő letiltása - + Prevent screensaver while playing Képernyővédő letiltása lejátszás közben - + This skin does not support color schemes Ez a kinézet nem támogat színsémákat - + Information Információ - + Mixxx must be restarted before the new locale setting will take effect. @@ -6911,17 +6911,17 @@ The loudness target is approximate and assumes track pregain and master output l RGB - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8790,33 +8790,31 @@ Do you want to scan your library for cover files now? Kódoló - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10198,27 +10196,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Feloldás - + Lock Zárolás @@ -10372,47 +10370,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. Kérlek ellenőrizd az internet kapcsolatodat! - + Can't connect to streaming server Nem lehet csatlakozni a stream szerverhez - + Please check your connection to the Internet and verify that your username and password are correct. Kérlek ellenőrizd az internet kapcsolatodat és bizonyosodj meg róla, hogy a felhasználónet és a jelszót pontosan adtad meg! @@ -14188,22 +14186,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14211,52 +14209,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14266,17 +14264,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14284,52 +14282,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Válasszon zene gyűjtemény könyvtárat - + controllers - + Cannot open database Az adatbázis megnyitása nem sikerült - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14530,4 +14528,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_hy.qm b/res/translations/mixxx_hy.qm index a2cf6316842..6031c5e78a3 100644 Binary files a/res/translations/mixxx_hy.qm and b/res/translations/mixxx_hy.qm differ diff --git a/res/translations/mixxx_hy.ts b/res/translations/mixxx_hy.ts index 74f83f6a00e..7d732b377b7 100644 --- a/res/translations/mixxx_hy.ts +++ b/res/translations/mixxx_hy.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Չկարողացա բացել երգը @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock - + Lock Լոք @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_ia.qm b/res/translations/mixxx_ia.qm index 112cdc18892..de4ef5d3900 100644 Binary files a/res/translations/mixxx_ia.qm and b/res/translations/mixxx_ia.qm differ diff --git a/res/translations/mixxx_id.qm b/res/translations/mixxx_id.qm index 10ab4e2a4a6..023c9f520dc 100644 Binary files a/res/translations/mixxx_id.qm and b/res/translations/mixxx_id.qm differ diff --git a/res/translations/mixxx_id.ts b/res/translations/mixxx_id.ts index d7868fed85a..e096542aba7 100644 --- a/res/translations/mixxx_id.ts +++ b/res/translations/mixxx_id.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Tidak dapat memuat lagu @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Buka Kunci - + Lock Kunci @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Pilih petunjuk pustaka musik. - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_is.qm b/res/translations/mixxx_is.qm index 762494aab83..73a3d50860f 100644 Binary files a/res/translations/mixxx_is.qm and b/res/translations/mixxx_is.qm differ diff --git a/res/translations/mixxx_is.ts b/res/translations/mixxx_is.ts index 740dfeaa039..459692ba119 100644 --- a/res/translations/mixxx_is.ts +++ b/res/translations/mixxx_is.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Gat ekki opnað lag. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? Kóðari - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock - + Lock Læsa @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Veldu möppu sem inniheldur lagasafn - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_it.qm b/res/translations/mixxx_it.qm index 93a2140c131..582df9dc583 100644 Binary files a/res/translations/mixxx_it.qm and b/res/translations/mixxx_it.qm differ diff --git a/res/translations/mixxx_it.ts b/res/translations/mixxx_it.ts index 71ef9b60ad1..8e14aad0b94 100644 --- a/res/translations/mixxx_it.ts +++ b/res/translations/mixxx_it.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Impossibile caricare la traccia @@ -403,12 +403,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3442,12 +3442,12 @@ Collaboratori passati - + Official Website - + Donate @@ -5569,37 +5569,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. La dimensione minore della skin selezionata è maggiore della risoluzione del tuo schermo. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes Questa skin non supporta gli schemi di colore. - + Information Informazione - + Mixxx must be restarted before the new locale setting will take effect. @@ -6894,17 +6894,17 @@ Il loudness finale è approssimativo e presume che pregain e master livello mast RGB - + OpenGL not available OpenGL non disponibile - + dropped frames frames persi - + Cached waveforms occupy %1 MiB on disk. I waveforms nella cache occupano %1 Mib sul disco @@ -8780,39 +8780,31 @@ Vuoi scansionare la tua libreria alla ricerca di file di cover adesso?Encoder - + Mixxx Needs Access to: %1 Mixxx Richiede Accesso a: %1 - - Due to Mac Sandboxing, we need your permission to access this file: - -%1 - -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - A causa del Sandboxing dei Mac, è necessaria la tua autorizzazione per l'accesso a questo file: + + Your permission is required to access the following location: %1 -Dopo aver cliccato su OK, apparirà una maschera di selezione file. Per concedere i permessi di accesso a Mixxx dovrai selezionare '%2' per procedere. Se non sei d'accordo a concedere i permessi di accesso a Mixxx, clicca Cancel sulla maschera di apertura file. Ci scusiamo per l'inconveniente. - -Per annullare questa azione, clicca su Cancel nella maschera di dialogo. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. E' stato selezionato il file errato. Per carantire i diritti di accesso a Mixxx, prego selezionare il file '%1'. Se non intendi continuare , clicca Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10194,27 +10186,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Storico - + Unlock Sblocca - + Lock Bloccato @@ -10368,47 +10360,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server Impossibile connettersi al server streaming - + Please check your connection to the Internet and verify that your username and password are correct. Controlla la tua connessione a Internet e verifica che username e password siano corrette @@ -14184,22 +14176,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14207,52 +14199,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14262,17 +14254,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14280,52 +14272,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects effetti - + audio interface - + decks - + library - + Choose music library directory Scegli la cartella della tua libreria musicale - + controllers - + Cannot open database Impossibile aprire il database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14529,4 +14521,12 @@ Clicca su OK per uscire. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + Nessun effetto caricato. + + \ No newline at end of file diff --git a/res/translations/mixxx_it_IT.qm b/res/translations/mixxx_it_IT.qm index 50be00acbb8..12523cf1259 100644 Binary files a/res/translations/mixxx_it_IT.qm and b/res/translations/mixxx_it_IT.qm differ diff --git a/res/translations/mixxx_it_IT.ts b/res/translations/mixxx_it_IT.ts index b9909f3a5c3..773146d07cb 100644 --- a/res/translations/mixxx_it_IT.ts +++ b/res/translations/mixxx_it_IT.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Non posso caricare la traccia. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Azione fallita - + Please enable at least one connection to use Live Broadcasting. Abilitare almeno una connessione per usare il Live Broadcasting. @@ -3442,12 +3442,12 @@ - + Official Website - + Donate @@ -5604,37 +5604,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6928,17 +6928,17 @@ The loudness target is approximate and assumes track pregain and master output l RGB - + OpenGL not available OpenGL non disponibile - + dropped frames - + Cached waveforms occupy %1 MiB on disk. Le forme d'onda memorizzate in cache occupano %1 MiB sul disco. @@ -8809,33 +8809,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10220,27 +10218,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Storia - + Unlock Sblocca - + Lock Blocca @@ -10394,47 +10392,47 @@ Fully right: end of the effect period - + Connection error Errore Connessione - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message Messaggio connessione - + <b>Message from Live Broadcasting connection '%1':</b><br> <b>Messaggio dalla connessione Live Broadcasting '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. Persa connessione al server streaming e %1 tentativi di riconnessione sono falliti. - + Lost connection to streaming server. Persa connessione al server streaming - + Please check your connection to the Internet. Controlla la tua connessione ad Internet. - + Can't connect to streaming server Non posso connettermi al server streaming - + Please check your connection to the Internet and verify that your username and password are correct. Controlla la tua connessione ad Internet e verifica che il tuo username e password siano corrette. @@ -14210,22 +14208,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14233,52 +14231,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14288,17 +14286,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14306,52 +14304,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14552,4 +14550,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + Nessun effetto caricato. + + \ No newline at end of file diff --git a/res/translations/mixxx_ja.qm b/res/translations/mixxx_ja.qm index b6b4eaf79d2..f3734f29e05 100644 Binary files a/res/translations/mixxx_ja.qm and b/res/translations/mixxx_ja.qm differ diff --git a/res/translations/mixxx_ja.ts b/res/translations/mixxx_ja.ts index 5983689fb1d..84a85dc8c54 100644 --- a/res/translations/mixxx_ja.ts +++ b/res/translations/mixxx_ja.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. トラックを読み込めませんでした @@ -401,12 +401,12 @@ BroadcastManager - + Action failed 操作に失敗しました - + Please enable at least one connection to use Live Broadcasting. 生放送での利用には少なくとも一つの接続を有効にして下さい @@ -3441,12 +3441,12 @@ 過去の開発 - + Official Website - + Donate @@ -5567,37 +5567,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information 通知 - + Mixxx must be restarted before the new locale setting will take effect. @@ -6891,17 +6891,17 @@ The loudness target is approximate and assumes track pregain and master output l RGB - + OpenGL not available OpenGLが利用できません - + dropped frames ドロップフレーム - + Cached waveforms occupy %1 MiB on disk. @@ -8772,33 +8772,31 @@ Do you want to scan your library for cover files now? エンコーダ - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10180,27 +10178,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock ロックを解除 - + Lock ロックをかける @@ -10354,47 +10352,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. インターネットの接続、ユーザ名とパスワードを確認してください @@ -14170,22 +14168,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14193,52 +14191,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14248,17 +14246,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14266,52 +14264,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory 音楽ライブラリのディレクトリを選択してください - + controllers - + Cannot open database データベースが開けません。 - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14515,4 +14513,12 @@ OKを押すと終了します。 + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_ko.qm b/res/translations/mixxx_ko.qm index c86eaa0f3da..dc8f68461f2 100644 Binary files a/res/translations/mixxx_ko.qm and b/res/translations/mixxx_ko.qm differ diff --git a/res/translations/mixxx_ko.ts b/res/translations/mixxx_ko.ts index 6f344a5b941..d9c74a129ca 100644 --- a/res/translations/mixxx_ko.ts +++ b/res/translations/mixxx_ko.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. 트랙을 불러올 수 없습니다. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5567,37 +5567,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information 정보 - + Mixxx must be restarted before the new locale setting will take effect. @@ -6891,17 +6891,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available OpenGL 사용 불가능 - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8770,33 +8770,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10178,27 +10176,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock 잠금 해제 - + Lock 잠그기 @@ -10352,47 +10350,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14168,22 +14166,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14191,52 +14189,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14246,17 +14244,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14264,52 +14262,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory 음악 라이브러리 디렉토리를 선택하세요 - + controllers - + Cannot open database 자료모음을 열 수 없음 - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14510,4 +14508,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_ky.qm b/res/translations/mixxx_ky.qm index 66e4d8b1b0b..66ca656d56a 100644 Binary files a/res/translations/mixxx_ky.qm and b/res/translations/mixxx_ky.qm differ diff --git a/res/translations/mixxx_lb.qm b/res/translations/mixxx_lb.qm index 5ce9467bfa8..49a92446411 100644 Binary files a/res/translations/mixxx_lb.qm and b/res/translations/mixxx_lb.qm differ diff --git a/res/translations/mixxx_lb.ts b/res/translations/mixxx_lb.ts index 1e347fdb876..d7a5d69eb30 100644 --- a/res/translations/mixxx_lb.ts +++ b/res/translations/mixxx_lb.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Konnt net gelueden gin @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information Informatioun - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Opgespart - + Lock Späer @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_lt.qm b/res/translations/mixxx_lt.qm index 58f8ebc3f1e..f751fc83b8f 100644 Binary files a/res/translations/mixxx_lt.qm and b/res/translations/mixxx_lt.qm differ diff --git a/res/translations/mixxx_lt.ts b/res/translations/mixxx_lt.ts index 54f29e5160d..f58cb3288ba 100644 --- a/res/translations/mixxx_lt.ts +++ b/res/translations/mixxx_lt.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Negalima įkrauti takelio. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed Veiksmas nepavyko - + Please enable at least one connection to use Live Broadcasting. Prašome įgalinti nors vieną jungtį norint naudoti Tiesioginį Transliavimą @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Atrakinti - + Lock Užrakinti @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_lv.qm b/res/translations/mixxx_lv.qm index bd26b53a5ab..f2ea589e91e 100644 Binary files a/res/translations/mixxx_lv.qm and b/res/translations/mixxx_lv.qm differ diff --git a/res/translations/mixxx_lv.ts b/res/translations/mixxx_lv.ts index 18e061a7da6..38753473206 100644 --- a/res/translations/mixxx_lv.ts +++ b/res/translations/mixxx_lv.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Nevar ielādēt celiņu @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Atbloķēt - + Lock Bloķēt @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_mi.qm b/res/translations/mixxx_mi.qm index b121a6eb628..2bfae6dfcda 100644 Binary files a/res/translations/mixxx_mi.qm and b/res/translations/mixxx_mi.qm differ diff --git a/res/translations/mixxx_mi.ts b/res/translations/mixxx_mi.ts index 11bb1481f30..ea44fe297bb 100644 --- a/res/translations/mixxx_mi.ts +++ b/res/translations/mixxx_mi.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock - + Lock Raka @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_mi_NZ.qm b/res/translations/mixxx_mi_NZ.qm index 95f9664b33d..2bfae6dfcda 100644 Binary files a/res/translations/mixxx_mi_NZ.qm and b/res/translations/mixxx_mi_NZ.qm differ diff --git a/res/translations/mixxx_mk.qm b/res/translations/mixxx_mk.qm index 83e1516faf6..113ed3c8347 100644 Binary files a/res/translations/mixxx_mk.qm and b/res/translations/mixxx_mk.qm differ diff --git a/res/translations/mixxx_mk.ts b/res/translations/mixxx_mk.ts index 1cf3f92d430..8e282946b88 100644 --- a/res/translations/mixxx_mk.ts +++ b/res/translations/mixxx_mk.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Не може да се вчита датотеката @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Отклучи - + Lock Заклучи @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_ml.qm b/res/translations/mixxx_ml.qm index a610d388d55..db4b8d7ad64 100644 Binary files a/res/translations/mixxx_ml.qm and b/res/translations/mixxx_ml.qm differ diff --git a/res/translations/mixxx_ml.ts b/res/translations/mixxx_ml.ts index ffa2f6be465..123f006bc07 100644 --- a/res/translations/mixxx_ml.ts +++ b/res/translations/mixxx_ml.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information വിവരം - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock - + Lock പൂട്ടു് @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_mn.qm b/res/translations/mixxx_mn.qm index bd9c977e816..5c705056657 100644 Binary files a/res/translations/mixxx_mn.qm and b/res/translations/mixxx_mn.qm differ diff --git a/res/translations/mixxx_mn.ts b/res/translations/mixxx_mn.ts index c65ace08c9a..85cb227f0dc 100644 --- a/res/translations/mixxx_mn.ts +++ b/res/translations/mixxx_mn.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Уншиж чадахгүй байна @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock - + Lock @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_mr.qm b/res/translations/mixxx_mr.qm index ff48c01e8ae..0c8e0e964be 100644 Binary files a/res/translations/mixxx_mr.qm and b/res/translations/mixxx_mr.qm differ diff --git a/res/translations/mixxx_mr.ts b/res/translations/mixxx_mr.ts index e47f1ae0f80..266342a9efb 100644 --- a/res/translations/mixxx_mr.ts +++ b/res/translations/mixxx_mr.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock कुलूप उघडा - + Lock कुलूपबंद करा @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_ms.qm b/res/translations/mixxx_ms.qm index 133e7e49c4a..bee39742496 100644 Binary files a/res/translations/mixxx_ms.qm and b/res/translations/mixxx_ms.qm differ diff --git a/res/translations/mixxx_ms.ts b/res/translations/mixxx_ms.ts index 4d2a37ee93e..5a7141e94f8 100644 --- a/res/translations/mixxx_ms.ts +++ b/res/translations/mixxx_ms.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Tidak dapat memuatkan trek. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Buka - + Lock Kunci @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_my.qm b/res/translations/mixxx_my.qm index b69c7485ff1..b3ca6481af0 100644 Binary files a/res/translations/mixxx_my.qm and b/res/translations/mixxx_my.qm differ diff --git a/res/translations/mixxx_my.ts b/res/translations/mixxx_my.ts index 69e36e61bcc..e61ac7ef939 100644 --- a/res/translations/mixxx_my.ts +++ b/res/translations/mixxx_my.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. တေးဂီတပုဒ် မဖွင့်နိုင်ပါ @@ -401,12 +401,12 @@ BroadcastManager - + Action failed လုပ်ဆောင်မှုမအောင်မြင်ပါ - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8771,33 +8771,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10179,27 +10177,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock - + Lock ပိတ် @@ -10353,47 +10351,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14169,22 +14167,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14192,52 +14190,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14247,17 +14245,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14265,52 +14263,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14511,4 +14509,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_nb.qm b/res/translations/mixxx_nb.qm index 37df2be495a..38ae659af7e 100644 Binary files a/res/translations/mixxx_nb.qm and b/res/translations/mixxx_nb.qm differ diff --git a/res/translations/mixxx_nb.ts b/res/translations/mixxx_nb.ts index fbb315943a8..bb6c998659f 100644 --- a/res/translations/mixxx_nb.ts +++ b/res/translations/mixxx_nb.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Fikk ikke lastet sporet @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Handling feilet - + Please enable at least one connection to use Live Broadcasting. Vennligst aktivér minst en oppkobling for å bruke Live Broadcasting. @@ -3443,12 +3443,12 @@ Markørknapp Tidligere bidragsytere - + Official Website - + Donate @@ -5569,37 +5569,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information Informasjon - + Mixxx must be restarted before the new locale setting will take effect. @@ -6893,17 +6893,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available OpenGL ikke tilgjengelig - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8772,33 +8772,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10180,27 +10178,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Lås opp - + Lock Lås @@ -10354,47 +10352,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14170,22 +14168,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14193,52 +14191,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14248,17 +14246,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14266,52 +14264,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database Får ikke åpnet databasen - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14512,4 +14510,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_nl.qm b/res/translations/mixxx_nl.qm index e04858823b9..609e1a6d52f 100644 Binary files a/res/translations/mixxx_nl.qm and b/res/translations/mixxx_nl.qm differ diff --git a/res/translations/mixxx_nl.ts b/res/translations/mixxx_nl.ts index 11201f3b766..3dc585777c5 100644 --- a/res/translations/mixxx_nl.ts +++ b/res/translations/mixxx_nl.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Kan het nummer niet laden. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Actie mislukt - + Please enable at least one connection to use Live Broadcasting. Schakel ten minste één verbinding in om Live Broadcasting te gebruiken. @@ -3442,12 +3442,12 @@ Eerdere Medewerkers - + Official Website - + Donate @@ -5628,37 +5628,37 @@ U kunt de tracks ten allen tijde op het scherm slepen en neerzetten om een deck DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. De minimale grootte van de geselecteerde skin is groter dan uw schermresolutie. - + Allow screensaver to run Toestaan om screensaver te laten uitvoeren - + Prevent screensaver from running Voorkom dat screensaver wordt uitgevoerd - + Prevent screensaver while playing Voorkom screensaver tijdens afspelen - + This skin does not support color schemes Deze skin ondersteunt geen kleurenschema's - + Information Informatie - + Mixxx must be restarted before the new locale setting will take effect. Mixxx moet opnieuw worden gestart voordat de nieuwe locale-instelling van kracht wordt. @@ -6954,17 +6954,17 @@ Het doelvolume is bij benadering en gaat ervan uit dat track pregain en master o RGB - + OpenGL not available OpenGL niet beschikbaar - + dropped frames verloren frames - + Cached waveforms occupy %1 MiB on disk. Waveforms in cache gebruiken %1 Mb op schijf @@ -8849,39 +8849,31 @@ Wilt u nu uw bibliotheek scannen op albumhoezen? Encoder - + Mixxx Needs Access to: %1 Mixxx heeft toegang nodig tot: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - Vanwege Mac Sandboxing hebben we uw toestemming nodig om dit bestand te openen: - -% 1 - -Nadat u op OK heeft geklikt, ziet u een bestandskiezer. Om Mixxx toestemming te geven, moet je '% 2' selecteren om door te gaan. Als u Mixxx geen toegang wilt verlenen, klikt u op Annuleren in de bestandskiezer. Onze excuses voor het ongemak. - -Om deze actie af te breken, drukt u op Annuleren in het bestandsdialoogvenster. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. Je selecteerde het verkeerde bestand. Om Mixxx toegang te verlenen, selecteer het bestand% 1 . Als u niet wil doorgaan, druk op Annuleren. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10289,27 +10281,27 @@ Volledig rechts: einde van de effectperiode SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Historiek - + Unlock Ontgrendel - + Lock Vergrendelen @@ -10463,47 +10455,47 @@ Volledig rechts: einde van de effectperiode Netwerk cache overflow - + Connection error Connectiefout - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> Een van de Live Uitzending-verbindingen veroorzaakte deze fout:<br><b>Fout met verbinding '%1':</b><br> - + Connection message Connectiebericht - + <b>Message from Live Broadcasting connection '%1':</b><br> <b>Bericht van Live Uitzending-verbinding '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. Verbinding met streaming-server is verbroken en %1 pogingen om opnieuw verbinding te maken, zijn mislukt. - + Lost connection to streaming server. Verbinding met de streaming-server verbroken. - + Please check your connection to the Internet. Controleer uw verbinding met internet. - + Can't connect to streaming server Kan niet verbinden met de streaming-server - + Please check your connection to the Internet and verify that your username and password are correct. Controleer uw verbinding met internet en controleer of uw gebruikersnaam en wachtwoord correct zijn. @@ -14281,22 +14273,22 @@ Gebruik deze optie om alleen het verwerkte (Wet) signaal met EQ en filtereffecte WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) (GLSL ES) - + (GL ES) (GL ES) @@ -14304,52 +14296,52 @@ Gebruik deze optie om alleen het verwerkte (Wet) signaal met EQ en filtereffecte main - + Starts Mixxx in full-screen mode Start Mixxx in volledige scherm modus - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. Top-level hoofdmap waar Mixxx moet zoeken naar zijn bronbestanden zoals MIDI-mappings, waarbij de standaard installatielocatie wordt overschreven. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14359,17 +14351,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14377,52 +14369,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects effecten - + audio interface audio-interface - + decks decks - + library - + Choose music library directory Kies de map voor de muziekbibliotheek - + controllers - + Cannot open database Kan database niet openen - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14626,4 +14618,12 @@ Klik op OK om af te sluiten. Geen netwerktoegang + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_nl_BE.qm b/res/translations/mixxx_nl_BE.qm index 59f14b619f3..050f5d0d6ff 100644 Binary files a/res/translations/mixxx_nl_BE.qm and b/res/translations/mixxx_nl_BE.qm differ diff --git a/res/translations/mixxx_nl_BE.ts b/res/translations/mixxx_nl_BE.ts index 5a0d80d8c42..483b13da4b2 100644 --- a/res/translations/mixxx_nl_BE.ts +++ b/res/translations/mixxx_nl_BE.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Kan het nummer niet laden. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Actie mislukt - + Please enable at least one connection to use Live Broadcasting. Schakel ten minste één verbinding in om Live Broadcasting te gebruiken. @@ -3442,14 +3442,14 @@ Eerdere Medewerkers - + Official Website Officiële Website - + Donate - + Donaties @@ -3469,7 +3469,7 @@ Date: - + Datum: @@ -5631,37 +5631,37 @@ U kunt de tracks ten allen tijde op het scherm slepen en neerzetten om een deck DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. De minimale grootte van de geselecteerde skin is groter dan uw schermresolutie. - + Allow screensaver to run Toestaan om screensaver te laten uitvoeren - + Prevent screensaver from running Voorkom dat screensaver wordt uitgevoerd - + Prevent screensaver while playing Voorkom screensaver tijdens afspelen - + This skin does not support color schemes Deze skin ondersteunt geen kleurenschema's - + Information Informatie - + Mixxx must be restarted before the new locale setting will take effect. Mixxx moet opnieuw worden gestart voordat de nieuwe locale-instelling van kracht wordt. @@ -6958,17 +6958,17 @@ Het doelvolume is bij benadering en gaat ervan uit dat track pregain en master o RGB - + OpenGL not available OpenGL niet beschikbaar - + dropped frames verloren frames - + Cached waveforms occupy %1 MiB on disk. Waveforms in cache gebruiken %1 Mb op schijf @@ -8228,12 +8228,12 @@ Wil je het echt overschrijven? One or more MixxxControls specified in the outputs section of the loaded mapping were invalid. - + Een of meer MixxxControls die in de uitvoersectie van de geladen mapping zijn gespecificeerd, waren ongeldig. * Make sure the MixxxControls in question actually exist. Visit the manual for a complete list: - + * Zorg ervoor dat de MixxxControls in kwestie echt bestaan. Ga naar de handleiding voor een volledige lijst: @@ -8853,45 +8853,41 @@ Wilt u nu uw bibliotheek scannen op albumhoezen? Encoder - + Mixxx Needs Access to: %1 Mixxx heeft toegang nodig tot: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - Vanwege Mac Sandboxing hebben we uw toestemming nodig om dit bestand te openen: - -% 1 - -Nadat u op OK heeft geklikt, ziet u een bestandskiezer. Om Mixxx toestemming te geven, moet je '% 2' selecteren om door te gaan. Als u Mixxx geen toegang wilt verlenen, klikt u op Annuleren in de bestandskiezer. Onze excuses voor het ongemak. - -Om deze actie af te breken, drukt u op Annuleren in het bestandsdialoogvenster. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. Je selecteerde het verkeerde bestand. Om Mixxx toegang te verlenen, selecteer het bestand% 1 . Als u niet wil doorgaan, druk op Annuleren. - + Upgrading old Mixxx settings - + Oude Mixxx-instellingen upgraden - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. If you do not want to grant Mixxx access, click Cancel on the file picker. Mixxx will create a new music library and use default settings. - + Als gevolg van macOS sandboxing heeft Mixxx uw toestemming nodig om toegang te krijgen tot uw muziekbibliotheek en instellingen van Mixxx-versies vóór 2.3.0. Nadat u op OK hebt geklikt, ziet u een dialoogvenster voor bestandsselectie. + +Als u Mixxx toestemming wilt geven uw oude bibliotheek en instellingen te gebruiken, klikt u op de knop Openen in het dialoogvenster voor bestandsselectie. Mixxx zal dan uw oude instellingen naar de zandbak verplaatsen. Dit hoeft maar één keer te worden gedaan. + +Als u Mixxx geen toegang wilt verlenen, klikt u op Annuleren in de bestandkiezer. Mixxx maakt een nieuwe muziekbibliotheek en gebruikt standaardinstellingen. @@ -9949,7 +9945,7 @@ Volledig rechts: einde van de effectperiode Parameters of %1 - + Parameters van %1 @@ -10010,34 +10006,34 @@ Volledig rechts: einde van de effectperiode <html>Mixxx cannot record or stream in AAC or HE-AAC without the FDK-AAC encoder. In order to record or stream in AAC or AAC+, you need to download <b>libfdk-aac</b> and install it on your system. - + <html>Mixxx kan niet opnemen of streamen in AAC of HE-AAC zonder de FDK-AAC-encoder. Om op te nemen of te streamen in AAC of AAC+, moet u <b>libfdk-aac</b> downloaden en op uw systeem installeren. The installed AAC encoding library does not support HE-AAC, only plain AAC. Configure a different encoding format in the preferences. - + De geïnstalleerde AAC-coderingsbibliotheek ondersteunt HE-AAC niet, alleen gewone AAC. Configureer een ander coderingsformaat in de voorkeuren. MP3 encoding is not supported. Lame could not be initialized - + MP3-codering wordt niet ondersteund. Lame kan niet worden geïnitialiseerd OGG recording is not supported. OGG/Vorbis library could not be initialized. - + OGG-opname wordt niet ondersteund. OGG/Vorbis-bibliotheek kan niet worden geïnitialiseerd. encoder failure - + encoderfout Failed to apply the selected settings. - + Kan de geselecteerde instellingen niet toepassen. @@ -10170,7 +10166,7 @@ Volledig rechts: einde van de effectperiode Reads databases exported for Pioneer CDJ / XDJ players using the Rekordbox Export mode.<br/>Rekordbox can only export to USB or SD devices with a FAT or HFS file system.<br/>Mixxx can read a database from any device that contains the database folders (<tt>PIONEER</tt> and <tt>Contents</tt>).<br/>Not supported are Rekordbox databases that have been moved to an external device via<br/><i>Preferences > Advanced > Database management</i>.<br/><br/>The following data is read: - + Leest databases die zijn geëxporteerd voor Pioneer CDJ / XDJ-spelers met behulp van de <br/>Rekordbox Exportmodus.Rekordbox kan alleen exporteren naar USB- of SD-apparaten met een FAT- of HFS-bestandssysteem. <br/>Mixxx kan een database lezen van elk apparaat dat de databasemappen bevat (<tt>PIONEER</tt> en <tt>Inhoud</tt>). <br/>Niet ondersteund worden Rekordbox-databases die zijn verplaatst naar een extern apparaat via <br/><i>Voorkeuren > Geavanceerd > Databasebeheer</i>.<br/><br/>De volgende gegevens worden gelezen: @@ -10180,12 +10176,12 @@ Volledig rechts: einde van de effectperiode Loops (only the first loop is currently usable in Mixxx) - + Loops (alleen de eerste loop is momenteel bruikbaar in Mixxx) Check for attached Rekordbox USB / SD devices (refresh) - + Controleer op aangesloten Rekordbox USB / SD-apparaten (vernieuwen) @@ -10232,7 +10228,7 @@ Volledig rechts: einde van de effectperiode Mixxx Sampler Banks (*%1) - + Mixxx Sampler-banken (*%1) @@ -10293,27 +10289,27 @@ Volledig rechts: einde van de effectperiode SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Historiek - + Unlock Ontgrendel - + Lock Vergrendelen @@ -10414,17 +10410,17 @@ Volledig rechts: einde van de effectperiode Unknown stream encoding format! - + Onbekend stream coderingsformaat! Use a libshout version with %1 enabled - + Gebruik een libshout-versie met %1 ingeschakeld Error setting stream encoding format! - + Fout bij instellen van streamcoderingsformaat! @@ -10454,7 +10450,7 @@ Volledig rechts: einde van de effectperiode Error: Shoutcast only supports MP3 and AAC encoders - + Error: Shoutcast only supports MP3 and AAC encoders @@ -10467,47 +10463,47 @@ Volledig rechts: einde van de effectperiode Netwerk cache overflow - + Connection error Connectiefout - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> Een van de Live Uitzending-verbindingen veroorzaakte deze fout:<br><b>Fout met verbinding '%1':</b><br> - + Connection message Connectiebericht - + <b>Message from Live Broadcasting connection '%1':</b><br> <b>Bericht van Live Uitzending-verbinding '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. Verbinding met streaming-server is verbroken en %1 pogingen om opnieuw verbinding te maken, zijn mislukt. - + Lost connection to streaming server. Verbinding met de streaming-server verbroken. - + Please check your connection to the Internet. Controleer uw verbinding met internet. - + Can't connect to streaming server Kan niet verbinden met de streaming-server - + Please check your connection to the Internet and verify that your username and password are correct. Controleer uw verbinding met internet en controleer of uw gebruikersnaam en wachtwoord correct zijn. @@ -10635,7 +10631,7 @@ Volledig rechts: einde van de effectperiode Double-click - + Dubbelklik @@ -10645,7 +10641,7 @@ Volledig rechts: einde van de effectperiode Shift-key - + Shift-toets @@ -11230,7 +11226,7 @@ Volledig rechts: einde van de effectperiode (while previewing) - + (tijdens het bekijken) @@ -11250,7 +11246,7 @@ Volledig rechts: einde van de effectperiode Is latching the playing state. - + Vergrendelt de afspeelstatus. @@ -11280,7 +11276,7 @@ Volledig rechts: einde van de effectperiode Tempo Range Display - + <div></div> @@ -11310,12 +11306,12 @@ Volledig rechts: einde van de effectperiode Big Spinny/Cover Art - + Big Spinny/Cover Art Show a big version of the Spinny or track cover art if enabled. - + Toon een grote versie van de Spinny of track cover art indien ingeschakeld. @@ -11397,32 +11393,32 @@ Volledig rechts: einde van de effectperiode Show/hide Cover Art of the selected track in the library. - + Toon/verberg Cover Art van de geselecteerde track in de bibliotheek. Show/hide the scrolling waveforms - + De scrollende waveforms tonen/verbergen Show/hide the beatgrid controls section - + Toon/verberg de beatgrid-besturingssectie Hide all skin sections except the decks to have more screen space for the track library. - + Verberg alle skinsecties behalve de decks om meer schermruimte te hebben voor de trackbibliotheek. Volume Meters - + Volume Meters Show/hide volume meters for channels and master output. - + Toon/verberg volumemeters voor kanalen en masteruitgang. @@ -14285,22 +14281,22 @@ Gebruik deze optie om alleen het verwerkte (Wet) signaal met EQ en filtereffecte WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) (GLSL ES) - + (GL ES) (GL ES) @@ -14308,52 +14304,52 @@ Gebruik deze optie om alleen het verwerkte (Wet) signaal met EQ en filtereffecte main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14363,17 +14359,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14381,52 +14377,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Kies de map voor de muziekbibliotheek - + controllers - + Cannot open database Kan database niet openen - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14556,7 +14552,7 @@ Klik op OK om af te sluiten. Abort - + Afbreken @@ -14630,4 +14626,12 @@ Klik op OK om af te sluiten. Geen netwerktoegang + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_nl_NL.qm b/res/translations/mixxx_nl_NL.qm index ee29a629c42..135ddb9d5ad 100644 Binary files a/res/translations/mixxx_nl_NL.qm and b/res/translations/mixxx_nl_NL.qm differ diff --git a/res/translations/mixxx_nl_NL.ts b/res/translations/mixxx_nl_NL.ts index 1bccca9abdd..fc0e41b12b7 100644 --- a/res/translations/mixxx_nl_NL.ts +++ b/res/translations/mixxx_nl_NL.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Kan track niet laden. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Actie mislukt - + Please enable at least one connection to use Live Broadcasting. Zet minstens één connectie aan om Live Uitzenden te gebruiken. @@ -3442,12 +3442,12 @@ - + Official Website - + Donate @@ -5568,37 +5568,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information Informatie - + Mixxx must be restarted before the new locale setting will take effect. @@ -6892,17 +6892,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8771,33 +8771,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10179,27 +10177,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Onsluit - + Lock Zet vast @@ -10353,47 +10351,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14169,22 +14167,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14192,52 +14190,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14247,17 +14245,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14265,52 +14263,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14511,4 +14509,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_nn.qm b/res/translations/mixxx_nn.qm index 454d2edd7e3..f9f430d3e55 100644 Binary files a/res/translations/mixxx_nn.qm and b/res/translations/mixxx_nn.qm differ diff --git a/res/translations/mixxx_nn.ts b/res/translations/mixxx_nn.ts index 2afc80b8d3f..bcddd0c5c9d 100644 --- a/res/translations/mixxx_nn.ts +++ b/res/translations/mixxx_nn.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Kunne ikkje åpna sangen @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Lås opp - + Lock Lås @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_oc.qm b/res/translations/mixxx_oc.qm index 04833206e9b..64ca28cfc9f 100644 Binary files a/res/translations/mixxx_oc.qm and b/res/translations/mixxx_oc.qm differ diff --git a/res/translations/mixxx_oc.ts b/res/translations/mixxx_oc.ts index ed783c9ac0b..2cd15383e98 100644 --- a/res/translations/mixxx_oc.ts +++ b/res/translations/mixxx_oc.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Impossible de cargar la pista. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information Informacions - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Desvarrolhar - + Lock Varrolhar @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface interfàcia àudio - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_pl.qm b/res/translations/mixxx_pl.qm index bbfae9291bb..5fb27558a70 100644 Binary files a/res/translations/mixxx_pl.qm and b/res/translations/mixxx_pl.qm differ diff --git a/res/translations/mixxx_pl.ts b/res/translations/mixxx_pl.ts index e91207d6a12..071d84bf20d 100644 --- a/res/translations/mixxx_pl.ts +++ b/res/translations/mixxx_pl.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Nie mogę załadować ścieżki. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Akcja zakończona niepowodzeniem - + Please enable at least one connection to use Live Broadcasting. Aby użyć Live Broadcasting ustaw przynajmniej jedno połączenie. @@ -3442,12 +3442,12 @@ Byli współpracownicy - + Official Website - + Donate @@ -5569,37 +5569,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. Minimalny rozmiar wybranej skórki jest większy niż dostępna rozdzielczość ekranu. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes Ta skórka nie obsługuje schematów kolorów. - + Information Informacja - + Mixxx must be restarted before the new locale setting will take effect. @@ -6893,17 +6893,17 @@ The loudness target is approximate and assumes track pregain and master output l RGB - + OpenGL not available OpenGL niedostępne - + dropped frames opuszczone ramki - + Cached waveforms occupy %1 MiB on disk. @@ -8777,39 +8777,31 @@ Czy chcesz przeskanować Twoją bibliotekę plików teraz? Program kodujący - + Mixxx Needs Access to: %1 Mixxx wymaga dostępu do: %1 - - Due to Mac Sandboxing, we need your permission to access this file: - -%1 - -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - Z powodu Mac Sandboxing, potrzebujemy Twojej zgody na dostęp to tego pliku: + + Your permission is required to access the following location: %1 -Gdy klikniesz OK, zobaczysz wybór pliku. Aby udzielić Mixx'owi zgody musisz wybrać '%2' aby kontynuować. Jeśli nie chcesz Mixxx'owi zagwarantować dostępu kliknij Anuluj przy wyborze pliku. Przepraszamy za niedogodności. - -Aby anulować tą akcję , wciśniej Anuluj na okienku dialogowym pliku. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. Wybrano zły plik. Aby zagwarantować Mixxx'owi dostęp, proszę wybrać plik '%1'. Jeśli nie chcesz kontynuować wciśnij Anuluj. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10191,27 +10183,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Historia - + Unlock Odblokuj - + Lock Zablokuj @@ -10365,47 +10357,47 @@ Fully right: end of the effect period - + Connection error Błąd połączenia - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. Utracono połączenie z serwerem strumieniowym. Liczba nieudanych połączeń: %1 - + Lost connection to streaming server. Utracono połączenie z serwerem strumieniowym. - + Please check your connection to the Internet. Sprawdź swoje połączenie z Internetem. - + Can't connect to streaming server Nie można połączyć się z serwerem strumienia - + Please check your connection to the Internet and verify that your username and password are correct. Sprawdź połączenie z Internetem i zweryfikuj nazwę użytkownika i hasło @@ -14183,22 +14175,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14206,52 +14198,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14261,17 +14253,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14279,52 +14271,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Wybierz katalog biblioteki utworów. - + controllers - + Cannot open database Nie mogę otworzyć bazy danych - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14528,4 +14520,12 @@ Kliknij OK aby wyjść. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + Nie załadowano efektu. + + \ No newline at end of file diff --git a/res/translations/mixxx_pt.qm b/res/translations/mixxx_pt.qm index 52ed8c52753..9227eb0a6a4 100644 Binary files a/res/translations/mixxx_pt.qm and b/res/translations/mixxx_pt.qm differ diff --git a/res/translations/mixxx_pt.ts b/res/translations/mixxx_pt.ts index 7737db72b85..223006c9c58 100644 --- a/res/translations/mixxx_pt.ts +++ b/res/translations/mixxx_pt.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. NAO FOI Possível carregar a Faixa @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ Colaboradores antigos - + Official Website - + Donate @@ -5567,37 +5567,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information Informação - + Mixxx must be restarted before the new locale setting will take effect. @@ -6891,17 +6891,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available OpenGL não disponível - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8773,33 +8773,31 @@ Do you want to scan your library for cover files now? Codificador - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10181,27 +10179,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Histórico - + Unlock Desbloquear - + Lock Bloquear @@ -10355,47 +10353,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. Queira verificar a sua ligação à Internet e que a sua identificação e palavra passe estão correctas. @@ -14171,22 +14169,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14194,52 +14192,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14249,17 +14247,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14267,52 +14265,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Escolha a pasta da biblioteca musical - + controllers - + Cannot open database Não é possível abrir a base de dados - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14516,4 +14514,12 @@ Clique em OK para sair. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_pt_BR.qm b/res/translations/mixxx_pt_BR.qm index b02513c9705..0cf53a8bc53 100644 Binary files a/res/translations/mixxx_pt_BR.qm and b/res/translations/mixxx_pt_BR.qm differ diff --git a/res/translations/mixxx_pt_BR.ts b/res/translations/mixxx_pt_BR.ts index 97556366629..61f997ba976 100644 --- a/res/translations/mixxx_pt_BR.ts +++ b/res/translations/mixxx_pt_BR.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Não foi possível carregar a faixa. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Ação falhou - + Please enable at least one connection to use Live Broadcasting. Ativar pelo menos uma conexão para usar a transmissão ao vivo. @@ -3442,12 +3442,12 @@ Contribuidores Anteriores - + Official Website - + Donate @@ -5589,37 +5589,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. O tamanho mínimo da skin selecionada é maior do que a sua resolução de tela. - + Allow screensaver to run Permitir que o protetor de tela execute - + Prevent screensaver from running Prevenir que o protetor de tela execute - + Prevent screensaver while playing Prevenir o protetor de tela quando tocando - + This skin does not support color schemes Esta skin não suporta esquemas de cor - + Information Informação - + Mixxx must be restarted before the new locale setting will take effect. O Mixxx deve ser reiniciado para que a nova mudança de localidade tenha efeito. @@ -6915,17 +6915,17 @@ O volume-alvo é aproximado e assume que o pré-ganho da faixa e o nível da sa RGB - + OpenGL not available OpenGL não disponível - + dropped frames quadros perdidos - + Cached waveforms occupy %1 MiB on disk. Ondas no cache ocupam %1 MiB no disco. @@ -8800,39 +8800,31 @@ Você quer examinar a sua biblioteca procurando por arquivos de capa agora?Codificador - + Mixxx Needs Access to: %1 Mixxx Precisa Acessar: %1 - - Due to Mac Sandboxing, we need your permission to access this file: - -%1 - -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - Por causa da Caixa de Areia do Mac, nós precisamos da sua permissão para acessar este arquivo: + + Your permission is required to access the following location: %1 -Depois de clicar OK, você vai ver um seletor de arquivos. Para dar a permissão ao Mixxx, você deve selecionar '%2' para prosseguir. Se você não quiser dar o acesso ao Mixxx, clique Cancelar no seletor de arquivos. Desculpe pelo inconveniente. - -Para abortar esta ação, pressione Cancelar no diálogo de arquivos. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. Você selecionou o arquivo errado. Para conceder acesso ao Mixxx, por favor selecione o arquivo '%1'. Se você não quer continuar, pressione Cancelar. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10214,27 +10206,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Histórico - + Unlock Destravar - + Lock Travar @@ -10388,47 +10380,47 @@ Fully right: end of the effect period Overflow do cache da rede - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. A conexão com o servidor de streaming foi perdida e %1 tentativas de reconectar falharam. - + Lost connection to streaming server. A conexão com o servidor de streaming foi perdida. - + Please check your connection to the Internet. Por favor verifique a sua conexão com a internet. - + Can't connect to streaming server A conexão com o servidor de streaming não foi possível. - + Please check your connection to the Internet and verify that your username and password are correct. Por favor verifique a sua conexão com a internet e verifique se o seu usuário e senha estão corretos. @@ -14204,22 +14196,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14227,52 +14219,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode Começa o Mixxx em tela cheia - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. Diretório de nível alto onde o Mixxx deve procurar por seus arquivos de recursos como mapeamentos MIDI, sendo usado no lugar da localização da instalação. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14282,17 +14274,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14300,52 +14292,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Escolha o diretório da biblioteca de música - + controllers - + Cannot open database Não foi possível abrir o banco de dados - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14549,4 +14541,12 @@ Clique OK para sair. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_pt_PT.qm b/res/translations/mixxx_pt_PT.qm index 89838f36db8..671eb6dc7ad 100644 Binary files a/res/translations/mixxx_pt_PT.qm and b/res/translations/mixxx_pt_PT.qm differ diff --git a/res/translations/mixxx_pt_PT.ts b/res/translations/mixxx_pt_PT.ts index 44a7b154632..b942e26ab42 100644 --- a/res/translations/mixxx_pt_PT.ts +++ b/res/translations/mixxx_pt_PT.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Não conseguiu carregar a faixa. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Ação falhada - + Please enable at least one connection to use Live Broadcasting. Por favor ative pelo menos uma ligação para usar Emissão em Direto @@ -3442,12 +3442,12 @@ Colaboradores antigos - + Official Website - + Donate @@ -5589,37 +5589,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. O tamanho mínimo da Skin escolhida é maior que a resolução do seu ecrã. - + Allow screensaver to run Permitir correr o protetor de ecrã - + Prevent screensaver from running Impedir correr o protetor de ecrã - + Prevent screensaver while playing Impedir protetor de ecrã enquanto estiver a tocar - + This skin does not support color schemes Esta Skin não suporta esquemas de cores - + Information Informação - + Mixxx must be restarted before the new locale setting will take effect. O Mixxx deve ser reiniciado antes de a nova definição de localização ter efeito. @@ -6914,17 +6914,17 @@ O nível de loudness é aproximado e assume que o ganho do preamplificador da fa RGB - + OpenGL not available OpenGL não disponível - + dropped frames fotogramas perdidos - + Cached waveforms occupy %1 MiB on disk. Formas de onda em cache ocupam %1 MB em disco. @@ -8805,39 +8805,31 @@ Deseja examinar a sua biblioteca para encontrar ficheiros de capa de disco, agor Codificador - + Mixxx Needs Access to: %1 Mixxx Precisa de Acesso a: %1 - - Due to Mac Sandboxing, we need your permission to access this file: - -%1 - -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - Devido à Sandbox do Mac, precisamos que dê permissão para aceder a este ficheiro: + + Your permission is required to access the following location: %1 -Depois de carregar em OK, irá ver o seletor de ficheiros. Para dar ao Mixx permissão, tem de seleccionar '%2' para proceguir. Se não quiser dar ao Mixx acesso, carregue em Cancelar no seletor de ficheiros. Lamentamos a inconveniencia. - -Para abortar esta acção, prima Cancelar no diálogo de ficheiro. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. Selecionou o ficheiro errado. Para conceder acesso ao Mixxx, por favor selecione o ficheiro '%1'. Se não desejar continuar, pressione Cancelar. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10244,27 +10236,27 @@ Tudo direita: fim do período do efeito SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Histórico - + Unlock Desbloquear - + Lock Bloquear @@ -10418,47 +10410,47 @@ Tudo direita: fim do período do efeito Erro de overflow na cache de rede - + Connection error Erro de ligação - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> Uma das ligações de Emissão em Direto apresentou este erro:<br><b>Erro com a ligação '%1':</b><br> - + Connection message Mensagem da ligação - + <b>Message from Live Broadcasting connection '%1':</b><br> <b>Mensagem da ligação Emissão em Direto '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. Ligação ao servidor de streaming perdida e %1 tentativas de religação falharam. - + Lost connection to streaming server. A ligação ao servidor de streaming perdida. - + Please check your connection to the Internet. Por favor, verifique a sua conecção à internet. - + Can't connect to streaming server Não se consegue ligar ao servidor de streaming. - + Please check your connection to the Internet and verify that your username and password are correct. Por favor, verifique a sua ligação à Internet e verifique que o seu nome de utilizador e password estão corretos. @@ -14236,22 +14228,22 @@ Usar isto para alterar apenas o sinal já com os efeitos (molhado) de EQ e filtr WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) (GLSL ES) - + (GL ES) (GL ES) @@ -14259,52 +14251,52 @@ Usar isto para alterar apenas o sinal já com os efeitos (molhado) de EQ e filtr main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14314,17 +14306,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14332,52 +14324,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Escolher a pasta biblioteca musical - + controllers - + Cannot open database Não pode abrir a base de dados. - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14581,4 +14573,12 @@ Clique OK para sair. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + No effect loaded. + + \ No newline at end of file diff --git a/res/translations/mixxx_ro.qm b/res/translations/mixxx_ro.qm index db2ef617d35..a3f06ae61bb 100644 Binary files a/res/translations/mixxx_ro.qm and b/res/translations/mixxx_ro.qm differ diff --git a/res/translations/mixxx_ro.ts b/res/translations/mixxx_ro.ts index 91b2b95fbd7..2253da049ea 100644 --- a/res/translations/mixxx_ro.ts +++ b/res/translations/mixxx_ro.ts @@ -261,7 +261,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Nu se poate încărca pista. @@ -402,12 +402,12 @@ BroadcastManager - + Action failed Acțiune eșuată - + Please enable at least one connection to use Live Broadcasting. @@ -3441,12 +3441,12 @@ Foști contribuitori - + Official Website - + Donate @@ -5569,37 +5569,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. Dimensiunea minimă a aspectului aplicației este mai mare decât rezoluția ecranului. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes Acest aspect aplicație nu suportă scheme de culoare - + Information Informație - + Mixxx must be restarted before the new locale setting will take effect. @@ -6894,17 +6894,17 @@ The loudness target is approximate and assumes track pregain and master output l RGB - + OpenGL not available OpenGL nu este disponibil - + dropped frames cadre omise - + Cached waveforms occupy %1 MiB on disk. @@ -8776,33 +8776,31 @@ Doriți să scanați acum biblioteca pentru fișiere copertă? Codor - + Mixxx Needs Access to: %1 Mixxx are nevoie de acces la %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. Ați selectat fișierul greșit. Pentru a asigura accesul Mixxx, selectați fișierul '%1'. Dacă nu doriți să continuați, apăsați Anulare. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10184,27 +10182,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Istoric - + Unlock Deblochează - + Lock Blochează @@ -10358,47 +10356,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server Nu se poate conecta la serverul de transmisie - + Please check your connection to the Internet and verify that your username and password are correct. Verificați conexiunea la internet și verificați dacă numele de utilizator și parola sunt corecte. @@ -14174,22 +14172,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14197,52 +14195,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14252,17 +14250,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14270,52 +14268,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Alege directorul bibliotecii de muzică - + controllers - + Cannot open database Baza de date nu poate fi deschisă - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14519,4 +14517,12 @@ Apăsați OK să ieșiți. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_ru.qm b/res/translations/mixxx_ru.qm index 3b157518183..32378d06639 100644 Binary files a/res/translations/mixxx_ru.qm and b/res/translations/mixxx_ru.qm differ diff --git a/res/translations/mixxx_ru.ts b/res/translations/mixxx_ru.ts index 3addbdb2287..7d2bf12b3ed 100644 --- a/res/translations/mixxx_ru.ts +++ b/res/translations/mixxx_ru.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Не удалось загрузить трек. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Действие провалено - + Please enable at least one connection to use Live Broadcasting. Пожалуйста, включите хотя бы одно подключение для Живой Трансляции @@ -3442,12 +3442,12 @@ Последние участники - + Official Website - + Donate @@ -5580,37 +5580,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. Минимальный размер выбранного кожи больше, чем разрешение экрана. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes Эта кожа не поддерживает цветовые схемы - + Information Информация - + Mixxx must be restarted before the new locale setting will take effect. @@ -6906,17 +6906,17 @@ The loudness target is approximate and assumes track pregain and master output l RGB - + OpenGL not available OpenGL не доступны - + dropped frames пропуск кадров - + Cached waveforms occupy %1 MiB on disk. Кэшированные осциллограммы занимают %1 МБ на диске. @@ -8791,35 +8791,31 @@ Do you want to scan your library for cover files now? Кодировщик - + Mixxx Needs Access to: %1 Mixxx необходим доступ к: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - Благодаря Mac песочниц, нам необходимо ваше разрешение на доступ к этот файл: %1 после нажатия кнопки ОК, вы увидите средство выбора файлов. Чтобы предоставить разрешение Mixxx, необходимо выбрать «%2» для продолжения. Если вы не хотите предоставлять Mixxx доступа нажмите кнопку Отмена на средства выбора файлов. Мы приносим извинения за неудобства. - -Для отмены этого действия, нажмите кнопку Отмена в диалоговом окне файла. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. Вы выбрали неправильный файл. Чтобы предоставить доступ Mixxx, пожалуйста, выберите файл «%1». Если вы не хотите, чтобы продолжить, нажмите кнопку Отмена. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10201,27 +10197,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History История - + Unlock Разблокировать - + Lock Заблокировать @@ -10375,47 +10371,47 @@ Fully right: end of the effect period Переполнение сетевого кэша - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. Соединение с сервером потеряно. - + Please check your connection to the Internet. Пожалуйста, проверьте ваше соединение с Internet. - + Can't connect to streaming server Не удается подключиться к сервер потокового - + Please check your connection to the Internet and verify that your username and password are correct. Пожалуйста, проверьте подключение к Интернету и проверить правильность имени пользователя и пароля. @@ -14191,22 +14187,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14214,52 +14210,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14269,17 +14265,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14287,52 +14283,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts шрифты - + database база данных - + effects эффекты - + audio interface аудио интерфейс - + decks деки - + library библиотека - + Choose music library directory Выберите каталог библиотеки музыки - + controllers контроллеры - + Cannot open database Не удалось открыть базу данных - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14536,4 +14532,12 @@ Mixxx требует QT с поддержкой SQLite. Пожалуйста, п Нет доступа к сети + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_ru_RU.qm b/res/translations/mixxx_ru_RU.qm index 9cbc467610f..1b6d411c04d 100644 Binary files a/res/translations/mixxx_ru_RU.qm and b/res/translations/mixxx_ru_RU.qm differ diff --git a/res/translations/mixxx_ru_RU.ts b/res/translations/mixxx_ru_RU.ts index 966a95d5627..ecab39874f9 100644 --- a/res/translations/mixxx_ru_RU.ts +++ b/res/translations/mixxx_ru_RU.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Невозможно загрузить трек. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Действие не удалось - + Please enable at least one connection to use Live Broadcasting. @@ -3442,12 +3442,12 @@ Прошлые помощники - + Official Website - + Donate @@ -5568,37 +5568,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information Информация - + Mixxx must be restarted before the new locale setting will take effect. Mixxx должен быть перезапущен до вступления в силу новых настроек локали. @@ -6892,17 +6892,17 @@ The loudness target is approximate and assumes track pregain and master output l RGB - + OpenGL not available OpenGL недоступен - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8773,33 +8773,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 Mixxx требует доступ к: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10181,27 +10179,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History История - + Unlock Разблокировать - + Lock Блокировать @@ -10355,47 +10353,47 @@ Fully right: end of the effect period - + Connection error Ошибка подключения - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. Пожалуйста, проверьте подключение к интернету. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. Пожалуйста, проверьте подключение к интернету и убедитесь, что логин и пароль верные. @@ -14171,22 +14169,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) (GLSL ES) - + (GL ES) (GL ES) @@ -14194,52 +14192,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14249,17 +14247,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14267,52 +14265,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database Невозможно открыть базу данных - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14513,4 +14511,12 @@ Click OK to exit. Нет доступа к сети + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_si.qm b/res/translations/mixxx_si.qm index efcaed69b0d..400708d5885 100644 Binary files a/res/translations/mixxx_si.qm and b/res/translations/mixxx_si.qm differ diff --git a/res/translations/mixxx_si.ts b/res/translations/mixxx_si.ts index 7c86b7e1a29..0584c6bf2e9 100644 --- a/res/translations/mixxx_si.ts +++ b/res/translations/mixxx_si.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. පථය ප්‍රවේශණය කල නොහැක. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock අගුළු අරින්න - + Lock අගුළුලන්න @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_sk.qm b/res/translations/mixxx_sk.qm index 1fa87b714c8..dc03b7a9e4d 100644 Binary files a/res/translations/mixxx_sk.qm and b/res/translations/mixxx_sk.qm differ diff --git a/res/translations/mixxx_sk.ts b/res/translations/mixxx_sk.ts index 097d0161363..1fdaf9cadc6 100644 --- a/res/translations/mixxx_sk.ts +++ b/res/translations/mixxx_sk.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Chyba pri načítaní súboru @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Odomkni - + Lock Uzamknúť @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_sl.qm b/res/translations/mixxx_sl.qm index 5bd8b34999a..08d8e3c4d63 100644 Binary files a/res/translations/mixxx_sl.qm and b/res/translations/mixxx_sl.qm differ diff --git a/res/translations/mixxx_sl.ts b/res/translations/mixxx_sl.ts index d0b0a94cee3..5154042bf89 100644 --- a/res/translations/mixxx_sl.ts +++ b/res/translations/mixxx_sl.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Ne morem naložiti skladbe. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Spodletelo dejanje - + Please enable at least one connection to use Live Broadcasting. Za oddajanje v živo aktivirajte vsaj eno povezavo. @@ -3442,12 +3442,12 @@ Bivši sodelujoči - + Official Website Uradna spletna stran - + Donate @@ -5629,37 +5629,37 @@ Vedno lahko skladbe tudi povlečete in sputite, da podvojite nek predvajalnik. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. Najmanjša velikost izbrane preobleke je večja od ločljivosti vašega zaslona. - + Allow screensaver to run Dovoli zagon ohranjevalniku zaslona - + Prevent screensaver from running Prepreči delovanje ohranjevalniku zaslona - + Prevent screensaver while playing Prepreči ohranjevalnik zaslona med predvajanjem - + This skin does not support color schemes Ta preobleka ne podpira barvnih shem - + Information Informacija - + Mixxx must be restarted before the new locale setting will take effect. Mixxx je potrebno ponovno zagnati, da bi nove lokalne nastavitve začele delovati. @@ -6956,17 +6956,17 @@ Ciljna glasnost je približna in predpostavlja, da ostaneta predojačitev in izh RGB - + OpenGL not available OpenGL ni na voljo - + dropped frames izpuščenih sličic - + Cached waveforms occupy %1 MiB on disk. Predpomnjene valovne oblike na disku zasedajo %1 MiB. @@ -8851,39 +8851,31 @@ Do you want to scan your library for cover files now? Kodirnik - + Mixxx Needs Access to: %1 Mixxx potrebuje dostop do: %1 - - Due to Mac Sandboxing, we need your permission to access this file: - -%1 - -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - Zaradi macovih pskovnikov je potrebno dovoljenje za dostop do te datoteke: + + Your permission is required to access the following location: %1 -Po kliku na V redu boste videli izbirnik datotek. Da bi Mixxx pridobil pravice je potrebno izbrati '%2'. Če tega ne želite kliknite na Prekini. Opravičujemo se za nevšečnosti. - -Če želite prekiniti to dejanje, pristisnite Prekini. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. Izbrali ste napačno datoteko. Da bi Mixxx pridobil pravice, izberite datoteko '%1'. Če ne želite nadaljevati, pritisnite Prekini. - + Upgrading old Mixxx settings Nadgradnja starih Mixxx nastavitev - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10294,27 +10286,27 @@ Popolnoma na desni: konec periode efekta SetlogFeature - + Join with previous (below) Združi s prejšnjim (spodaj) - + Finish current and start new Zaključi trenutnega in začni novega - + History Zgodovina - + Unlock Odkleni - + Lock Zakleni @@ -10468,47 +10460,47 @@ Popolnoma na desni: konec periode efekta Presežena količina za mrežni medpomnilnik! - + Connection error Napaka pri povezovanju - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> Ena od povezav za oddajanje v živo je povzročila naslednjo napako:<br><b>Napaka pri povezavi '%1':</b><br> - + Connection message Sporočilo povezave - + <b>Message from Live Broadcasting connection '%1':</b><br> <b>Sporočilo povezave za oddajanje v živo '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. Izgubljena povezava s pretočnim strežnikom in %1 neuspelih poskusov ponovnega povezovanja. - + Lost connection to streaming server. Izgubljena povezava s pretočnim strežnikom. - + Please check your connection to the Internet. Preverite internetno povezavo. - + Can't connect to streaming server Ni se mogoče povezati s pretočnim strežnikom. - + Please check your connection to the Internet and verify that your username and password are correct. Preverite internetno povezavo in poskrbite, da sta uprabniško ime in geslo pravilna. @@ -14286,22 +14278,22 @@ To se uporablja za spreminjanje zvoka zgolj z učinki obogatenega signala (wet) WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) (GLSL ES) - + (GL ES) (GL ES) @@ -14309,52 +14301,52 @@ To se uporablja za spreminjanje zvoka zgolj z učinki obogatenega signala (wet) main - + Starts Mixxx in full-screen mode Zaženi Mixxx preko celega zaslona - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. Vrhnji direktorij v katerem Mixxx išče resurse, kot so MIDI mapiranja. S tem se povozi sicer privzeta lokacija namestitve. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14364,17 +14356,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14382,52 +14374,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects učinki - + audio interface - + decks predvajalnikov - + library - + Choose music library directory Izberi mapo glasbene zbirke - + controllers - + Cannot open database Ni možno odpreti baze podatkov. - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14630,4 +14622,12 @@ Pritisnite OK za izhod. Ni dostopa do omrežja + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_sn.qm b/res/translations/mixxx_sn.qm index cb984058163..157848ab300 100644 Binary files a/res/translations/mixxx_sn.qm and b/res/translations/mixxx_sn.qm differ diff --git a/res/translations/mixxx_sn.ts b/res/translations/mixxx_sn.ts index be5c44a87a7..e2733dc60f6 100644 --- a/res/translations/mixxx_sn.ts +++ b/res/translations/mixxx_sn.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Tatadza kuridza rwiyo. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Zvaramba kuita - + Please enable at least one connection to use Live Broadcasting. Tinokumbira uvhure chero konection imwe zvayo kuti ushandise Live Broadcasting @@ -3442,12 +3442,12 @@ - + Official Website - + Donate @@ -5568,37 +5568,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6892,17 +6892,17 @@ The loudness target is approximate and assumes track pregain and master output l RGB - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8773,33 +8773,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10181,27 +10179,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Sunungura - + Lock Kiya @@ -10355,47 +10353,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14171,22 +14169,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14194,52 +14192,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14249,17 +14247,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14267,52 +14265,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14513,4 +14511,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_sq_AL.qm b/res/translations/mixxx_sq_AL.qm index 4ab59f716cd..fda8d219aa4 100644 Binary files a/res/translations/mixxx_sq_AL.qm and b/res/translations/mixxx_sq_AL.qm differ diff --git a/res/translations/mixxx_sq_AL.ts b/res/translations/mixxx_sq_AL.ts index 5e8fb37cf38..3f455ed3f87 100644 --- a/res/translations/mixxx_sq_AL.ts +++ b/res/translations/mixxx_sq_AL.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock - + Lock Kyç @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_sr.qm b/res/translations/mixxx_sr.qm index 633e153e43e..317b1d86922 100644 Binary files a/res/translations/mixxx_sr.qm and b/res/translations/mixxx_sr.qm differ diff --git a/res/translations/mixxx_sr.ts b/res/translations/mixxx_sr.ts index 9730478a3d7..35c227af3b3 100644 --- a/res/translations/mixxx_sr.ts +++ b/res/translations/mixxx_sr.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Не могу да учитам нумеру. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Операција неуспешна - + Please enable at least one connection to use Live Broadcasting. Бар једна веза мора бити активна за емитовање уживо. @@ -3474,12 +3474,12 @@ Претходни доприносиоци - + Official Website - + Donate @@ -5713,39 +5713,39 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. Овај дизајн захтева резолуцију екрана која је већа од тренутне. - + Allow screensaver to run Дозволи штедњу екрана при раду - + Prevent screensaver from running Спречи штедњу екрана - + Prevent screensaver while playing Спречи гашење екрана при репродукцији - + This skin does not support color schemes Овај дизајн не подржава промену палете боја - + Information Обавештење - + Mixxx must be restarted before the new locale setting will take effect. Миксиксикс ће активирати регионалне поставке тек након следећег покретања. @@ -7108,17 +7108,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available ОпенГЛ није доступан - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8989,33 +8989,31 @@ Do you want to scan your library for cover files now? Кодер - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10397,27 +10395,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Историјат - + Unlock Откључај - + Lock Закључај @@ -10571,47 +10569,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. Молим проверите вашу везу на Интернет и утврдите да ли су ваше корисничко име и лозинка исправни. @@ -14387,22 +14385,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (ГЛСЛ) - + (GL) (ГЛ) - + (GLSL ES) - + (GL ES) @@ -14410,52 +14408,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14465,17 +14463,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14483,52 +14481,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Изаберите директоријум музичке библиотеке - + controllers - + Cannot open database Не могу да отворим базу података - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14732,4 +14730,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_sv.qm b/res/translations/mixxx_sv.qm index ead888bc9a6..a7f9f45fd5e 100644 Binary files a/res/translations/mixxx_sv.qm and b/res/translations/mixxx_sv.qm differ diff --git a/res/translations/mixxx_sv.ts b/res/translations/mixxx_sv.ts index 1c8bf39abbc..20dc00b85f5 100644 --- a/res/translations/mixxx_sv.ts +++ b/res/translations/mixxx_sv.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Kunde inte ladda in låt. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed Åtgärden misslyckades - + Please enable at least one connection to use Live Broadcasting. Vänligen aktivera minst en anslutning för att använda Live-sändning. @@ -3442,12 +3442,12 @@ Tidigare bidragsgivare - + Official Website - + Donate @@ -5570,37 +5570,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. Den minsta storleken för det valda skinnet är större än din skärmupplösning. - + Allow screensaver to run Tillåt skärmsläckare att starta - + Prevent screensaver from running Hindra skärmsläckare från att starta - + Prevent screensaver while playing Hindra skärmsläckare vid uppspelning - + This skin does not support color schemes Det här skinnet har inte stöd för färgscheman - + Information Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6894,17 +6894,17 @@ The loudness target is approximate and assumes track pregain and master output l RGB - + OpenGL not available OpenGL är inte tillgängligt - + dropped frames tappade frames - + Cached waveforms occupy %1 MiB on disk. @@ -8779,39 +8779,31 @@ Do you want to scan your library for cover files now? Kodare - + Mixxx Needs Access to: %1 Mixxx behöver tillgång till: %1 - - Due to Mac Sandboxing, we need your permission to access this file: - -%1 - -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - På grund av Macs sandbox-funktion, behöver vi din tillåtelse att öppna denna fil: + + Your permission is required to access the following location: %1 -Efter att du har klickat på OK kommer du att se en filhanterare. För att ge Mixxx tillåtelse måste du välja '%2' för att fortsätta. Om du inte vill ge Mixxx tillträde klicka Avbryt i filhanteraren. Vi ber om ursäkt för denne obekvämhet. - -För att avbryta denna funktion, klicka på Avbryt i Filfönstret. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. Du valde fel fil. För att ge Mixxx tillgång, välj filen '%1'. Om du inte vill fortsätta, klicka på Avbryt. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10193,27 +10185,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Historia - + Unlock Lås upp - + Lock Lås @@ -10367,47 +10359,47 @@ Fully right: end of the effect period - + Connection error Anslutningsfel - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. Förlorade anslutning till streamingserver. - + Please check your connection to the Internet. - + Can't connect to streaming server Kan inte ansluta till streaming-server - + Please check your connection to the Internet and verify that your username and password are correct. Var god kontrollera anslutningen till Internet och verifiera att användarnamn och lösenord är korrekta. @@ -14183,22 +14175,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14206,52 +14198,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14261,17 +14253,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14279,52 +14271,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Välj mapp för musikbibliotek - + controllers - + Cannot open database Kan inte öppna databasen - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14528,4 +14520,12 @@ Klicka på OK för att avsluta. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_ta.qm b/res/translations/mixxx_ta.qm index a096f2e41de..9dfa550416d 100644 Binary files a/res/translations/mixxx_ta.qm and b/res/translations/mixxx_ta.qm differ diff --git a/res/translations/mixxx_te.qm b/res/translations/mixxx_te.qm index 64003e30975..8b70a1ea710 100644 Binary files a/res/translations/mixxx_te.qm and b/res/translations/mixxx_te.qm differ diff --git a/res/translations/mixxx_te.ts b/res/translations/mixxx_te.ts index 7b394d9923e..ed6a51429e2 100644 --- a/res/translations/mixxx_te.ts +++ b/res/translations/mixxx_te.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock - + Lock తాళంవేయి @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_tr.qm b/res/translations/mixxx_tr.qm index 595af27600b..975d59b8414 100644 Binary files a/res/translations/mixxx_tr.qm and b/res/translations/mixxx_tr.qm differ diff --git a/res/translations/mixxx_tr.ts b/res/translations/mixxx_tr.ts index df4e2634a18..d40e46688a8 100644 --- a/res/translations/mixxx_tr.ts +++ b/res/translations/mixxx_tr.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Parça aktarılamadı. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed İşlem başarısız - + Please enable at least one connection to use Live Broadcasting. Canlı Yayın'ı kullanmak için lütfen en az bir bağlantıyı etkinleştirin. @@ -3445,12 +3445,12 @@ - + Official Website - + Donate @@ -5572,37 +5572,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information Bilgi - + Mixxx must be restarted before the new locale setting will take effect. @@ -6896,17 +6896,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available OpenGL mevcut değil - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8775,33 +8775,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10183,27 +10181,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Geçmiş - + Unlock Kilidi Kaldır - + Lock Kilitle @@ -10357,47 +10355,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14173,22 +14171,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14196,52 +14194,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14251,17 +14249,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14269,52 +14267,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database Veritabanı açılamadı - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14518,4 +14516,12 @@ Mixxx SQLite desteği ile QT gerektirir. Nasıl kurulacağını öğrenmek için + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_uk.qm b/res/translations/mixxx_uk.qm index 9e2b8da0e00..5c0aff40d71 100644 Binary files a/res/translations/mixxx_uk.qm and b/res/translations/mixxx_uk.qm differ diff --git a/res/translations/mixxx_uk.ts b/res/translations/mixxx_uk.ts index 1f28cfdf558..de2d27a19a1 100644 --- a/res/translations/mixxx_uk.ts +++ b/res/translations/mixxx_uk.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Неможливо завантажити трек @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ Попередні автори - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information Інформація - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available OpenGL не доступно - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8771,33 +8771,31 @@ Do you want to scan your library for cover files now? Кодек - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10179,27 +10177,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Історія - + Unlock Розблокувати - + Lock Заблокувати @@ -10353,47 +10351,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. Перевірте підключення до Інтернету і переконайтеся, що ваше ім'я користувача та пароль правильні. @@ -14169,22 +14167,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14192,52 +14190,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14247,17 +14245,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14265,52 +14263,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Виберіть каталог музичної бібліотеки - + controllers - + Cannot open database Не вдається відкрити базу даних - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14514,4 +14512,12 @@ Mixxx необхідно QT з підтримкою SQLite. Будь ласка, + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_uz.qm b/res/translations/mixxx_uz.qm index 6db65a1b18d..068df3adfa6 100644 Binary files a/res/translations/mixxx_uz.qm and b/res/translations/mixxx_uz.qm differ diff --git a/res/translations/mixxx_uz.ts b/res/translations/mixxx_uz.ts index ad290c00a0a..1e4cb36af55 100644 --- a/res/translations/mixxx_uz.ts +++ b/res/translations/mixxx_uz.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Қўшиқ қўшилмади @@ -401,12 +401,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock Қулфдан чиқариш - + Lock Қулфлаш @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_vi.qm b/res/translations/mixxx_vi.qm index 78838198ba2..f8219796cbb 100644 Binary files a/res/translations/mixxx_vi.qm and b/res/translations/mixxx_vi.qm differ diff --git a/res/translations/mixxx_vi.ts b/res/translations/mixxx_vi.ts index 123b31d3cb1..ab7accb7d38 100644 --- a/res/translations/mixxx_vi.ts +++ b/res/translations/mixxx_vi.ts @@ -262,7 +262,7 @@ BaseTrackPlayerImpl - + Couldn't load track. Không thể nạp theo dõi. @@ -403,12 +403,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3442,12 +3442,12 @@ Trong quá khứ những người đóng góp - + Official Website - + Donate @@ -5570,37 +5570,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. Kích thước tối thiểu của vẻ ngoài đã chọn là lớn hơn độ phân giải màn hình của bạn. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes Da này không hỗ trợ phối màu - + Information Thông tin - + Mixxx must be restarted before the new locale setting will take effect. @@ -6896,17 +6896,17 @@ Mục tiêu âm sắc là gần đúng và giả định theo dõi sản lượn RGB - + OpenGL not available OpenGL không sẵn dùng - + dropped frames bỏ khung - + Cached waveforms occupy %1 MiB on disk. @@ -8781,35 +8781,31 @@ Bạn có muốn quét thư viện của bạn cho tệp bìa bây giờ?Mã hóa - + Mixxx Needs Access to: %1 Mixxx cần quyền truy cập vào: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - Do cho Sandboxing Mac, chúng tôi cần sự cho phép của bạn để truy cập vào tập tin này: %1 sau khi nhấp vào OK, bạn sẽ thấy một bảng chọn tập tin. Để cho phép Mixxx, bạn phải chọn '%2' để tiến hành. Nếu bạn không muốn cấp Mixxx truy cập click hủy bỏ vào bộ chọn tập tin. Chúng tôi xin lỗi vì sự bất tiện này. - -Để hủy bỏ hành động này, hãy bấm Hủy trên hộp thoại tập tin. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. Bạn đã chọn các tập tin sai. Để cấp quyền truy cập Mixxx, hãy chọn tệp '%1'. Nếu bạn không muốn tiếp tục, bấm Hủy bỏ. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10191,27 +10187,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History Lịch sử - + Unlock Mở khóa - + Lock Khóa @@ -10365,47 +10361,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server Không thể kết nối với máy chủ streaming - + Please check your connection to the Internet and verify that your username and password are correct. Xin vui lòng kiểm tra kết nối Internet của bạn và xác minh rằng tên người dùng và mật khẩu của bạn là chính xác. @@ -14181,22 +14177,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14204,52 +14200,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14259,17 +14255,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14277,52 +14273,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory Chọn âm nhạc thư viện thư mục - + controllers - + Cannot open database Không thể mở cơ sở dữ liệu - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14526,4 +14522,12 @@ Nhấp vào OK để thoát. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_zh_CN.qm b/res/translations/mixxx_zh_CN.qm index 84ba8e1dea2..1ed29fb88d2 100644 Binary files a/res/translations/mixxx_zh_CN.qm and b/res/translations/mixxx_zh_CN.qm differ diff --git a/res/translations/mixxx_zh_CN.ts b/res/translations/mixxx_zh_CN.ts index a5f4daee427..c52098eb369 100644 --- a/res/translations/mixxx_zh_CN.ts +++ b/res/translations/mixxx_zh_CN.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. 无法加载音轨。 @@ -401,12 +401,12 @@ BroadcastManager - + Action failed 操作失败 - + Please enable at least one connection to use Live Broadcasting. 请在使用实况直播功能之前至少启用一条连接。 @@ -2523,37 +2523,37 @@ Jump / Move Loop Backward %1 Beats - + Jump / Move Loop Backward %1 Beats Jump forward by %1 beats, or if a loop is enabled, move the loop forward %1 beats - + Jump forward by %1 beats, or if a loop is enabled, move the loop forward %1 beats Jump backward by %1 beats, or if a loop is enabled, move the loop backward %1 beats - + Jump backward by %1 beats, or if a loop is enabled, move the loop backward %1 beats Beat Jump / Loop Move Forward Selected Beats - + Beat Jump / Loop Move Forward Selected Beats Jump forward by the selected number of beats, or if a loop is enabled, move the loop forward by the selected number of beats - + Jump forward by the selected number of beats, or if a loop is enabled, move the loop forward by the selected number of beats Beat Jump / Loop Move Backward Selected Beats - + Beat Jump / Loop Move Backward Selected Beats Jump backward by the selected number of beats, or if a loop is enabled, move the loop backward by the selected number of beats - + Jump backward by the selected number of beats, or if a loop is enabled, move the loop backward by the selected number of beats @@ -2703,12 +2703,12 @@ Go to the currently selected item - + Go to the currently selected item Choose the currently selected item and advance forward one pane if appropriate - + Choose the currently selected item and advance forward one pane if appropriate @@ -2758,12 +2758,12 @@ Deck %1 Quick Effect Enable Button - + Deck %1 Quick Effect Enable Button Quick Effect Enable Button - + Quick Effect Enable Button @@ -2773,17 +2773,17 @@ Super Knob (control effects' Meta Knobs) - + Super Knob (control effects' Meta Knobs) Mix Mode Toggle - + Mix Mode Toggle Toggle effect unit between D/W and D+W modes - + Toggle effect unit between D/W and D+W modes @@ -2829,7 +2829,7 @@ Effect Meta Knob (control linked effect parameters) - + Effect Meta Knob (control linked effect parameters) @@ -2849,7 +2849,7 @@ Invert how linked effect parameters change when turning the Meta Knob. - + Invert how linked effect parameters change when turning the Meta Knob. @@ -3440,12 +3440,12 @@ 早期贡献者 - + Official Website - + Donate @@ -3700,7 +3700,7 @@ last sound. Displays the duration and number of selected tracks. - + Displays the duration and number of selected tracks. @@ -3718,7 +3718,8 @@ last sound. Adds a random track from track sources (crates) to the Auto DJ queue. If no track sources are configured, the track is added from the library instead. - + Adds a random track from track sources (crates) to the Auto DJ queue. +If no track sources are configured, the track is added from the library instead. @@ -4199,38 +4200,39 @@ Often results in higher quality beatgrids, but will not do well on tracks that h '%1' has the same Icecast mountpoint as '%2'. Two source connections to the same server can't have the same mountpoint. - + '%1' has the same Icecast mountpoint as '%2'. +Two source connections to the same server can't have the same mountpoint. You can't create more than %1 source connections. - + You can't create more than %1 source connections. Source connection %1 - + Source connection %1 At least one source connection is required. - + At least one source connection is required. Are you sure you want to disconnect every active source connection? - + Are you sure you want to disconnect every active source connection? Confirmation required - + Confirmation required Are you sure you want to delete '%1'? - + Are you sure you want to delete '%1'? @@ -4323,12 +4325,12 @@ Two source connections to the same server can't have the same mountpoint. ICQ - + ICQ AIM - + AIM @@ -4343,12 +4345,12 @@ Two source connections to the same server can't have the same mountpoint. IRC - + IRC Select a source connection above to edit its settings here - + Select a source connection above to edit its settings here @@ -5137,7 +5139,7 @@ Apply settings and continue? Deck Preferences - + Deck Preferences @@ -5543,12 +5545,12 @@ You can always drag-and-drop tracks on screen to clone a deck. Keep metaknob position - + Keep metaknob position Reset metaknob to effect default - + Reset metaknob to effect default @@ -5589,39 +5591,39 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. 您的屏幕分辨率太低,无法容纳所选皮肤的最小尺寸。 - + Allow screensaver to run 允许屏幕保护程序运行 - + Prevent screensaver from running 防止屏幕保护程序运行 - + Prevent screensaver while playing 播放时防止屏幕保护程序运行 - + This skin does not support color schemes 该皮肤不支持色彩方案 - + Information 信息 - + Mixxx must be restarted before the new locale setting will take effect. - + Mixxx must be restarted before the new locale setting will take effect. @@ -5833,7 +5835,7 @@ and allows you to pitch adjust them for harmonic mixing. Discovered LV2 effects - + Discovered LV2 effects @@ -5957,7 +5959,7 @@ and allows you to pitch adjust them for harmonic mixing. Track Metadata Synchronization - + Track Metadata Synchronization @@ -6022,12 +6024,12 @@ and allows you to pitch adjust them for harmonic mixing. Edit metadata after clicking selected track - + Edit metadata after clicking selected track Search-as-you-type timeout: - + Search-as-you-type timeout: @@ -6551,17 +6553,17 @@ The loudness target is approximate and assumes track pregain and master output l Soundcard Clock - + Soundcard Clock Network Clock - + Network Clock Direct monitor (recording and broadcasting only) - + Direct monitor (recording and broadcasting only) @@ -6601,28 +6603,28 @@ The loudness target is approximate and assumes track pregain and master output l Microphone inputs are out of time in the record & broadcast signal compared to what you hear. - + Microphone inputs are out of time in the record & broadcast signal compared to what you hear. Measure round trip latency and enter it above for Microphone Latency Compensation to align microphone timing. - + Measure round trip latency and enter it above for Microphone Latency Compensation to align microphone timing. Refer to the Mixxx User Manual for details. - + Refer to the Mixxx User Manual for details. Configured latency has changed. - + Configured latency has changed. Remeasure round trip latency and enter it above for Microphone Latency Compensation to align microphone timing. - + Remeasure round trip latency and enter it above for Microphone Latency Compensation to align microphone timing. @@ -6675,12 +6677,12 @@ The loudness target is approximate and assumes track pregain and master output l Engine Clock - + Engine Clock Use soundcard clock for live audience setups and lowest latency.<br>Use network clock for broadcasting without a live audience. - + Use soundcard clock for live audience setups and lowest latency.<br>Use network clock for broadcasting without a live audience. @@ -6695,12 +6697,12 @@ The loudness target is approximate and assumes track pregain and master output l Microphone Monitor Mode - + Microphone Monitor Mode Microphone Latency Compensation - + Microphone Latency Compensation @@ -6922,17 +6924,17 @@ The loudness target is approximate and assumes track pregain and master output l RGB - + OpenGL not available OpenGL不可用 - + dropped frames 丢帧 - + Cached waveforms occupy %1 MiB on disk. 缓存的波形占用了 %1 MB 磁盘空间。 @@ -7049,23 +7051,25 @@ The loudness target is approximate and assumes track pregain and master output l The waveform overview shows the waveform envelope of the entire track. Select from different types of displays for the waveform overview, which differ primarily in the level of detail shown in the waveform. - + The waveform overview shows the waveform envelope of the entire track. +Select from different types of displays for the waveform overview, which differ primarily in the level of detail shown in the waveform. The waveform shows the waveform envelope of the track near the current playback position. Select from different types of displays for the waveform, which differ primarily in the level of detail shown in the waveform. - + The waveform shows the waveform envelope of the track near the current playback position. +Select from different types of displays for the waveform, which differ primarily in the level of detail shown in the waveform. Waveform overview type - + Waveform overview type fps - + fps @@ -7100,12 +7104,12 @@ Select from different types of displays for the waveform, which differ primarily Beat grid opacity - + Beat grid opacity Set amount of opacity on beat grid lines. - + Set amount of opacity on beat grid lines. @@ -7115,12 +7119,12 @@ Select from different types of displays for the waveform, which differ primarily Play marker position - + Play marker position Moves the play marker position on the waveforms to the left, right or center (default). - + Moves the play marker position on the waveforms to the left, right or center (default). @@ -7188,7 +7192,7 @@ Select from different types of displays for the waveform, which differ primarily LV2 Plugins - + LV2 Plugins @@ -7678,7 +7682,7 @@ Select from different types of displays for the waveform, which differ primarily Import Metadata from MusicBrainz - + Import Metadata from MusicBrainz @@ -7813,7 +7817,7 @@ Often results in higher quality beatgrids, but will not do well on tracks that h Visible - + Visible @@ -7861,7 +7865,7 @@ Often results in higher quality beatgrids, but will not do well on tracks that h Tremolo - + Tremolo @@ -8123,7 +8127,7 @@ support. Overwrite File? - + Overwrite File? @@ -8131,7 +8135,10 @@ support. The default "m3u" extension was added because none was specified. Do you really want to overwrite it? - + A playlist file with the name "%1" already exists. +The default "m3u" extension was added because none was specified. + +Do you really want to overwrite it? @@ -8425,7 +8432,7 @@ Do you want to select an input device? Direct rendering is not enabled on your machine.<br><br>This means that the waveform displays will be very<br><b>slow and may tax your CPU heavily</b>. Either update your<br>configuration to enable direct rendering, or disable<br>the waveform displays in the Mixxx preferences by selecting<br>"Empty" as the waveform display in the 'Interface' section. - + Direct rendering is not enabled on your machine.<br><br>This means that the waveform displays will be very<br><b>slow and may tax your CPU heavily</b>. Either update your<br>configuration to enable direct rendering, or disable<br>the waveform displays in the Mixxx preferences by selecting<br>"Empty" as the waveform display in the 'Interface' section. @@ -8740,7 +8747,7 @@ Do you want to scan your library for cover files now? Booth - + Booth @@ -8775,7 +8782,7 @@ Do you want to scan your library for cover files now? Record/Broadcast - + Record/Broadcast @@ -8808,39 +8815,31 @@ Do you want to scan your library for cover files now? 编码器 - + Mixxx Needs Access to: %1 Mixxx 需要权限以访问:%1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - 由于 Mac 的沙箱机制,我们需要更高的权限才能访问此文件: - -%1 - -点击 Ok 之后,您将会看到文件选择对话框。为了获取访问权限,您必须选择“%2”。若您不希望赋予 Mixxx 权限,请点击“取消”。我们对此带来的不便表示歉意。 - -要中断此操作,请点击对话框上的“取消”按钮。 +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. 您选择了错误的文件。为了使 Mixxx 能正确访问,请选择文件“%1”。若您不希望继续,请选择“取消”。 - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -8858,17 +8857,17 @@ If you do not want to grant Mixxx access, click Cancel on the file picker. Mixxx Bitcrusher - + Bitcrusher Adds noise by the reducing the bit depth and sample rate - + Adds noise by the reducing the bit depth and sample rate The bit depth of the samples - + The bit depth of the samples @@ -8883,7 +8882,7 @@ If you do not want to grant Mixxx access, click Cancel on the file picker. Mixxx The sample rate to which the signal is downsampled - + The sample rate to which the signal is downsampled @@ -8895,13 +8894,13 @@ If you do not want to grant Mixxx access, click Cancel on the file picker. Mixxx Time - + Time Ping Pong - + Ping Pong @@ -8927,14 +8926,16 @@ If you do not want to grant Mixxx access, click Cancel on the file picker. Mixxx Stores the input signal in a temporary buffer and outputs it after a short time - + Stores the input signal in a temporary buffer and outputs it after a short time Delay time 1/8 - 2 beats if tempo is detected 1/8 - 2 seconds if no tempo is detected - + Delay time +1/8 - 2 beats if tempo is detected +1/8 - 2 seconds if no tempo is detected @@ -8944,7 +8945,7 @@ If you do not want to grant Mixxx access, click Cancel on the file picker. Mixxx How much the echoed sound bounces between the left and right sides of the stereo field - + How much the echoed sound bounces between the left and right sides of the stereo field @@ -8957,7 +8958,7 @@ If you do not want to grant Mixxx access, click Cancel on the file picker. Mixxx Round the Time parameter to the nearest 1/4 beat. - + Round the Time parameter to the nearest 1/4 beat. @@ -8968,12 +8969,12 @@ If you do not want to grant Mixxx access, click Cancel on the file picker. Mixxx Triplets - + Triplets When the Quantize parameter is enabled, divide rounded 1/4 beats of Time parameter by 3. - + When the Quantize parameter is enabled, divide rounded 1/4 beats of Time parameter by 3. @@ -8984,12 +8985,12 @@ If you do not want to grant Mixxx access, click Cancel on the file picker. Mixxx Allows only high or low frequencies to play. - + Allows only high or low frequencies to play. Low Pass Filter Cutoff - + Low Pass Filter Cutoff @@ -9012,12 +9013,13 @@ If you do not want to grant Mixxx access, click Cancel on the file picker. Mixxx Resonance of the filters Default: flat top - + Resonance of the filters +Default: flat top High Pass Filter Cutoff - + High Pass Filter Cutoff @@ -9060,58 +9062,61 @@ Default: flat top Mixes the input with a delayed, pitch modulated copy of itself to create comb filtering - + Mixes the input with a delayed, pitch modulated copy of itself to create comb filtering Speed of the LFO (low frequency oscillator) 32 - 1/4 beats rounded to 1/2 beat per LFO cycle if tempo is detected 1/32 - 4 Hz if no tempo is detected - + Speed of the LFO (low frequency oscillator) +32 - 1/4 beats rounded to 1/2 beat per LFO cycle if tempo is detected +1/32 - 4 Hz if no tempo is detected Delay amplitude of the LFO (low frequency oscillator) - + Delay amplitude of the LFO (low frequency oscillator) Delay offset of the LFO (low frequency oscillator). With width at zero, this allows for manually sweeping over the entire delay range. - + Delay offset of the LFO (low frequency oscillator). +With width at zero, this allows for manually sweeping over the entire delay range. Regeneration - + Regeneration Regen - + Regen How much of the delay output is feed back into the input - + How much of the delay output is feed back into the input Intensity of the effect - + Intensity of the effect Divide rounded 1/2 beats of the Period parameter by 3. - + Divide rounded 1/2 beats of the Period parameter by 3. Mix - + Mix @@ -9126,12 +9131,12 @@ With width at zero, this allows for manually sweeping over the entire delay rang Metronome - + Metronome Adds a metronome click sound to the stream - + Adds a metronome click sound to the stream @@ -9141,7 +9146,7 @@ With width at zero, this allows for manually sweeping over the entire delay rang Set the beats per minute value of the click sound - + Set the beats per minute value of the click sound @@ -9151,7 +9156,7 @@ With width at zero, this allows for manually sweeping over the entire delay rang Synchronizes the BPM with the track if it can be retrieved - + Synchronizes the BPM with the track if it can be retrieved @@ -9165,19 +9170,21 @@ With width at zero, this allows for manually sweeping over the entire delay rang Autopan - + Autopan Bounce the sound left and right across the stereo field - + Bounce the sound left and right across the stereo field How fast the sound goes from one side to another 1/4 - 4 beats rounded to 1/2 beat if tempo is detected 1/4 - 4 seconds if no tempo is detected - + How fast the sound goes from one side to another +1/4 - 4 beats rounded to 1/2 beat if tempo is detected +1/4 - 4 seconds if no tempo is detected @@ -9192,12 +9199,12 @@ With width at zero, this allows for manually sweeping over the entire delay rang How smoothly the signal goes from one side to the other - + How smoothly the signal goes from one side to the other How far the signal goes to each side - + How far the signal goes to each side @@ -9207,7 +9214,7 @@ With width at zero, this allows for manually sweeping over the entire delay rang Emulates the sound of the signal bouncing off the walls of a room - + Emulates the sound of the signal bouncing off the walls of a room @@ -9218,18 +9225,19 @@ With width at zero, this allows for manually sweeping over the entire delay rang Lower decay values cause reverberations to fade out more quickly. - + Lower decay values cause reverberations to fade out more quickly. Bandwidth of the low pass filter at the input. Higher values result in less attenuation of high frequencies. - + Bandwidth of the low pass filter at the input. +Higher values result in less attenuation of high frequencies. How much of the signal to send in to the effect - + How much of the signal to send in to the effect @@ -9335,7 +9343,7 @@ Higher values result in less attenuation of high frequencies. To adjust frequency shelves, go to Preferences -> Equalizers. - + To adjust frequency shelves, go to Preferences -> Equalizers. @@ -9419,14 +9427,16 @@ Higher values result in less attenuation of high frequencies. Mixes the input signal with a copy passed through a series of all-pass filters to create comb filtering - + Mixes the input signal with a copy passed through a series of all-pass filters to create comb filtering Period of the LFO (low frequency oscillator) 1/4 - 4 beats rounded to 1/2 beat if tempo is detected 1/4 - 4 seconds if no tempo is detected - + Period of the LFO (low frequency oscillator) +1/4 - 4 beats rounded to 1/2 beat if tempo is detected +1/4 - 4 seconds if no tempo is detected @@ -9447,12 +9457,12 @@ Higher values result in less attenuation of high frequencies. Number of stages - + Number of stages Sets the LFOs (low frequency oscillators) for the left and right channels out of phase with each others - + Sets the LFOs (low frequency oscillators) for the left and right channels out of phase with each others @@ -9651,33 +9661,33 @@ Higher values result in less attenuation of high frequencies. Adjust the left/right balance and stereo width - + Adjust the left/right balance and stereo width Adjust balance between left and right channels - + Adjust balance between left and right channels Mid/Side - + Mid/Side Bypass Fr. - + Bypass Fr. Bypass Frequency - + Bypass Frequency Stereo Balance - + Stereo Balance @@ -9685,12 +9695,15 @@ Higher values result in less attenuation of high frequencies. Fully left: mono Fully right: only side ambiance Center: does not change the original signal. - + Adjust stereo width by changing balance between middle and side of the signal. +Fully left: mono +Fully right: only side ambiance +Center: does not change the original signal. Frequencies below this cutoff are not adjusted in the stereo field - + Frequencies below this cutoff are not adjusted in the stereo field @@ -9706,7 +9719,8 @@ Center: does not change the original signal. An gentle 2-band parametric equalizer based on biquad filters. It is designed as a complement to the steep mixing equalizers. - + An gentle 2-band parametric equalizer based on biquad filters. +It is designed as a complement to the steep mixing equalizers. @@ -9723,25 +9737,27 @@ It is designed as a complement to the steep mixing equalizers. Q 1 - + Q 1 Controls the bandwidth of Filter 1. A lower Q affects a wider band of frequencies, a higher Q affects a narrower band of frequencies. - + Controls the bandwidth of Filter 1. +A lower Q affects a wider band of frequencies, +a higher Q affects a narrower band of frequencies. Center 1 - + Center 1 Center frequency for Filter 1, from 100 Hz to 14 kHz - + Center frequency for Filter 1, from 100 Hz to 14 kHz @@ -9758,41 +9774,43 @@ a higher Q affects a narrower band of frequencies. Q 2 - + Q 2 Controls the bandwidth of Filter 2. A lower Q affects a wider band of frequencies, a higher Q affects a narrower band of frequencies. - + Controls the bandwidth of Filter 2. +A lower Q affects a wider band of frequencies, +a higher Q affects a narrower band of frequencies. Center 2 - + Center 2 Center frequency for Filter 2, from 100 Hz to 14 kHz - + Center frequency for Filter 2, from 100 Hz to 14 kHz Tremolo - + Tremolo Cycles the volume up and down - + Cycles the volume up and down How much the effect changes the volume - + How much the effect changes the volume @@ -9805,25 +9823,30 @@ a higher Q affects a narrower band of frequencies. Rate of the volume changes 4 beats - 1/8 beat if tempo is detected 1/4 Hz - 8 Hz if no tempo is detected - + Rate of the volume changes +4 beats - 1/8 beat if tempo is detected +1/4 Hz - 8 Hz if no tempo is detected Width of the volume peak 10% - 90% of the effect period - + Width of the volume peak +10% - 90% of the effect period Shape of the volume modulation wave Fully left: Square wave Fully right: Sine wave - + Shape of the volume modulation wave +Fully left: Square wave +Fully right: Sine wave When the Quantize parameter is enabled, divide the effect period by 3. - + When the Quantize parameter is enabled, divide the effect period by 3. @@ -9842,17 +9865,19 @@ Fully right: Sine wave Shifts the position of the volume peak within the period Fully left: beginning of the effect period Fully right: end of the effect period - + Shifts the position of the volume peak within the period +Fully left: beginning of the effect period +Fully right: end of the effect period Round the Rate parameter to the nearest whole division of a beat. - + Round the Rate parameter to the nearest whole division of a beat. Triplet - + Triplet @@ -9863,17 +9888,17 @@ Fully right: end of the effect period This plugin does not support stereo samples as input/output - + This plugin does not support stereo samples as input/output This plugin has features which are not yet supported - + This plugin has features which are not yet supported Unknown status - + Unknown status @@ -10040,12 +10065,12 @@ Fully right: end of the effect period Low Disk Space Warning - + Low Disk Space Warning There is less than 1 GiB of useable space in the recording folder - + There is less than 1 GiB of useable space in the recording folder @@ -10065,7 +10090,7 @@ Fully right: end of the effect period You can change the location of the Recordings folder in Preferences -> Recording. - + You can change the location of the Recordings folder in Preferences -> Recording. @@ -10222,27 +10247,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History 历史 - + Unlock 解锁 - + Lock 锁定 @@ -10273,7 +10298,7 @@ Fully right: end of the effect period Error setting tls mode: - + Error setting tls mode: @@ -10323,17 +10348,17 @@ Fully right: end of the effect period Error setting stream IRC! - + Error setting stream IRC! Error setting stream AIM! - + Error setting stream AIM! Error setting stream ICQ! - + Error setting stream ICQ! @@ -10396,47 +10421,47 @@ Fully right: end of the effect period 网络缓存溢出 - + Connection error - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. 到流服务器的连接中断,且在 %1 次重试之后仍然无法重新连接 - + Lost connection to streaming server. 到流服务器的连接断开 - + Please check your connection to the Internet. 请检查您的互联网连接 - + Can't connect to streaming server 无法连接到流服务器 - + Please check your connection to the Internet and verify that your username and password are correct. 请检查您的互联网连接,并确保用户名和密码正确。 @@ -10579,12 +10604,12 @@ Fully right: end of the effect period loop active - + loop active loop inactive - + loop inactive @@ -10650,7 +10675,7 @@ Fully right: end of the effect period Right click to show cover art of loaded track. - + Right click to show cover art of loaded track. @@ -10730,12 +10755,12 @@ Fully right: end of the effect period Booth Gain - + Booth Gain Adjusts the booth output gain. - + Adjusts the booth output gain. @@ -10857,12 +10882,12 @@ Fully right: end of the effect period Show Effects - + Show Effects Show or hide the effects. - + Show or hide the effects. @@ -10917,27 +10942,27 @@ Fully right: end of the effect period Microphone Talkover Mode - + Microphone Talkover Mode Off: Do not reduce music volume - + Off: Do not reduce music volume Manual: Reduce music volume by a fixed amount set by the Strength knob. - + Manual: Reduce music volume by a fixed amount set by the Strength knob. Behavior depends on Microphone Talkover Mode: - + Behavior depends on Microphone Talkover Mode: Off: Does nothing - + Off: Does nothing @@ -11154,7 +11179,7 @@ Fully right: end of the effect period Toggle visibility of Rate Control - + Toggle visibility of Rate Control @@ -11194,7 +11219,7 @@ Fully right: end of the effect period Plays track from the cue point. - + Plays track from the cue point. @@ -11448,92 +11473,92 @@ Fully right: end of the effect period Sets the track Loop-In Marker to the current play position. - + Sets the track Loop-In Marker to the current play position. Press and hold to move Loop-In Marker. - + Press and hold to move Loop-In Marker. Jump to Loop-In Marker. - + Jump to Loop-In Marker. Sets the track Loop-Out Marker to the current play position. - + Sets the track Loop-Out Marker to the current play position. Press and hold to move Loop-Out Marker. - + Press and hold to move Loop-Out Marker. Jump to Loop-Out Marker. - + Jump to Loop-Out Marker. Beatloop Size - + Beatloop Size Select the size of the loop in beats to set with the Beatloop button. - + Select the size of the loop in beats to set with the Beatloop button. Changing this resizes the loop if the loop already matches this size. - + Changing this resizes the loop if the loop already matches this size. Halve the size of an existing beatloop, or halve the size of the next beatloop set with the Beatloop button. - + Halve the size of an existing beatloop, or halve the size of the next beatloop set with the Beatloop button. Double the size of an existing beatloop, or double the size of the next beatloop set with the Beatloop button. - + Double the size of an existing beatloop, or double the size of the next beatloop set with the Beatloop button. Start a loop over the set number of beats. - + Start a loop over the set number of beats. Temporarily enable a rolling loop over the set number of beats. - + Temporarily enable a rolling loop over the set number of beats. Beatjump/Loop Move Size - + Beatjump/Loop Move Size Select the number of beats to jump or move the loop with the Beatjump Forward/Backward buttons. - + Select the number of beats to jump or move the loop with the Beatjump Forward/Backward buttons. Beatjump Forward - + Beatjump Forward Jump forward by the set number of beats. - + Jump forward by the set number of beats. Move the loop forward by the set number of beats. - + Move the loop forward by the set number of beats. @@ -11588,7 +11613,7 @@ Fully right: end of the effect period Enable loop, jump to Loop-In Marker, and stop playback. - + Enable loop, jump to Loop-In Marker, and stop playback. @@ -11657,44 +11682,46 @@ Fully right: end of the effect period Mix - + Mix Adjust the mixing of the dry (input) signal with the wet (output) signal of the effect unit - + Adjust the mixing of the dry (input) signal with the wet (output) signal of the effect unit D/W mode: Crossfade between dry and wet - + D/W mode: Crossfade between dry and wet D+W mode: Add wet to dry - + D+W mode: Add wet to dry Mix Mode - + Mix Mode Adjust how the dry (input) signal is mixed with the wet (output) signal of the effect unit - + Adjust how the dry (input) signal is mixed with the wet (output) signal of the effect unit Dry/Wet mode (crossed lines): Mix knob crossfades between dry and wet Use this to change the sound of the track with EQ and filter effects. - + Dry/Wet mode (crossed lines): Mix knob crossfades between dry and wet +Use this to change the sound of the track with EQ and filter effects. Dry+Wet mode (flat dry line): Mix knob adds wet to dry Use this to change only the effected (wet) signal with EQ and filter effects. - + Dry+Wet mode (flat dry line): Mix knob adds wet to dry +Use this to change only the effected (wet) signal with EQ and filter effects. @@ -11704,27 +11731,27 @@ Use this to change only the effected (wet) signal with EQ and filter effects. Route the left crossfader bus through this effect unit. - + Route the left crossfader bus through this effect unit. Route the right crossfader bus through this effect unit. - + Route the right crossfader bus through this effect unit. Right side active: parameter moves with right half of Meta Knob turn - + Right side active: parameter moves with right half of Meta Knob turn Skin Settings Menu - + Skin Settings Menu Show/hide skin settings menu - + Show/hide skin settings menu @@ -11734,7 +11761,7 @@ Use this to change only the effected (wet) signal with EQ and filter effects. Save the collection of samples loaded in the samplers. - + Save the collection of samples loaded in the samplers. @@ -11744,7 +11771,7 @@ Use this to change only the effected (wet) signal with EQ and filter effects. Load a previously saved collection of samples into the samplers. - + Load a previously saved collection of samples into the samplers. @@ -11834,7 +11861,7 @@ Use this to change only the effected (wet) signal with EQ and filter effects. Show/hide parameters for effects in this unit. - + Show/hide parameters for effects in this unit. @@ -11844,27 +11871,27 @@ Use this to change only the effected (wet) signal with EQ and filter effects. Enable or disable this whole effect unit. - + Enable or disable this whole effect unit. Controls the Meta Knob of all effects in this unit together. - + Controls the Meta Knob of all effects in this unit together. Load next effect chain preset into this effect unit. - + Load next effect chain preset into this effect unit. Load previous effect chain preset into this effect unit. - + Load previous effect chain preset into this effect unit. Load next or previous effect chain preset into this effect unit. - + Load next or previous effect chain preset into this effect unit. @@ -11877,42 +11904,42 @@ Use this to change only the effected (wet) signal with EQ and filter effects. Assign Effect Unit - + Assign Effect Unit Assign this effect unit to the channel output. - + Assign this effect unit to the channel output. Route the headphone channel through this effect unit. - + Route the headphone channel through this effect unit. Route this deck through the indicated effect unit. - + Route this deck through the indicated effect unit. Route this sampler through the indicated effect unit. - + Route this sampler through the indicated effect unit. Route this microphone through the indicated effect unit. - + Route this microphone through the indicated effect unit. Route this auxiliary input through the indicated effect unit. - + Route this auxiliary input through the indicated effect unit. The effect unit must also be assigned to a deck or other sound source to hear the effect. - + The effect unit must also be assigned to a deck or other sound source to hear the effect. @@ -11982,22 +12009,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. Inactive: parameter not linked - + Inactive: parameter not linked Active: parameter moves with Meta Knob - + Active: parameter moves with Meta Knob Left side active: parameter moves with left half of Meta Knob turn - + Left side active: parameter moves with left half of Meta Knob turn Left and right side active: parameter moves across range with half of Meta Knob turn and back with the other half - + Left and right side active: parameter moves across range with half of Meta Knob turn and back with the other half @@ -12308,7 +12335,7 @@ Use this to change only the effected (wet) signal with EQ and filter effects. Microphone Talkover Ducking Strength - + Microphone Talkover Ducking Strength @@ -12318,7 +12345,7 @@ Use this to change only the effected (wet) signal with EQ and filter effects. Changes the number of hotcue buttons displayed in the deck - + Changes the number of hotcue buttons displayed in the deck @@ -12602,17 +12629,17 @@ Use this to change only the effected (wet) signal with EQ and filter effects. Crossfader Orientation - + Crossfader Orientation Set the channel's crossfader orientation. - + Set the channel's crossfader orientation. Either to the left side of crossfader, to the right side or to the center (unaffected by crossfader) - + Either to the left side of crossfader, to the right side or to the center (unaffected by crossfader) @@ -13075,7 +13102,7 @@ Use this to change only the effected (wet) signal with EQ and filter effects. Clear cover clears the set cover art -- does not touch files on disk - + Clear cover @@ -13271,12 +13298,12 @@ Use this to change only the effected (wet) signal with EQ and filter effects. Show Skin Settings Menu - + Show Skin Settings Menu Show the Skin Settings Menu of the currently selected Skin - + Show the Skin Settings Menu of the currently selected Skin @@ -13886,12 +13913,12 @@ Use this to change only the effected (wet) signal with EQ and filter effects. Remove from Playlist - + Remove from Playlist Remove from Crate - + Remove from Crate @@ -13921,12 +13948,12 @@ Use this to change only the effected (wet) signal with EQ and filter effects. Import From File Tags - + Import From File Tags Import From MusicBrainz - + Import From MusicBrainz @@ -14212,75 +14239,75 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GLSL ES) - + (GL ES) - + (GL ES) main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14290,17 +14317,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14308,52 +14335,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory 选择音乐库目录 - + controllers - + Cannot open database 无法打开数据库 - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14442,12 +14469,12 @@ Mixxx 需要 QT 支持 SQLite。请阅读 Qt SQL 驱动文档以了解相关构 Export Modified Track Metadata - + Export Modified Track Metadata Mixxx may wait to modify files until they are not loaded to any decks or samplers. If you do not see changed metadata in other programs immediately, eject the track from all decks and samplers or shutdown Mixxx. - + Mixxx may wait to modify files until they are not loaded to any decks or samplers. If you do not see changed metadata in other programs immediately, eject the track from all decks and samplers or shutdown Mixxx. @@ -14557,4 +14584,12 @@ Mixxx 需要 QT 支持 SQLite。请阅读 Qt SQL 驱动文档以了解相关构 无网络连接 + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_zh_HK.qm b/res/translations/mixxx_zh_HK.qm index 1a817725e1b..e19319d2172 100644 Binary files a/res/translations/mixxx_zh_HK.qm and b/res/translations/mixxx_zh_HK.qm differ diff --git a/res/translations/mixxx_zh_HK.ts b/res/translations/mixxx_zh_HK.ts index 4cb37c536ce..53c18862e8e 100644 --- a/res/translations/mixxx_zh_HK.ts +++ b/res/translations/mixxx_zh_HK.ts @@ -272,7 +272,7 @@ BaseTrackPlayerImpl - + Couldn't load track. @@ -413,12 +413,12 @@ BroadcastManager - + Action failed - + Please enable at least one connection to use Live Broadcasting. @@ -3456,12 +3456,12 @@ - + Official Website - + Donate @@ -5583,37 +5583,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6908,17 +6908,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8789,33 +8789,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10198,27 +10196,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock - + Lock @@ -10373,47 +10371,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14195,22 +14193,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14218,52 +14216,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14273,17 +14271,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14291,52 +14289,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14537,4 +14535,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_zh_TW.Big5.qm b/res/translations/mixxx_zh_TW.Big5.qm index 4091bbbe96d..5dff8f45663 100644 Binary files a/res/translations/mixxx_zh_TW.Big5.qm and b/res/translations/mixxx_zh_TW.Big5.qm differ diff --git a/res/translations/mixxx_zh_TW.Big5.ts b/res/translations/mixxx_zh_TW.Big5.ts index 8e95d74d530..c9244a3ad37 100644 --- a/res/translations/mixxx_zh_TW.Big5.ts +++ b/res/translations/mixxx_zh_TW.Big5.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. 無法載入音軌。 @@ -401,12 +401,12 @@ BroadcastManager - + Action failed 動作失敗 - + Please enable at least one connection to use Live Broadcasting. @@ -3440,12 +3440,12 @@ - + Official Website - + Donate @@ -5566,37 +5566,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. - + Allow screensaver to run - + Prevent screensaver from running - + Prevent screensaver while playing - + This skin does not support color schemes - + Information - + Mixxx must be restarted before the new locale setting will take effect. @@ -6890,17 +6890,17 @@ The loudness target is approximate and assumes track pregain and master output l - + OpenGL not available - + dropped frames - + Cached waveforms occupy %1 MiB on disk. @@ -8769,33 +8769,31 @@ Do you want to scan your library for cover files now? - + Mixxx Needs Access to: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10177,27 +10175,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History - + Unlock 解鎖 - + Lock 鎖定 @@ -10351,47 +10349,47 @@ Fully right: end of the effect period - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. - + Can't connect to streaming server - + Please check your connection to the Internet and verify that your username and password are correct. @@ -14167,22 +14165,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) - + (GL) - + (GLSL ES) - + (GL ES) @@ -14190,52 +14188,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14245,17 +14243,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14263,52 +14261,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory - + controllers - + Cannot open database - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14509,4 +14507,12 @@ Click OK to exit. + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + + + \ No newline at end of file diff --git a/res/translations/mixxx_zh_TW.qm b/res/translations/mixxx_zh_TW.qm index 301d458e7a4..1e94f2a5699 100644 Binary files a/res/translations/mixxx_zh_TW.qm and b/res/translations/mixxx_zh_TW.qm differ diff --git a/res/translations/mixxx_zh_TW.ts b/res/translations/mixxx_zh_TW.ts index 5de4159cffc..802bbb005ec 100644 --- a/res/translations/mixxx_zh_TW.ts +++ b/res/translations/mixxx_zh_TW.ts @@ -260,7 +260,7 @@ BaseTrackPlayerImpl - + Couldn't load track. 無法載入音軌 @@ -401,12 +401,12 @@ BroadcastManager - + Action failed 行動失敗 - + Please enable at least one connection to use Live Broadcasting. 請啟用至少一個連線以啟用LIVE廣播。 @@ -3440,12 +3440,12 @@ 過去的貢獻者 - + Official Website - + Donate @@ -5569,37 +5569,37 @@ You can always drag-and-drop tracks on screen to clone a deck. DlgPrefInterface - + The minimum size of the selected skin is bigger than your screen resolution. 所選的外觀的最小大小大於您的螢幕解析度。 - + Allow screensaver to run 允許螢幕保護程式執行 - + Prevent screensaver from running 在程式運行中防止螢幕保護程式 - + Prevent screensaver while playing 當播放歌曲時禁止螢幕保護程式 - + This skin does not support color schemes 這種皮膚不支援色彩配置 - + Information 資訊 - + Mixxx must be restarted before the new locale setting will take effect. @@ -6895,17 +6895,17 @@ The loudness target is approximate and assumes track pregain and master output l RGB - + OpenGL not available OpenGL 不可用 - + dropped frames 丟棄的幀 - + Cached waveforms occupy %1 MiB on disk. 緩存的波形佔據磁片上的 MiB %1。 @@ -8777,35 +8777,31 @@ Do you want to scan your library for cover files now? 編碼器 - + Mixxx Needs Access to: %1 Mixxx 需要訪問: %1 - - Due to Mac Sandboxing, we need your permission to access this file: + + Your permission is required to access the following location: %1 -After clicking OK, you will see a file picker. To give Mixxx permission, you must select '%2' to proceed. If you do not want to grant Mixxx access click Cancel on the file picker. We're sorry for this inconvenience. - -To abort this action, press Cancel on the file dialog. - 由於 Mac 沙箱,我們需要您的許可才能訪問此檔: %1 後按一下確定,您將看到一個檔選擇器。要給予 Mixxx 許可權,您必須選擇 '%2',繼續。如果你不想要授予檔選取器 Mixxx 訪問按一下取消。我們由此引起的不便表示歉意。 - -要中止此操作,請按取消在檔對話方塊中。 +After clicking OK, you will see a file picker. Please select '%2' to proceed or click Cancel if you don't want to grant Mixxx access and abort this action. + - + You selected the wrong file. To grant Mixxx access, please select the file '%1'. If you do not want to continue, press Cancel. 您選擇了錯誤的檔。要授予 Mixxx 的存取權限,請選擇檔 '%1'。如果你不想要繼續,請按取消。 - + Upgrading old Mixxx settings - + Due to macOS sandboxing, Mixxx needs your permission to access your music library and settings from Mixxx versions before 2.3.0. After clicking OK, you will see a file selection dialog. To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. @@ -10187,27 +10183,27 @@ Fully right: end of the effect period SetlogFeature - + Join with previous (below) - + Finish current and start new - + History 歷史 - + Unlock 解鎖 - + Lock @@ -10361,47 +10357,47 @@ Fully right: end of the effect period 網路的快取溢出 - + Connection error - + One of the Live Broadcasting connections raised this error:<br><b>Error with connection '%1':</b><br> - + Connection message - + <b>Message from Live Broadcasting connection '%1':</b><br> - + Lost connection to streaming server and %1 attempts to reconnect have failed. - + Lost connection to streaming server. - + Please check your connection to the Internet. 請檢你的網際網路連線 - + Can't connect to streaming server 無法連接到流媒體伺服器 - + Please check your connection to the Internet and verify that your username and password are correct. 請檢查您連接到 Internet,請驗證您的使用者名和密碼正確。 @@ -14177,22 +14173,22 @@ Use this to change only the effected (wet) signal with EQ and filter effects. WaveformWidgetFactory - + (GLSL) (GLSL) - + (GL) (GL) - + (GLSL ES) - + (GL ES) @@ -14200,52 +14196,52 @@ Use this to change only the effected (wet) signal with EQ and filter effects. main - + Starts Mixxx in full-screen mode - + Use a custom locale for loading translations. (e.g 'fr') - + Top-level directory where Mixxx should look for settings. Default is: - + Top-level directory where Mixxx should look for its resource files such as MIDI mappings, overriding the default installation location. - + Path the timeline is written to - + Causes Mixxx to display/log all of the controller data it receives and script functions it loads - + Enables developer-mode. Includes extra log info, stats on performance, and a Developer tools menu. - + Enables safe-mode. Disables OpenGL waveforms, and spinning vinyl widgets. Try this option if Mixxx is crashing on startup. - + [auto|always|never] Use colors on the console output. - + Sets the verbosity of command line logging. critical - Critical/Fatal only warning - Above + Warnings @@ -14255,17 +14251,17 @@ trace - Above + Profiling messages - + Sets the the logging level at which the log buffer is flushed to mixxx.log. LEVEL is one of the values defined at --logLevel above. - + Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to false. Under a debugger you can continue afterwards. - + Load the specified music file(s) at start-up. Each file you specify will be loaded into the next virtual deck. @@ -14273,52 +14269,52 @@ trace - Above + Profiling messages mixxx::CoreServices - + fonts - + database - + effects - + audio interface - + decks - + library - + Choose music library directory 選擇音樂庫目錄 - + controllers - + Cannot open database 無法打開資料庫 - + Unable to establish a database connection. Mixxx requires QT with SQLite support. Please read the Qt SQL driver documentation for information on how to build it. @@ -14522,4 +14518,12 @@ Mixxx 需要 qt 離散度與 SQLite 支援。請閱讀有關如何構建它的 + + mixxx::skin::qml::QmlVisibleEffectsModel + + + No effect loaded. + 沒有影響載入。 + + \ No newline at end of file diff --git a/src/analyzer/analyzer.h b/src/analyzer/analyzer.h index 2704717aa50..815514c56f8 100644 --- a/src/analyzer/analyzer.h +++ b/src/analyzer/analyzer.h @@ -1,5 +1,6 @@ #pragma once +#include "audio/types.h" #include "util/assert.h" #include "util/types.h" @@ -21,7 +22,9 @@ class Analyzer { // 1. Check if the track needs to be analyzed, otherwise return false. // 2. Perform the initialization and return true on success. // 3. If the initialization failed log the internal error and return false. - virtual bool initialize(TrackPointer tio, int sampleRate, int totalSamples) = 0; + virtual bool initialize(TrackPointer tio, + mixxx::audio::SampleRate sampleRate, + int totalSamples) = 0; ///////////////////////////////////////////////////////////////////////// // All following methods will only be invoked after initialize() @@ -66,7 +69,7 @@ class AnalyzerWithState final { return m_active; } - bool initialize(TrackPointer tio, int sampleRate, int totalSamples) { + bool initialize(TrackPointer tio, mixxx::audio::SampleRate sampleRate, int totalSamples) { DEBUG_ASSERT(!m_active); return m_active = m_analyzer->initialize(tio, sampleRate, totalSamples); } diff --git a/src/analyzer/analyzerbeats.cpp b/src/analyzer/analyzerbeats.cpp index 4317d616bea..173bf1af46e 100644 --- a/src/analyzer/analyzerbeats.cpp +++ b/src/analyzer/analyzerbeats.cpp @@ -42,7 +42,9 @@ AnalyzerBeats::AnalyzerBeats(UserSettingsPointer pConfig, bool enforceBpmDetecti m_iCurrentSample(0) { } -bool AnalyzerBeats::initialize(TrackPointer pTrack, int sampleRate, int totalSamples) { +bool AnalyzerBeats::initialize(TrackPointer pTrack, + mixxx::audio::SampleRate sampleRate, + int totalSamples) { if (totalSamples == 0) { return false; } @@ -143,7 +145,7 @@ bool AnalyzerBeats::shouldAnalyze(TrackPointer pTrack) const { if (!pBeats) { return true; } - if (!mixxx::Bpm::isValidValue(pBeats->getBpm())) { + if (!pBeats->getBpm().isValid()) { // Tracks with an invalid bpm <= 0 should be re-analyzed, // independent of the preference settings. We expect that // all tracks have a bpm > 0 when analyzed. Users that want @@ -158,7 +160,7 @@ bool AnalyzerBeats::shouldAnalyze(TrackPointer pTrack) const { return m_bPreferencesReanalyzeImported; } - if (subVersion.isEmpty() && pBeats->findNextBeat(0) <= 0.0 && + if (subVersion.isEmpty() && pBeats->firstBeat() <= mixxx::audio::kStartFramePos && m_pluginId != mixxx::AnalyzerSoundTouchBeats::pluginInfo().id()) { // This happens if the beat grid was created from the metadata BPM value. qDebug() << "First beat is 0 for grid so analyzing track to find first beat."; @@ -219,7 +221,7 @@ void AnalyzerBeats::storeResults(TrackPointer pTrack) { mixxx::BeatsPointer pBeats; if (m_pPlugin->supportsBeatTracking()) { - QVector beats = m_pPlugin->getBeats(); + QVector beats = m_pPlugin->getBeats(); QHash extraVersionInfo = getExtraVersionInfo( m_pluginId, m_bPreferencesFastAnalysis); pBeats = BeatFactory::makePreferredBeats( @@ -228,11 +230,11 @@ void AnalyzerBeats::storeResults(TrackPointer pTrack) { m_bPreferencesFixedTempo, m_sampleRate); qDebug() << "AnalyzerBeats plugin detected" << beats.size() - << "beats. Average BPM:" << (pBeats ? pBeats->getBpm() : 0.0); + << "beats. Average BPM:" << (pBeats ? pBeats->getBpm() : mixxx::Bpm()); } else { - float bpm = m_pPlugin->getBpm(); + mixxx::Bpm bpm = m_pPlugin->getBpm(); qDebug() << "AnalyzerBeats plugin detected constant BPM: " << bpm; - pBeats = BeatFactory::makeBeatGrid(m_sampleRate, bpm, 0.0f); + pBeats = BeatFactory::makeBeatGrid(m_sampleRate, bpm, mixxx::audio::kStartFramePos); } pTrack->trySetBeats(pBeats); diff --git a/src/analyzer/analyzerbeats.h b/src/analyzer/analyzerbeats.h index 0e4e44f74b0..e1a375dd9cc 100644 --- a/src/analyzer/analyzerbeats.h +++ b/src/analyzer/analyzerbeats.h @@ -26,7 +26,9 @@ class AnalyzerBeats : public Analyzer { static QList availablePlugins(); static mixxx::AnalyzerPluginInfo defaultPlugin(); - bool initialize(TrackPointer pTrack, int sampleRate, int totalSamples) override; + bool initialize(TrackPointer pTrack, + mixxx::audio::SampleRate sampleRate, + int totalSamples) override; bool processSamples(const CSAMPLE *pIn, const int iLen) override; void storeResults(TrackPointer tio) override; void cleanup() override; diff --git a/src/analyzer/analyzerebur128.cpp b/src/analyzer/analyzerebur128.cpp index c8fee49b7b7..62fd541a8aa 100644 --- a/src/analyzer/analyzerebur128.cpp +++ b/src/analyzer/analyzerebur128.cpp @@ -21,7 +21,7 @@ AnalyzerEbur128::~AnalyzerEbur128() { } bool AnalyzerEbur128::initialize(TrackPointer tio, - int sampleRate, + mixxx::audio::SampleRate sampleRate, int totalSamples) { if (m_rgSettings.isAnalyzerDisabled(2, tio) || totalSamples == 0) { qDebug() << "Skipping AnalyzerEbur128"; diff --git a/src/analyzer/analyzerebur128.h b/src/analyzer/analyzerebur128.h index 5cc794425d1..07ffca23ff2 100644 --- a/src/analyzer/analyzerebur128.h +++ b/src/analyzer/analyzerebur128.h @@ -14,7 +14,9 @@ class AnalyzerEbur128 : public Analyzer { return rgSettings.isAnalyzerEnabled(2); } - bool initialize(TrackPointer tio, int sampleRate, int totalSamples) override; + bool initialize(TrackPointer tio, + mixxx::audio::SampleRate sampleRate, + int totalSamples) override; bool processSamples(const CSAMPLE* pIn, const int iLen) override; void storeResults(TrackPointer tio) override; void cleanup() override; diff --git a/src/analyzer/analyzergain.cpp b/src/analyzer/analyzergain.cpp index 56a95609d07..0451afc759a 100644 --- a/src/analyzer/analyzergain.cpp +++ b/src/analyzer/analyzergain.cpp @@ -21,13 +21,15 @@ AnalyzerGain::~AnalyzerGain() { delete m_pReplayGain; } -bool AnalyzerGain::initialize(TrackPointer tio, int sampleRate, int totalSamples) { +bool AnalyzerGain::initialize(TrackPointer tio, + mixxx::audio::SampleRate sampleRate, + int totalSamples) { if (m_rgSettings.isAnalyzerDisabled(1, tio) || totalSamples == 0) { qDebug() << "Skipping AnalyzerGain"; return false; } - return m_pReplayGain->initialise((long)sampleRate, 2); + return m_pReplayGain->initialise(static_cast(sampleRate), 2); } void AnalyzerGain::cleanup() { diff --git a/src/analyzer/analyzergain.h b/src/analyzer/analyzergain.h index ddc2d6df578..1a0344da0c4 100644 --- a/src/analyzer/analyzergain.h +++ b/src/analyzer/analyzergain.h @@ -21,7 +21,9 @@ class AnalyzerGain : public Analyzer { return rgSettings.isAnalyzerEnabled(1); } - bool initialize(TrackPointer tio, int sampleRate, int totalSamples) override; + bool initialize(TrackPointer tio, + mixxx::audio::SampleRate sampleRate, + int totalSamples) override; bool processSamples(const CSAMPLE* pIn, const int iLen) override; void storeResults(TrackPointer tio) override; void cleanup() override; diff --git a/src/analyzer/analyzerkey.cpp b/src/analyzer/analyzerkey.cpp index 5408f14ea3f..b92d6729cc1 100644 --- a/src/analyzer/analyzerkey.cpp +++ b/src/analyzer/analyzerkey.cpp @@ -41,7 +41,9 @@ AnalyzerKey::AnalyzerKey(const KeyDetectionSettings& keySettings) m_bPreferencesReanalyzeEnabled(false) { } -bool AnalyzerKey::initialize(TrackPointer tio, int sampleRate, int totalSamples) { +bool AnalyzerKey::initialize(TrackPointer tio, + mixxx::audio::SampleRate sampleRate, + int totalSamples) { if (totalSamples == 0) { return false; } diff --git a/src/analyzer/analyzerkey.h b/src/analyzer/analyzerkey.h index 504df21705a..a4e40c22c20 100644 --- a/src/analyzer/analyzerkey.h +++ b/src/analyzer/analyzerkey.h @@ -19,7 +19,9 @@ class AnalyzerKey : public Analyzer { static QList availablePlugins(); static mixxx::AnalyzerPluginInfo defaultPlugin(); - bool initialize(TrackPointer tio, int sampleRate, int totalSamples) override; + bool initialize(TrackPointer tio, + mixxx::audio::SampleRate sampleRate, + int totalSamples) override; bool processSamples(const CSAMPLE *pIn, const int iLen) override; void storeResults(TrackPointer tio) override; void cleanup() override; diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 4b0c0e8b6a1..625afd0d190 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -15,7 +15,7 @@ bool shouldAnalyze(TrackPointer pTrack) { CuePointer pOutroCue = pTrack->findCueByType(mixxx::CueType::Outro); CuePointer pAudibleSound = pTrack->findCueByType(mixxx::CueType::AudibleSound); - if (!pIntroCue || !pOutroCue || !pAudibleSound || pAudibleSound->getLength() <= 0) { + if (!pIntroCue || !pOutroCue || !pAudibleSound || pAudibleSound->getLengthFrames() <= 0) { return true; } return false; @@ -32,7 +32,9 @@ AnalyzerSilence::AnalyzerSilence(UserSettingsPointer pConfig) m_iSignalEnd(-1) { } -bool AnalyzerSilence::initialize(TrackPointer pTrack, int sampleRate, int totalSamples) { +bool AnalyzerSilence::initialize(TrackPointer pTrack, + mixxx::audio::SampleRate sampleRate, + int totalSamples) { Q_UNUSED(sampleRate); Q_UNUSED(totalSamples); @@ -90,16 +92,16 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { m_iSignalEnd = m_iFramesProcessed; } - double firstSound = mixxx::kAnalysisChannels * m_iSignalStart; - double lastSound = mixxx::kAnalysisChannels * m_iSignalEnd; + const auto firstSoundPosition = mixxx::audio::FramePos(m_iSignalStart); + const auto lastSoundPosition = mixxx::audio::FramePos(m_iSignalEnd); CuePointer pAudibleSound = pTrack->findCueByType(mixxx::CueType::AudibleSound); if (pAudibleSound == nullptr) { pAudibleSound = pTrack->createAndAddCue( mixxx::CueType::AudibleSound, Cue::kNoHotCue, - firstSound, - lastSound); + firstSoundPosition, + lastSoundPosition); } else { // The user has no way to directly edit the AudibleSound cue. If the user // has deleted the Intro or Outro Cue, this analysis will be rerun when @@ -107,33 +109,35 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { // positions. This could be helpful, for example, when the track length // is changed in a different program, or the silence detection threshold // is changed. - pAudibleSound->setStartAndEndPosition(firstSound, lastSound); + pAudibleSound->setStartAndEndPosition(firstSoundPosition, lastSoundPosition); } CuePointer pIntroCue = pTrack->findCueByType(mixxx::CueType::Intro); - double mainCue = pTrack->getCuePoint().getPosition(); - double introStart = firstSound; + mixxx::audio::FramePos mainCuePosition = pTrack->getMainCuePosition(); + mixxx::audio::FramePos introStartPosition = firstSoundPosition; // Before Mixxx 2.3, the default position for the main cue was 0.0. In this // case, move the main cue point to the first sound. This case can be // distinguished from a user intentionally setting the main cue position // to 0.0 at a later time after analysis because in that case the intro cue // would have already been created by this analyzer. - bool upgradingWithMainCueAtDefault = (mainCue == 0.0 && pIntroCue == nullptr); - if (mainCue == Cue::kNoPosition || upgradingWithMainCueAtDefault) { - pTrack->setCuePoint(CuePosition(firstSound)); + bool upgradingWithMainCueAtDefault = + (mainCuePosition == mixxx::audio::kStartFramePos && + pIntroCue == nullptr); + if (!mainCuePosition.isValid() || upgradingWithMainCueAtDefault) { + pTrack->setMainCuePosition(firstSoundPosition); // NOTE: the actual default for this ConfigValue is set in DlgPrefDeck. } else if (m_pConfig->getValue(ConfigKey("[Controls]", "SetIntroStartAtMainCue"), false) && pIntroCue == nullptr) { - introStart = mainCue; + introStartPosition = mainCuePosition; } if (pIntroCue == nullptr) { pIntroCue = pTrack->createAndAddCue( mixxx::CueType::Intro, Cue::kNoHotCue, - introStart, - Cue::kNoPosition); + introStartPosition, + mixxx::audio::kInvalidFramePos); } CuePointer pOutroCue = pTrack->findCueByType(mixxx::CueType::Outro); @@ -141,7 +145,7 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { pOutroCue = pTrack->createAndAddCue( mixxx::CueType::Outro, Cue::kNoHotCue, - Cue::kNoPosition, - lastSound); + mixxx::audio::kInvalidFramePos, + lastSoundPosition); } } diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h index e9950fa0e76..8e3bf0784ad 100644 --- a/src/analyzer/analyzersilence.h +++ b/src/analyzer/analyzersilence.h @@ -10,7 +10,9 @@ class AnalyzerSilence : public Analyzer { explicit AnalyzerSilence(UserSettingsPointer pConfig); ~AnalyzerSilence() override = default; - bool initialize(TrackPointer pTrack, int sampleRate, int totalSamples) override; + bool initialize(TrackPointer pTrack, + mixxx::audio::SampleRate sampleRate, + int totalSamples) override; bool processSamples(const CSAMPLE* pIn, const int iLen) override; void storeResults(TrackPointer pTrack) override; void cleanup() override; diff --git a/src/analyzer/analyzerwaveform.cpp b/src/analyzer/analyzerwaveform.cpp index f3ab634f86f..200f85b2e0d 100644 --- a/src/analyzer/analyzerwaveform.cpp +++ b/src/analyzer/analyzerwaveform.cpp @@ -34,7 +34,9 @@ AnalyzerWaveform::~AnalyzerWaveform() { destroyFilters(); } -bool AnalyzerWaveform::initialize(TrackPointer tio, int sampleRate, int totalSamples) { +bool AnalyzerWaveform::initialize(TrackPointer tio, + mixxx::audio::SampleRate sampleRate, + int totalSamples) { if (totalSamples == 0) { qWarning() << "AnalyzerWaveform::initialize - no waveform/waveform summary"; return false; @@ -145,7 +147,7 @@ bool AnalyzerWaveform::shouldAnalyze(TrackPointer tio) const { return true; } -void AnalyzerWaveform::createFilters(int sampleRate) { +void AnalyzerWaveform::createFilters(mixxx::audio::SampleRate sampleRate) { // m_filter[Low] = new EngineFilterButterworth8(FILTER_LOWPASS, sampleRate, 200); // m_filter[Mid] = new EngineFilterButterworth8(FILTER_BANDPASS, sampleRate, 200, 2000); // m_filter[High] = new EngineFilterButterworth8(FILTER_HIGHPASS, sampleRate, 2000); diff --git a/src/analyzer/analyzerwaveform.h b/src/analyzer/analyzerwaveform.h index 85e4e05bb5d..0c19875c69a 100644 --- a/src/analyzer/analyzerwaveform.h +++ b/src/analyzer/analyzerwaveform.h @@ -140,7 +140,9 @@ class AnalyzerWaveform : public Analyzer { const QSqlDatabase& dbConnection); ~AnalyzerWaveform() override; - bool initialize(TrackPointer tio, int sampleRate, int totalSamples) override; + bool initialize(TrackPointer tio, + mixxx::audio::SampleRate sampleRate, + int totalSamples) override; bool processSamples(const CSAMPLE* buffer, const int bufferLength) override; void storeResults(TrackPointer tio) override; void cleanup() override; @@ -151,7 +153,7 @@ class AnalyzerWaveform : public Analyzer { void storeCurrentStridePower(); void resetCurrentStride(); - void createFilters(int sampleRate); + void createFilters(mixxx::audio::SampleRate sampleRate); void destroyFilters(); void storeIfGreater(float* pDest, float source); diff --git a/src/analyzer/plugins/analyzerkeyfinder.cpp b/src/analyzer/plugins/analyzerkeyfinder.cpp index 97b4ee57ba9..85a7efddf1c 100644 --- a/src/analyzer/plugins/analyzerkeyfinder.cpp +++ b/src/analyzer/plugins/analyzerkeyfinder.cpp @@ -80,8 +80,8 @@ AnalyzerPluginInfo AnalyzerKeyFinder::pluginInfo() { return AnalyzerPluginInfo(pluginId, pluginAuthor, pluginName, false); } -bool AnalyzerKeyFinder::initialize(int samplerate) { - m_audioData.setFrameRate(samplerate); +bool AnalyzerKeyFinder::initialize(mixxx::audio::SampleRate sampleRate) { + m_audioData.setFrameRate(sampleRate); m_audioData.setChannels(kAnalysisChannels); return true; } diff --git a/src/analyzer/plugins/analyzerkeyfinder.h b/src/analyzer/plugins/analyzerkeyfinder.h index 9de531a033a..237608d98d8 100644 --- a/src/analyzer/plugins/analyzerkeyfinder.h +++ b/src/analyzer/plugins/analyzerkeyfinder.h @@ -19,7 +19,7 @@ class AnalyzerKeyFinder : public AnalyzerKeyPlugin { return pluginInfo(); } - bool initialize(int samplerate) override; + bool initialize(mixxx::audio::SampleRate sampleRate) override; bool processSamples(const CSAMPLE* pIn, const int iLen) override; bool finalize() override; diff --git a/src/analyzer/plugins/analyzerplugin.h b/src/analyzer/plugins/analyzerplugin.h index 18298a98a85..98cbd078d4f 100644 --- a/src/analyzer/plugins/analyzerplugin.h +++ b/src/analyzer/plugins/analyzerplugin.h @@ -2,7 +2,9 @@ #include +#include "audio/frame.h" #include "track/beats.h" +#include "track/bpm.h" #include "track/keys.h" #include "util/types.h" @@ -58,7 +60,7 @@ class AnalyzerPlugin { } virtual AnalyzerPluginInfo info() const = 0; - virtual bool initialize(int samplerate) = 0; + virtual bool initialize(mixxx::audio::SampleRate sampleRate) = 0; virtual bool processSamples(const CSAMPLE* pIn, const int iLen) = 0; virtual bool finalize() = 0; }; @@ -68,11 +70,11 @@ class AnalyzerBeatsPlugin : public AnalyzerPlugin { ~AnalyzerBeatsPlugin() override = default; virtual bool supportsBeatTracking() const = 0; - virtual float getBpm() const { - return 0.0f; + virtual mixxx::Bpm getBpm() const { + return {}; } - virtual QVector getBeats() const { - return QVector(); + virtual QVector getBeats() const { + return {}; } }; diff --git a/src/analyzer/plugins/analyzerqueenmarybeats.cpp b/src/analyzer/plugins/analyzerqueenmarybeats.cpp index 47ba8a13479..f259d6f73e4 100644 --- a/src/analyzer/plugins/analyzerqueenmarybeats.cpp +++ b/src/analyzer/plugins/analyzerqueenmarybeats.cpp @@ -22,12 +22,12 @@ constexpr float kStepSecs = 0.01161f; // results in 43 Hz @ 44.1 kHz / 47 Hz @ 48 kHz / 47 Hz @ 96 kHz constexpr int kMaximumBinSizeHz = 50; // Hz -DFConfig makeDetectionFunctionConfig(int stepSize, int windowSize) { +DFConfig makeDetectionFunctionConfig(int stepSizeFrames, int windowSize) { // These are the defaults for the VAMP beat tracker plugin we used in Mixxx // 2.0. DFConfig config; config.DFType = DF_COMPLEXSD; - config.stepSize = stepSize; + config.stepSize = stepSizeFrames; config.frameLength = windowSize; config.dbRise = 3; config.adaptiveWhitening = false; @@ -39,25 +39,24 @@ DFConfig makeDetectionFunctionConfig(int stepSize, int windowSize) { } // namespace AnalyzerQueenMaryBeats::AnalyzerQueenMaryBeats() - : m_iSampleRate(0), - m_windowSize(0), - m_stepSize(0) { + : m_windowSize(0), + m_stepSizeFrames(0) { } AnalyzerQueenMaryBeats::~AnalyzerQueenMaryBeats() { } -bool AnalyzerQueenMaryBeats::initialize(int samplerate) { +bool AnalyzerQueenMaryBeats::initialize(mixxx::audio::SampleRate sampleRate) { m_detectionResults.clear(); - m_iSampleRate = samplerate; - m_stepSize = static_cast(m_iSampleRate * kStepSecs); - m_windowSize = MathUtilities::nextPowerOfTwo(m_iSampleRate / kMaximumBinSizeHz); + m_sampleRate = sampleRate; + m_stepSizeFrames = static_cast(m_sampleRate * kStepSecs); + m_windowSize = MathUtilities::nextPowerOfTwo(m_sampleRate / kMaximumBinSizeHz); m_pDetectionFunction = std::make_unique( - makeDetectionFunctionConfig(m_stepSize, m_windowSize)); - qDebug() << "input sample rate is " << m_iSampleRate << ", step size is " << m_stepSize; + makeDetectionFunctionConfig(m_stepSizeFrames, m_windowSize)); + qDebug() << "input sample rate is " << m_sampleRate << ", step size is " << m_stepSizeFrames; m_helper.initialize( - m_windowSize, m_stepSize, [this](double* pWindow, size_t) { + m_windowSize, m_stepSizeFrames, [this](double* pWindow, size_t) { // TODO(rryan) reserve? m_detectionResults.push_back( m_pDetectionFunction->processTimeDomain(pWindow)); @@ -97,7 +96,7 @@ bool AnalyzerQueenMaryBeats::finalize() { beatPeriod.push_back(0.0); } - TempoTrackV2 tt(m_iSampleRate, m_stepSize); + TempoTrackV2 tt(m_sampleRate, m_stepSizeFrames); tt.calculateBeatPeriod(df, beatPeriod, tempi); std::vector beats; @@ -105,9 +104,10 @@ bool AnalyzerQueenMaryBeats::finalize() { m_resultBeats.reserve(static_cast(beats.size())); for (size_t i = 0; i < beats.size(); ++i) { - // we add the halve m_stepSize here, because the beat + // we add the halve m_stepSizeFrames here, because the beat // is detected between the two samples. - double result = (beats.at(i) * m_stepSize) + m_stepSize / 2; + const auto result = mixxx::audio::FramePos( + (beats.at(i) * m_stepSizeFrames) + m_stepSizeFrames / 2); m_resultBeats.push_back(result); } diff --git a/src/analyzer/plugins/analyzerqueenmarybeats.h b/src/analyzer/plugins/analyzerqueenmarybeats.h index 5dc70ae85c9..bab39d63e24 100644 --- a/src/analyzer/plugins/analyzerqueenmarybeats.h +++ b/src/analyzer/plugins/analyzerqueenmarybeats.h @@ -32,7 +32,7 @@ class AnalyzerQueenMaryBeats : public AnalyzerBeatsPlugin { return pluginInfo(); } - bool initialize(int samplerate) override; + bool initialize(mixxx::audio::SampleRate sampleRate) override; bool processSamples(const CSAMPLE* pIn, const int iLen) override; bool finalize() override; @@ -40,18 +40,18 @@ class AnalyzerQueenMaryBeats : public AnalyzerBeatsPlugin { return true; } - QVector getBeats() const override { + QVector getBeats() const override { return m_resultBeats; } private: std::unique_ptr m_pDetectionFunction; DownmixAndOverlapHelper m_helper; - int m_iSampleRate; + mixxx::audio::SampleRate m_sampleRate; int m_windowSize; - int m_stepSize; + int m_stepSizeFrames; std::vector m_detectionResults; - QVector m_resultBeats; + QVector m_resultBeats; }; } // namespace mixxx diff --git a/src/analyzer/plugins/analyzerqueenmarykey.cpp b/src/analyzer/plugins/analyzerqueenmarykey.cpp index 59336996064..8f6a9c59394 100644 --- a/src/analyzer/plugins/analyzerqueenmarykey.cpp +++ b/src/analyzer/plugins/analyzerqueenmarykey.cpp @@ -27,7 +27,7 @@ AnalyzerQueenMaryKey::AnalyzerQueenMaryKey() AnalyzerQueenMaryKey::~AnalyzerQueenMaryKey() { } -bool AnalyzerQueenMaryKey::initialize(int samplerate) { +bool AnalyzerQueenMaryKey::initialize(mixxx::audio::SampleRate sampleRate) { m_prevKey = mixxx::track::io::key::INVALID; m_resultKeys.clear(); m_currentFrame = 0; @@ -42,17 +42,17 @@ bool AnalyzerQueenMaryKey::initialize(int samplerate) { // 8 = normal chroma overlap int decimationFactor; - Config(double _sampleRate, float _tuningFrequency) : - sampleRate(_sampleRate), - tuningFrequency(_tuningFrequency), - hpcpAverage(10), - medianAverage(10), - frameOverlapFactor(1), - decimationFactor(8) { + Config(mixxx::audio::SampleRate _sampleRate, float _tuningFrequency) + : sampleRate(_sampleRate.toDouble()), + tuningFrequency(_tuningFrequency), + hpcpAverage(10), + medianAverage(10), + frameOverlapFactor(1), + decimationFactor(8) { } }; - GetKeyMode::Config config(samplerate, kTuningFrequencyHertz); + GetKeyMode::Config config(sampleRate, kTuningFrequencyHertz); m_pKeyMode = std::make_unique(config); size_t windowSize = m_pKeyMode->getBlockSize(); size_t stepSize = m_pKeyMode->getHopSize(); diff --git a/src/analyzer/plugins/analyzerqueenmarykey.h b/src/analyzer/plugins/analyzerqueenmarykey.h index ea9d014f6fc..5883e96c3c8 100644 --- a/src/analyzer/plugins/analyzerqueenmarykey.h +++ b/src/analyzer/plugins/analyzerqueenmarykey.h @@ -32,7 +32,7 @@ class AnalyzerQueenMaryKey : public AnalyzerKeyPlugin { return pluginInfo(); } - bool initialize(int samplerate) override; + bool initialize(mixxx::audio::SampleRate sampleRate) override; bool processSamples(const CSAMPLE* pIn, const int iLen) override; bool finalize() override; diff --git a/src/analyzer/plugins/analyzersoundtouchbeats.cpp b/src/analyzer/plugins/analyzersoundtouchbeats.cpp index 8d122a3b29d..4d490f68e6f 100644 --- a/src/analyzer/plugins/analyzersoundtouchbeats.cpp +++ b/src/analyzer/plugins/analyzersoundtouchbeats.cpp @@ -8,16 +8,15 @@ namespace mixxx { AnalyzerSoundTouchBeats::AnalyzerSoundTouchBeats() - : m_downmixBuffer(kAnalysisFramesPerChunk), // mono, i.e. 1 sample per frame - m_fResultBpm(0.0f) { + : m_downmixBuffer(kAnalysisFramesPerChunk) { } AnalyzerSoundTouchBeats::~AnalyzerSoundTouchBeats() { } -bool AnalyzerSoundTouchBeats::initialize(int samplerate) { - m_fResultBpm = 0.0f; - m_pSoundTouch = std::make_unique(2, samplerate); +bool AnalyzerSoundTouchBeats::initialize(mixxx::audio::SampleRate sampleRate) { + m_resultBpm = mixxx::Bpm(); + m_pSoundTouch = std::make_unique(2, sampleRate); return true; } @@ -42,7 +41,7 @@ bool AnalyzerSoundTouchBeats::finalize() { if (!m_pSoundTouch) { return false; } - m_fResultBpm = m_pSoundTouch->getBpm(); + m_resultBpm = mixxx::Bpm(m_pSoundTouch->getBpm()); m_pSoundTouch.reset(); return true; } diff --git a/src/analyzer/plugins/analyzersoundtouchbeats.h b/src/analyzer/plugins/analyzersoundtouchbeats.h index 1c8e26a359b..9e1fd236d3f 100644 --- a/src/analyzer/plugins/analyzersoundtouchbeats.h +++ b/src/analyzer/plugins/analyzersoundtouchbeats.h @@ -29,7 +29,7 @@ class AnalyzerSoundTouchBeats : public AnalyzerBeatsPlugin { return pluginInfo(); } - bool initialize(int samplerate) override; + bool initialize(mixxx::audio::SampleRate sampleRate) override; bool processSamples(const CSAMPLE* pIn, const int iLen) override; bool finalize() override; @@ -37,14 +37,15 @@ class AnalyzerSoundTouchBeats : public AnalyzerBeatsPlugin { return false; } - float getBpm() const override { - return m_fResultBpm; + mixxx::Bpm getBpm() const override { + return m_resultBpm; } private: std::unique_ptr m_pSoundTouch; + /// mono, i.e. 1 sample per frame SampleBuffer m_downmixBuffer; - float m_fResultBpm; + mixxx::Bpm m_resultBpm; }; } // namespace mixxx diff --git a/src/audio/frame.h b/src/audio/frame.h new file mode 100644 index 00000000000..71b70595295 --- /dev/null +++ b/src/audio/frame.h @@ -0,0 +1,214 @@ +#pragma once + +#include +#include +#include + +#include "engine/engine.h" +#include "util/fpclassify.h" + +namespace mixxx { +namespace audio { +/// FrameDiff_t can be used to store the difference in position between +/// two frames and to store the length of a segment of track in terms of frames. +typedef double FrameDiff_t; + +/// FramePos defines the position of a frame in a track +/// with respect to a fixed origin, i.e. start of the track. +/// +/// Note that all invalid frame positions are considered equal. +class FramePos final { + public: + typedef double value_t; + static constexpr value_t kStartValue = 0; + static constexpr value_t kInvalidValue = std::numeric_limits::quiet_NaN(); + static constexpr double kLegacyInvalidEnginePosition = -1.0; + + constexpr FramePos() + : m_framePosition(kInvalidValue) { + } + + constexpr explicit FramePos(value_t framePosition) + : m_framePosition(framePosition) { + } + + /// Return a `FramePos` from a given engine sample position. To catch + /// "invalid" positions (e.g. when parsing values from control objects), + /// use `FramePos::fromEngineSamplePosMaybeInvalid` instead. + static constexpr FramePos fromEngineSamplePos(double engineSamplePos) { + return FramePos(engineSamplePos / mixxx::kEngineChannelCount); + } + + /// Return an engine sample position. The `FramePos` is expected to be + /// valid. If invalid positions are possible (e.g. for control object + /// values), use `FramePos::toEngineSamplePosMaybeInvalid` instead. + double toEngineSamplePos() const { + DEBUG_ASSERT(isValid()); + return value() * mixxx::kEngineChannelCount; + } + + /// Return a `FramePos` from a given engine sample position. Sample + /// positions that equal `kLegacyInvalidEnginePosition` are considered + /// invalid and result in an invalid `FramePos` instead. + /// + /// In general, using this method should be avoided and is only necessary + /// for compatiblity with our control objects and legacy parts of the code + /// base. Using a different code path based on the output of `isValid()` is + /// preferable. + static constexpr FramePos fromEngineSamplePosMaybeInvalid(double engineSamplePos) { + if (engineSamplePos == kLegacyInvalidEnginePosition) { + return {}; + } + return fromEngineSamplePos(engineSamplePos); + } + + /// Return an engine sample position. If the `FramePos` is invalid, + /// `kLegacyInvalidEnginePosition` is returned instad. + /// + /// In general, using this method should be avoided and is only necessary + /// for compatiblity with our control objects and legacy parts of the code + /// base. Using a different code path based on the output of `isValid()` is + /// preferable. + double toEngineSamplePosMaybeInvalid() const { + if (!isValid()) { + return kLegacyInvalidEnginePosition; + } + return toEngineSamplePos(); + } + + /// Return true if the frame position is valid. Any finite value is + /// considered valid, i.e. any value except NaN and negative/positive + /// infinity. + bool isValid() const { + return util_isfinite(m_framePosition); + } + + void setValue(value_t framePosition) { + m_framePosition = framePosition; + } + + /// Return the underlying primitive value for this frame position. + value_t value() const { + VERIFY_OR_DEBUG_ASSERT(isValid()) { + return FramePos::kInvalidValue; + } + return m_framePosition; + } + + /// Return true if the frame position has a fractional part, i.e. if it is + /// not located at a full frame boundary. + bool isFractional() const { + DEBUG_ASSERT(isValid()); + value_t integerPart; + return std::modf(value(), &integerPart) != 0; + } + + /// Return position rounded to the next lower full frame position, without + /// the fractional part. + [[nodiscard]] FramePos toLowerFrameBoundary() const { + return FramePos(std::floor(value())); + } + + FramePos& operator+=(FrameDiff_t increment) { + DEBUG_ASSERT(isValid()); + m_framePosition += increment; + return *this; + } + + FramePos& operator-=(FrameDiff_t decrement) { + DEBUG_ASSERT(isValid()); + m_framePosition -= decrement; + return *this; + } + + FramePos& operator*=(double multiple) { + DEBUG_ASSERT(isValid()); + m_framePosition *= multiple; + return *this; + } + + FramePos& operator/=(double divisor) { + DEBUG_ASSERT(isValid()); + m_framePosition /= divisor; + return *this; + } + + private: + value_t m_framePosition; +}; + +/// FramePos can be added to a FrameDiff_t +inline FramePos operator+(FramePos framePos, FrameDiff_t frameDiff) { + return FramePos(framePos.value() + frameDiff); +} + +/// FramePos can be subtracted from a FrameDiff_t +inline FramePos operator-(FramePos framePos, FrameDiff_t frameDiff) { + return FramePos(framePos.value() - frameDiff); +} + +/// Two FramePos can be subtracted to get a FrameDiff_t +inline FrameDiff_t operator-(FramePos framePos1, FramePos framePos2) { + return framePos1.value() - framePos2.value(); +} + +// Adding two FramePos is not allowed since every FramePos shares a common +// reference or origin i.e. the start of the track. + +/// FramePos can be multiplied or divided by a double +inline FramePos operator*(FramePos framePos, double multiple) { + return FramePos(framePos.value() * multiple); +} + +inline FramePos operator/(FramePos framePos, double divisor) { + return FramePos(framePos.value() / divisor); +} + +inline bool operator<(FramePos frame1, FramePos frame2) { + return frame1.value() < frame2.value(); +} + +inline bool operator<=(FramePos frame1, FramePos frame2) { + return frame1.value() <= frame2.value(); +} + +inline bool operator>(FramePos frame1, FramePos frame2) { + return frame1.value() > frame2.value(); +} + +inline bool operator>=(FramePos frame1, FramePos frame2) { + return frame1.value() >= frame2.value(); +} + +inline bool operator==(FramePos frame1, FramePos frame2) { + if (frame1.isValid() && frame2.isValid()) { + return frame1.value() == frame2.value(); + } + + if (!frame1.isValid() && !frame2.isValid()) { + return true; + } + + return false; +} + +inline bool operator!=(FramePos frame1, FramePos frame2) { + return !(frame1 == frame2); +} + +inline QDebug operator<<(QDebug dbg, FramePos arg) { + if (arg.isValid()) { + dbg.nospace() << "FramePos(" << arg.value() << ")"; + } else { + dbg << "FramePos()"; + } + return dbg; +} + +constexpr FramePos kInvalidFramePos = FramePos(FramePos::kInvalidValue); +constexpr FramePos kStartFramePos = FramePos(FramePos::kStartValue); +} // namespace audio +} // namespace mixxx + +Q_DECLARE_TYPEINFO(mixxx::audio::FramePos, Q_MOVABLE_TYPE); +Q_DECLARE_METATYPE(mixxx::audio::FramePos); diff --git a/src/audio/types.h b/src/audio/types.h index fae725a5e4d..bb72a88d232 100644 --- a/src/audio/types.h +++ b/src/audio/types.h @@ -107,9 +107,12 @@ class ChannelCount { return kValueMin <= m_value; } - /*implicit*/ constexpr operator value_t() const { + constexpr value_t value() const { return m_value; } + /*implicit*/ constexpr operator value_t() const { + return value(); + } private: value_t m_value; @@ -151,12 +154,23 @@ class SampleRate { m_value = value; } - /*implicit*/ constexpr operator value_t() const { + constexpr value_t value() const { return m_value; } + /*implicit*/ constexpr operator value_t() const { + return value(); + } + + static SampleRate fromDouble(double value) { + const auto sampleRate = SampleRate(static_cast(value)); + // The sample rate should always be an integer value + // and this conversion is supposed to be lossless. + DEBUG_ASSERT(sampleRate.toDouble() == value); + return sampleRate; + } - static constexpr SampleRate fromDouble(double value) { - return SampleRate(static_cast(value)); + constexpr double toDouble() const { + return static_cast(value()); } private: @@ -165,6 +179,11 @@ class SampleRate { QDebug operator<<(QDebug dbg, SampleRate arg); +/// Division of a SampleRate by another SampleRate returns a ratio as double. +inline double operator/(SampleRate sampleRate1, SampleRate sampleRate2) { + return sampleRate1.toDouble() / sampleRate2.toDouble(); +} + // The bitrate is measured in kbit/s (kbps) and provides information // about the level of compression for lossily encoded audio streams. // @@ -194,10 +213,10 @@ class Bitrate { return m_value > kValueDefault; } - value_t value() const { + constexpr value_t value() const { return m_value; } - /*implicit*/ operator value_t() const { + /*implicit*/ constexpr operator value_t() const { return value(); } diff --git a/src/broadcast/broadcastmanager.cpp b/src/broadcast/broadcastmanager.cpp index 39e4a10847a..6fa80519a4e 100644 --- a/src/broadcast/broadcastmanager.cpp +++ b/src/broadcast/broadcastmanager.cpp @@ -92,8 +92,7 @@ void BroadcastManager::slotControlEnabled(double v) { // Wrap around manually . // Wrapping around in WPushbutton does not work // since the status button has 4 states, but this CO is bool - m_pBroadcastEnabled->set(0.0); - emit broadcastEnabled(false); + v = 0.0; } if (v > 0.0) { @@ -116,6 +115,7 @@ void BroadcastManager::slotControlEnabled(double v) { slotProfilesChanged(); } else { + m_pBroadcastEnabled->set(false); m_pStatusCO->forceSet(STATUSCO_UNCONNECTED); QList profiles = m_pBroadcastSettings->profiles(); for(BroadcastProfilePtr profile : profiles) { diff --git a/src/broadcast/broadcastmanager.h b/src/broadcast/broadcastmanager.h index 75479e3bf69..8a68d16efae 100644 --- a/src/broadcast/broadcastmanager.h +++ b/src/broadcast/broadcastmanager.h @@ -15,10 +15,10 @@ class BroadcastManager : public QObject { public: enum StatusCOStates { STATUSCO_UNCONNECTED = 0, // IDLE state, no error - STATUSCO_CONNECTING = 1, // 30 s max - STATUSCO_CONNECTED = 2, // On Air - STATUSCO_FAILURE = 3, // Happens when all connection fails - STATUSCO_WARNING = 4 + STATUSCO_CONNECTING = 1, // 30 s max + STATUSCO_CONNECTED = 2, // On Air + STATUSCO_FAILURE = 3, // Happens when all connection fail + STATUSCO_WARNING = 4 // Happens when at least one but not all fail }; BroadcastManager(SettingsManager* pSettingsManager, diff --git a/src/controllers/hid/hidcontroller.cpp b/src/controllers/hid/hidcontroller.cpp index 9126db1bac8..e86290c6b34 100644 --- a/src/controllers/hid/hidcontroller.cpp +++ b/src/controllers/hid/hidcontroller.cpp @@ -168,6 +168,8 @@ QList HidController::getInputReport(unsigned int reportID) { int bytesRead; m_pPollData[m_pollingBufferIndex][0] = reportID; + // FIXME: implement upstream for hidraw backend on Linux + // https://github.com/libusb/hidapi/issues/259 bytesRead = hid_get_input_report(m_pHidDevice, m_pPollData[m_pollingBufferIndex], kBufferSize); controllerDebug(bytesRead @@ -188,7 +190,7 @@ QList HidController::getInputReport(unsigned int reportID) { } // Convert array of bytes read in a JavaScript compatible return type - // For compatibilty with the array provided by HidController::poll the reportID is contained as prefix + // For compatibility with the array provided by HidController::poll the reportID is contained as prefix QList dataList; dataList.reserve(bytesRead); for (int i = 0; i < bytesRead; i++) { @@ -324,7 +326,7 @@ QList HidController::getFeatureReport( } // Convert array of bytes read in a JavaScript compatible return type - // For compatibilty with input array HidController::sendFeatureReport, a reportID prefix is not added here + // For compatibility with input array HidController::sendFeatureReport, a reportID prefix is not added here QList dataList; dataList.reserve(bytesRead - kReportIdSize); for (int i = kReportIdSize; i < bytesRead; i++) { diff --git a/src/controllers/hid/hidenumerator.cpp b/src/controllers/hid/hidenumerator.cpp index 68c0f70a453..75adf0b6cb6 100644 --- a/src/controllers/hid/hidenumerator.cpp +++ b/src/controllers/hid/hidenumerator.cpp @@ -65,23 +65,33 @@ HidEnumerator::~HidEnumerator() { QList HidEnumerator::queryDevices() { qInfo() << "Scanning USB HID devices"; + QStringList enumeratedDevices; hid_device_info* device_info_list = hid_enumerate(0x0, 0x0); for (const auto* device_info = device_info_list; device_info; device_info = device_info->next) { auto deviceInfo = mixxx::hid::DeviceInfo(*device_info); + // The hidraw backend of hidapi on Linux returns many duplicate hid_device_info's from hid_enumerate, + // so filter them out. + // https://github.com/libusb/hidapi/issues/298 + if (enumeratedDevices.contains(deviceInfo.pathRaw())) { + qInfo() << "Duplicate HID device, excluding" << deviceInfo; + continue; + } + enumeratedDevices.append(QString(deviceInfo.pathRaw())); + if (!recognizeDevice(*device_info)) { qInfo() - << "Excluding USB HID device" + << "Excluding HID device" << deviceInfo; continue; } - qInfo() << "Found USB HID device:" + qInfo() << "Found HID device:" << deviceInfo; if (!deviceInfo.isValid()) { - qWarning() << "USB permissions problem or device error." - << "Your account needs write access to USB HID controllers."; + qWarning() << "HID device permissions problem or device error." + << "Your account needs write access to HID controllers."; continue; } diff --git a/src/coreservices.cpp b/src/coreservices.cpp index 7bbfc4761f7..0b8b43c595f 100644 --- a/src/coreservices.cpp +++ b/src/coreservices.cpp @@ -107,6 +107,17 @@ CoreServices::CoreServices(const CmdlineArgs& args) } void CoreServices::initializeSettings() { +#ifdef __APPLE__ + // TODO: At this point it is too late to provide the same settings path to all components + // and too early to log errors and give users advises in their system language. + // Calling this from main.cpp before the QApplication is initialized may cause a crash + // due to potential QMessageBox invocations within migrateOldSettings(). + // Solution: Start Mixxx with default settings, migrate the preferences, and then restart + // immediately. + if (!m_cmdlineArgs.getSettingsPathSet()) { + CmdlineArgs::Instance().setSettingsPath(Sandbox::migrateOldSettings()); + } +#endif QString settingsPath = m_cmdlineArgs.getSettingsPath(); m_pSettingsManager = std::make_unique(settingsPath); } diff --git a/src/database/mixxxdb.cpp b/src/database/mixxxdb.cpp index 9e707bf260a..34d6b66b98f 100644 --- a/src/database/mixxxdb.cpp +++ b/src/database/mixxxdb.cpp @@ -12,7 +12,7 @@ const QString MixxxDb::kDefaultSchemaFile(":/schema.xml"); //static -const int MixxxDb::kRequiredSchemaVersion = 36; +const int MixxxDb::kRequiredSchemaVersion = 38; namespace { diff --git a/src/defs_urls.h b/src/defs_urls.h index eaf58616e0b..8f607789b6c 100644 --- a/src/defs_urls.h +++ b/src/defs_urls.h @@ -35,7 +35,7 @@ #define MIXXX_MANUAL_SHORTCUTS_URL \ MIXXX_MANUAL_URL "/chapters/controlling_mixxx.html#using-a-keyboard" #define MIXXX_MANUAL_COMMANDLINEOPTIONS_URL \ - MIXXX_MANUAL_URL "/chapters/appendix.html#command-line-options" + MIXXX_MANUAL_URL "/chapters/appendix/commandline_dev_tools.html" #define MIXXX_MANUAL_CONTROLLERS_URL \ MIXXX_MANUAL_URL "/chapters/controlling_mixxx.html#using-midi-hid-controllers" #define MIXXX_MANUAL_CONTROLLERMANUAL_PREFIX \ diff --git a/src/dialog/dlgabout.cpp b/src/dialog/dlgabout.cpp index 5210fa95a1f..bcd436d4857 100644 --- a/src/dialog/dlgabout.cpp +++ b/src/dialog/dlgabout.cpp @@ -107,7 +107,9 @@ DlgAbout::DlgAbout(QWidget* parent) : QDialog(parent), Ui::DlgAboutDlg() { << "Al Hadebe" << "Javier Vilarroig" << "Balló György" - << "Pino Toscano"; + << "Pino Toscano" + << "Alexander Horner" + << "Michael Ehlen"; QStringList specialThanks; specialThanks diff --git a/src/encoder/encoder.h b/src/encoder/encoder.h index da63351c7dd..f1c174438d0 100644 --- a/src/encoder/encoder.h +++ b/src/encoder/encoder.h @@ -1,11 +1,12 @@ #pragma once +#include "audio/types.h" +#include "encoder/encodercallback.h" +#include "encoder/encoderrecordingsettings.h" +#include "encoder/encodersettings.h" +#include "preferences/usersettings.h" #include "util/memory.h" #include "util/types.h" -#include "preferences/usersettings.h" -#include "encoder/encodersettings.h" -#include "encoder/encoderrecordingsettings.h" -#include "encoder/encodercallback.h" class Encoder { public: @@ -29,7 +30,7 @@ class Encoder { Encoder() {} virtual ~Encoder() = default; - virtual int initEncoder(int samplerate, QString* pUserErrorMessage) = 0; + virtual int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) = 0; // encodes the provided buffer of audio. virtual void encodeBuffer(const CSAMPLE *samples, const int size) = 0; // Adds metadata to the encoded audio, i.e., the ID3 tag. Currently only used diff --git a/src/encoder/encoderfdkaac.cpp b/src/encoder/encoderfdkaac.cpp index 81e4db74fee..29acb144e98 100644 --- a/src/encoder/encoderfdkaac.cpp +++ b/src/encoder/encoderfdkaac.cpp @@ -28,7 +28,6 @@ EncoderFdkAac::EncoderFdkAac(EncoderCallback* pCallback) m_aacAot(AOT_AAC_LC), m_bitrate(0), m_channels(0), - m_samplerate(0), m_pCallback(pCallback), m_pLibrary(nullptr), m_pInputFifo(nullptr), @@ -252,8 +251,8 @@ void EncoderFdkAac::setEncoderSettings(const EncoderSettings& settings) { } } -int EncoderFdkAac::initEncoder(int samplerate, QString* pUserErrorMessage) { - m_samplerate = samplerate; +int EncoderFdkAac::initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) { + m_sampleRate = sampleRate; if (!m_pLibrary) { kLogger.warning() << "initEncoder failed: fdk-aac library not loaded"; @@ -293,7 +292,7 @@ int EncoderFdkAac::initEncoder(int samplerate, QString* pUserErrorMessage) { } // Input audio samplerate - if (aacEncoder_SetParam(m_aacEnc, AACENC_SAMPLERATE, m_samplerate) != AACENC_OK) { + if (aacEncoder_SetParam(m_aacEnc, AACENC_SAMPLERATE, m_sampleRate) != AACENC_OK) { kLogger.warning() << "aac encoder setting samplerate failed!"; return -1; } @@ -359,7 +358,7 @@ void EncoderFdkAac::encodeBuffer(const CSAMPLE* samples, const int sampleCount) int writeCount = sampleCount; int writeAvailable = m_pInputFifo->writeAvailable(); if (writeCount > writeAvailable) { - kLogger.warning() << "FIFO buffer too small, loosing samples!" + kLogger.warning() << "FIFO buffer too small, losing samples!" << "required:" << writeCount << "; available: " << writeAvailable; writeCount = writeAvailable; diff --git a/src/encoder/encoderfdkaac.h b/src/encoder/encoderfdkaac.h index b5f94278f48..d9a8a217a7f 100644 --- a/src/encoder/encoderfdkaac.h +++ b/src/encoder/encoderfdkaac.h @@ -12,7 +12,7 @@ class EncoderFdkAac : public Encoder { EncoderFdkAac(EncoderCallback* pCallback); virtual ~EncoderFdkAac(); - int initEncoder(int samplerate, QString* pUserErrorMessage) override; + int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) override; void encodeBuffer(const CSAMPLE* samples, const int sampleCount) override; void updateMetaData(const QString& artist, const QString& title, const QString& album) override; void flush() override; @@ -201,7 +201,7 @@ class EncoderFdkAac : public Encoder { int m_aacAot; int m_bitrate; int m_channels; - int m_samplerate; + mixxx::audio::SampleRate m_sampleRate; EncoderCallback* m_pCallback; std::unique_ptr m_pLibrary; FIFO* m_pInputFifo; diff --git a/src/encoder/encoderffmpegcore.cpp b/src/encoder/encoderffmpegcore.cpp index 273209a5cbf..0517b3755d7 100644 --- a/src/encoder/encoderffmpegcore.cpp +++ b/src/encoder/encoderffmpegcore.cpp @@ -197,13 +197,14 @@ void EncoderFfmpegCore::updateMetaData(const QString& artist, const QString& tit m_strMetaDataAlbum = album; } -int EncoderFfmpegCore::initEncoder(int samplerate, QString* pUserErrorMessage) { +int EncoderFfmpegCore::initEncoder( + mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) { #ifndef avformat_alloc_output_context2 qDebug() << "EncoderFfmpegCore::initEncoder: Old Style initialization"; m_pEncodeFormatCtx = avformat_alloc_context(); #endif - m_lSampleRate = samplerate; + m_lSampleRate = sampleRate; QString codecString; #if LIBAVCODEC_VERSION_INT > 3544932 diff --git a/src/encoder/encoderffmpegcore.h b/src/encoder/encoderffmpegcore.h index 9ce1e561933..8eea67cb82b 100644 --- a/src/encoder/encoderffmpegcore.h +++ b/src/encoder/encoderffmpegcore.h @@ -43,7 +43,7 @@ class EncoderFfmpegCore : public Encoder { CodecID codec = CODEC_ID_MP2); #endif ~EncoderFfmpegCore(); - int initEncoder(int samplerate, QString* pUserErrorMessage) override; + int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) override; void encodeBuffer(const CSAMPLE *samples, const int size) override; void updateMetaData(const QString& artist, const QString& title, const QString& album) override; void flush() override; diff --git a/src/encoder/encodermp3.cpp b/src/encoder/encodermp3.cpp index a3b8d0fee67..c79376945e4 100644 --- a/src/encoder/encodermp3.cpp +++ b/src/encoder/encodermp3.cpp @@ -172,8 +172,8 @@ void EncoderMp3::initStream() { m_bufferIn[1] = (float *)malloc(m_bufferOutSize * sizeof(float)); } -int EncoderMp3::initEncoder(int samplerate, QString* pUserErrorMessage) { - unsigned long samplerate_in = samplerate; +int EncoderMp3::initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) { + unsigned long samplerate_in = sampleRate; // samplerate_out 0 means "let LAME pick the appropriate one" unsigned long samplerate_out = (samplerate_in > 48000 ? 48000 : 0); diff --git a/src/encoder/encodermp3.h b/src/encoder/encodermp3.h index 36477f03b55..153ff3505ab 100644 --- a/src/encoder/encodermp3.h +++ b/src/encoder/encodermp3.h @@ -14,7 +14,7 @@ class EncoderMp3 final : public Encoder { EncoderMp3(EncoderCallback* callback=nullptr); ~EncoderMp3() override; - int initEncoder(int samplerate, QString* pUserErrorMessage) override; + int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) override; void encodeBuffer(const CSAMPLE *samples, const int size) override; void updateMetaData(const QString& artist, const QString& title, const QString& album) override; void flush() override; diff --git a/src/encoder/encoderopus.cpp b/src/encoder/encoderopus.cpp index 6c6e9d3dd4f..d8e2632d9d0 100644 --- a/src/encoder/encoderopus.cpp +++ b/src/encoder/encoderopus.cpp @@ -90,7 +90,6 @@ EncoderOpus::EncoderOpus(EncoderCallback* pCallback) : m_bitrate(0), m_bitrateMode(0), m_channels(0), - m_samplerate(0), m_readRequired(0), m_pCallback(pCallback), m_fifoBuffer(EngineSideChain::SIDECHAIN_BUFFER_SIZE * kOpusChannelCount), @@ -138,10 +137,10 @@ void EncoderOpus::setEncoderSettings(const EncoderSettings& settings) { } } -int EncoderOpus::initEncoder(int samplerate, QString* pUserErrorMessage) { +int EncoderOpus::initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) { Q_UNUSED(pUserErrorMessage); - if (samplerate != kMasterSamplerate) { + if (sampleRate != kMasterSamplerate) { kLogger.warning() << "initEncoder failed: samplerate not supported by Opus"; const QString invalidSamplerateMessage = getInvalidSamplerateMessage(); @@ -154,13 +153,13 @@ int EncoderOpus::initEncoder(int samplerate, QString* pUserErrorMessage) { ErrorDialogHandler::instance()->requestErrorDialog(props); return -1; } - m_samplerate = samplerate; - DEBUG_ASSERT(m_samplerate == 8000 || m_samplerate == 12000 || - m_samplerate == 16000 || m_samplerate == 24000 || - m_samplerate == 48000); + m_sampleRate = sampleRate; + DEBUG_ASSERT(m_sampleRate == 8000 || m_sampleRate == 12000 || + m_sampleRate == 16000 || m_sampleRate == 24000 || + m_sampleRate == 48000); int createResult = 0; - m_pOpus = opus_encoder_create(m_samplerate, m_channels, OPUS_APPLICATION_AUDIO, &createResult); + m_pOpus = opus_encoder_create(m_sampleRate, m_channels, OPUS_APPLICATION_AUDIO, &createResult); if (createResult != OPUS_OK) { kLogger.warning() << "opus_encoder_create failed:" << opusErrorString(createResult); @@ -187,7 +186,7 @@ int EncoderOpus::initEncoder(int samplerate, QString* pUserErrorMessage) { opus_encoder_ctl(m_pOpus, OPUS_SET_VBR_CONSTRAINT(0)); // Unconstrained VBR } - m_readRequired = m_samplerate * kOpusFrameMs; + m_readRequired = m_sampleRate * kOpusFrameMs; m_pFifoChunkBuffer = std::make_unique(m_readRequired); initStream(); @@ -243,7 +242,7 @@ void EncoderOpus::pushHeaderPacket() { // Sample rate (4 bytes, little endian) for (int x = 0; x < 4; x++) { - unsigned char samplerateByte = (m_samplerate >> (x*8)) & 0xFF; + unsigned char samplerateByte = (m_sampleRate >> (x * 8)) & 0xFF; frame.append(samplerateByte); } diff --git a/src/encoder/encoderopus.h b/src/encoder/encoderopus.h index 733b112bc47..6d674fc4ca8 100644 --- a/src/encoder/encoderopus.h +++ b/src/encoder/encoderopus.h @@ -23,7 +23,7 @@ class EncoderOpus: public Encoder { explicit EncoderOpus(EncoderCallback* pCallback = nullptr); ~EncoderOpus() override; - int initEncoder(int samplerate, QString* pUserErrorMessage) override; + int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) override; void encodeBuffer(const CSAMPLE *samples, const int size) override; void updateMetaData(const QString& artist, const QString& title, const QString& album) override; void flush() override; @@ -39,7 +39,7 @@ class EncoderOpus: public Encoder { int m_bitrate; int m_bitrateMode; int m_channels; - int m_samplerate; + mixxx::audio::SampleRate m_sampleRate; int m_readRequired; EncoderCallback* m_pCallback; FIFO m_fifoBuffer; diff --git a/src/encoder/encodervorbis.cpp b/src/encoder/encodervorbis.cpp index 803346eb2a2..a60678b39bd 100644 --- a/src/encoder/encodervorbis.cpp +++ b/src/encoder/encodervorbis.cpp @@ -200,11 +200,11 @@ void EncoderVorbis::initStream() { m_bStreamInitialized = true; } -int EncoderVorbis::initEncoder(int samplerate, QString* pUserErrorMessage) { +int EncoderVorbis::initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) { vorbis_info_init(&m_vinfo); // initialize VBR quality based mode - int ret = vorbis_encode_init(&m_vinfo, m_channels, samplerate, -1, m_bitrate*1000, -1); + int ret = vorbis_encode_init(&m_vinfo, m_channels, sampleRate, -1, m_bitrate * 1000, -1); if (ret != 0) { qDebug() << "Error initializing OGG recording. IS OGG/Vorbis library installed? Error code: " << ret; diff --git a/src/encoder/encodervorbis.h b/src/encoder/encodervorbis.h index 36eb88a2d4a..31a54aa66a1 100644 --- a/src/encoder/encodervorbis.h +++ b/src/encoder/encodervorbis.h @@ -19,7 +19,7 @@ class EncoderVorbis : public Encoder { EncoderVorbis(EncoderCallback* pCallback = nullptr); ~EncoderVorbis() override; - int initEncoder(int samplerate, QString* pUserErrorMessage) override; + int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) override; void encodeBuffer(const CSAMPLE *samples, const int size) override; void updateMetaData(const QString& artist, const QString& title, const QString& album) override; void flush() override; diff --git a/src/encoder/encoderwave.cpp b/src/encoder/encoderwave.cpp index 0779fceba87..3bdec355d42 100644 --- a/src/encoder/encoderwave.cpp +++ b/src/encoder/encoderwave.cpp @@ -194,11 +194,11 @@ void EncoderWave::initStream() { } } -int EncoderWave::initEncoder(int samplerate, QString* pUserErrorMessage) { +int EncoderWave::initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) { Q_UNUSED(pUserErrorMessage); // set sfInfo. // m_sfInfo.format is setup on setEncoderSettings previous to calling initEncoder. - m_sfInfo.samplerate = samplerate; + m_sfInfo.samplerate = sampleRate; m_sfInfo.channels = 2; m_sfInfo.frames = 0; m_sfInfo.sections = 0; diff --git a/src/encoder/encoderwave.h b/src/encoder/encoderwave.h index f3fb0f48f08..54d67184998 100644 --- a/src/encoder/encoderwave.h +++ b/src/encoder/encoderwave.h @@ -21,7 +21,7 @@ class EncoderWave : public Encoder { EncoderWave(EncoderCallback* pCallback = nullptr); ~EncoderWave() override; - int initEncoder(int samplerate, QString* pUserErrorMessage) override; + int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) override; void encodeBuffer(const CSAMPLE *samples, const int size) override; void updateMetaData(const QString& artist, const QString& title, const QString& album) override; void flush() override; diff --git a/src/engine/controls/bpmcontrol.cpp b/src/engine/controls/bpmcontrol.cpp index 6579826992a..6e98ea99ca7 100644 --- a/src/engine/controls/bpmcontrol.cpp +++ b/src/engine/controls/bpmcontrol.cpp @@ -162,8 +162,8 @@ BpmControl::~BpmControl() { delete m_pAdjustBeatsSlower; } -double BpmControl::getBpm() const { - return m_pEngineBpm->get(); +mixxx::Bpm BpmControl::getBpm() const { + return mixxx::Bpm(m_pEngineBpm->get()); } void BpmControl::adjustBeatsBpm(double deltaBpm) { @@ -173,9 +173,9 @@ void BpmControl::adjustBeatsBpm(double deltaBpm) { } const mixxx::BeatsPointer pBeats = pTrack->getBeats(); if (pBeats && (pBeats->getCapabilities() & mixxx::Beats::BEATSCAP_SETBPM)) { - double bpm = pBeats->getBpm(); - double centerBpm = math_max(kBpmAdjustMin, bpm + deltaBpm); - double adjustedBpm = BeatUtils::roundBpmWithinRange( + mixxx::Bpm bpm = pBeats->getBpm(); + const auto centerBpm = mixxx::Bpm(math_max(kBpmAdjustMin, bpm.value() + deltaBpm)); + mixxx::Bpm adjustedBpm = BeatUtils::roundBpmWithinRange( centerBpm - kBpmAdjustStep / 2, centerBpm, centerBpm + kBpmAdjustStep / 2); pTrack->trySetBeats(pBeats->setBpm(adjustedBpm)); } @@ -206,8 +206,9 @@ void BpmControl::slotTranslateBeatsEarlier(double v) { const mixxx::BeatsPointer pBeats = pTrack->getBeats(); if (pBeats && (pBeats->getCapabilities() & mixxx::Beats::BEATSCAP_TRANSLATE)) { - const double translate_dist = getSampleOfTrack().rate * -.01; - pTrack->trySetBeats(pBeats->translate(translate_dist)); + const double sampleOffset = getSampleOfTrack().rate * -0.01; + const mixxx::audio::FrameDiff_t frameOffset = sampleOffset / mixxx::kEngineChannelCount; + pTrack->trySetBeats(pBeats->translate(frameOffset)); } } @@ -223,8 +224,9 @@ void BpmControl::slotTranslateBeatsLater(double v) { if (pBeats && (pBeats->getCapabilities() & mixxx::Beats::BEATSCAP_TRANSLATE)) { // TODO(rryan): Track::getSampleRate is possibly inaccurate! - const double translate_dist = getSampleOfTrack().rate * .01; - pTrack->trySetBeats(pBeats->translate(translate_dist)); + const double sampleOffset = getSampleOfTrack().rate * 0.01; + const mixxx::audio::FrameDiff_t frameOffset = sampleOffset / mixxx::kEngineChannelCount; + pTrack->trySetBeats(pBeats->translate(frameOffset)); } } @@ -257,7 +259,7 @@ void BpmControl::slotTapFilter(double averageLength, int numSamples) { // (60 seconds per minute) * (1000 milliseconds per second) / (X millis per // beat) = Y beats/minute - double averageBpm = 60.0 * 1000.0 / averageLength / rateRatio; + auto averageBpm = mixxx::Bpm(60.0 * 1000.0 / averageLength / rateRatio); averageBpm = BeatUtils::roundBpmWithinRange(averageBpm - kBpmTabRounding, averageBpm, averageBpm + kBpmTabRounding); @@ -311,14 +313,14 @@ bool BpmControl::syncTempo() { return false; } - double fThisBpm = m_pEngineBpm->get(); - double fThisLocalBpm = m_pLocalBpm->get(); + const auto thisBpm = getBpm(); + const auto thisLocalBpm = getLocalBpm(); - double fOtherBpm = pOtherEngineBuffer->getBpm(); - double fOtherLocalBpm = pOtherEngineBuffer->getLocalBpm(); + const auto otherBpm = pOtherEngineBuffer->getBpm(); + const auto otherLocalBpm = pOtherEngineBuffer->getLocalBpm(); - //qDebug() << "this" << "bpm" << fThisBpm << "filebpm" << fThisLocalBpm; - //qDebug() << "other" << "bpm" << fOtherBpm << "filebpm" << fOtherLocalBpm; + //qDebug() << "this" << "bpm" << thisBpm << "filebpm" << thisLocalBpm; + //qDebug() << "other" << "bpm" << otherBpm << "filebpm" << otherLocalBpm; //////////////////////////////////////////////////////////////////////////// // Rough proof of how syncing works -- rryan 3/2011 @@ -346,21 +348,21 @@ bool BpmControl::syncTempo() { // // thisRateScale = ((otherFileBpm * (1.0 + otherRate)) / thisFileBpm - 1.0) / (thisRateDir * thisRateRange) - if (fOtherBpm > 0.0 && fThisBpm > 0.0) { + if (otherBpm.isValid() && thisBpm.isValid() && thisLocalBpm.isValid()) { // The desired rate is the other decks effective rate divided by this // deck's file BPM. This gives us the playback rate that will produce an // effective BPM equivalent to the other decks. - double desiredRate = fOtherBpm / fThisLocalBpm; + double desiredRate = otherBpm / thisLocalBpm; // Test if this buffer's bpm is the double of the other one, and adjust // the rate scale. I believe this is intended to account for our BPM // algorithm sometimes finding double or half BPMs. This avoids drastic // scales. - double fFileBpmDelta = fabs(fThisLocalBpm - fOtherLocalBpm); - if (fabs(fThisLocalBpm * 2.0 - fOtherLocalBpm) < fFileBpmDelta) { + const double fileBpmDelta = fabs(thisLocalBpm - otherLocalBpm); + if (fabs(thisLocalBpm * 2.0 - otherLocalBpm) < fileBpmDelta) { desiredRate /= 2.0; - } else if (fabs(fThisLocalBpm - 2.0 * fOtherLocalBpm) < fFileBpmDelta) { + } else if (fabs(thisLocalBpm - otherLocalBpm * 2.0) < fileBpmDelta) { desiredRate *= 2.0; } @@ -582,22 +584,26 @@ bool BpmControl::getBeatContext(const mixxx::BeatsPointer& pBeats, return false; } - double dPrevBeat; - double dNextBeat; - if (!pBeats->findPrevNextBeats(dPosition, &dPrevBeat, &dNextBeat, false)) { + const auto position = mixxx::audio::FramePos::fromEngineSamplePos(dPosition); + mixxx::audio::FramePos prevBeatPosition; + mixxx::audio::FramePos nextBeatPosition; + if (!pBeats->findPrevNextBeats(position, &prevBeatPosition, &nextBeatPosition, false)) { return false; } if (dpPrevBeat != nullptr) { - *dpPrevBeat = dPrevBeat; + *dpPrevBeat = prevBeatPosition.toEngineSamplePos(); } if (dpNextBeat != nullptr) { - *dpNextBeat = dNextBeat; + *dpNextBeat = nextBeatPosition.toEngineSamplePos(); } - return getBeatContextNoLookup(dPosition, dPrevBeat, dNextBeat, - dpBeatLength, dpBeatPercentage); + return getBeatContextNoLookup(position.toEngineSamplePos(), + prevBeatPosition.toEngineSamplePos(), + nextBeatPosition.toEngineSamplePos(), + dpBeatLength, + dpBeatPercentage); } // static @@ -733,7 +739,8 @@ double BpmControl::getNearestPositionInPhase( } else if (this_near_next && !other_near_next) { dNewPlaypos += dThisNextBeat; } else { //!this_near_next && other_near_next - dThisPrevBeat = pBeats->findNthBeat(dThisPosition, -2); + const auto thisBeatPosition = mixxx::audio::FramePos::fromEngineSamplePos(dThisPosition); + dThisPrevBeat = pBeats->findNthBeat(thisBeatPosition, -2).toEngineSamplePos(); dNewPlaypos += dThisPrevBeat; } @@ -1018,7 +1025,7 @@ void BpmControl::trackLoaded(TrackPointer pNewTrack) { void BpmControl::trackBeatsUpdated(mixxx::BeatsPointer pBeats) { if (kLogger.traceEnabled()) { kLogger.trace() << getGroup() << "BpmControl::trackBeatsUpdated" - << (pBeats ? pBeats->getBpm() : 0.0); + << (pBeats ? pBeats->getBpm() : mixxx::Bpm()); } m_pBeats = pBeats; updateLocalBpm(); @@ -1035,12 +1042,12 @@ void BpmControl::slotBeatsTranslate(double v) { } const mixxx::BeatsPointer pBeats = pTrack->getBeats(); if (pBeats && (pBeats->getCapabilities() & mixxx::Beats::BEATSCAP_TRANSLATE)) { - double currentSample = getSampleOfTrack().current; - double closestBeat = pBeats->findClosestBeat(currentSample); - int delta = static_cast(currentSample - closestBeat); - if (delta % 2 != 0) { - delta--; - } + const auto currentPosition = + mixxx::audio::FramePos::fromEngineSamplePos( + getSampleOfTrack().current) + .toLowerFrameBoundary(); + const auto closestBeat = pBeats->findClosestBeat(currentPosition); + const mixxx::audio::FrameDiff_t delta = currentPosition - closestBeat; pTrack->trySetBeats(pBeats->translate(delta)); } } @@ -1059,30 +1066,38 @@ void BpmControl::slotBeatsTranslateMatchAlignment(double v) { // otherwise it will always return 0 if sync lock is active. m_dUserOffset.setValue(0.0); - double offset = getPhaseOffset(getSampleOfTrack().current); - pTrack->trySetBeats(pBeats->translate(-offset)); + double sampleOffset = getPhaseOffset(getSampleOfTrack().current); + const mixxx::audio::FrameDiff_t frameOffset = sampleOffset / mixxx::kEngineChannelCount; + pTrack->trySetBeats(pBeats->translate(-frameOffset)); } } -double BpmControl::updateLocalBpm() { - double prev_local_bpm = m_pLocalBpm->get(); - double local_bpm = 0; +mixxx::Bpm BpmControl::updateLocalBpm() { + mixxx::Bpm prevLocalBpm = mixxx::Bpm(m_pLocalBpm->get()); + mixxx::Bpm localBpm; const mixxx::BeatsPointer pBeats = m_pBeats; if (pBeats) { - local_bpm = pBeats->getBpmAroundPosition( - getSampleOfTrack().current, kLocalBpmSpan); - if (local_bpm == -1) { - local_bpm = pBeats->getBpm(); + const auto currentPosition = + mixxx::audio::FramePos::fromEngineSamplePos( + getSampleOfTrack().current); + localBpm = pBeats->getBpmAroundPosition(currentPosition, kLocalBpmSpan); + if (!localBpm.isValid()) { + localBpm = pBeats->getBpm(); } } - if (local_bpm != prev_local_bpm) { + if (localBpm != prevLocalBpm) { if (kLogger.traceEnabled()) { - kLogger.trace() << getGroup() << "BpmControl::updateLocalBpm" << local_bpm; + kLogger.trace() << getGroup() << "BpmControl::updateLocalBpm" << localBpm; + } + // FIXME: Should this really update the engine bpm if it's invalid? + double localBpmValue = mixxx::Bpm::kValueUndefined; + if (localBpm.isValid()) { + localBpmValue = localBpm.value(); } - m_pLocalBpm->set(local_bpm); + m_pLocalBpm->set(localBpmValue); slotUpdateEngineBpm(); } - return local_bpm; + return localBpm; } double BpmControl::updateBeatDistance() { diff --git a/src/engine/controls/bpmcontrol.h b/src/engine/controls/bpmcontrol.h index 540f93e4d2c..248a6ddc07a 100644 --- a/src/engine/controls/bpmcontrol.h +++ b/src/engine/controls/bpmcontrol.h @@ -25,8 +25,11 @@ class BpmControl : public EngineControl { BpmControl(const QString& group, UserSettingsPointer pConfig); ~BpmControl() override; - double getBpm() const; - double getLocalBpm() const { return m_pLocalBpm ? m_pLocalBpm->get() : 0.0; } + mixxx::Bpm getBpm() const; + mixxx::Bpm getLocalBpm() const { + return m_pLocalBpm ? mixxx::Bpm(m_pLocalBpm->get()) : mixxx::Bpm(); + } + // When in sync lock mode, ratecontrol calls calcSyncedRate to figure out // how fast the track should play back. The returned rate is usually just // the correct pitch to match bpms. The usertweak argument represents @@ -49,7 +52,7 @@ class BpmControl : public EngineControl { void setTargetBeatDistance(double beatDistance); void updateInstantaneousBpm(double instantaneousBpm); void resetSyncAdjustment(); - double updateLocalBpm(); + mixxx::Bpm updateLocalBpm(); /// updateBeatDistance is adjusted to include the user offset so /// it's transparent to other decks. double updateBeatDistance(); diff --git a/src/engine/controls/clockcontrol.cpp b/src/engine/controls/clockcontrol.cpp index 8b6c8fdd777..bc97303a1c7 100644 --- a/src/engine/controls/clockcontrol.cpp +++ b/src/engine/controls/clockcontrol.cpp @@ -61,13 +61,13 @@ void ClockControl::updateIndicators(const double dRate, const double currentSample, const double sampleRate) { /* This method sets the control beat_active is set to the following values: - * 0.0 --> No beat indication (ouside 20% area or play direction changed while indication was on) + * 0.0 --> No beat indication (outside 20% area or play direction changed while indication was on) * 1.0 --> Forward playing, set at the beat and set back to 0.0 at 20% of beat distance * 2.0 --> Reverse playing, set at the beat and set back to 0.0 at -20% of beat distance */ // No position change since last indicator update (e.g. deck stopped) -> No indicator update needed - // The kSignificiantRateThreshold condition ensures an immidiate indicator update, when the play/cue button is pressed + // The kSignificiantRateThreshold condition ensures an immediate indicator update, when the play/cue button is pressed if ((currentSample <= (m_lastEvaluatedSample + kStandStillTolerance * sampleRate)) && (currentSample >= (m_lastEvaluatedSample - kStandStillTolerance * sampleRate)) && (fabs(dRate) <= kSignificiantRateThreshold)) { @@ -88,10 +88,18 @@ void ClockControl::updateIndicators(const double dRate, if (pBeats) { if ((currentSample >= m_NextBeatSamples) || (currentSample <= m_PrevBeatSamples)) { - pBeats->findPrevNextBeats(currentSample, - &m_PrevBeatSamples, - &m_NextBeatSamples, + mixxx::audio::FramePos prevBeatPosition; + mixxx::audio::FramePos nextBeatPosition; + pBeats->findPrevNextBeats(mixxx::audio::FramePos::fromEngineSamplePos(currentSample), + &prevBeatPosition, + &nextBeatPosition, false); // Precise compare without tolerance needed + m_PrevBeatSamples = prevBeatPosition.isValid() + ? prevBeatPosition.toEngineSamplePos() + : -1; + m_NextBeatSamples = nextBeatPosition.isValid() + ? nextBeatPosition.toEngineSamplePos() + : -1; } } else { m_PrevBeatSamples = -1; diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index eddb395589c..5303344e6fb 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -484,7 +484,7 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { pNewTrack->findCueByType(mixxx::CueType::AudibleSound); double audibleSoundPosition = Cue::kNoPosition; if (pAudibleSound) { - audibleSoundPosition = pAudibleSound->getPosition(); + audibleSoundPosition = pAudibleSound->getPosition().toEngineSamplePosMaybeInvalid(); } if (audibleSoundPosition != Cue::kNoPosition) { seekOnLoad(audibleSoundPosition); @@ -581,8 +581,8 @@ void CueControl::loadCuesFromTrack() { } else { // If the old hotcue is the same, then we only need to update Cue::StartAndEndPositions pos = pCue->getStartAndEndPosition(); - pControl->setPosition(pos.startPosition); - pControl->setEndPosition(pos.endPosition); + pControl->setPosition(pos.startPosition.toEngineSamplePosMaybeInvalid()); + pControl->setEndPosition(pos.endPosition.toEngineSamplePosMaybeInvalid()); pControl->setColor(pCue->getColor()); pControl->setType(pCue->getType()); } @@ -604,8 +604,8 @@ void CueControl::loadCuesFromTrack() { } if (pIntroCue) { - double startPosition = pIntroCue->getPosition(); - double endPosition = pIntroCue->getEndPosition(); + double startPosition = pIntroCue->getPosition().toEngineSamplePosMaybeInvalid(); + double endPosition = pIntroCue->getEndPosition().toEngineSamplePosMaybeInvalid(); m_pIntroStartPosition->set(quantizeCuePoint(startPosition)); m_pIntroStartEnabled->forceSet( @@ -621,8 +621,8 @@ void CueControl::loadCuesFromTrack() { } if (pOutroCue) { - double startPosition = pOutroCue->getPosition(); - double endPosition = pOutroCue->getEndPosition(); + double startPosition = pOutroCue->getPosition().toEngineSamplePosMaybeInvalid(); + double endPosition = pOutroCue->getEndPosition().toEngineSamplePosMaybeInvalid(); m_pOutroStartPosition->set(quantizeCuePoint(startPosition)); m_pOutroStartEnabled->forceSet( @@ -642,7 +642,7 @@ void CueControl::loadCuesFromTrack() { // The mixxx::CueType::MainCue from getCuePoints() has the priority CuePosition mainCuePoint; if (pMainCue) { - double position = pMainCue->getPosition(); + double position = pMainCue->getPosition().toEngineSamplePosMaybeInvalid(); mainCuePoint.setPosition(position); // adjust the track cue accordingly m_pLoadedTrack->setCuePoint(mainCuePoint); @@ -766,7 +766,17 @@ void CueControl::hotcueSet(HotcueControl* pControl, double value, HotcueSetMode if (beatloopSize <= 0 || !pBeats) { return; } - cueEndPosition = pBeats->findNBeatsFromSample(cueStartPosition, beatloopSize); + mixxx::audio::FramePos cueEndPositionFrames; + if (cueStartPosition != Cue::kNoPosition) { + const auto cueStartPositionFrames = + mixxx::audio::FramePos::fromEngineSamplePos( + cueStartPosition); + cueEndPositionFrames = pBeats->findNBeatsFromPosition( + cueStartPositionFrames, beatloopSize); + } + cueEndPosition = cueEndPositionFrames.isValid() + ? cueEndPositionFrames.toEngineSamplePos() + : Cue::kNoPosition; } cueType = mixxx::CueType::Loop; break; @@ -889,7 +899,7 @@ void CueControl::hotcueGotoAndLoop(HotcueControl* pControl, double value) { return; } - double startPosition = pCue->getPosition(); + double startPosition = pCue->getPosition().toEngineSamplePosMaybeInvalid(); if (startPosition == Cue::kNoPosition) { return; } @@ -923,10 +933,10 @@ void CueControl::hotcueCueLoop(HotcueControl* pControl, double value) { CuePointer pCue = pControl->getCue(); - if (!pCue || pCue->getPosition() == Cue::kNoPosition) { + if (!pCue || !pCue->getPosition().isValid()) { hotcueSet(pControl, value, HotcueSetMode::Cue); pCue = pControl->getCue(); - VERIFY_OR_DEBUG_ASSERT(pCue && pCue->getPosition() != Cue::kNoPosition) { + VERIFY_OR_DEBUG_ASSERT(pCue && pCue->getPosition().isValid()) { return; } } @@ -941,7 +951,9 @@ void CueControl::hotcueCueLoop(HotcueControl* pControl, double value) { } else { bool loopActive = pControl->getStatus() == HotcueControl::Status::Active; Cue::StartAndEndPositions pos = pCue->getStartAndEndPosition(); - setLoop(pos.startPosition, pos.endPosition, !loopActive); + setLoop(pos.startPosition.toEngineSamplePosMaybeInvalid(), + pos.endPosition.toEngineSamplePosMaybeInvalid(), + !loopActive); } } break; case mixxx::CueType::HotCue: { @@ -949,7 +961,7 @@ void CueControl::hotcueCueLoop(HotcueControl* pControl, double value) { // create a beatloop starting at the hotcue position. This is useful for // mapping the CUE LOOP mode labeled on some controllers. setCurrentSavedLoopControlAndActivate(nullptr); - double startPosition = pCue->getPosition(); + double startPosition = pCue->getPosition().toEngineSamplePosMaybeInvalid(); bool loopActive = m_pLoopEnabled->toBool() && (startPosition == m_pLoopStartPosition->get()); setBeatLoop(startPosition, !loopActive); @@ -968,7 +980,7 @@ void CueControl::hotcueActivate(HotcueControl* pControl, double value, HotcueSet CuePointer pCue = pControl->getCue(); if (value > 0) { // pressed - if (pCue && pCue->getPosition() != Cue::kNoPosition && + if (pCue && pCue->getPosition().isValid() && pCue->getType() != mixxx::CueType::Invalid) { if (m_pPlay->toBool() && m_currentlyPreviewingIndex == Cue::kNoHotCue) { // playing by Play button @@ -983,7 +995,10 @@ void CueControl::hotcueActivate(HotcueControl* pControl, double value, HotcueSet bool loopActive = pControl->getStatus() == HotcueControl::Status::Active; Cue::StartAndEndPositions pos = pCue->getStartAndEndPosition(); - setLoop(pos.startPosition, pos.endPosition, !loopActive); + setLoop(pos.startPosition + .toEngineSamplePosMaybeInvalid(), + pos.endPosition.toEngineSamplePosMaybeInvalid(), + !loopActive); } break; default: @@ -1086,7 +1101,9 @@ void CueControl::hotcuePositionChanged( if (newPosition == Cue::kNoPosition) { detachCue(pControl); } else if (newPosition > 0 && newPosition < m_pTrackSamples->get()) { - if (pCue->getType() == mixxx::CueType::Loop && newPosition >= pCue->getEndPosition()) { + if (pCue->getType() == mixxx::CueType::Loop && + newPosition >= pCue->getEndPosition() + .toEngineSamplePosMaybeInvalid()) { return; } pCue->setStartPosition(newPosition); @@ -1105,7 +1122,7 @@ void CueControl::hotcueEndPositionChanged( pCue->setType(mixxx::CueType::HotCue); pCue->setEndPosition(Cue::kNoPosition); } else { - if (newEndPosition > pCue->getPosition()) { + if (newEndPosition > pCue->getPosition().toEngineSamplePosMaybeInvalid()) { pCue->setEndPosition(newEndPosition); } } @@ -1979,10 +1996,12 @@ double CueControl::quantizeCuePoint(double cuePos) { return cuePos; } - double closestBeat = pBeats->findClosestBeat(cuePos); + const auto cuePosition = mixxx::audio::FramePos::fromEngineSamplePos(cuePos); + const auto closestBeatPosition = pBeats->findClosestBeat(cuePosition); // The closest beat can be an unreachable interpolated beat past the end of // the track. - if (closestBeat != -1.0 && closestBeat <= total) { + const double closestBeat = closestBeatPosition.toEngineSamplePos(); + if (closestBeatPosition.isValid() && closestBeat <= total) { return closestBeat; } @@ -2080,12 +2099,14 @@ void CueControl::setCurrentSavedLoopControlAndActivate(HotcueControl* pControl) VERIFY_OR_DEBUG_ASSERT( type == mixxx::CueType::Loop && - pos.endPosition != Cue::kNoPosition) { + pos.endPosition.isValid()) { return; } // Set new control as active - setLoop(pos.startPosition, pos.endPosition, true); + setLoop(pos.startPosition.toEngineSamplePosMaybeInvalid(), + pos.endPosition.toEngineSamplePosMaybeInvalid(), + true); pControl->setStatus(HotcueControl::Status::Active); m_pCurrentSavedLoopControl.storeRelease(pControl); } @@ -2101,14 +2122,14 @@ void CueControl::slotLoopEnabledChanged(bool enabled) { } DEBUG_ASSERT(pSavedLoopControl->getStatus() != HotcueControl::Status::Empty); - DEBUG_ASSERT( - pSavedLoopControl->getCue() && + DEBUG_ASSERT(pSavedLoopControl->getCue() && pSavedLoopControl->getCue()->getPosition() == - m_pLoopStartPosition->get()); - DEBUG_ASSERT( - pSavedLoopControl->getCue() && + mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid( + m_pLoopStartPosition->get())); + DEBUG_ASSERT(pSavedLoopControl->getCue() && pSavedLoopControl->getCue()->getEndPosition() == - m_pLoopEndPosition->get()); + mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid( + m_pLoopEndPosition->get())); if (enabled) { pSavedLoopControl->setStatus(HotcueControl::Status::Active); @@ -2409,8 +2430,8 @@ double HotcueControl::getEndPosition() const { void HotcueControl::setCue(const CuePointer& pCue) { DEBUG_ASSERT(!m_pCue); Cue::StartAndEndPositions pos = pCue->getStartAndEndPosition(); - setPosition(pos.startPosition); - setEndPosition(pos.endPosition); + setPosition(pos.startPosition.toEngineSamplePosMaybeInvalid()); + setEndPosition(pos.endPosition.toEngineSamplePosMaybeInvalid()); setColor(pCue->getColor()); setStatus((pCue->getType() == mixxx::CueType::Invalid) ? HotcueControl::Status::Empty diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 7f3b35ae583..5296a8d68ba 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -112,7 +112,7 @@ class HotcueControl : public QObject { /// for the case the cue is deleted during preview. void cachePreviewingStartState() { if (m_pCue) { - m_previewingPosition.setValue(m_pCue->getPosition()); + m_previewingPosition.setValue(m_pCue->getPosition().toEngineSamplePosMaybeInvalid()); m_previewingType.setValue(m_pCue->getType()); } else { m_previewingType.setValue(mixxx::CueType::Invalid); diff --git a/src/engine/controls/enginecontrol.h b/src/engine/controls/enginecontrol.h index 094ab1c1d7c..0331a6fdb76 100644 --- a/src/engine/controls/enginecontrol.h +++ b/src/engine/controls/enginecontrol.h @@ -5,6 +5,7 @@ #include #include +#include "audio/frame.h" #include "control/controlvalue.h" #include "engine/cachingreader/cachingreader.h" #include "engine/effects/groupfeaturestate.h" @@ -17,6 +18,9 @@ class EngineMaster; class EngineBuffer; const int kNoTrigger = -1; +static_assert( + mixxx::audio::FramePos::kLegacyInvalidEnginePosition == kNoTrigger, + "Invalid engine position value mismatch"); /** * EngineControl is an abstract base class for objects which implement diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index c83b618ebda..d944725c929 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -527,8 +527,8 @@ double LoopingControl::getSyncPositionInsideLoop(double dRequestedPlaypos, doubl return dSyncedPlayPos; } -void LoopingControl::setBeatLoop(double startPosition, bool enabled) { - VERIFY_OR_DEBUG_ASSERT(startPosition != Cue::kNoPosition) { +void LoopingControl::setBeatLoop(double startPositionSamples, bool enabled) { + VERIFY_OR_DEBUG_ASSERT(startPositionSamples != Cue::kNoPosition) { return; } @@ -541,9 +541,12 @@ void LoopingControl::setBeatLoop(double startPosition, bool enabled) { // TODO(XXX): This is not realtime safe. See this Zulip discussion for details: // https://mixxx.zulipchat.com/#narrow/stream/109171-development/topic/getting.20locks.20out.20of.20Beats - double endPosition = pBeats->findNBeatsFromSample(startPosition, beatloopSize); + const auto startPosition = mixxx::audio::FramePos::fromEngineSamplePos(startPositionSamples); + const auto endPosition = pBeats->findNBeatsFromPosition(startPosition, beatloopSize); - setLoop(startPosition, endPosition, enabled); + if (startPosition.isValid() && endPosition.isValid()) { + setLoop(startPositionSamples, endPosition.toEngineSamplePos(), enabled); + } } void LoopingControl::setLoop(double startPosition, double endPosition, bool enabled) { @@ -615,8 +618,11 @@ void LoopingControl::setLoopInToCurrentPosition() { if (loopSamples.end != kNoTrigger && (loopSamples.end - pos) < MINIMUM_AUDIBLE_LOOP_SIZE) { if (quantizedBeat != -1 && pBeats) { - pos = pBeats->findNthBeat(quantizedBeat, -2); - if (pos == -1 || (loopSamples.end - pos) < MINIMUM_AUDIBLE_LOOP_SIZE) { + const auto quantizedBeatPosition = + mixxx::audio::FramePos::fromEngineSamplePos(quantizedBeat); + const auto position = pBeats->findNthBeat(quantizedBeatPosition, -2); + pos = position.toEngineSamplePos(); + if (!position.isValid() || (loopSamples.end - pos) < MINIMUM_AUDIBLE_LOOP_SIZE) { pos = loopSamples.end - MINIMUM_AUDIBLE_LOOP_SIZE; } } else { @@ -640,8 +646,9 @@ void LoopingControl::setLoopInToCurrentPosition() { if (m_pQuantizeEnabled->toBool() && loopSamples.start < loopSamples.end && pBeats) { - m_pCOBeatLoopSize->setAndConfirm( - pBeats->numBeatsInRange(loopSamples.start, loopSamples.end)); + const auto startPosition = mixxx::audio::FramePos::fromEngineSamplePos(loopSamples.start); + const auto endPosition = mixxx::audio::FramePos::fromEngineSamplePos(loopSamples.end); + m_pCOBeatLoopSize->setAndConfirm(pBeats->numBeatsInRange(startPosition, endPosition)); updateBeatLoopingControls(); } else { clearActiveBeatLoop(); @@ -721,8 +728,11 @@ void LoopingControl::setLoopOutToCurrentPosition() { // use the smallest pre-defined beatloop instead (when possible) if ((pos - loopSamples.start) < MINIMUM_AUDIBLE_LOOP_SIZE) { if (quantizedBeat != -1 && pBeats) { - pos = static_cast(floor(pBeats->findNthBeat(quantizedBeat, 2))); - if (pos == -1 || (pos - loopSamples.start) < MINIMUM_AUDIBLE_LOOP_SIZE) { + const auto quantizedBeatPosition = + mixxx::audio::FramePos::fromEngineSamplePos(quantizedBeat); + const auto position = pBeats->findNthBeat(quantizedBeatPosition, 2); + pos = static_cast(position.toLowerFrameBoundary().toEngineSamplePos()); + if (!position.isValid() || (pos - loopSamples.start) < MINIMUM_AUDIBLE_LOOP_SIZE) { pos = loopSamples.start + MINIMUM_AUDIBLE_LOOP_SIZE; } } else { @@ -745,8 +755,9 @@ void LoopingControl::setLoopOutToCurrentPosition() { } if (m_pQuantizeEnabled->toBool() && pBeats) { - m_pCOBeatLoopSize->setAndConfirm( - pBeats->numBeatsInRange(loopSamples.start, loopSamples.end)); + const auto startPosition = mixxx::audio::FramePos::fromEngineSamplePos(loopSamples.start); + const auto endPosition = mixxx::audio::FramePos::fromEngineSamplePos(loopSamples.end); + m_pCOBeatLoopSize->setAndConfirm(pBeats->numBeatsInRange(startPosition, endPosition)); updateBeatLoopingControls(); } else { clearActiveBeatLoop(); @@ -1097,8 +1108,12 @@ bool LoopingControl::currentLoopMatchesBeatloopSize() { LoopSamples loopSamples = m_loopSamples.getValue(); // Calculate where the loop out point would be if it is a beatloop - double beatLoopOutPoint = - pBeats->findNBeatsFromSample(loopSamples.start, m_pCOBeatLoopSize->get()); + const auto loopStartPosition = mixxx::audio::FramePos::fromEngineSamplePos(loopSamples.start); + const auto loopEndPosition = pBeats->findNBeatsFromPosition( + loopStartPosition, m_pCOBeatLoopSize->get()); + const double beatLoopOutPoint = loopEndPosition.isValid() + ? loopEndPosition.toEngineSamplePos() + : -1; return loopSamples.end > beatLoopOutPoint - 2 && loopSamples.end < beatLoopOutPoint + 2; @@ -1110,11 +1125,15 @@ double LoopingControl::findBeatloopSizeForLoop(double start, double end) const { return -1; } + const auto loopStartPosition = mixxx::audio::FramePos::fromEngineSamplePos(start); for (unsigned int i = 0; i < (sizeof(s_dBeatSizes) / sizeof(s_dBeatSizes[0])); ++i) { - double beatLoopOutPoint = - pBeats->findNBeatsFromSample(start, s_dBeatSizes[i]); - if (end > beatLoopOutPoint - 2 && end < beatLoopOutPoint + 2) { - return s_dBeatSizes[i]; + const auto loopEndPosition = pBeats->findNBeatsFromPosition( + loopStartPosition, s_dBeatSizes[i]); + if (loopEndPosition.isValid()) { + const double beatLoopOutPoint = loopEndPosition.toEngineSamplePos(); + if (end > beatLoopOutPoint - 2 && end < beatLoopOutPoint + 2) { + return s_dBeatSizes[i]; + } } } return -1; @@ -1149,10 +1168,10 @@ void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable } // if a seek was queued in the engine buffer move the current sample to its position - double p_seekPosition = 0; - if (getEngineBuffer()->getQueuedSeekPosition(&p_seekPosition)) { + const mixxx::audio::FramePos seekPosition = getEngineBuffer()->queuedSeekPosition(); + if (seekPosition.isValid()) { // seek position is already quantized if quantization is enabled - m_currentSample.setValue(p_seekPosition); + m_currentSample.setValue(seekPosition.toEngineSamplePos()); } double maxBeatSize = s_dBeatSizes[sizeof(s_dBeatSizes)/sizeof(s_dBeatSizes[0]) - 1]; @@ -1192,15 +1211,26 @@ void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable } else { // loop_in is set to the closest beat if quantize is on and the loop size is >= 1 beat. // The closest beat might be ahead of play position and will cause a catching loop. - double prevBeat; - double nextBeat; - pBeats->findPrevNextBeats(currentSample, &prevBeat, &nextBeat, true); + mixxx::audio::FramePos prevBeatPosition; + mixxx::audio::FramePos nextBeatPosition; + const auto currentPosition = mixxx::audio::FramePos::fromEngineSamplePos(currentSample); + pBeats->findPrevNextBeats(currentPosition, &prevBeatPosition, &nextBeatPosition, true); + const double prevBeat = prevBeatPosition.isValid() + ? prevBeatPosition.toEngineSamplePos() + : -1; + const double nextBeat = nextBeatPosition.isValid() + ? nextBeatPosition.toEngineSamplePos() + : -1; if (m_pQuantizeEnabled->toBool() && prevBeat != -1) { double beatLength = nextBeat - prevBeat; double loopLength = beatLength * beats; - double closestBeat = pBeats->findClosestBeat(currentSample); + const mixxx::audio::FramePos closestBeatPosition = + pBeats->findClosestBeat(currentPosition); + double closestBeat = closestBeatPosition.isValid() + ? closestBeatPosition.toEngineSamplePos() + : -1; if (beats >= 1.0) { newloopSamples.start = closestBeat; } else { @@ -1239,7 +1269,11 @@ void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable } } - newloopSamples.end = pBeats->findNBeatsFromSample(newloopSamples.start, beats); + const auto newLoopStartPosition = + mixxx::audio::FramePos::fromEngineSamplePos(newloopSamples.start); + const auto newLoopEndPosition = pBeats->findNBeatsFromPosition(newLoopStartPosition, beats); + newloopSamples.end = newLoopEndPosition.isValid() ? newLoopEndPosition.toEngineSamplePos() : -1; + if (newloopSamples.start >= newloopSamples.end // happens when the call above fails || newloopSamples.end > samples) { // Do not allow beat loops to go beyond the end of the track // If a track is loaded with beatloop_size larger than @@ -1247,8 +1281,12 @@ void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable // the end of the track, let beatloop_size be set to // a smaller size, but not get larger. double previousBeatloopSize = m_pCOBeatLoopSize->get(); - double previousBeatloopOutPoint = pBeats->findNBeatsFromSample( - newloopSamples.start, previousBeatloopSize); + const mixxx::audio::FramePos previousLoopEndPosition = + pBeats->findNBeatsFromPosition( + newLoopStartPosition, previousBeatloopSize); + double previousBeatloopOutPoint = previousLoopEndPosition.isValid() + ? previousLoopEndPosition.toEngineSamplePos() + : -1; if (previousBeatloopOutPoint < newloopSamples.start && beats < previousBeatloopSize) { m_pCOBeatLoopSize->setAndConfirm(beats); @@ -1352,7 +1390,11 @@ void LoopingControl::slotBeatJump(double beats) { slotLoopMove(beats); } else { // seekExact bypasses Quantize, because a beat jump is implicit quantized - seekExact(pBeats->findNBeatsFromSample(currentSample, beats)); + const auto currentPosition = mixxx::audio::FramePos::fromEngineSamplePos(currentSample); + const auto seekPosition = pBeats->findNBeatsFromPosition(currentPosition, beats); + if (seekPosition.isValid()) { + seekExact(seekPosition.toEngineSamplePos()); + } } } @@ -1380,10 +1422,19 @@ void LoopingControl::slotLoopMove(double beats) { if (BpmControl::getBeatContext(pBeats, m_currentSample.getValue(), nullptr, nullptr, nullptr, nullptr)) { - double new_loop_in = pBeats->findNBeatsFromSample(loopSamples.start, beats); - double new_loop_out = currentLoopMatchesBeatloopSize() ? - pBeats->findNBeatsFromSample(new_loop_in, m_pCOBeatLoopSize->get()) : - pBeats->findNBeatsFromSample(loopSamples.end, beats); + const auto loopStartPosition = + mixxx::audio::FramePos::fromEngineSamplePos(loopSamples.start); + const auto loopEndPosition = mixxx::audio::FramePos::fromEngineSamplePos(loopSamples.end); + const auto newLoopStartPosition = pBeats->findNBeatsFromPosition(loopStartPosition, beats); + const auto newLoopEndPosition = currentLoopMatchesBeatloopSize() + ? pBeats->findNBeatsFromPosition(newLoopStartPosition, m_pCOBeatLoopSize->get()) + : pBeats->findNBeatsFromPosition(loopEndPosition, beats); + double new_loop_in = newLoopStartPosition.isValid() + ? newLoopStartPosition.toEngineSamplePos() + : kNoTrigger; + double new_loop_out = newLoopEndPosition.isValid() + ? newLoopEndPosition.toEngineSamplePos() + : kNoTrigger; // The track would stop as soon as the playhead crosses track end, // so we don't allow moving a loop beyond end. diff --git a/src/engine/controls/quantizecontrol.cpp b/src/engine/controls/quantizecontrol.cpp index fe84ae53bea..e8af94836a4 100644 --- a/src/engine/controls/quantizecontrol.cpp +++ b/src/engine/controls/quantizecontrol.cpp @@ -79,10 +79,17 @@ void QuantizeControl::playPosChanged(double dNewPlaypos) { void QuantizeControl::lookupBeatPositions(double dCurrentSample) { mixxx::BeatsPointer pBeats = m_pBeats; if (pBeats) { - double prevBeat, nextBeat; - pBeats->findPrevNextBeats(dCurrentSample, &prevBeat, &nextBeat, true); - m_pCOPrevBeat->set(prevBeat); - m_pCONextBeat->set(nextBeat); + const auto position = mixxx::audio::FramePos::fromEngineSamplePos(dCurrentSample); + mixxx::audio::FramePos prevBeatPosition; + mixxx::audio::FramePos nextBeatPosition; + pBeats->findPrevNextBeats(position, &prevBeatPosition, &nextBeatPosition, true); + // FIXME: -1.0 is a valid frame position, should we set the COs to NaN? + m_pCOPrevBeat->set(prevBeatPosition.isValid() + ? prevBeatPosition.toEngineSamplePos() + : -1.0); + m_pCONextBeat->set(nextBeatPosition.isValid() + ? nextBeatPosition.toEngineSamplePos() + : -1.0); } } diff --git a/src/engine/controls/ratecontrol.cpp b/src/engine/controls/ratecontrol.cpp index 1ad1419ff22..b84f7759a95 100644 --- a/src/engine/controls/ratecontrol.cpp +++ b/src/engine/controls/ratecontrol.cpp @@ -535,26 +535,24 @@ void RateControl::processTempRate(const int bufferSamples) { } } } else if (m_eRateRampMode == RampMode::Linear) { - if (rampDirection != RampDirection::None) { - if (!m_bTempStarted) { - m_bTempStarted = true; - double latrate = ((double)bufferSamples / (double)m_pSampleRate->get()); - m_dRateTempRampChange = (latrate / ((double)m_iRateRampSensitivity / 100.)); - } + if (!m_bTempStarted) { + m_bTempStarted = true; + double latrate = bufferSamples / m_pSampleRate->get(); + m_dRateTempRampChange = latrate / (m_iRateRampSensitivity / 100.0); + } - switch (rampDirection) { - case RampDirection::Up: - case RampDirection::UpSmall: - addRateTemp(m_dRateTempRampChange * m_pRateRange->get()); - break; - case RampDirection::Down: - case RampDirection::DownSmall: - subRateTemp(m_dRateTempRampChange * m_pRateRange->get()); - break; - case RampDirection::None: - default: - DEBUG_ASSERT(false); - } + switch (rampDirection) { + case RampDirection::Up: + case RampDirection::UpSmall: + addRateTemp(m_dRateTempRampChange * m_pRateRange->get()); + break; + case RampDirection::Down: + case RampDirection::DownSmall: + subRateTemp(m_dRateTempRampChange * m_pRateRange->get()); + break; + case RampDirection::None: + default: + DEBUG_ASSERT(false); } } } else if (m_bTempStarted) { diff --git a/src/engine/controls/vinylcontrolcontrol.cpp b/src/engine/controls/vinylcontrolcontrol.cpp index f9660249581..f7c3ef50f29 100644 --- a/src/engine/controls/vinylcontrolcontrol.cpp +++ b/src/engine/controls/vinylcontrolcontrol.cpp @@ -89,25 +89,35 @@ void VinylControlControl::slotControlVinylSeek(double fractionalPos) { return; } - double total_samples = getSampleOfTrack().total; - double new_playpos = round(fractionalPos * total_samples); + const auto trackEndPosition = + mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid( + getSampleOfTrack().total); + if (!trackEndPosition.isValid()) { + return; + } + const auto newPlayPos = mixxx::audio::kStartFramePos + + (trackEndPosition - mixxx::audio::kStartFramePos) * fractionalPos; if (m_pControlVinylEnabled->get() > 0.0 && m_pControlVinylMode->get() == MIXXX_VCMODE_RELATIVE) { int cuemode = (int)m_pControlVinylCueing->get(); //if in preroll, always seek - if (new_playpos < 0) { - seekExact(new_playpos); + if (newPlayPos < mixxx::audio::kStartFramePos) { + seekExact(newPlayPos.toEngineSamplePos()); return; } switch (cuemode) { case MIXXX_RELATIVE_CUE_OFF: return; // If off, do nothing. - case MIXXX_RELATIVE_CUE_ONECUE: + case MIXXX_RELATIVE_CUE_ONECUE: { //if onecue, just seek to the regular cue - seekExact(pTrack->getCuePoint().getPosition()); + const mixxx::audio::FramePos mainCuePosition = pTrack->getMainCuePosition(); + if (mainCuePosition.isValid()) { + seekExact(mainCuePosition.toEngineSamplePos()); + } return; + } case MIXXX_RELATIVE_CUE_HOTCUE: // Continue processing in this function. break; @@ -116,8 +126,8 @@ void VinylControlControl::slotControlVinylSeek(double fractionalPos) { return; } - double shortest_distance = 0; - double nearest_playpos = -1; + mixxx::audio::FrameDiff_t shortestDistance = 0; + mixxx::audio::FramePos nearestPlayPos; const QList cuePoints(pTrack->getCuePoints()); QListIterator it(cuePoints); @@ -127,24 +137,26 @@ void VinylControlControl::slotControlVinylSeek(double fractionalPos) { continue; } - double cue_position = pCue->getPosition(); - // pick cues closest to new_playpos - if ((nearest_playpos == -1) || - (fabs(new_playpos - cue_position) < shortest_distance)) { - nearest_playpos = cue_position; - shortest_distance = fabs(new_playpos - cue_position); + const mixxx::audio::FramePos cuePosition = pCue->getPosition(); + if (!cuePosition.isValid()) { + continue; + } + // pick cues closest to newPlayPos + if (!nearestPlayPos.isValid() || (fabs(newPlayPos - cuePosition) < shortestDistance)) { + nearestPlayPos = cuePosition; + shortestDistance = fabs(newPlayPos - cuePosition); } } - if (nearest_playpos == -1) { - if (new_playpos >= 0) { + if (!nearestPlayPos.isValid()) { + if (newPlayPos >= mixxx::audio::kStartFramePos) { //never found an appropriate cue, so don't seek? return; } //if negative, allow a seek by falling down to the bottom } else { m_bSeekRequested = true; - seekExact(nearest_playpos); + seekExact(nearestPlayPos.toEngineSamplePos()); m_bSeekRequested = false; return; } @@ -152,7 +164,7 @@ void VinylControlControl::slotControlVinylSeek(double fractionalPos) { // Just seek where it wanted to originally. m_bSeekRequested = true; - seekExact(new_playpos); + seekExact(newPlayPos.toEngineSamplePos()); m_bSeekRequested = false; } diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index 09b5aad2b0e..4ae3773f391 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -79,7 +79,6 @@ EngineBuffer::EngineBuffer(const QString& group, m_baserate_old(0), m_rate_old(0.), m_trackSamplesOld(0), - m_trackSampleRateOld(0), m_dSlipPosition(0.), m_dSlipRate(1.0), m_bSlipEnabledProcessing(false), @@ -92,7 +91,6 @@ EngineBuffer::EngineBuffer(const QString& group, m_iSyncModeQueued(SYNC_INVALID), m_iTrackLoading(0), m_bPlayAfterLoading(false), - m_iSampleRate(0), m_pCrossfadeBuffer(SampleUtil::alloc(MAX_BUFFER_LEN)), m_bCrossfadeReady(false), m_iLastBufferSize(0) { @@ -363,11 +361,11 @@ void EngineBuffer::enableIndependentPitchTempoScaling(bool bEnable, } } -double EngineBuffer::getBpm() const { +mixxx::Bpm EngineBuffer::getBpm() const { return m_pBpmControl->getBpm(); } -double EngineBuffer::getLocalBpm() const { +mixxx::Bpm EngineBuffer::getLocalBpm() const { return m_pBpmControl->getLocalBpm(); } @@ -385,7 +383,7 @@ void EngineBuffer::setEngineMaster(EngineMaster* pEngineMaster) { } } -void EngineBuffer::queueNewPlaypos(double newpos, enum SeekRequest seekType) { +void EngineBuffer::queueNewPlaypos(mixxx::audio::FramePos position, enum SeekRequest seekType) { // All seeks need to be done in the Engine thread so queue it up. // Write the position before the seek type, to reduce a possible race // condition effect @@ -394,7 +392,7 @@ void EngineBuffer::queueNewPlaypos(double newpos, enum SeekRequest seekType) { // use SEEK_STANDARD for that seekType = SEEK_STANDARD; } - m_queuedSeek.setValue({newpos, seekType}); + m_queuedSeek.setValue({position, seekType}); } void EngineBuffer::requestSyncPhase() { @@ -459,7 +457,9 @@ void EngineBuffer::readToCrossfadeBuffer(const int iBufferSize) { } void EngineBuffer::seekCloneBuffer(EngineBuffer* pOtherBuffer) { - doSeekPlayPos(pOtherBuffer->getExactPlayPos(), SEEK_EXACT); + const auto position = mixxx::audio::FramePos::fromEngineSamplePos( + pOtherBuffer->getExactPlayPos()); + doSeekPlayPos(position, SEEK_EXACT); } // WARNING: This method is not thread safe and must not be called from outside @@ -586,7 +586,7 @@ void EngineBuffer::ejectTrack() { m_pause.lock(); m_visualPlayPos->set(0.0, 0.0, 0.0, 0.0, 0.0); - doSeekPlayPos(0.0, SEEK_EXACT); + doSeekPlayPos(mixxx::audio::kStartFramePos, SEEK_EXACT); m_pCurrentTrack.reset(); m_pTrackSamples->set(0); @@ -656,12 +656,16 @@ void EngineBuffer::slotControlSeek(double fractionalPos) { // WARNING: This method runs from SyncWorker and Engine Worker void EngineBuffer::slotControlSeekAbs(double playPosition) { - doSeekPlayPos(playPosition, SEEK_STANDARD); + // TODO: Check if we can assert a valid play position here + const auto position = mixxx::audio::FramePos::fromEngineSamplePos(playPosition); + doSeekPlayPos(position, SEEK_STANDARD); } // WARNING: This method runs from SyncWorker and Engine Worker void EngineBuffer::slotControlSeekExact(double playPosition) { - doSeekPlayPos(playPosition, SEEK_EXACT); + // TODO: Check if we can assert a valid play position here + const auto position = mixxx::audio::FramePos::fromEngineSamplePos(playPosition); + doSeekPlayPos(position, SEEK_EXACT); } double EngineBuffer::fractionalPlayposFromAbsolute(double absolutePlaypos) { @@ -678,11 +682,18 @@ void EngineBuffer::doSeekFractional(double fractionalPos, enum SeekRequest seekT VERIFY_OR_DEBUG_ASSERT(!util_isnan(fractionalPos)) { return; } - double newSamplePosition = fractionalPos * m_pTrackSamples->get(); - doSeekPlayPos(newSamplePosition, seekType); + + // FIXME: Use maybe invalid here + const auto trackEndPosition = + mixxx::audio::FramePos::fromEngineSamplePos(m_pTrackSamples->get()); + VERIFY_OR_DEBUG_ASSERT(trackEndPosition.isValid()) { + return; + } + const auto seekPosition = trackEndPosition * fractionalPos; + doSeekPlayPos(seekPosition, seekType); } -void EngineBuffer::doSeekPlayPos(double new_playpos, enum SeekRequest seekType) { +void EngineBuffer::doSeekPlayPos(mixxx::audio::FramePos position, enum SeekRequest seekType) { #ifdef __VINYLCONTROL__ // Notify the vinyl control that a seek has taken place in case it is in // absolute mode and needs be switched to relative. @@ -691,7 +702,7 @@ void EngineBuffer::doSeekPlayPos(double new_playpos, enum SeekRequest seekType) } #endif - queueNewPlaypos(new_playpos, seekType); + queueNewPlaypos(position, seekType); } bool EngineBuffer::updateIndicatorsAndModifyPlay(bool newPlay, bool oldPlay) { @@ -790,15 +801,15 @@ void EngineBuffer::slotKeylockEngineChanged(double dIndex) { } void EngineBuffer::processTrackLocked( - CSAMPLE* pOutput, const int iBufferSize, int sample_rate) { + CSAMPLE* pOutput, const int iBufferSize, mixxx::audio::SampleRate sampleRate) { ScopedTimer t("EngineBuffer::process_pauselock"); - m_trackSampleRateOld = m_pTrackSampleRate->get(); + m_trackSampleRateOld = mixxx::audio::SampleRate::fromDouble(m_pTrackSampleRate->get()); m_trackSamplesOld = m_pTrackSamples->get(); double baserate = 0.0; - if (sample_rate > 0) { - baserate = m_trackSampleRateOld / sample_rate; + if (sampleRate.isValid()) { + baserate = m_trackSampleRateOld / sampleRate; } // Sync requests can affect rate, so process those first. @@ -1113,19 +1124,18 @@ void EngineBuffer::process(CSAMPLE* pOutput, const int iBufferSize) { // - Set last sample value (m_fLastSampleValue) so that rampOut works? Other // miscellaneous upkeep issues. - m_iSampleRate = static_cast(m_pSampleRate->get()); + m_sampleRate = mixxx::audio::SampleRate::fromDouble(m_pSampleRate->get()); // If the sample rate has changed, force Rubberband to reset so that // it doesn't reallocate when the user engages keylock during playback. // We do this even if rubberband is not active. - const auto sampleRate = mixxx::audio::SampleRate(m_iSampleRate); - m_pScaleLinear->setSampleRate(sampleRate); - m_pScaleST->setSampleRate(sampleRate); - m_pScaleRB->setSampleRate(sampleRate); + m_pScaleLinear->setSampleRate(m_sampleRate); + m_pScaleST->setSampleRate(m_sampleRate); + m_pScaleRB->setSampleRate(m_sampleRate); bool bTrackLoading = atomicLoadRelaxed(m_iTrackLoading) != 0; if (!bTrackLoading && m_pause.tryLock()) { - processTrackLocked(pOutput, iBufferSize, m_iSampleRate); + processTrackLocked(pOutput, iBufferSize, m_sampleRate); // release the pauselock m_pause.unlock(); } else { @@ -1227,12 +1237,7 @@ void EngineBuffer::processSeek(bool paused) { const QueuedSeek queuedSeek = m_queuedSeek.getValue(); SeekRequests seekType = queuedSeek.seekType; - double position = queuedSeek.position; - - // Don't allow the playposition to go past the end. - if (position > m_trackSamplesOld) { - position = m_trackSamplesOld; - } + mixxx::audio::FramePos framePosition = queuedSeek.position; // Add SEEK_PHASE bit, if any if (m_iSeekPhaseQueued.fetchAndStoreRelease(0)) { @@ -1244,7 +1249,7 @@ void EngineBuffer::processSeek(bool paused) { return; case SEEK_PHASE: // only adjust phase - position = m_filepos_play; + framePosition = mixxx::audio::FramePos::fromEngineSamplePos(m_filepos_play); break; case SEEK_STANDARD: if (m_pQuantize->toBool()) { @@ -1263,6 +1268,17 @@ void EngineBuffer::processSeek(bool paused) { return; } + VERIFY_OR_DEBUG_ASSERT(framePosition.isValid()) { + return; + } + + auto position = framePosition.toEngineSamplePos(); + + // Don't allow the playposition to go past the end. + if (position > m_trackSamplesOld) { + position = m_trackSamplesOld; + } + if (!paused && (seekType & SEEK_PHASE)) { if (kLogger.traceEnabled()) { kLogger.trace() << "EngineBuffer::processSeek" << getGroup() << "Seeking phase"; @@ -1295,9 +1311,14 @@ void EngineBuffer::postProcess(const int iBufferSize) { if (kLogger.traceEnabled()) { kLogger.trace() << getGroup() << "EngineBuffer::postProcess"; } - double localBpm = m_pBpmControl->updateLocalBpm(); + const mixxx::Bpm localBpm = m_pBpmControl->updateLocalBpm(); double beatDistance = m_pBpmControl->updateBeatDistance(); - m_pSyncControl->setLocalBpm(localBpm); + // FIXME: Double check if calling setLocalBpm with an invalid value is correct and intended. + double localBpmValue = mixxx::Bpm::kValueUndefined; + if (localBpm.isValid()) { + localBpmValue = localBpm.value(); + } + m_pSyncControl->setLocalBpm(localBpmValue); m_pSyncControl->updateAudible(); SyncMode mode = m_pSyncControl->getSyncMode(); if (isLeader(mode)) { @@ -1313,14 +1334,17 @@ void EngineBuffer::postProcess(const int iBufferSize) { updateIndicators(m_speed_old, iBufferSize); } -bool EngineBuffer::getQueuedSeekPosition(double* pSeekPosition) const { +mixxx::audio::FramePos EngineBuffer::queuedSeekPosition() const { const QueuedSeek queuedSeek = m_queuedSeek.getValue(); - *pSeekPosition = queuedSeek.position; - return (queuedSeek.seekType != SEEK_NONE); + if (queuedSeek.seekType == SEEK_NONE) { + return {}; + } + + return queuedSeek.position; } void EngineBuffer::updateIndicators(double speed, int iBufferSize) { - if (m_trackSampleRateOld == 0) { + if (!m_trackSampleRateOld.isValid()) { // This happens if Deck Passthrough is active but no track is loaded. // We skip indicator updates. return; diff --git a/src/engine/enginebuffer.h b/src/engine/enginebuffer.h index 61090a22b93..75f66a0b369 100644 --- a/src/engine/enginebuffer.h +++ b/src/engine/enginebuffer.h @@ -6,11 +6,13 @@ #include #include +#include "audio/frame.h" #include "control/controlvalue.h" #include "engine/cachingreader/cachingreader.h" #include "engine/engineobject.h" #include "engine/sync/syncable.h" #include "preferences/usersettings.h" +#include "track/bpm.h" #include "track/track_decl.h" #include "util/rotary.h" #include "util/types.h" @@ -97,10 +99,10 @@ class EngineBuffer : public EngineObject { double getSpeed() const; bool getScratching() const; bool isReverse() const; - // Returns current bpm value (not thread-safe) - double getBpm() const; - // Returns the BPM of the loaded track around the current position (not thread-safe) - double getLocalBpm() const; + /// Returns current bpm value (not thread-safe) + mixxx::Bpm getBpm() const; + /// Returns the BPM of the loaded track around the current position (not thread-safe) + mixxx::Bpm getLocalBpm() const; /// Sets a beatloop for the loaded track (not thread safe) void setBeatLoop(double startPosition, bool enabled); /// Sets a loop for the loaded track (not thread safe) @@ -109,7 +111,7 @@ class EngineBuffer : public EngineObject { void setEngineMaster(EngineMaster*); // Queues a new seek position. Use SEEK_EXACT or SEEK_STANDARD as seekType - void queueNewPlaypos(double newpos, enum SeekRequest seekType); + void queueNewPlaypos(mixxx::audio::FramePos newpos, enum SeekRequest seekType); void requestSyncPhase(); void requestEnableSync(bool enabled); void requestSyncMode(SyncMode mode); @@ -120,9 +122,9 @@ class EngineBuffer : public EngineObject { void processSlip(int iBufferSize); void postProcess(const int iBufferSize); - /// Return true iff a seek is currently queued but not yet processed - /// If no seek was queued, the seek position is set to -1 - bool getQueuedSeekPosition(double* pSeekPosition) const; + /// Returns the seek position iff a seek is currently queued but not yet + /// processed. If no seek was queued, and invalid frame position is returned. + mixxx::audio::FramePos queuedSeekPosition() const; bool isTrackLoaded() const; TrackPointer getLoadedTrack() const; @@ -194,7 +196,7 @@ class EngineBuffer : public EngineObject { private: struct QueuedSeek { - double position; + mixxx::audio::FramePos position; enum SeekRequest seekType; }; @@ -214,7 +216,7 @@ class EngineBuffer : public EngineObject { double fractionalPlayposFromAbsolute(double absolutePlaypos); void doSeekFractional(double fractionalPos, enum SeekRequest seekType); - void doSeekPlayPos(double playpos, enum SeekRequest seekType); + void doSeekPlayPos(mixxx::audio::FramePos position, enum SeekRequest seekType); // Read one buffer from the current scaler into the crossfade buffer. Used // for transitioning from one scaler to another, or reseeking a scaler @@ -233,7 +235,9 @@ class EngineBuffer : public EngineObject { bool updateIndicatorsAndModifyPlay(bool newPlay, bool oldPlay); void verifyPlay(); void notifyTrackLoaded(TrackPointer pNewTrack, TrackPointer pOldTrack); - void processTrackLocked(CSAMPLE* pOutput, const int iBufferSize, int sample_rate); + void processTrackLocked(CSAMPLE* pOutput, + const int iBufferSize, + mixxx::audio::SampleRate sampleRate); // Holds the name of the control group const QString m_group; @@ -310,7 +314,7 @@ class EngineBuffer : public EngineObject { double m_trackSamplesOld; // Copy of file sample rate - double m_trackSampleRateOld; + mixxx::audio::SampleRate m_trackSampleRateOld; // Mutex controlling whether the process function is in pause mode. This happens // during seek and loading of a new track @@ -388,8 +392,9 @@ class EngineBuffer : public EngineObject { QAtomicInt m_iEnableSyncQueued; QAtomicInt m_iSyncModeQueued; ControlValueAtomic m_queuedSeek; - static constexpr QueuedSeek kNoQueuedSeek = { - -1.0, SEEK_NONE}; // value used if no seek is queued + + /// Indicates that no seek is queued + static constexpr QueuedSeek kNoQueuedSeek = {mixxx::audio::kInvalidFramePos, SEEK_NONE}; QAtomicPointer m_pChannelToCloneFrom; // Is true if the previous buffer was silent due to pausing @@ -397,7 +402,7 @@ class EngineBuffer : public EngineObject { bool m_bPlayAfterLoading; // Records the sample rate so we can detect when it changes. Initialized to // 0 to guarantee we see a change on the first callback. - int m_iSampleRate; + mixxx::audio::SampleRate m_sampleRate; TrackPointer m_pCurrentTrack; #ifdef __SCALER_DEBUG__ diff --git a/src/engine/enginemaster.cpp b/src/engine/enginemaster.cpp index 8b63b51360d..34cb9d22e86 100644 --- a/src/engine/enginemaster.cpp +++ b/src/engine/enginemaster.cpp @@ -426,7 +426,7 @@ void EngineMaster::process(const int iBufferSize) { if (headphoneEnabled) { // Process effects and mix PFL channels together for the headphones. - // Effects will be reprocessed post-fader for the crossfader busses + // Effects will be reprocessed post-fader for the crossfader buses // and master mix, so the channel input buffers cannot be modified here. ChannelMixer::applyEffectsAndMixChannels( m_headphoneGain, &m_activeHeadphoneChannels, diff --git a/src/engine/sidechain/shoutconnection.cpp b/src/engine/sidechain/shoutconnection.cpp index d819cb29540..d6d2db18fbc 100644 --- a/src/engine/sidechain/shoutconnection.cpp +++ b/src/engine/sidechain/shoutconnection.cpp @@ -461,7 +461,7 @@ void ShoutConnection::updateFromPreferences() { QString userErrorMsg; int ret = -1; if (m_encoder) { - ret = m_encoder->initEncoder(static_cast(masterSamplerate), &userErrorMsg); + ret = m_encoder->initEncoder(masterSamplerate, &userErrorMsg); } // TODO(XXX): Use mixxx::audio::SampleRate instead of int in initEncoder @@ -808,10 +808,9 @@ void ShoutConnection::updateMetaData() { * To conclude: Only write OGG metadata one time, i.e., if static metadata is used. */ - - // If we use either MP3 streaming or OGG streaming with dynamic update of + // If we use either MP3 streaming, AAC streaming or OGG streaming with dynamic update of // metadata being enabled, we want dynamic metadata changes - if (!m_custom_metadata && (m_format_is_mp3 || m_ogg_dynamic_update)) { + if (!m_custom_metadata && (m_format_is_mp3 || m_format_is_aac || m_ogg_dynamic_update)) { if (m_pMetaData != nullptr) { QString artist = m_pMetaData->getArtist(); diff --git a/src/engine/sync/enginesync.cpp b/src/engine/sync/enginesync.cpp index 66b9f80032a..f816377fb93 100644 --- a/src/engine/sync/enginesync.cpp +++ b/src/engine/sync/enginesync.cpp @@ -471,7 +471,7 @@ Syncable* EngineSync::pickNonSyncSyncTarget(EngineChannel* pDontPick) const { // mix, and are primary decks. if (pChannel->isActive() && pChannel->isMasterEnabled() && pChannel->isPrimaryDeck()) { EngineBuffer* pBuffer = pChannel->getEngineBuffer(); - if (pBuffer && pBuffer->getBpm() > 0) { + if (pBuffer && pBuffer->getBpm().isValid()) { if (pBuffer->getSpeed() != 0.0) { if (pSyncable->getSyncMode() != SYNC_NONE) { // Second choice: first playing sync deck diff --git a/src/engine/sync/synccontrol.cpp b/src/engine/sync/synccontrol.cpp index 8268ead97a5..7d3473fabd3 100644 --- a/src/engine/sync/synccontrol.cpp +++ b/src/engine/sync/synccontrol.cpp @@ -518,7 +518,7 @@ void SyncControl::notifySeek(double dNewPlaypos) { double SyncControl::fileBpm() const { mixxx::BeatsPointer pBeats = m_pBeats; if (pBeats) { - return pBeats->getBpm(); + return pBeats->getBpm().value(); } - return 0.0; + return mixxx::Bpm::kValueUndefined; } diff --git a/src/library/analysisfeature.cpp b/src/library/analysisfeature.cpp index 6de7480371f..73a8276409e 100644 --- a/src/library/analysisfeature.cpp +++ b/src/library/analysisfeature.cpp @@ -48,12 +48,12 @@ AnalyzerModeFlags getAnalyzerModeFlags( AnalysisFeature::AnalysisFeature( Library* pLibrary, UserSettingsPointer pConfig) - : LibraryFeature(pLibrary, pConfig), - m_baseTitle(tr("Analyze")), - m_icon(":/images/library/ic_library_prepare.svg"), - m_pTrackAnalysisScheduler(TrackAnalysisScheduler::NullPointer()), - m_pAnalysisView(nullptr), - m_title(m_baseTitle) { + : LibraryFeature(pLibrary, pConfig, QStringLiteral("prepare")), + m_baseTitle(tr("Analyze")), + m_pTrackAnalysisScheduler(TrackAnalysisScheduler::NullPointer()), + m_pSidebarModel(make_parented(this)), + m_pAnalysisView(nullptr), + m_title(m_baseTitle) { } void AnalysisFeature::resetTitle() { @@ -111,8 +111,8 @@ void AnalysisFeature::bindLibraryWidget(WLibrary* libraryWidget, libraryWidget->registerView(kViewName, m_pAnalysisView); } -TreeItemModel* AnalysisFeature::getChildModel() { - return &m_childModel; +TreeItemModel* AnalysisFeature::sidebarModel() const { + return m_pSidebarModel; } void AnalysisFeature::refreshLibraryModels() { diff --git a/src/library/analysisfeature.h b/src/library/analysisfeature.h index f9a60047c12..d6c85f9dbb7 100644 --- a/src/library/analysisfeature.h +++ b/src/library/analysisfeature.h @@ -1,17 +1,18 @@ #pragma once +#include +#include +#include #include #include -#include #include -#include -#include -#include "library/libraryfeature.h" +#include "analyzer/trackanalysisscheduler.h" #include "library/dlganalysis.h" +#include "library/libraryfeature.h" #include "library/treeitemmodel.h" -#include "analyzer/trackanalysisscheduler.h" #include "preferences/usersettings.h" +#include "util/parented_ptr.h" class TrackCollection; @@ -26,16 +27,12 @@ class AnalysisFeature : public LibraryFeature { return m_title; } - QIcon getIcon() override { - return m_icon; - } - bool dropAccept(const QList& urls, QObject* pSource) override; bool dragMoveAccept(const QUrl& url) override; void bindLibraryWidget(WLibrary* libraryWidget, KeyboardEventFilter* keyboard) override; - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; void refreshLibraryModels(); signals: @@ -64,11 +61,10 @@ class AnalysisFeature : public LibraryFeature { void setTitleProgress(int currentTrackNumber, int totalTracksCount); const QString m_baseTitle; - const QIcon m_icon; TrackAnalysisScheduler::Pointer m_pTrackAnalysisScheduler; - TreeItemModel m_childModel; + parented_ptr m_pSidebarModel; DlgAnalysis* m_pAnalysisView; // The title is dynamic and reflects the current progress diff --git a/src/library/autodj/autodjfeature.cpp b/src/library/autodj/autodjfeature.cpp index af4a685be9e..c34e0849292 100644 --- a/src/library/autodj/autodjfeature.cpp +++ b/src/library/autodj/autodjfeature.cpp @@ -48,14 +48,14 @@ namespace { AutoDJFeature::AutoDJFeature(Library* pLibrary, UserSettingsPointer pConfig, PlayerManagerInterface* pPlayerManager) - : LibraryFeature(pLibrary, pConfig), + : LibraryFeature(pLibrary, pConfig, QStringLiteral("autodj")), m_pTrackCollection(pLibrary->trackCollectionManager()->internalCollection()), m_playlistDao(m_pTrackCollection->getPlaylistDAO()), m_iAutoDJPlaylistId(findOrCrateAutoDjPlaylistId(m_playlistDao)), m_pAutoDJProcessor(nullptr), + m_pSidebarModel(make_parented(this)), m_pAutoDJView(nullptr), - m_autoDjCratesDao(m_iAutoDJPlaylistId, pLibrary->trackCollectionManager(), m_pConfig), - m_icon(":/images/library/ic_library_autodj.svg") { + m_autoDjCratesDao(m_iAutoDJPlaylistId, pLibrary->trackCollectionManager(), m_pConfig) { qRegisterMetaType("AutoDJState"); m_pAutoDJProcessor = new AutoDJProcessor(this, m_pConfig, @@ -76,7 +76,7 @@ AutoDJFeature::AutoDJFeature(Library* pLibrary, // Create tree-items under "Crates". constructCrateChildModel(); - m_childModel.setRootItem(std::move(pRootItem)); + m_pSidebarModel->setRootItem(std::move(pRootItem)); // Be notified when the status of crates changes. connect(m_pTrackCollection, @@ -110,10 +110,6 @@ QVariant AutoDJFeature::title() { return tr("Auto DJ"); } -QIcon AutoDJFeature::getIcon() { - return m_icon; -} - void AutoDJFeature::bindLibraryWidget( WLibrary* libraryWidget, KeyboardEventFilter* keyboard) { @@ -154,8 +150,8 @@ void AutoDJFeature::bindSidebarWidget(WLibrarySidebar* pSidebarWidget) { m_pSidebarWidget = pSidebarWidget; } -TreeItemModel* AutoDJFeature::getChildModel() { - return &m_childModel; +TreeItemModel* AutoDJFeature::sidebarModel() const { + return m_pSidebarModel; } void AutoDJFeature::activate() { @@ -204,9 +200,9 @@ void AutoDJFeature::slotCrateChanged(CrateId crateId) { // -> Find and update the corresponding child item for (int i = 0; i < m_crateList.length(); ++i) { if (m_crateList[i].getId() == crateId) { - QModelIndex parentIndex = m_childModel.index(0, 0); - QModelIndex childIndex = m_childModel.index(i, 0, parentIndex); - m_childModel.setData(childIndex, crate.getName(), Qt::DisplayRole); + QModelIndex parentIndex = m_pSidebarModel->index(0, 0); + QModelIndex childIndex = m_pSidebarModel->index(i, 0, parentIndex); + m_pSidebarModel->setData(childIndex, crate.getName(), Qt::DisplayRole); m_crateList[i] = crate; return; // early exit } @@ -215,17 +211,17 @@ void AutoDJFeature::slotCrateChanged(CrateId crateId) { // -> Create and append a new child item for this crate QList rows; rows.append(new TreeItem(crate.getName(), crate.getId().toVariant())); - QModelIndex parentIndex = m_childModel.index(0, 0); - m_childModel.insertTreeItemRows(rows, m_crateList.length(), parentIndex); - DEBUG_ASSERT(rows.isEmpty()); // ownership passed to m_childModel + QModelIndex parentIndex = m_pSidebarModel->index(0, 0); + m_pSidebarModel->insertTreeItemRows(rows, m_crateList.length(), parentIndex); + DEBUG_ASSERT(rows.isEmpty()); // ownership passed to m_pSidebarModel m_crateList.append(crate); } else { // Crate does not exist or is not a source for AutoDJ // -> Find and remove the corresponding child item for (int i = 0; i < m_crateList.length(); ++i) { if (m_crateList[i].getId() == crateId) { - QModelIndex parentIndex = m_childModel.index(0, 0); - m_childModel.removeRows(i, 1, parentIndex); + QModelIndex parentIndex = m_pSidebarModel->index(0, 0); + m_pSidebarModel->removeRows(i, 1, parentIndex); m_crateList.removeAt(i); return; // early exit } diff --git a/src/library/autodj/autodjfeature.h b/src/library/autodj/autodjfeature.h index c6f3ef12a72..35ee88e903d 100644 --- a/src/library/autodj/autodjfeature.h +++ b/src/library/autodj/autodjfeature.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include @@ -16,6 +15,7 @@ #include "library/trackset/crate/crate.h" #include "library/treeitemmodel.h" #include "preferences/usersettings.h" +#include "util/parented_ptr.h" class DlgAutoDJ; class Library; @@ -34,7 +34,6 @@ class AutoDJFeature : public LibraryFeature { virtual ~AutoDJFeature(); QVariant title() override; - QIcon getIcon() override; bool dropAccept(const QList& urls, QObject* pSource) override; bool dragMoveAccept(const QUrl& url) override; @@ -43,7 +42,7 @@ class AutoDJFeature : public LibraryFeature { KeyboardEventFilter* keyboard) override; void bindSidebarWidget(WLibrarySidebar* pSidebarWidget) override; - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; bool hasTrackTable() override { return true; @@ -62,7 +61,7 @@ class AutoDJFeature : public LibraryFeature { // The id of the AutoDJ playlist. int m_iAutoDJPlaylistId; AutoDJProcessor* m_pAutoDJProcessor; - TreeItemModel m_childModel; + parented_ptr m_pSidebarModel; DlgAutoDJ* m_pAutoDJView; // Initialize the list of crates loaded into the auto-DJ queue. @@ -83,7 +82,6 @@ class AutoDJFeature : public LibraryFeature { // auto-DJ list. QAction *m_pRemoveCrateFromAutoDj; - QIcon m_icon; QPointer m_pSidebarWidget; private slots: diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index a39682797af..068cdec09cf 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -17,8 +17,6 @@ const char* kTransitionModePreferenceName = "TransitionMode"; const double kTransitionPreferenceDefault = 10.0; const double kKeepPosition = -1.0; -const mixxx::audio::ChannelCount kChannelCount = mixxx::kEngineChannelCount; - static const bool sDebug = false; } // anonymous namespace @@ -1057,43 +1055,44 @@ void AutoDJProcessor::playerOutroEndChanged(DeckAttributes* pAttributes, double } double AutoDJProcessor::getIntroStartSecond(DeckAttributes* pDeck) { - double introStartSample = pDeck->introStartPosition(); - if (introStartSample == Cue::kNoPosition) { + const mixxx::audio::FramePos introStartPosition = pDeck->introStartPosition(); + if (!introStartPosition.isValid()) { return getFirstSoundSecond(pDeck); } - return samplePositionToSeconds(introStartSample, pDeck); + return framePositionToSeconds(introStartPosition, pDeck); } double AutoDJProcessor::getIntroEndSecond(DeckAttributes* pDeck) { - double introEndSample = pDeck->introEndPosition(); - if (introEndSample == Cue::kNoPosition) { + const mixxx::audio::FramePos introEndPosition = pDeck->introEndPosition(); + if (!introEndPosition.isValid()) { // Assume a zero length intro if introEnd is not set. // The introStart is automatically placed by AnalyzerSilence, so use // that as a fallback if the user has not placed outroStart. If it has // not been placed, getIntroStartPosition will return 0:00. return getIntroStartSecond(pDeck); } - return samplePositionToSeconds(introEndSample, pDeck); + return framePositionToSeconds(introEndPosition, pDeck); } double AutoDJProcessor::getOutroStartSecond(DeckAttributes* pDeck) { - double outroStartSample = pDeck->outroStartPosition(); - if (outroStartSample == Cue::kNoPosition) { + const mixxx::audio::FramePos outroStartPosition = pDeck->outroStartPosition(); + if (!outroStartPosition.isValid()) { // Assume a zero length outro if outroStart is not set. // The outroEnd is automatically placed by AnalyzerSilence, so use // that as a fallback if the user has not placed outroStart. If it has // not been placed, getOutroEndPosition will return the end of the track. return getOutroEndSecond(pDeck); } - return samplePositionToSeconds(outroStartSample, pDeck); + return framePositionToSeconds(outroStartPosition, pDeck); } double AutoDJProcessor::getOutroEndSecond(DeckAttributes* pDeck) { - double outroEndSample = pDeck->outroEndPosition(); - if (outroEndSample == Cue::kNoPosition) { + const mixxx::audio::FramePos outroEndPosition = pDeck->outroEndPosition(); + if (!outroEndPosition.isValid()) { return getLastSoundSecond(pDeck); } - return samplePositionToSeconds(outroEndSample, pDeck);; + return framePositionToSeconds(outroEndPosition, pDeck); + ; } double AutoDJProcessor::getFirstSoundSecond(DeckAttributes* pDeck) { @@ -1104,9 +1103,9 @@ double AutoDJProcessor::getFirstSoundSecond(DeckAttributes* pDeck) { CuePointer pFromTrackAudibleSound = pTrack->findCueByType(mixxx::CueType::AudibleSound); if (pFromTrackAudibleSound) { - double firstSound = pFromTrackAudibleSound->getPosition(); - if (firstSound > 0.0) { - return samplePositionToSeconds(firstSound, pDeck); + const mixxx::audio::FramePos firstSound = pFromTrackAudibleSound->getPosition(); + if (firstSound.isValid()) { + return framePositionToSeconds(firstSound, pDeck); } } return 0.0; @@ -1121,8 +1120,9 @@ double AutoDJProcessor::getLastSoundSecond(DeckAttributes* pDeck) { CuePointer pFromTrackAudibleSound = pTrack->findCueByType(mixxx::CueType::AudibleSound); if (pFromTrackAudibleSound) { Cue::StartAndEndPositions pos = pFromTrackAudibleSound->getStartAndEndPosition(); - if (pos.endPosition > 0 && (pos.endPosition - pos.startPosition) > 0) { - return samplePositionToSeconds(pos.endPosition, pDeck); + if (pos.endPosition > mixxx::audio::kStartFramePos && + (pos.endPosition - pos.startPosition) > 0) { + return framePositionToSeconds(pos.endPosition, pDeck); } } return getEndSecond(pDeck); @@ -1134,17 +1134,18 @@ double AutoDJProcessor::getEndSecond(DeckAttributes* pDeck) { return 0.0; } - double endSamplePosition = pDeck->trackSamples(); - return samplePositionToSeconds(endSamplePosition, pDeck); + mixxx::audio::FramePos trackEndPosition = pDeck->trackEndPosition(); + return framePositionToSeconds(trackEndPosition, pDeck); } -double AutoDJProcessor::samplePositionToSeconds(double samplePosition, DeckAttributes* pDeck) { - samplePosition /= kChannelCount; +double AutoDJProcessor::framePositionToSeconds( + mixxx::audio::FramePos position, DeckAttributes* pDeck) { mixxx::audio::SampleRate sampleRate = pDeck->sampleRate(); - if (!sampleRate.isValid()) { + if (!sampleRate.isValid() || !position.isValid()) { return 0.0; } - return samplePosition / sampleRate / pDeck->rateRatio(); + + return position.value() / sampleRate / pDeck->rateRatio(); } void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 1504d9c62fc..2aa8e2f9662 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -61,28 +61,28 @@ class DeckAttributes : public QObject { m_repeat.set(enabled ? 1.0 : 0.0); } - double introStartPosition() const { - return m_introStartPos.get(); + mixxx::audio::FramePos introStartPosition() const { + return mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid(m_introStartPos.get()); } - double introEndPosition() const { - return m_introEndPos.get(); + mixxx::audio::FramePos introEndPosition() const { + return mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid(m_introEndPos.get()); } - double outroStartPosition() const { - return m_outroStartPos.get(); + mixxx::audio::FramePos outroStartPosition() const { + return mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid(m_outroStartPos.get()); } - double outroEndPosition() const { - return m_outroEndPos.get(); + mixxx::audio::FramePos outroEndPosition() const { + return mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid(m_outroEndPos.get()); } mixxx::audio::SampleRate sampleRate() const { return mixxx::audio::SampleRate::fromDouble(m_sampleRate.get()); } - double trackSamples() const { - return m_trackSamples.get(); + mixxx::audio::FramePos trackEndPosition() const { + return mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid(m_trackSamples.get()); } double rateRatio() const { @@ -252,7 +252,7 @@ class AutoDJProcessor : public QObject { double getFirstSoundSecond(DeckAttributes* pDeck); double getLastSoundSecond(DeckAttributes* pDeck); double getEndSecond(DeckAttributes* pDeck); - double samplePositionToSeconds(double samplePosition, DeckAttributes* pDeck); + double framePositionToSeconds(mixxx::audio::FramePos position, DeckAttributes* pDeck); TrackPointer getNextTrackFromQueue(); bool loadNextTrackFromQueue(const DeckAttributes& pDeck, bool play = false); diff --git a/src/library/banshee/bansheefeature.cpp b/src/library/banshee/bansheefeature.cpp index 800b5bd7fa2..b6680e4cf8a 100644 --- a/src/library/banshee/bansheefeature.cpp +++ b/src/library/banshee/bansheefeature.cpp @@ -17,9 +17,9 @@ const QString BansheeFeature::BANSHEE_MOUNT_KEY = "mixxx.BansheeFeature.mount"; QString BansheeFeature::m_databaseFile; BansheeFeature::BansheeFeature(Library* pLibrary, UserSettingsPointer pConfig) - : BaseExternalLibraryFeature(pLibrary, pConfig), - m_cancelImport(false), - m_icon(":/images/library/ic_library_banshee.svg") { + : BaseExternalLibraryFeature(pLibrary, pConfig, QStringLiteral("banshee")), + m_pSidebarModel(make_parented(this)), + m_cancelImport(false) { Q_UNUSED(pConfig); m_pBansheePlaylistModel = new BansheePlaylistModel( this, m_pLibrary->trackCollectionManager(), &m_connection); @@ -58,10 +58,6 @@ QVariant BansheeFeature::title() { return m_title; } -QIcon BansheeFeature::getIcon() { - return m_icon; -} - void BansheeFeature::activate() { //qDebug("BansheeFeature::activate()"); @@ -102,7 +98,7 @@ void BansheeFeature::activate() { // append the playlist to the child model pRootItem->appendChild(playlist.name, playlist.playlistId); } - m_childModel.setRootItem(std::move(pRootItem)); + m_pSidebarModel->setRootItem(std::move(pRootItem)); if (m_isActivated) { activate(); @@ -130,8 +126,8 @@ void BansheeFeature::activateChild(const QModelIndex& index) { } } -TreeItemModel* BansheeFeature::getChildModel() { - return &m_childModel; +TreeItemModel* BansheeFeature::sidebarModel() const { + return m_pSidebarModel; } void BansheeFeature::appendTrackIdsFromRightClickIndex(QList* trackIds, QString* pPlaylist) { diff --git a/src/library/banshee/bansheefeature.h b/src/library/banshee/bansheefeature.h index 46e9bcf695c..dfb7e556269 100644 --- a/src/library/banshee/bansheefeature.h +++ b/src/library/banshee/bansheefeature.h @@ -24,9 +24,8 @@ class BansheeFeature : public BaseExternalLibraryFeature { static void prepareDbPath(UserSettingsPointer pConfig); virtual QVariant title(); - virtual QIcon getIcon(); - virtual TreeItemModel* getChildModel(); + virtual TreeItemModel* sidebarModel() const; public slots: virtual void activate(); @@ -36,7 +35,7 @@ class BansheeFeature : public BaseExternalLibraryFeature { virtual void appendTrackIdsFromRightClickIndex(QList* trackIds, QString* pPlaylist); BansheePlaylistModel* m_pBansheePlaylistModel; - TreeItemModel m_childModel; + parented_ptr m_pSidebarModel; QStringList m_playlists; //a new DB connection for the worker thread @@ -50,7 +49,6 @@ class BansheeFeature : public BaseExternalLibraryFeature { QFuture m_future; QString m_title; bool m_cancelImport; - QIcon m_icon; static QString m_databaseFile; diff --git a/src/library/baseexternallibraryfeature.cpp b/src/library/baseexternallibraryfeature.cpp index 36afe30291e..6492f092584 100644 --- a/src/library/baseexternallibraryfeature.cpp +++ b/src/library/baseexternallibraryfeature.cpp @@ -18,8 +18,9 @@ const mixxx::Logger kLogger("BaseExternalLibraryFeature"); BaseExternalLibraryFeature::BaseExternalLibraryFeature( Library* pLibrary, - UserSettingsPointer pConfig) - : LibraryFeature(pLibrary, pConfig), + UserSettingsPointer pConfig, + const QString& iconName) + : LibraryFeature(pLibrary, pConfig, iconName), m_pTrackCollection(pLibrary->trackCollectionManager()->internalCollection()) { m_pAddToAutoDJAction = make_parented(tr("Add to Auto DJ Queue (bottom)"), this); connect(m_pAddToAutoDJAction, diff --git a/src/library/baseexternallibraryfeature.h b/src/library/baseexternallibraryfeature.h index 97ab683c09c..3838f2871b3 100644 --- a/src/library/baseexternallibraryfeature.h +++ b/src/library/baseexternallibraryfeature.h @@ -16,7 +16,8 @@ class BaseExternalLibraryFeature : public LibraryFeature { public: BaseExternalLibraryFeature( Library* pLibrary, - UserSettingsPointer pConfig); + UserSettingsPointer pConfig, + const QString& iconName); ~BaseExternalLibraryFeature() override = default; public slots: diff --git a/src/library/basetracktablemodel.cpp b/src/library/basetracktablemodel.cpp index a60826304ae..81dc6d49b8e 100644 --- a/src/library/basetracktablemodel.cpp +++ b/src/library/basetracktablemodel.cpp @@ -109,9 +109,9 @@ BaseTrackTableModel::BaseTrackTableModel( this, &BaseTrackTableModel::slotRefreshAllRows); connect(&PlayerInfo::instance(), - &PlayerInfo::trackLoaded, + &PlayerInfo::trackChanged, this, - &BaseTrackTableModel::slotTrackLoaded); + &BaseTrackTableModel::slotTrackChanged); } void BaseTrackTableModel::initTableColumnsAndHeaderProperties( @@ -664,11 +664,11 @@ QVariant BaseTrackTableModel::roleValue( bpm = mixxx::Bpm(bpmValue); } } - if (bpm.hasValue()) { + if (bpm.isValid()) { if (role == Qt::ToolTipRole || role == kDataExportRole) { - return QString::number(bpm.getValue(), 'f', 4); + return QString::number(bpm.value(), 'f', 4); } else { - return QString::number(bpm.getValue(), 'f', 1); + return QString::number(bpm.value(), 'f', 1); } } else { return QChar('-'); @@ -782,7 +782,7 @@ QVariant BaseTrackTableModel::roleValue( case ColumnCache::COLUMN_LIBRARYTABLE_BPM: { bool ok; const auto bpmValue = rawValue.toDouble(&ok); - return ok ? bpmValue : mixxx::Bpm().getValue(); + return ok ? bpmValue : mixxx::Bpm().value(); } case ColumnCache::COLUMN_LIBRARYTABLE_TIMESPLAYED: return index.sibling( @@ -941,9 +941,11 @@ QMimeData* BaseTrackTableModel::mimeData( } } -void BaseTrackTableModel::slotTrackLoaded( +void BaseTrackTableModel::slotTrackChanged( const QString& group, - TrackPointer pTrack) { + TrackPointer pNewTrack, + TrackPointer pOldTrack) { + Q_UNUSED(pOldTrack); if (group == m_previewDeckGroup) { // If there was a previously loaded track, refresh its rows so the // preview state will update. @@ -957,7 +959,7 @@ void BaseTrackTableModel::slotTrackLoaded( emit dataChanged(topLeft, bottomRight); } } - m_previewDeckTrackId = doGetTrackId(pTrack); + m_previewDeckTrackId = doGetTrackId(pNewTrack); } } diff --git a/src/library/basetracktablemodel.h b/src/library/basetracktablemodel.h index 1d8d2435c83..9012ee1908c 100644 --- a/src/library/basetracktablemodel.h +++ b/src/library/basetracktablemodel.h @@ -221,9 +221,10 @@ class BaseTrackTableModel : public QAbstractTableModel, public TrackModel { } private slots: - void slotTrackLoaded( + void slotTrackChanged( const QString& group, - TrackPointer pTrack); + TrackPointer pNewTrack, + TrackPointer pOldTrack); void slotRefreshCoverRows( const QList& rows); diff --git a/src/library/browse/browsefeature.cpp b/src/library/browse/browsefeature.cpp index 66c375c3fbb..cda1b0c3e35 100644 --- a/src/library/browse/browsefeature.cpp +++ b/src/library/browse/browsefeature.cpp @@ -31,12 +31,12 @@ BrowseFeature::BrowseFeature( Library* pLibrary, UserSettingsPointer pConfig, RecordingManager* pRecordingManager) - : LibraryFeature(pLibrary, pConfig), + : LibraryFeature(pLibrary, pConfig, QString("computer")), m_pTrackCollection(pLibrary->trackCollectionManager()->internalCollection()), m_browseModel(this, pLibrary->trackCollectionManager(), pRecordingManager), m_proxyModel(&m_browseModel), - m_pLastRightClickedItem(nullptr), - m_icon(":/images/library/ic_library_computer.svg") { + m_pSidebarModel(new FolderTreeModel(this)), + m_pLastRightClickedItem(nullptr) { connect(this, &BrowseFeature::requestAddDir, pLibrary, @@ -131,7 +131,7 @@ BrowseFeature::BrowseFeature( } // initialize the model - m_childModel.setRootItem(std::move(pRootItem)); + m_pSidebarModel->setRootItem(std::move(pRootItem)); } BrowseFeature::~BrowseFeature() { @@ -150,12 +150,12 @@ void BrowseFeature::slotAddQuickLink() { QString spath = vpath.toString(); QString name = extractNameFromPath(spath); - QModelIndex parent = m_childModel.index(m_pQuickLinkItem->parentRow(), 0); + QModelIndex parent = m_pSidebarModel->index(m_pQuickLinkItem->parentRow(), 0); auto pNewChild = std::make_unique(name, vpath); QList rows; rows.append(pNewChild.get()); pNewChild.release(); - m_childModel.insertTreeItemRows(rows, m_pQuickLinkItem->childRows(), parent); + m_pSidebarModel->insertTreeItemRows(rows, m_pQuickLinkItem->childRows(), parent); m_quickLinkList.append(spath); saveQuickLinks(); @@ -206,19 +206,15 @@ void BrowseFeature::slotRemoveQuickLink() { return; } - QModelIndex parent = m_childModel.index(m_pQuickLinkItem->parentRow(), 0); - m_childModel.removeRow(index, parent); + QModelIndex parent = m_pSidebarModel->index(m_pQuickLinkItem->parentRow(), 0); + m_pSidebarModel->removeRow(index, parent); m_quickLinkList.removeAt(index); saveQuickLinks(); } -QIcon BrowseFeature::getIcon() { - return m_icon; -} - -TreeItemModel* BrowseFeature::getChildModel() { - return &m_childModel; +TreeItemModel* BrowseFeature::sidebarModel() const { + return m_pSidebarModel; } void BrowseFeature::bindLibraryWidget(WLibrary* libraryWidget, @@ -392,7 +388,7 @@ void BrowseFeature::onLazyChildExpandation(const QModelIndex& index) { } // Before we populate the subtree, we need to delete old subtrees - m_childModel.removeRows(0, item->childRows(), index); + m_pSidebarModel->removeRows(0, item->childRows(), index); // List of subfolders or drive letters QList folders; @@ -428,7 +424,7 @@ void BrowseFeature::onLazyChildExpandation(const QModelIndex& index) { // On Ubuntu 10.04, otherwise, this will draw an icon although the folder // has no subfolders if (!folders.isEmpty()) { - m_childModel.insertTreeItemRows(folders, 0, index); + m_pSidebarModel->insertTreeItemRows(folders, 0, index); } } diff --git a/src/library/browse/browsefeature.h b/src/library/browse/browsefeature.h index a90fdded19a..9eda8d77e2f 100644 --- a/src/library/browse/browsefeature.h +++ b/src/library/browse/browsefeature.h @@ -30,23 +30,22 @@ class BrowseFeature : public LibraryFeature { RecordingManager* pRecordingManager); virtual ~BrowseFeature(); - QVariant title(); - QIcon getIcon(); + QVariant title() override; void bindLibraryWidget(WLibrary* libraryWidget, - KeyboardEventFilter* keyboard); - void bindSidebarWidget(WLibrarySidebar* pSidebarWidget); + KeyboardEventFilter* keyboard) override; + void bindSidebarWidget(WLibrarySidebar* pSidebarWidget) override; - TreeItemModel* getChildModel(); + TreeItemModel* sidebarModel() const override; public slots: void slotAddQuickLink(); void slotRemoveQuickLink(); void slotAddToLibrary(); - void activate(); - void activateChild(const QModelIndex& index); - void onRightClickChild(const QPoint& globalPos, const QModelIndex& index); - void onLazyChildExpandation(const QModelIndex& index); + void activate() override; + void activateChild(const QModelIndex& index) override; + void onRightClickChild(const QPoint& globalPos, const QModelIndex& index) override; + void onLazyChildExpandation(const QModelIndex& index) override; void slotLibraryScanStarted(); void slotLibraryScanFinished(); @@ -66,13 +65,12 @@ class BrowseFeature : public LibraryFeature { BrowseTableModel m_browseModel; ProxyTrackModel m_proxyModel; - FolderTreeModel m_childModel; + FolderTreeModel* m_pSidebarModel; QAction* m_pAddQuickLinkAction; QAction* m_pRemoveQuickLinkAction; QAction* m_pAddtoLibraryAction; TreeItem* m_pLastRightClickedItem; TreeItem* m_pQuickLinkItem; QStringList m_quickLinkList; - QIcon m_icon; QPointer m_pSidebarWidget; }; diff --git a/src/library/browse/browsetablemodel.cpp b/src/library/browse/browsetablemodel.cpp index e35f805079f..8d37f4124ae 100644 --- a/src/library/browse/browsetablemodel.cpp +++ b/src/library/browse/browsetablemodel.cpp @@ -155,10 +155,12 @@ BrowseTableModel::BrowseTableModel(QObject* parent, Qt::QueuedConnection); connect(&PlayerInfo::instance(), - &PlayerInfo::trackLoaded, + &PlayerInfo::trackChanged, this, - &BrowseTableModel::trackLoaded); - trackLoaded(m_previewDeckGroup, PlayerInfo::instance().getTrackInfo(m_previewDeckGroup)); + &BrowseTableModel::trackChanged); + trackChanged(m_previewDeckGroup, + PlayerInfo::instance().getTrackInfo(m_previewDeckGroup), + TrackPointer()); } BrowseTableModel::~BrowseTableModel() { @@ -435,7 +437,9 @@ bool BrowseTableModel::setData( return true; } -void BrowseTableModel::trackLoaded(const QString& group, TrackPointer pTrack) { +void BrowseTableModel::trackChanged( + const QString& group, TrackPointer pNewTrack, TrackPointer pOldTrack) { + Q_UNUSED(pOldTrack); if (group == m_previewDeckGroup) { for (int row = 0; row < rowCount(); ++row) { QModelIndex i = index(row, COLUMN_PREVIEW); @@ -444,8 +448,8 @@ void BrowseTableModel::trackLoaded(const QString& group, TrackPointer pTrack) { item->setText("0"); } } - if (pTrack) { - QString trackLocation = pTrack->getLocation(); + if (pNewTrack) { + QString trackLocation = pNewTrack->getLocation(); for (int row = 0; row < rowCount(); ++row) { QModelIndex i = index(row, COLUMN_PREVIEW); QString location = getTrackLocation(i); diff --git a/src/library/browse/browsetablemodel.h b/src/library/browse/browsetablemodel.h index e0473e01b72..e299320d19a 100644 --- a/src/library/browse/browsetablemodel.h +++ b/src/library/browse/browsetablemodel.h @@ -81,7 +81,7 @@ class BrowseTableModel final : public QStandardItemModel, public virtual TrackMo public slots: void slotClear(BrowseTableModel*); void slotInsert(const QList< QList >&, BrowseTableModel*); - void trackLoaded(const QString& group, TrackPointer pTrack); + void trackChanged(const QString& group, TrackPointer pNewTrack, TrackPointer pOldTrack); private: void addSearchColumn(int index); diff --git a/src/library/browse/browsethread.cpp b/src/library/browse/browsethread.cpp index a9c87e73bf9..f4a7e7e4bcd 100644 --- a/src/library/browse/browsethread.cpp +++ b/src/library/browse/browsethread.cpp @@ -226,7 +226,8 @@ void BrowseThread::populateModel() { item = new QStandardItem(trackMetadata.getTrackInfo().getBpmText()); item->setToolTip(item->text()); - item->setData(trackMetadata.getTrackInfo().getBpm().getValue(), Qt::UserRole); + const mixxx::Bpm bpm = trackMetadata.getTrackInfo().getBpm(); + item->setData(bpm.isValid() ? bpm.value() : mixxx::Bpm::kValueUndefined, Qt::UserRole); row_data.insert(COLUMN_BPM, item); item = new QStandardItem(trackMetadata.getTrackInfo().getKey()); diff --git a/src/library/dao/autodjcratesdao.cpp b/src/library/dao/autodjcratesdao.cpp index a5176b16cef..f03ab04d50d 100644 --- a/src/library/dao/autodjcratesdao.cpp +++ b/src/library/dao/autodjcratesdao.cpp @@ -265,13 +265,9 @@ void AutoDJCratesDAO::createAndConnectAutoDjCratesDatabase() { // These count as auto-DJ references, i.e. prevent the track from being // selected randomly. connect(&PlayerInfo::instance(), - &PlayerInfo::trackLoaded, + &PlayerInfo::trackChanged, this, - &AutoDJCratesDAO::slotPlayerInfoTrackLoaded); - connect(&PlayerInfo::instance(), - &PlayerInfo::trackUnloaded, - this, - &AutoDJCratesDAO::slotPlayerInfoTrackUnloaded); + &AutoDJCratesDAO::slotPlayerInfoTrackChanged); // Remember that the auto-DJ-crates database has been created. m_bAutoDjCratesDbCreated = true; @@ -1079,8 +1075,14 @@ void AutoDJCratesDAO::slotPlaylistTrackRemoved(int playlistId, } } +void AutoDJCratesDAO::slotPlayerInfoTrackChanged( + const QString& group, TrackPointer pNewTrack, TrackPointer pOldTrack) { + playerInfoTrackUnloaded(group, pOldTrack); + playerInfoTrackLoaded(group, pNewTrack); +} + // Signaled by the PlayerInfo singleton when a track is loaded to a deck. -void AutoDJCratesDAO::slotPlayerInfoTrackLoaded(const QString& a_strGroup, +void AutoDJCratesDAO::playerInfoTrackLoaded(const QString& a_strGroup, TrackPointer a_pTrack) { // This gets called with a null track during an unload. Filter that out. if (a_pTrack == nullptr) { @@ -1111,7 +1113,7 @@ void AutoDJCratesDAO::slotPlayerInfoTrackLoaded(const QString& a_strGroup, } // Signaled by the PlayerInfo singleton when a track is unloaded from a deck. -void AutoDJCratesDAO::slotPlayerInfoTrackUnloaded(const QString& group, +void AutoDJCratesDAO::playerInfoTrackUnloaded(const QString& group, TrackPointer pTrack) { // This counts as an auto-DJ reference. The idea is to prevent tracks that // are loaded into a deck from being randomly chosen. diff --git a/src/library/dao/autodjcratesdao.h b/src/library/dao/autodjcratesdao.h index 2ecf1a35d25..10fcef32653 100644 --- a/src/library/dao/autodjcratesdao.h +++ b/src/library/dao/autodjcratesdao.h @@ -89,10 +89,13 @@ class AutoDJCratesDAO : public QObject { // Signaled by the PlayerInfo singleton when a track is loaded to, or // unloaded from, a deck. - void slotPlayerInfoTrackLoaded(const QString& group, TrackPointer pTrack); - void slotPlayerInfoTrackUnloaded(const QString& group, TrackPointer pTrack); + void slotPlayerInfoTrackChanged(const QString& group, + TrackPointer pNewTrack, + TrackPointer pOldTrack); private: + void playerInfoTrackLoaded(const QString& group, TrackPointer pTrack); + void playerInfoTrackUnloaded(const QString& group, TrackPointer pTrack); void updateAutoDjCrate(CrateId crateId); void deleteAutoDjCrate(CrateId crateId); diff --git a/src/library/dao/cuedao.cpp b/src/library/dao/cuedao.cpp index afab8ab2ec4..a6fd9a5253b 100644 --- a/src/library/dao/cuedao.cpp +++ b/src/library/dao/cuedao.cpp @@ -4,6 +4,7 @@ #include #include +#include "engine/engine.h" #include "library/queryutil.h" #include "track/track.h" #include "util/assert.h" @@ -40,8 +41,10 @@ CuePointer cueFromRow(const QSqlRecord& row) { const auto id = DbId(row.value(row.indexOf("id"))); TrackId trackId(row.value(row.indexOf("track_id"))); int type = row.value(row.indexOf("type")).toInt(); - int position = row.value(row.indexOf("position")).toInt(); - int length = row.value(row.indexOf("length")).toInt(); + const auto position = + mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid( + row.value(row.indexOf("position")).toInt()); + int lengthFrames = row.value(row.indexOf("length")).toInt() / mixxx::kEngineChannelCount; int hotcue = row.value(row.indexOf("hotcue")).toInt(); QString label = labelFromQVariant(row.value(row.indexOf("label"))); mixxx::RgbColor::optional_t color = mixxx::RgbColor::fromQVariant(row.value(row.indexOf("color"))); @@ -51,7 +54,7 @@ CuePointer cueFromRow(const QSqlRecord& row) { CuePointer pCue(new Cue(id, static_cast(type), position, - length, + lengthFrames, hotcue, label, *color)); @@ -165,8 +168,8 @@ bool CueDAO::saveCue(TrackId trackId, Cue* cue) const { // Bind values and execute query query.bindValue(":track_id", trackId.toVariant()); query.bindValue(":type", static_cast(cue->getType())); - query.bindValue(":position", cue->getPosition()); - query.bindValue(":length", cue->getLength()); + query.bindValue(":position", cue->getPosition().toEngineSamplePosMaybeInvalid()); + query.bindValue(":length", cue->getLengthFrames() * mixxx::kEngineChannelCount); query.bindValue(":hotcue", cue->getHotCue()); query.bindValue(":label", labelToQVariant(cue->getLabel())); query.bindValue(":color", mixxx::RgbColor::toQVariant(cue->getColor())); diff --git a/src/library/dao/trackdao.cpp b/src/library/dao/trackdao.cpp index 747725ff068..5235ce9716e 100644 --- a/src/library/dao/trackdao.cpp +++ b/src/library/dao/trackdao.cpp @@ -396,6 +396,7 @@ void TrackDAO::addTracksPrepare() { "played," "mixxx_deleted," "header_parsed," + "source_synchronized_ms," "channels," "samplerate," "bitrate," @@ -443,6 +444,7 @@ void TrackDAO::addTracksPrepare() { ":played," ":mixxx_deleted," ":header_parsed," + ":source_synchronized_ms," ":channels," ":samplerate," ":bitrate," @@ -534,7 +536,8 @@ void bindTrackLibraryValues( pTrackLibraryQuery->bindValue(":comment", trackInfo.getComment()); pTrackLibraryQuery->bindValue(":url", track.getUrl()); pTrackLibraryQuery->bindValue(":rating", track.getRating()); - pTrackLibraryQuery->bindValue(":cuepoint", track.getCuePoint().getPosition()); + pTrackLibraryQuery->bindValue(":cuepoint", + track.getMainCuePosition().toEngineSamplePosMaybeInvalid()); pTrackLibraryQuery->bindValue(":bpm_lock", track.getBpmLocked() ? 1 : 0); pTrackLibraryQuery->bindValue(":replaygain", trackInfo.getReplayGain().getRatio()); pTrackLibraryQuery->bindValue(":replaygain_peak", trackInfo.getReplayGain().getPeak()); @@ -549,7 +552,17 @@ void bindTrackLibraryValues( trackMetadata.getStreamInfo().getDuration().toDoubleSeconds()); pTrackLibraryQuery->bindValue(":header_parsed", - track.getMetadataSynchronized() ? 1 : 0); + track.isSourceSynchronized() ? 1 : 0); + const QDateTime sourceSynchronizedAt = + track.getSourceSynchronizedAt(); + if (sourceSynchronizedAt.isValid()) { + DEBUG_ASSERT(sourceSynchronizedAt.timeSpec() == Qt::UTC); + pTrackLibraryQuery->bindValue(":source_synchronized_ms", + sourceSynchronizedAt.toMSecsSinceEpoch()); + } else { + pTrackLibraryQuery->bindValue(":source_synchronized_ms", + QVariant()); + } const PlayCounter& playCounter = track.getPlayCounter(); pTrackLibraryQuery->bindValue(":timesplayed", playCounter.getTimesPlayed()); @@ -569,14 +582,15 @@ void bindTrackLibraryValues( QString beatsVersion; QString beatsSubVersion; // Fall back on cached BPM - double dBpm = trackInfo.getBpm().getValue(); + mixxx::Bpm bpm = trackInfo.getBpm(); if (!pBeats.isNull()) { beatsBlob = pBeats->toByteArray(); beatsVersion = pBeats->getVersion(); beatsSubVersion = pBeats->getSubVersion(); - dBpm = pBeats->getBpm(); + bpm = pBeats->getBpm(); } - pTrackLibraryQuery->bindValue(":bpm", dBpm); + const double bpmValue = bpm.isValid() ? bpm.value() : mixxx::Bpm::kValueUndefined; + pTrackLibraryQuery->bindValue(":bpm", bpmValue); pTrackLibraryQuery->bindValue(":beats_version", beatsVersion); pTrackLibraryQuery->bindValue(":beats_sub_version", beatsSubVersion); pTrackLibraryQuery->bindValue(":beats", beatsBlob); @@ -828,7 +842,7 @@ TrackPointer TrackDAO::addTracksAddFile( // Initially (re-)import the metadata for the newly created track // from the file. SoundSourceProxy(pTrack).updateTrackFromSource(); - if (!pTrack->isMetadataSynchronized()) { + if (!pTrack->isSourceSynchronized()) { qWarning() << "TrackDAO::addTracksAddFile:" << "Failed to parse track metadata from file" << pTrack->getLocation(); @@ -1132,7 +1146,8 @@ bool setTrackRating(const QSqlRecord& record, const int column, bool setTrackCuePoint(const QSqlRecord& record, const int column, TrackPointer pTrack) { - pTrack->setCuePoint(CuePosition(record.value(column).toDouble())); + pTrack->setMainCuePosition(mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid( + record.value(column).toDouble())); return false; } @@ -1189,9 +1204,24 @@ bool setTrackFiletype(const QSqlRecord& record, const int column, return false; } -bool setTrackMetadataSynchronized(const QSqlRecord& record, const int column, - TrackPointer pTrack) { - pTrack->setMetadataSynchronized(record.value(column).toBool()); +bool setTrackHeaderParsed(const QSqlRecord& record, const int column, TrackPointer pTrack) { + pTrack->setHeaderParsedFromTrackDAO(record.value(column).toBool()); + return false; +} + +bool setTrackSourceSynchronizedAt(const QSqlRecord& record, const int column, TrackPointer pTrack) { + QDateTime sourceSynchronizedAt; + const QVariant value = record.value(column); + // Observation (Qt 5.15): QVariant::isValid() may return true even + // if the column value is NULL and then converts to 0 (zero). This + // is NOT desired and therefore we MUST USE QVariant::isNull() instead! + if (!value.isNull() && value.canConvert()) { + DEBUG_ASSERT(value.isValid()); + const quint64 msecsSinceEpoch = qvariant_cast(value); + sourceSynchronizedAt.setTimeSpec(Qt::UTC); + sourceSynchronizedAt.setMSecsSinceEpoch(msecsSinceEpoch); + } + pTrack->setSourceSynchronizedAt(sourceSynchronizedAt); return false; } @@ -1213,7 +1243,7 @@ bool setTrackAudioProperties( bool setTrackBeats(const QSqlRecord& record, const int column, TrackPointer pTrack) { - double bpm = record.value(column).toDouble(); + const auto bpm = mixxx::Bpm(record.value(column).toDouble()); QString beatsVersion = record.value(column + 1).toString(); QString beatsSubVersion = record.value(column + 2).toString(); QByteArray beatsBlob = record.value(column + 3).toByteArray(); @@ -1228,7 +1258,8 @@ bool setTrackBeats(const QSqlRecord& record, const int column, } } else { // Load a temorary beat grid without offset that will be replaced by the analyzer. - const auto pBeats = BeatFactory::makeBeatGrid(pTrack->getSampleRate(), bpm, 0.0); + const auto pBeats = BeatFactory::makeBeatGrid( + pTrack->getSampleRate(), bpm, mixxx::audio::kStartFramePos); pTrack->trySetBeats(pBeats); } return false; @@ -1332,7 +1363,8 @@ TrackPointer TrackDAO::getTrackById(TrackId trackId) const { {"last_played_at", setTrackLastPlayedAt}, {"played", setTrackPlayed}, {"datetime_added", setTrackDateAdded}, - {"header_parsed", setTrackMetadataSynchronized}, + {"header_parsed", setTrackHeaderParsed}, + {"source_synchronized_ms", setTrackSourceSynchronizedAt}, // Audio properties are set together at once. Do not change the // ordering of these columns or put other columns in between them! @@ -1600,6 +1632,7 @@ bool TrackDAO::updateTrack(Track* pTrack) const { "last_played_at=:last_played_at," "played=:played," "header_parsed=:header_parsed," + "source_synchronized_ms=:source_synchronized_ms," "channels=:channels," "bitrate=:bitrate," "samplerate=:samplerate," diff --git a/src/library/dlgtagfetcher.cpp b/src/library/dlgtagfetcher.cpp index 2e3eeac7ac2..5c8bfe59994 100644 --- a/src/library/dlgtagfetcher.cpp +++ b/src/library/dlgtagfetcher.cpp @@ -18,12 +18,12 @@ QStringList trackColumnValues( QStringList columnValues; columnValues.reserve(6); columnValues - << trackMetadata.getTrackInfo().getYear() + << trackMetadata.getTrackInfo().getTitle() + << trackMetadata.getTrackInfo().getArtist() << trackMetadata.getAlbumInfo().getTitle() - << trackMetadata.getAlbumInfo().getArtist() + << trackMetadata.getTrackInfo().getYear() << trackNumberAndTotal - << trackMetadata.getTrackInfo().getTitle() - << trackMetadata.getTrackInfo().getArtist(); + << trackMetadata.getAlbumInfo().getArtist(); return columnValues; } @@ -35,12 +35,12 @@ QStringList trackReleaseColumnValues( QStringList columnValues; columnValues.reserve(6); columnValues - << trackRelease.date + << trackRelease.title + << trackRelease.artist << trackRelease.albumTitle - << trackRelease.albumArtist + << trackRelease.date << trackNumberAndTotal - << trackRelease.title - << trackRelease.artist; + << trackRelease.albumArtist; return columnValues; } @@ -50,7 +50,7 @@ void addTrack( QTreeWidget* parent) { QTreeWidgetItem* item = new QTreeWidgetItem(parent, trackRow); item->setData(0, Qt::UserRole, resultIndex); - item->setData(0, Qt::TextAlignmentRole, Qt::AlignRight); + item->setData(0, Qt::TextAlignmentRole, Qt::AlignLeft); } } // anonymous namespace @@ -83,14 +83,6 @@ void DlgTagFetcher::init() { connect(&m_tagFetcher, &TagFetcher::resultAvailable, this, &DlgTagFetcher::fetchTagFinished); connect(&m_tagFetcher, &TagFetcher::fetchProgress, this, &DlgTagFetcher::fetchTagProgress); connect(&m_tagFetcher, &TagFetcher::networkError, this, &DlgTagFetcher::slotNetworkResult); - - // Resize columns, this can't be set in the ui file - results->setColumnWidth(0, 50); // Year column - results->setColumnWidth(1, 160); // Album column - results->setColumnWidth(2, 160); // Album artist column - results->setColumnWidth(3, 50); // Track (numbers) column - results->setColumnWidth(4, 160); // Title column - results->setColumnWidth(5, 160); // Artist column } void DlgTagFetcher::slotNext() { @@ -305,6 +297,12 @@ void DlgTagFetcher::updateStack() { } } + for (int i = 0; i < results->model()->columnCount(); i++) { + results->resizeColumnToContents(i); + int sectionSize = (results->columnWidth(i) + 10); + results->header()->resizeSection(i, sectionSize); + } + // Find the item that was selected last time for (int i = 0; i < results->model()->rowCount(); ++i) { const QModelIndex index = results->model()->index(i, 0); diff --git a/src/library/dlgtagfetcher.ui b/src/library/dlgtagfetcher.ui index 471061db12a..2caba2d16d4 100644 --- a/src/library/dlgtagfetcher.ui +++ b/src/library/dlgtagfetcher.ui @@ -17,7 +17,7 @@ - 2 + 0 @@ -45,34 +45,37 @@ 50 + + true + - Year + Title - Album + Artist - Album Artist + Album - Track + Year - Title + Track - Artist + Album Artist diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index 5f4b7e73b3f..1df9aa179e0 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -44,7 +44,6 @@ DlgTrackInfo::DlgTrackInfo( : QDialog(nullptr), m_pTrackModel(trackModel), m_tapFilter(this, kFilterLength, kMaxInterval), - m_dLastTapedBpm(-1.), m_pWCoverArtLabel(make_parented(this)), m_pWStarRating(make_parented(nullptr, this)) { init(); @@ -370,7 +369,7 @@ void DlgTrackInfo::updateTrackMetadataFields() { void DlgTrackInfo::reloadTrackBeats(const Track& track) { m_pBeatsClone = track.getBeats(); if (m_pBeatsClone) { - spinBpm->setValue(m_pBeatsClone->getBpm()); + spinBpm->setValue(m_pBeatsClone->getBpm().value()); } else { spinBpm->setValue(0.0); } @@ -519,45 +518,45 @@ void DlgTrackInfo::clear() { } void DlgTrackInfo::slotBpmDouble() { - m_pBeatsClone = m_pBeatsClone->scale(mixxx::Beats::DOUBLE); + m_pBeatsClone = m_pBeatsClone->scale(mixxx::Beats::BpmScale::Double); // read back the actual value - double newValue = m_pBeatsClone->getBpm(); - spinBpm->setValue(newValue); + mixxx::Bpm newValue = m_pBeatsClone->getBpm(); + spinBpm->setValue(newValue.value()); } void DlgTrackInfo::slotBpmHalve() { - m_pBeatsClone = m_pBeatsClone->scale(mixxx::Beats::HALVE); + m_pBeatsClone = m_pBeatsClone->scale(mixxx::Beats::BpmScale::Halve); // read back the actual value - double newValue = m_pBeatsClone->getBpm(); - spinBpm->setValue(newValue); + const mixxx::Bpm newValue = m_pBeatsClone->getBpm(); + spinBpm->setValue(newValue.value()); } void DlgTrackInfo::slotBpmTwoThirds() { - m_pBeatsClone = m_pBeatsClone->scale(mixxx::Beats::TWOTHIRDS); + m_pBeatsClone = m_pBeatsClone->scale(mixxx::Beats::BpmScale::TwoThirds); // read back the actual value - double newValue = m_pBeatsClone->getBpm(); - spinBpm->setValue(newValue); + const mixxx::Bpm newValue = m_pBeatsClone->getBpm(); + spinBpm->setValue(newValue.value()); } void DlgTrackInfo::slotBpmThreeFourth() { - m_pBeatsClone = m_pBeatsClone->scale(mixxx::Beats::THREEFOURTHS); + m_pBeatsClone = m_pBeatsClone->scale(mixxx::Beats::BpmScale::ThreeFourths); // read back the actual value - double newValue = m_pBeatsClone->getBpm(); - spinBpm->setValue(newValue); + const mixxx::Bpm newValue = m_pBeatsClone->getBpm(); + spinBpm->setValue(newValue.value()); } void DlgTrackInfo::slotBpmFourThirds() { - m_pBeatsClone = m_pBeatsClone->scale(mixxx::Beats::FOURTHIRDS); + m_pBeatsClone = m_pBeatsClone->scale(mixxx::Beats::BpmScale::FourThirds); // read back the actual value - double newValue = m_pBeatsClone->getBpm(); - spinBpm->setValue(newValue); + const mixxx::Bpm newValue = m_pBeatsClone->getBpm(); + spinBpm->setValue(newValue.value()); } void DlgTrackInfo::slotBpmThreeHalves() { - m_pBeatsClone = m_pBeatsClone->scale(mixxx::Beats::THREEHALVES); + m_pBeatsClone = m_pBeatsClone->scale(mixxx::Beats::BpmScale::ThreeHalves); // read back the actual value - double newValue = m_pBeatsClone->getBpm(); - spinBpm->setValue(newValue); + const mixxx::Bpm newValue = m_pBeatsClone->getBpm(); + spinBpm->setValue(newValue.value()); } void DlgTrackInfo::slotBpmClear() { @@ -580,9 +579,11 @@ void DlgTrackInfo::slotBpmConstChanged(int state) { // almost all cases. // The cue point should be set on a beat, so this seems // to be a good alternative - CuePosition cue = m_pLoadedTrack->getCuePoint(); - m_pBeatsClone = BeatFactory::makeBeatGrid( - m_pLoadedTrack->getSampleRate(), spinBpm->value(), cue.getPosition()); + const mixxx::audio::FramePos cuePosition = m_pLoadedTrack->getMainCuePosition(); + m_pBeatsClone = + BeatFactory::makeBeatGrid(m_pLoadedTrack->getSampleRate(), + mixxx::Bpm(spinBpm->value()), + cuePosition); } else { m_pBeatsClone.clear(); } @@ -599,40 +600,43 @@ void DlgTrackInfo::slotBpmTap(double averageLength, int numSamples) { if (averageLength == 0) { return; } - double averageBpm = 60.0 * 1000.0 / averageLength; + auto averageBpm = mixxx::Bpm(60.0 * 1000.0 / averageLength); averageBpm = BeatUtils::roundBpmWithinRange(averageBpm - kBpmTabRounding, averageBpm, averageBpm + kBpmTabRounding); - if (averageBpm != m_dLastTapedBpm) { - m_dLastTapedBpm = averageBpm; - spinBpm->setValue(averageBpm); + if (averageBpm != m_lastTapedBpm) { + m_lastTapedBpm = averageBpm; + spinBpm->setValue(averageBpm.value()); } } void DlgTrackInfo::slotSpinBpmValueChanged(double value) { - if (value <= 0) { + const auto bpm = mixxx::Bpm(value); + if (!bpm.isValid()) { m_pBeatsClone.clear(); return; } if (!m_pBeatsClone) { - CuePosition cue = m_pLoadedTrack->getCuePoint(); + const mixxx::audio::FramePos cuePosition = m_pLoadedTrack->getMainCuePosition(); m_pBeatsClone = BeatFactory::makeBeatGrid( - m_pLoadedTrack->getSampleRate(), value, cue.getPosition()); + m_pLoadedTrack->getSampleRate(), + bpm, + cuePosition); } - double oldValue = m_pBeatsClone->getBpm(); - if (oldValue == value) { + const mixxx::Bpm oldValue = m_pBeatsClone->getBpm(); + if (oldValue == bpm) { return; } if (m_pBeatsClone->getCapabilities() & mixxx::Beats::BEATSCAP_SETBPM) { - m_pBeatsClone = m_pBeatsClone->setBpm(value); + m_pBeatsClone = m_pBeatsClone->setBpm(bpm); } // read back the actual value - double newValue = m_pBeatsClone->getBpm(); - spinBpm->setValue(newValue); + const mixxx::Bpm newValue = m_pBeatsClone->getBpm(); + spinBpm->setValue(newValue.value()); } mixxx::UpdateResult DlgTrackInfo::updateKeyText() { @@ -668,9 +672,13 @@ void DlgTrackInfo::slotImportMetadataFromFile() { // losing existing metadata or to lose the beat grid by replacing // it with a default grid created from an imprecise BPM. // See also: https://bugs.launchpad.net/mixxx/+bug/1929311 - mixxx::TrackMetadata trackMetadata = m_pLoadedTrack->getMetadata(); + // In additiona we need to preserve all other track properties + // that are stored in TrackRecord, which serves as the underlying + // model for this dialog. + mixxx::TrackRecord trackRecord = m_pLoadedTrack->getRecord(); + mixxx::TrackMetadata trackMetadata = trackRecord.getMetadata(); QImage coverImage; - const auto [importResult, metadataSynchronized] = + const auto [importResult, sourceSynchronizedAt] = SoundSourceProxy(m_pLoadedTrack) .importTrackMetadataAndCoverImage( &trackMetadata, &coverImage); @@ -682,10 +690,9 @@ void DlgTrackInfo::slotImportMetadataFromFile() { fileAccess.info(), trackMetadata.getAlbumInfo().getTitle(), coverImage); - mixxx::TrackRecord trackRecord; trackRecord.replaceMetadataFromSource( std::move(trackMetadata), - metadataSynchronized); + sourceSynchronizedAt); trackRecord.setCoverInfo( std::move(guessedCoverInfo)); replaceTrackRecord( diff --git a/src/library/dlgtrackinfo.h b/src/library/dlgtrackinfo.h index 2991ac0220a..fdb7ccf7905 100644 --- a/src/library/dlgtrackinfo.h +++ b/src/library/dlgtrackinfo.h @@ -115,7 +115,7 @@ class DlgTrackInfo : public QDialog, public Ui::DlgTrackInfo { bool m_trackHasBeatMap; TapFilter m_tapFilter; - double m_dLastTapedBpm; + mixxx::Bpm m_lastTapedBpm; parented_ptr m_pWCoverArtLabel; parented_ptr m_pWStarRating; diff --git a/src/library/export/engineprimeexportjob.cpp b/src/library/export/engineprimeexportjob.cpp index a37b79f3839..b933ab6f8be 100644 --- a/src/library/export/engineprimeexportjob.cpp +++ b/src/library/export/engineprimeexportjob.cpp @@ -65,16 +65,6 @@ std::optional toDjinteropKey( return keyMap[key]; } -inline double playPosToSampleOffset(double playPos) { - // Play positions are twice the sample offset expected by libdjinterop. - return playPos / 2; -} - -inline double sampleOffsetToPlayPos(double sampleOffset) { - // Play positions are twice the sample offset expected by libdjinterop. - return sampleOffset * 2; -} - QString exportFile(const QSharedPointer pRequest, TrackPointer pTrack) { if (!pRequest->engineLibraryDbDir.exists()) { @@ -151,8 +141,12 @@ void exportMetadata(djinterop::database* pDatabase, snapshot.comment = pTrack->getComment().toStdString(); snapshot.composer = pTrack->getComposer().toStdString(); snapshot.key = toDjinteropKey(pTrack->getKey()); - int64_t lastModifiedMillisSinceEpoch = - pTrack->getFileInfo().lastModified().toMSecsSinceEpoch(); + int64_t lastModifiedMillisSinceEpoch = 0; + const QDateTime fileLastModified = pTrack->getFileInfo().lastModified(); + if (fileLastModified.isValid()) { + // Only defined if valid + lastModifiedMillisSinceEpoch = fileLastModified.toMSecsSinceEpoch(); + } std::chrono::system_clock::time_point lastModifiedAt{ std::chrono::milliseconds{lastModifiedMillisSinceEpoch}}; snapshot.last_modified_at = lastModifiedAt; @@ -160,9 +154,9 @@ void exportMetadata(djinterop::database* pDatabase, snapshot.rating = pTrack->getRating() * 20; // note rating is in range 0-100 // Frames used interchangeably with "samples" here. - const auto sampleCount = static_cast(pTrack->getDuration() * pTrack->getSampleRate()); + const auto frameCount = static_cast(pTrack->getDuration() * pTrack->getSampleRate()); snapshot.sampling = djinterop::sampling_info{ - static_cast(pTrack->getSampleRate()), sampleCount}; + static_cast(pTrack->getSampleRate()), frameCount}; // Set track loudness. // Note that the djinterop API method for setting loudness may be revised @@ -173,10 +167,10 @@ void exportMetadata(djinterop::database* pDatabase, snapshot.average_loudness = pTrack->getReplayGain().getRatio(); // Set main cue-point. - double cuePlayPos = pTrack->getCuePoint().getPosition(); - double cueSampleOffset = playPosToSampleOffset(cuePlayPos); - snapshot.default_main_cue = cueSampleOffset; - snapshot.adjusted_main_cue = cueSampleOffset; + mixxx::audio::FramePos cuePlayPos = pTrack->getMainCuePosition(); + // FIXME: What if the cuePlayPos is invalid? + snapshot.default_main_cue = cuePlayPos.value(); + snapshot.adjusted_main_cue = cuePlayPos.value(); // Fill in beat grid. For now, assume a constant average BPM across // the whole track. Note that points in the track are specified as @@ -189,22 +183,22 @@ void exportMetadata(djinterop::database* pDatabase, // starts at the beginning of a bar, then move backwards towards the // beginning of the track in 4-beat decrements to find the first beat // in the track that also aligns with the start of a bar. - double firstBeatPlayPos = beats->findNextBeat(0); - double cueBeatPlayPos = beats->findClosestBeat(cuePlayPos); + const auto firstBeatPlayPos = beats->firstBeat(); + const auto cueBeatPlayPos = beats->findClosestBeat(cuePlayPos); int numBeatsToCue = beats->numBeatsInRange(firstBeatPlayPos, cueBeatPlayPos); - double firstBarAlignedBeatPlayPos = beats->findNBeatsFromSample( + const auto firstBarAlignedBeatPlayPos = beats->findNBeatsFromPosition( cueBeatPlayPos, numBeatsToCue & ~0x3); // We will treat the first bar-aligned beat as beat zero. Find the // number of beats from there until the end of the track in order to // correctly assign an index for the last beat. - double lastBeatPlayPos = beats->findPrevBeat(sampleOffsetToPlayPos(sampleCount)); + const auto lastBeatPlayPos = beats->findPrevBeat(mixxx::audio::kStartFramePos + frameCount); int numBeats = beats->numBeatsInRange(firstBarAlignedBeatPlayPos, lastBeatPlayPos); if (numBeats > 0) { std::vector beatgrid{ - {0, playPosToSampleOffset(firstBarAlignedBeatPlayPos)}, - {numBeats, playPosToSampleOffset(lastBeatPlayPos)}}; - beatgrid = el::normalize_beatgrid(std::move(beatgrid), sampleCount); + {0, firstBarAlignedBeatPlayPos.value()}, + {numBeats, lastBeatPlayPos.value()}}; + beatgrid = el::normalize_beatgrid(std::move(beatgrid), frameCount); snapshot.default_beatgrid = beatgrid; snapshot.adjusted_beatgrid = beatgrid; } else { @@ -241,8 +235,15 @@ void exportMetadata(djinterop::database* pDatabase, djinterop::hot_cue hotCue{}; hotCue.label = label.toStdString(); - hotCue.sample_offset = playPosToSampleOffset(pCue->getPosition()); - hotCue.color = el::standard_pad_colors::pads[hotCueIndex]; + hotCue.sample_offset = pCue->getPosition().value(); + + auto color = mixxx::RgbColor::toQColor(pCue->getColor()); + hotCue.color = djinterop::pad_color{ + static_cast(color.red()), + static_cast(color.green()), + static_cast(color.blue()), + 255}; + snapshot.hot_cues[hotCueIndex] = hotCue; } @@ -252,6 +253,8 @@ void exportMetadata(djinterop::database* pDatabase, // from a set of stored loops (and is easily overwritten), we do not export // it to the external database here. // + // TODO: This comment above is wrong, it does support saved loops now. + // // Note also that the loops on any existing track are not modified here. // Write waveform. @@ -260,7 +263,7 @@ void exportMetadata(djinterop::database* pDatabase, if (pWaveform) { int64_t samplesPerEntry = el::required_waveform_samples_per_entry(pTrack->getSampleRate()); - int64_t externalWaveformSize = (sampleCount + samplesPerEntry - 1) / samplesPerEntry; + int64_t externalWaveformSize = (frameCount + samplesPerEntry - 1) / samplesPerEntry; std::vector externalWaveform; externalWaveform.reserve(externalWaveformSize); for (int64_t i = 0; i < externalWaveformSize; ++i) { @@ -322,7 +325,7 @@ void exportCrate( auto extCrate = pExtRootCrate->create_sub_crate(crate.getName().toStdString()); // Loop through all track ids in this crate and add. - for (const auto trackId : trackIds) { + for (const auto& trackId : trackIds) { const auto extTrackId = mixxxToEnginePrimeTrackIdMap[trackId]; extCrate.add_track(extTrackId); } diff --git a/src/library/itunes/itunesfeature.cpp b/src/library/itunes/itunesfeature.cpp index 50ecab94783..d24eb34fc26 100644 --- a/src/library/itunes/itunesfeature.cpp +++ b/src/library/itunes/itunesfeature.cpp @@ -63,9 +63,9 @@ QString localhost_token() { } // anonymous namespace ITunesFeature::ITunesFeature(Library* pLibrary, UserSettingsPointer pConfig) - : BaseExternalLibraryFeature(pLibrary, pConfig), - m_cancelImport(false), - m_icon(":/images/library/ic_library_itunes.svg") { + : BaseExternalLibraryFeature(pLibrary, pConfig, QStringLiteral("itunes")), + m_pSidebarModel(make_parented(this)), + m_cancelImport(false) { QString tableName = "itunes_library"; QString idColumn = "id"; QStringList columns; @@ -152,10 +152,6 @@ QVariant ITunesFeature::title() { return m_title; } -QIcon ITunesFeature::getIcon() { - return m_icon; -} - void ITunesFeature::bindSidebarWidget(WLibrarySidebar* pSidebarWidget) { // store the sidebar widget pointer for later use in onRightClick() m_pSidebarWidget = pSidebarWidget; @@ -237,8 +233,8 @@ void ITunesFeature::activateChild(const QModelIndex& index) { emit enableCoverArtDisplay(false); } -TreeItemModel* ITunesFeature::getChildModel() { - return &m_childModel; +TreeItemModel* ITunesFeature::sidebarModel() const { + return m_pSidebarModel; } void ITunesFeature::onRightClick(const QPoint& globalPos) { @@ -820,7 +816,7 @@ void ITunesFeature::clearTable(const QString& table_name) { void ITunesFeature::onTrackCollectionLoaded() { std::unique_ptr root(m_future.result()); if (root) { - m_childModel.setRootItem(std::move(root)); + m_pSidebarModel->setRootItem(std::move(root)); // Tell the rhythmbox track source that it should re-build its index. m_trackSource->buildIndex(); diff --git a/src/library/itunes/itunesfeature.h b/src/library/itunes/itunesfeature.h index a3cd26b1ffe..6e9ba5ab20a 100644 --- a/src/library/itunes/itunesfeature.h +++ b/src/library/itunes/itunesfeature.h @@ -1,16 +1,17 @@ #pragma once -#include -#include #include -#include #include #include +#include +#include +#include #include "library/baseexternallibraryfeature.h" #include "library/trackcollection.h" -#include "library/treeitemmodel.h" #include "library/treeitem.h" +#include "library/treeitemmodel.h" +#include "util/parented_ptr.h" class BaseExternalTrackModel; class BaseExternalPlaylistModel; @@ -24,10 +25,9 @@ class ITunesFeature : public BaseExternalLibraryFeature { static bool isSupported(); QVariant title() override; - QIcon getIcon() override; void bindSidebarWidget(WLibrarySidebar* pSidebarWidget) override; - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; public slots: void activate() override; @@ -52,7 +52,7 @@ class ITunesFeature : public BaseExternalLibraryFeature { BaseExternalTrackModel* m_pITunesTrackModel; BaseExternalPlaylistModel* m_pITunesPlaylistModel; - TreeItemModel m_childModel; + parented_ptr m_pSidebarModel; QStringList m_playlists; // a new DB connection for the worker thread QSqlDatabase m_database; @@ -69,5 +69,4 @@ class ITunesFeature : public BaseExternalLibraryFeature { QSharedPointer m_trackSource; QPointer m_pSidebarWidget; - QIcon m_icon; }; diff --git a/src/library/library.cpp b/src/library/library.cpp index cf0191cf03a..33eef5602f9 100644 --- a/src/library/library.cpp +++ b/src/library/library.cpp @@ -606,3 +606,11 @@ std::unique_ptr Library::makeLibraryExporter( parent, m_pConfig, m_pTrackCollectionManager); } #endif + +LibraryTableModel* Library::trackTableModel() const { + VERIFY_OR_DEBUG_ASSERT(m_pMixxxLibraryFeature) { + return nullptr; + } + + return m_pMixxxLibraryFeature->trackTableModel(); +} diff --git a/src/library/library.h b/src/library/library.h index ec7198f9221..fc6624cc354 100644 --- a/src/library/library.h +++ b/src/library/library.h @@ -73,6 +73,14 @@ class Library: public QObject { void addFeature(LibraryFeature* feature); + /// Needed for exposing models to QML + LibraryTableModel* trackTableModel() const; + + /// Needed for exposing sidebar to QML + SidebarModel* sidebarModel() const { + return m_pSidebarModel.get(); + } + int getTrackTableRowHeight() const { return m_iTrackTableRowHeight; } diff --git a/src/library/libraryfeature.cpp b/src/library/libraryfeature.cpp index 20de2aa3189..51ad6ae3fac 100644 --- a/src/library/libraryfeature.cpp +++ b/src/library/libraryfeature.cpp @@ -15,15 +15,21 @@ namespace { const mixxx::Logger kLogger("LibraryFeature"); +const QString kIconPath = QStringLiteral(":/images/library/ic_library_%1.svg"); } // anonymous namespace LibraryFeature::LibraryFeature( Library* pLibrary, - UserSettingsPointer pConfig) + UserSettingsPointer pConfig, + const QString& iconName) : QObject(pLibrary), m_pLibrary(pLibrary), - m_pConfig(pConfig) { + m_pConfig(pConfig), + m_iconName(iconName) { + if (!m_iconName.isEmpty()) { + m_icon = QIcon(kIconPath.arg(m_iconName)); + } } QStringList LibraryFeature::getPlaylistFiles(QFileDialog::FileMode mode) const { diff --git a/src/library/libraryfeature.h b/src/library/libraryfeature.h index 465b48c23f2..a48f59b1b15 100644 --- a/src/library/libraryfeature.h +++ b/src/library/libraryfeature.h @@ -29,11 +29,25 @@ class LibraryFeature : public QObject { public: LibraryFeature( Library* pLibrary, - UserSettingsPointer pConfig); + UserSettingsPointer pConfig, + const QString& iconName); ~LibraryFeature() override = default; virtual QVariant title() = 0; - virtual QIcon getIcon() = 0; + + /// Returns the icon name. + /// + /// This is useful for QML skins that need to build a URL anyway and may use their own icon theme. + QString iconName() const { + return m_iconName; + } + + /// Returns the icon. + /// + /// This is used by legacy QWidget skins that display a QIcon directly. + QIcon icon() const { + return m_icon; + } virtual bool dropAccept(const QList& urls, QObject* pSource) { Q_UNUSED(urls); @@ -62,7 +76,7 @@ class LibraryFeature : public QObject { virtual void bindLibraryWidget(WLibrary* /* libraryWidget */, KeyboardEventFilter* /* keyboard */) {} virtual void bindSidebarWidget(WLibrarySidebar* /* sidebar widget */) {} - virtual TreeItemModel* getChildModel() = 0; + virtual TreeItemModel* sidebarModel() const = 0; virtual bool hasTrackTable() { return false; @@ -134,4 +148,7 @@ class LibraryFeature : public QObject { private: QStringList getPlaylistFiles(QFileDialog::FileMode mode) const; + + QString m_iconName; + QIcon m_icon; }; diff --git a/src/library/mixxxlibraryfeature.cpp b/src/library/mixxxlibraryfeature.cpp index 83f80252307..20e9866caa4 100644 --- a/src/library/mixxxlibraryfeature.cpp +++ b/src/library/mixxxlibraryfeature.cpp @@ -69,12 +69,12 @@ const QStringList DEFAULT_COLUMNS = { MixxxLibraryFeature::MixxxLibraryFeature(Library* pLibrary, UserSettingsPointer pConfig) - : LibraryFeature(pLibrary, pConfig), + : LibraryFeature(pLibrary, pConfig, QStringLiteral("tracks")), kMissingTitle(tr("Missing Tracks")), kHiddenTitle(tr("Hidden Tracks")), - m_icon(":/images/library/ic_library_tracks.svg"), m_pTrackCollection(pLibrary->trackCollectionManager()->internalCollection()), m_pLibraryTableModel(nullptr), + m_pSidebarModel(make_parented(this)), m_pMissingView(nullptr), m_pHiddenView(nullptr) { QStringList columns = DEFAULT_COLUMNS; @@ -110,7 +110,7 @@ MixxxLibraryFeature::MixxxLibraryFeature(Library* pLibrary, pRootItem->appendChild(kMissingTitle); pRootItem->appendChild(kHiddenTitle); - m_childModel.setRootItem(std::move(pRootItem)); + m_pSidebarModel->setRootItem(std::move(pRootItem)); #ifdef __ENGINEPRIME__ m_pExportLibraryAction = make_parented(tr("Export to Engine Prime"), this); @@ -144,12 +144,8 @@ QVariant MixxxLibraryFeature::title() { return tr("Tracks"); } -QIcon MixxxLibraryFeature::getIcon() { - return m_icon; -} - -TreeItemModel* MixxxLibraryFeature::getChildModel() { - return &m_childModel; +TreeItemModel* MixxxLibraryFeature::sidebarModel() const { + return m_pSidebarModel; } void MixxxLibraryFeature::refreshLibraryModels() { diff --git a/src/library/mixxxlibraryfeature.h b/src/library/mixxxlibraryfeature.h index c84d29c38c3..3ecd22a8196 100644 --- a/src/library/mixxxlibraryfeature.h +++ b/src/library/mixxxlibraryfeature.h @@ -34,10 +34,9 @@ class MixxxLibraryFeature final : public LibraryFeature { ~MixxxLibraryFeature() override = default; QVariant title() override; - QIcon getIcon() override; bool dropAccept(const QList& urls, QObject* pSource) override; bool dragMoveAccept(const QUrl& url) override; - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; void bindLibraryWidget(WLibrary* pLibrary, KeyboardEventFilter* pKeyboard) override; #ifdef __ENGINEPRIME__ @@ -48,6 +47,10 @@ class MixxxLibraryFeature final : public LibraryFeature { return true; } + LibraryTableModel* trackTableModel() const { + return m_pLibraryTableModel; + } + void searchAndActivate(const QString& query); public slots: @@ -67,13 +70,12 @@ class MixxxLibraryFeature final : public LibraryFeature { private: const QString kMissingTitle; const QString kHiddenTitle; - const QIcon m_icon; TrackCollection* const m_pTrackCollection; QSharedPointer m_pBaseTrackCache; LibraryTableModel* m_pLibraryTableModel; - TreeItemModel m_childModel; + parented_ptr m_pSidebarModel; DlgMissing* m_pMissingView; DlgHidden* m_pHiddenView; diff --git a/src/library/recording/recordingfeature.cpp b/src/library/recording/recordingfeature.cpp index 43655334291..8dc87e373b2 100644 --- a/src/library/recording/recordingfeature.cpp +++ b/src/library/recording/recordingfeature.cpp @@ -16,23 +16,19 @@ const QString kViewName = QStringLiteral("Recording"); } // anonymous namespace RecordingFeature::RecordingFeature(Library* pLibrary, - UserSettingsPointer pConfig, - RecordingManager* pRecordingManager) - : LibraryFeature(pLibrary, pConfig), + UserSettingsPointer pConfig, + RecordingManager* pRecordingManager) + : LibraryFeature(pLibrary, pConfig, QStringLiteral("recordings")), m_pRecordingManager(pRecordingManager), - m_icon(":/images/library/ic_library_recordings.svg") { + m_pSidebarModel(new FolderTreeModel(this)) { } QVariant RecordingFeature::title() { return QVariant(tr("Recordings")); } -QIcon RecordingFeature::getIcon() { - return m_icon; -} - -TreeItemModel* RecordingFeature::getChildModel() { - return &m_childModel; +TreeItemModel* RecordingFeature::sidebarModel() const { + return m_pSidebarModel; } void RecordingFeature::bindLibraryWidget(WLibrary* pLibraryWidget, KeyboardEventFilter *keyboard) { diff --git a/src/library/recording/recordingfeature.h b/src/library/recording/recordingfeature.h index 61b26ad7821..daae72076b8 100644 --- a/src/library/recording/recordingfeature.h +++ b/src/library/recording/recordingfeature.h @@ -20,12 +20,11 @@ class RecordingFeature final : public LibraryFeature { ~RecordingFeature() override = default; QVariant title() override; - QIcon getIcon() override; void bindLibraryWidget(WLibrary* libraryWidget, KeyboardEventFilter* keyboard) override; - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; public slots: void activate() override; @@ -37,7 +36,6 @@ class RecordingFeature final : public LibraryFeature { private: RecordingManager* const m_pRecordingManager; - const QIcon m_icon; - FolderTreeModel m_childModel; + FolderTreeModel* m_pSidebarModel; }; diff --git a/src/library/rekordbox/rekordboxfeature.cpp b/src/library/rekordbox/rekordboxfeature.cpp index 0e7a0d01552..586c9b51385 100644 --- a/src/library/rekordbox/rekordboxfeature.cpp +++ b/src/library/rekordbox/rekordboxfeature.cpp @@ -65,8 +65,8 @@ constexpr mixxx::RgbColor kColorForIDPurple(0x9808F8); constexpr mixxx::RgbColor kColorForIDNoColor(0x0); struct memory_cue_loop_t { - double startPosition; - double endPosition; + mixxx::audio::FramePos startPosition; + mixxx::audio::FramePos endPosition; QString comment; mixxx::RgbColor::optional_t color; }; @@ -855,8 +855,8 @@ void clearDeviceTables(QSqlDatabase& database, TreeItem* child) { } void setHotCue(TrackPointer track, - double startPosition, - double endPosition, + mixxx::audio::FramePos startPosition, + mixxx::audio::FramePos endPosition, int id, const QString& label, mixxx::RgbColor::optional_t color) { @@ -870,7 +870,7 @@ void setHotCue(TrackPointer track, } mixxx::CueType type = mixxx::CueType::HotCue; - if (endPosition != Cue::kNoPosition) { + if (endPosition.isValid()) { type = mixxx::CueType::Loop; } @@ -905,8 +905,7 @@ void readAnalyze(TrackPointer track, rekordbox_anlz_t anlz = rekordbox_anlz_t(&ks); - double sampleRateKhz = sampleRate / 1000.0; - double samples = sampleRateKhz * mixxx::kEngineChannelCount; + const double sampleRateKhz = sampleRate / 1000.0; QList memoryCuesAndLoops; int lastHotCueIndex = 0; @@ -925,7 +924,7 @@ void readAnalyze(TrackPointer track, static_cast( (*section)->body()); - QVector beats; + QVector beats; for (std::vector::iterator beat = beatGridTag->beats()->begin(); @@ -936,7 +935,7 @@ void readAnalyze(TrackPointer track, if (time < 1) { time = 1; } - beats << (sampleRateKhz * static_cast(time)); + beats << mixxx::audio::FramePos(sampleRateKhz * static_cast(time)); } const auto pBeats = mixxx::BeatMap::makeBeatMap( @@ -963,7 +962,8 @@ void readAnalyze(TrackPointer track, if (time < 1) { time = 1; } - double position = samples * static_cast(time); + const auto position = mixxx::audio::FramePos( + sampleRateKhz * static_cast(time)); switch (cuesTag->type()) { case rekordbox_anlz_t::CUE_LIST_TYPE_MEMORY_CUES: { @@ -971,7 +971,7 @@ void readAnalyze(TrackPointer track, case rekordbox_anlz_t::CUE_ENTRY_TYPE_MEMORY_CUE: { memory_cue_loop_t memoryCue; memoryCue.startPosition = position; - memoryCue.endPosition = Cue::kNoPosition; + memoryCue.endPosition = mixxx::audio::kInvalidFramePos; memoryCue.color = mixxx::RgbColor::nullopt(); memoryCuesAndLoops << memoryCue; } break; @@ -984,7 +984,8 @@ void readAnalyze(TrackPointer track, memory_cue_loop_t loop; loop.startPosition = position; - loop.endPosition = samples * static_cast(endTime); + loop.endPosition = mixxx::audio::FramePos( + sampleRateKhz * static_cast(endTime)); loop.color = mixxx::RgbColor::nullopt(); memoryCuesAndLoops << loop; } break; @@ -998,7 +999,7 @@ void readAnalyze(TrackPointer track, setHotCue( track, position, - Cue::kNoPosition, + mixxx::audio::kInvalidFramePos, hotCueIndex, QString(), mixxx::RgbColor::nullopt()); @@ -1024,7 +1025,8 @@ void readAnalyze(TrackPointer track, if (time < 1) { time = 1; } - double position = samples * static_cast(time); + const auto position = mixxx::audio::FramePos( + sampleRateKhz * static_cast(time)); switch (cuesExtendedTag->type()) { case rekordbox_anlz_t::CUE_LIST_TYPE_MEMORY_CUES: { @@ -1032,7 +1034,7 @@ void readAnalyze(TrackPointer track, case rekordbox_anlz_t::CUE_ENTRY_TYPE_MEMORY_CUE: { memory_cue_loop_t memoryCue; memoryCue.startPosition = position; - memoryCue.endPosition = Cue::kNoPosition; + memoryCue.endPosition = mixxx::audio::kInvalidFramePos; memoryCue.comment = toUnicode((*cueExtendedEntry)->comment()); memoryCue.color = colorFromID(static_cast( (*cueExtendedEntry)->color_id())); @@ -1050,7 +1052,8 @@ void readAnalyze(TrackPointer track, memory_cue_loop_t loop; loop.startPosition = position; - loop.endPosition = samples * static_cast(endTime); + loop.endPosition = mixxx::audio::FramePos( + sampleRateKhz * static_cast(endTime)); loop.comment = toUnicode((*cueExtendedEntry)->comment()); loop.color = colorFromID(static_cast((*cueExtendedEntry)->color_id())); memoryCuesAndLoops << loop; @@ -1064,7 +1067,7 @@ void readAnalyze(TrackPointer track, } setHotCue(track, position, - Cue::kNoPosition, + mixxx::audio::kInvalidFramePos, hotCueIndex, toUnicode((*cueExtendedEntry)->comment()), mixxx::RgbColor(qRgb( @@ -1097,9 +1100,9 @@ void readAnalyze(TrackPointer track, memoryCueOrLoopIndex++) { memory_cue_loop_t memoryCueOrLoop = memoryCuesAndLoops[memoryCueOrLoopIndex]; - if (!mainCueFound && memoryCueOrLoop.endPosition == Cue::kNoPosition) { + if (!mainCueFound && !memoryCueOrLoop.endPosition.isValid()) { // Set first chronological memory cue as Mixxx MainCue - track->setCuePoint(CuePosition(memoryCueOrLoop.startPosition)); + track->setMainCuePosition(memoryCueOrLoop.startPosition); CuePointer pMainCue = track->findCueByType(mixxx::CueType::MainCue); pMainCue->setLabel(memoryCueOrLoop.comment); pMainCue->setColor(*memoryCueOrLoop.color); @@ -1325,8 +1328,8 @@ bool RekordboxPlaylistModel::isColumnInternal(int column) { RekordboxFeature::RekordboxFeature( Library* pLibrary, UserSettingsPointer pConfig) - : BaseExternalLibraryFeature(pLibrary, pConfig), - m_icon(":/images/library/ic_library_rekordbox.svg") { + : BaseExternalLibraryFeature(pLibrary, pConfig, QStringLiteral("rekordbox")), + m_pSidebarModel(make_parented(this)) { QString tableName = kRekordboxLibraryTable; QString idColumn = LIBRARYTABLE_ID; QStringList columns; @@ -1391,7 +1394,7 @@ RekordboxFeature::RekordboxFeature( this, &RekordboxFeature::onTracksFound); // initialize the model - m_childModel.setRootItem(TreeItem::newRoot(this)); + m_pSidebarModel->setRootItem(TreeItem::newRoot(this)); } RekordboxFeature::~RekordboxFeature() { @@ -1438,16 +1441,12 @@ QVariant RekordboxFeature::title() { return m_title; } -QIcon RekordboxFeature::getIcon() { - return m_icon; -} - bool RekordboxFeature::isSupported() { return true; } -TreeItemModel* RekordboxFeature::getChildModel() { - return &m_childModel; +TreeItemModel* RekordboxFeature::sidebarModel() const { + return m_pSidebarModel; } QString RekordboxFeature::formatRootViewHtml() const { @@ -1554,7 +1553,7 @@ void RekordboxFeature::activateChild(const QModelIndex& index) { void RekordboxFeature::onRekordboxDevicesFound() { QList foundDevices = m_devicesFuture.result(); - TreeItem* root = m_childModel.getRootItem(); + TreeItem* root = m_pSidebarModel->getRootItem(); QSqlDatabase database = m_pTrackCollection->database(); @@ -1575,7 +1574,7 @@ void RekordboxFeature::onRekordboxDevicesFound() { if (root->childRows() > 0) { // Devices have since been unmounted - m_childModel.removeRows(0, root->childRows()); + m_pSidebarModel->removeRows(0, root->childRows()); } } else { for (int deviceIndex = 0; deviceIndex < root->childRows(); deviceIndex++) { @@ -1595,7 +1594,7 @@ void RekordboxFeature::onRekordboxDevicesFound() { // Device has since been unmounted, cleanup DB clearDeviceTables(database, child); - m_childModel.removeRows(deviceIndex, 1); + m_pSidebarModel->removeRows(deviceIndex, 1); } } @@ -1620,7 +1619,7 @@ void RekordboxFeature::onRekordboxDevicesFound() { } if (!childrenToAdd.empty()) { - m_childModel.insertTreeItemRows(childrenToAdd, 0); + m_pSidebarModel->insertTreeItemRows(childrenToAdd, 0); } } @@ -1631,9 +1630,15 @@ void RekordboxFeature::onRekordboxDevicesFound() { void RekordboxFeature::onTracksFound() { qDebug() << "onTracksFound"; - m_childModel.triggerRepaint(); + m_pSidebarModel->triggerRepaint(); - QString devicePlaylist = m_tracksFuture.result(); + QString devicePlaylist; + try { + devicePlaylist = m_tracksFuture.result(); + } catch (const std::exception& e) { + qWarning() << "Failed to load Rekordbox database:" << e.what(); + return; + } qDebug() << "Show Rekordbox Device Playlist: " << devicePlaylist; diff --git a/src/library/rekordbox/rekordboxfeature.h b/src/library/rekordbox/rekordboxfeature.h index c1388cef3f1..0d3c607c076 100644 --- a/src/library/rekordbox/rekordboxfeature.h +++ b/src/library/rekordbox/rekordboxfeature.h @@ -28,13 +28,13 @@ #include #include #include - #include #include "library/baseexternallibraryfeature.h" #include "library/baseexternalplaylistmodel.h" #include "library/baseexternaltrackmodel.h" #include "library/treeitemmodel.h" +#include "util/parented_ptr.h" class TrackCollectionManager; class BaseExternalPlaylistModel; @@ -59,12 +59,11 @@ class RekordboxFeature : public BaseExternalLibraryFeature { ~RekordboxFeature() override; QVariant title() override; - QIcon getIcon() override; static bool isSupported(); void bindLibraryWidget(WLibrary* libraryWidget, KeyboardEventFilter* keyboard) override; - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; public slots: void activate() override; @@ -80,7 +79,7 @@ class RekordboxFeature : public BaseExternalLibraryFeature { QString formatRootViewHtml() const; BaseSqlTableModel* getPlaylistModelForPlaylist(const QString& playlist) override; - TreeItemModel m_childModel; + parented_ptr m_pSidebarModel; RekordboxPlaylistModel* m_pRekordboxPlaylistModel; QFutureWatcher> m_devicesFutureWatcher; @@ -90,5 +89,4 @@ class RekordboxFeature : public BaseExternalLibraryFeature { QString m_title; QSharedPointer m_trackSource; - QIcon m_icon; }; diff --git a/src/library/rhythmbox/rhythmboxfeature.cpp b/src/library/rhythmbox/rhythmboxfeature.cpp index 5607d112585..ee2a12d7111 100644 --- a/src/library/rhythmbox/rhythmboxfeature.cpp +++ b/src/library/rhythmbox/rhythmboxfeature.cpp @@ -15,9 +15,9 @@ #include "moc_rhythmboxfeature.cpp" RhythmboxFeature::RhythmboxFeature(Library* pLibrary, UserSettingsPointer pConfig) - : BaseExternalLibraryFeature(pLibrary, pConfig), - m_cancelImport(false), - m_icon(":/images/library/ic_library_rhythmbox.svg") { + : BaseExternalLibraryFeature(pLibrary, pConfig, QStringLiteral("rhythmbox")), + m_pSidebarModel(make_parented(this)), + m_cancelImport(false) { QString tableName = "rhythmbox_library"; QString idColumn = "id"; QStringList columns; @@ -108,12 +108,8 @@ QVariant RhythmboxFeature::title() { return m_title; } -QIcon RhythmboxFeature::getIcon() { - return m_icon; -} - -TreeItemModel* RhythmboxFeature::getChildModel() { - return &m_childModel; +TreeItemModel* RhythmboxFeature::sidebarModel() const { + return m_pSidebarModel; } void RhythmboxFeature::activate() { @@ -432,7 +428,7 @@ void RhythmboxFeature::clearTable(const QString& table_name) { void RhythmboxFeature::onTrackCollectionLoaded() { std::unique_ptr root(m_track_future.result()); if (root) { - m_childModel.setRootItem(std::move(root)); + m_pSidebarModel->setRootItem(std::move(root)); // Tell the rhythmbox track source that it should re-build its index. m_trackSource->buildIndex(); diff --git a/src/library/rhythmbox/rhythmboxfeature.h b/src/library/rhythmbox/rhythmboxfeature.h index fd2ef67f76c..c4bfa546376 100644 --- a/src/library/rhythmbox/rhythmboxfeature.h +++ b/src/library/rhythmbox/rhythmboxfeature.h @@ -1,15 +1,16 @@ #pragma once +#include +#include #include -#include #include -#include #include -#include +#include #include "library/baseexternallibraryfeature.h" -#include "library/treeitemmodel.h" #include "library/trackcollection.h" +#include "library/treeitemmodel.h" +#include "util/parented_ptr.h" class BaseExternalTrackModel; class BaseExternalPlaylistModel; @@ -22,9 +23,8 @@ class RhythmboxFeature : public BaseExternalLibraryFeature { static bool isSupported(); QVariant title(); - QIcon getIcon(); - TreeItemModel* getChildModel(); + TreeItemModel* sidebarModel() const; // processes the music collection TreeItem* importMusicCollection(); // processes the playlist entries @@ -54,9 +54,8 @@ class RhythmboxFeature : public BaseExternalLibraryFeature { QFutureWatcher m_track_watcher; QFuture m_track_future; - TreeItemModel m_childModel; + parented_ptr m_pSidebarModel; bool m_cancelImport; QSharedPointer m_trackSource; - QIcon m_icon; }; diff --git a/src/library/serato/seratofeature.cpp b/src/library/serato/seratofeature.cpp index b9fe1182e74..f2c34ae2c36 100644 --- a/src/library/serato/seratofeature.cpp +++ b/src/library/serato/seratofeature.cpp @@ -846,8 +846,8 @@ bool dropTable(QSqlDatabase& database, const QString& tableName) { SeratoFeature::SeratoFeature( Library* pLibrary, UserSettingsPointer pConfig) - : BaseExternalLibraryFeature(pLibrary, pConfig), - m_icon(":/images/library/ic_library_serato.svg") { + : BaseExternalLibraryFeature(pLibrary, pConfig, QStringLiteral("serato")), + m_pSidebarModel(make_parented(this)) { QStringList columns; columns << LIBRARYTABLE_ID << LIBRARYTABLE_TITLE @@ -912,7 +912,7 @@ SeratoFeature::SeratoFeature( &SeratoFeature::onTracksFound); // initialize the model - m_childModel.setRootItem(TreeItem::newRoot(this)); + m_pSidebarModel->setRootItem(TreeItem::newRoot(this)); } SeratoFeature::~SeratoFeature() { @@ -959,16 +959,12 @@ QVariant SeratoFeature::title() { return m_title; } -QIcon SeratoFeature::getIcon() { - return m_icon; -} - bool SeratoFeature::isSupported() { return true; } -TreeItemModel* SeratoFeature::getChildModel() { - return &m_childModel; +TreeItemModel* SeratoFeature::sidebarModel() const { + return m_pSidebarModel; } QString SeratoFeature::formatRootViewHtml() const { @@ -1059,7 +1055,7 @@ void SeratoFeature::activateChild(const QModelIndex& index) { void SeratoFeature::onSeratoDatabasesFound() { QList foundDatabases = m_databasesFuture.result(); - TreeItem* root = m_childModel.getRootItem(); + TreeItem* root = m_pSidebarModel->getRootItem(); QSqlDatabase database = m_pTrackCollection->database(); @@ -1068,7 +1064,7 @@ void SeratoFeature::onSeratoDatabasesFound() { if (root->childRows() > 0) { // Devices have since been unmounted - m_childModel.removeRows(0, root->childRows()); + m_pSidebarModel->removeRows(0, root->childRows()); } } else { for (int databaseIndex = 0; databaseIndex < root->childRows(); databaseIndex++) { @@ -1087,7 +1083,7 @@ void SeratoFeature::onSeratoDatabasesFound() { if (removeChild) { // Device has since been unmounted, cleanup DB - m_childModel.removeRows(databaseIndex, 1); + m_pSidebarModel->removeRows(databaseIndex, 1); } } @@ -1112,7 +1108,7 @@ void SeratoFeature::onSeratoDatabasesFound() { } if (!childrenToAdd.empty()) { - m_childModel.insertTreeItemRows(childrenToAdd, 0); + m_pSidebarModel->insertTreeItemRows(childrenToAdd, 0); } } @@ -1123,7 +1119,7 @@ void SeratoFeature::onSeratoDatabasesFound() { void SeratoFeature::onTracksFound() { qDebug() << "onTracksFound"; - m_childModel.triggerRepaint(); + m_pSidebarModel->triggerRepaint(); QString databasePlaylist = m_tracksFuture.result(); diff --git a/src/library/serato/seratofeature.h b/src/library/serato/seratofeature.h index 515add942e8..1f19325b2f4 100644 --- a/src/library/serato/seratofeature.h +++ b/src/library/serato/seratofeature.h @@ -21,6 +21,7 @@ #include "library/baseexternaltrackmodel.h" #include "library/serato/seratoplaylistmodel.h" #include "library/treeitemmodel.h" +#include "util/parented_ptr.h" class SeratoFeature : public BaseExternalLibraryFeature { Q_OBJECT @@ -29,12 +30,11 @@ class SeratoFeature : public BaseExternalLibraryFeature { ~SeratoFeature() override; QVariant title() override; - QIcon getIcon() override; static bool isSupported(); void bindLibraryWidget(WLibrary* libraryWidget, KeyboardEventFilter* keyboard) override; - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; public slots: void activate() override; @@ -50,7 +50,7 @@ class SeratoFeature : public BaseExternalLibraryFeature { QString formatRootViewHtml() const; BaseSqlTableModel* getPlaylistModelForPlaylist(const QString& playlist) override; - TreeItemModel m_childModel; + parented_ptr m_pSidebarModel; SeratoPlaylistModel* m_pSeratoPlaylistModel; QFutureWatcher> m_databasesFutureWatcher; @@ -60,5 +60,4 @@ class SeratoFeature : public BaseExternalLibraryFeature { QString m_title; QSharedPointer m_trackSource; - QIcon m_icon; }; diff --git a/src/library/sidebarmodel.cpp b/src/library/sidebarmodel.cpp index eabd0f09213..73e8c48764b 100644 --- a/src/library/sidebarmodel.cpp +++ b/src/library/sidebarmodel.cpp @@ -18,6 +18,13 @@ namespace { // been chosen as a compromise between usability and responsiveness. const int kPressedUntilClickedTimeoutMillis = 300; +const QHash kRoleNames = { + // Only roles that are useful in QML are added here. + {Qt::DisplayRole, "display"}, + {Qt::ToolTipRole, "tooltip"}, + {SidebarModel::IconNameRole, "iconName"}, +}; + } // anonymous namespace SidebarModel::SidebarModel( @@ -47,7 +54,7 @@ void SidebarModel::addLibraryFeature(LibraryFeature* pFeature) { this, &SidebarModel::slotFeatureSelect); - QAbstractItemModel* model = pFeature->getChildModel(); + QAbstractItemModel* model = pFeature->sidebarModel(); connect(model, &QAbstractItemModel::modelAboutToBeReset, @@ -110,7 +117,7 @@ QModelIndex SidebarModel::index(int row, int column, * we return its associated childmodel */ if (parent.internalPointer() == this) { - const QAbstractItemModel* childModel = m_sFeatures[parent.row()]->getChildModel(); + const QAbstractItemModel* childModel = m_sFeatures[parent.row()]->sidebarModel(); QModelIndex childIndex = childModel->index(row, column); TreeItem* pTreeItem = static_cast(childIndex.internalPointer()); if (pTreeItem && childIndex.isValid()) { @@ -181,7 +188,7 @@ int SidebarModel::rowCount(const QModelIndex& parent) const { //qDebug() << "SidebarModel::rowCount parent=" << parent.getData(); if (parent.isValid()) { if (parent.internalPointer() == this) { - return m_sFeatures[parent.row()]->getChildModel()->rowCount(); + return m_sFeatures[parent.row()]->sidebarModel()->rowCount(); } else { // We support tree models deeper than 1 level TreeItem* pTreeItem = static_cast(parent.internalPointer()); @@ -209,7 +216,7 @@ bool SidebarModel::hasChildren(const QModelIndex& parent) const { TreeItem* pTreeItem = static_cast(parent.internalPointer()); if (pTreeItem) { LibraryFeature* pFeature = pTreeItem->feature(); - return pFeature->getChildModel()->hasChildren(parent); + return pFeature->sidebarModel()->hasChildren(parent); } } } @@ -226,40 +233,52 @@ QVariant SidebarModel::data(const QModelIndex& index, int role) const { if (index.internalPointer() == this) { //If it points to SidebarModel - if (role == Qt::DisplayRole) { + switch (role) { + case Qt::DisplayRole: return m_sFeatures[index.row()]->title(); - } else if (role == Qt::DecorationRole) { - return m_sFeatures[index.row()]->getIcon(); + case Qt::DecorationRole: + return m_sFeatures[index.row()]->icon(); + case SidebarModel::IconNameRole: + return m_sFeatures[index.row()]->iconName(); + default: + return QVariant(); } - } - - if (index.internalPointer() != this) { + } else { // If it points to a TreeItem TreeItem* pTreeItem = static_cast(index.internalPointer()); - if (pTreeItem) { - if (role == Qt::DisplayRole) { + if (!pTreeItem) { + return QVariant(); + } + + switch (role) { + case Qt::DisplayRole: + return pTreeItem->getLabel(); + case Qt::ToolTipRole: { + // If it's the "Quick Links" node, display it's name + if (pTreeItem->getData().toString() == QUICK_LINK_NODE) { return pTreeItem->getLabel(); - } else if (role == Qt::ToolTipRole) { - // If it's the "Quick Links" node, display it's name - if (pTreeItem->getData().toString() == QUICK_LINK_NODE) { - return pTreeItem->getLabel(); - } else { - return pTreeItem->getData(); - } - } else if (role == TreeItemModel::kDataRole) { - // We use Qt::UserRole to ask for the datapath. - return pTreeItem->getData(); - } else if (role == Qt::FontRole) { - QFont font; - font.setBold(pTreeItem->isBold()); - return font; - } else if (role == Qt::DecorationRole) { - return pTreeItem->getIcon(); } + return pTreeItem->getData(); + } + case Qt::FontRole: { + QFont font; + font.setBold(pTreeItem->isBold()); + return font; + } + case Qt::DecorationRole: + return pTreeItem->getIcon(); + case SidebarModel::DataRole: + return pTreeItem->getData(); + case SidebarModel::IconNameRole: + // TODO: Add support for icon names in tree items + default: + return QVariant(); } } +} - return QVariant(); +QHash SidebarModel::roleNames() const { + return kRoleNames; } void SidebarModel::startPressedUntilClickedTimer(const QModelIndex& pressedIndex) { @@ -409,7 +428,7 @@ QModelIndex SidebarModel::translateIndex( //Comment from Tobias Rafreider --> Dead Code???? for (int i = 0; i < m_sFeatures.size(); ++i) { - if (m_sFeatures[i]->getChildModel() == pModel) { + if (m_sFeatures[i]->sidebarModel() == pModel) { translatedIndex = createIndex(i, 0, this); } } diff --git a/src/library/sidebarmodel.h b/src/library/sidebarmodel.h index 25cee03ecf0..6327fca1333 100644 --- a/src/library/sidebarmodel.h +++ b/src/library/sidebarmodel.h @@ -15,6 +15,12 @@ class SidebarModel : public QAbstractItemModel { // for parented_ptr using QObject::parent; + enum Roles { + IconNameRole = Qt::UserRole + 1, + DataRole, + }; + Q_ENUM(Roles); + explicit SidebarModel( QObject* parent = nullptr); ~SidebarModel() override = default; @@ -32,6 +38,7 @@ class SidebarModel : public QAbstractItemModel { int columnCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + QHash roleNames() const override; bool dropAccept(const QModelIndex& index, const QList& urls, QObject* pSource); bool dragMoveAccept(const QModelIndex& index, const QUrl& url); bool hasChildren(const QModelIndex& parent = QModelIndex()) const override; diff --git a/src/library/trackset/baseplaylistfeature.cpp b/src/library/trackset/baseplaylistfeature.cpp index 47360198064..956d68026aa 100644 --- a/src/library/trackset/baseplaylistfeature.cpp +++ b/src/library/trackset/baseplaylistfeature.cpp @@ -31,8 +31,9 @@ constexpr QChar kUnsafeFilenameReplacement = '-'; BasePlaylistFeature::BasePlaylistFeature(Library* pLibrary, UserSettingsPointer pConfig, PlaylistTableModel* pModel, - const QString& rootViewName) - : BaseTrackSetFeature(pLibrary, pConfig, rootViewName), + const QString& rootViewName, + const QString& iconName) + : BaseTrackSetFeature(pLibrary, pConfig, rootViewName, iconName), m_playlistDao(pLibrary->trackCollectionManager() ->internalCollection() ->getPlaylistDAO()), @@ -369,7 +370,7 @@ int BasePlaylistFeature::getSiblingPlaylistIdOf(QModelIndex& start) { for (int i = start.row() + 1; i >= (start.row() - 1); i -= 2) { QModelIndex nextIndex = start.sibling(i, start.column()); if (nextIndex.isValid()) { - TreeItem* pTreeItem = m_childModel.getItem(nextIndex); + TreeItem* pTreeItem = m_pSidebarModel->getItem(nextIndex); DEBUG_ASSERT(pTreeItem != nullptr); if (!pTreeItem->hasChildren()) { return playlistIdFromIndex(nextIndex); @@ -656,8 +657,8 @@ void BasePlaylistFeature::slotAnalyzePlaylist() { } } -TreeItemModel* BasePlaylistFeature::getChildModel() { - return &m_childModel; +TreeItemModel* BasePlaylistFeature::sidebarModel() const { + return m_pSidebarModel; } void BasePlaylistFeature::bindLibraryWidget(WLibrary* libraryWidget, @@ -692,9 +693,9 @@ void BasePlaylistFeature::updateChildModel(int playlistId) { QVariant variantId = QVariant(playlistId); - for (int row = 0; row < m_childModel.rowCount(); ++row) { - QModelIndex index = m_childModel.index(row, 0); - TreeItem* pTreeItem = m_childModel.getItem(index); + for (int row = 0; row < m_pSidebarModel->rowCount(); ++row) { + QModelIndex index = m_pSidebarModel->index(row, 0); + TreeItem* pTreeItem = m_pSidebarModel->getItem(index); DEBUG_ASSERT(pTreeItem != nullptr); if (!pTreeItem->hasChildren() && // leaf node pTreeItem->getData() == variantId) { @@ -708,13 +709,13 @@ void BasePlaylistFeature::updateChildModel(int playlistId) { * Clears the child model dynamically, but the invisible root item remains */ void BasePlaylistFeature::clearChildModel() { - m_childModel.removeRows(0, m_childModel.rowCount()); + m_pSidebarModel->removeRows(0, m_pSidebarModel->rowCount()); } QModelIndex BasePlaylistFeature::indexFromPlaylistId(int playlistId) { QVariant variantId = QVariant(playlistId); - QModelIndexList results = m_childModel.match( - m_childModel.getRootIndex(), + QModelIndexList results = m_pSidebarModel->match( + m_pSidebarModel->getRootIndex(), TreeItemModel::kDataRole, variantId, 1, @@ -733,14 +734,14 @@ void BasePlaylistFeature::slotTrackSelected(TrackPointer pTrack) { } m_playlistDao.getPlaylistsTrackIsIn(trackId, &m_playlistIdsOfSelectedTrack); - for (int row = 0; row < m_childModel.rowCount(); ++row) { - QModelIndex index = m_childModel.index(row, 0); - TreeItem* pTreeItem = m_childModel.getItem(index); + for (int row = 0; row < m_pSidebarModel->rowCount(); ++row) { + QModelIndex index = m_pSidebarModel->index(row, 0); + TreeItem* pTreeItem = m_pSidebarModel->getItem(index); DEBUG_ASSERT(pTreeItem != nullptr); markTreeItem(pTreeItem); } - m_childModel.triggerRepaint(); + m_pSidebarModel->triggerRepaint(); } void BasePlaylistFeature::markTreeItem(TreeItem* pTreeItem) { diff --git a/src/library/trackset/baseplaylistfeature.h b/src/library/trackset/baseplaylistfeature.h index 60b18cb9a33..ea50f45256a 100644 --- a/src/library/trackset/baseplaylistfeature.h +++ b/src/library/trackset/baseplaylistfeature.h @@ -30,10 +30,11 @@ class BasePlaylistFeature : public BaseTrackSetFeature { BasePlaylistFeature(Library* pLibrary, UserSettingsPointer pConfig, PlaylistTableModel* pModel, - const QString& rootViewName); + const QString& rootViewName, + const QString& iconName); ~BasePlaylistFeature() override = default; - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; void bindLibraryWidget(WLibrary* libraryWidget, KeyboardEventFilter* keyboard) override; diff --git a/src/library/trackset/basetracksetfeature.cpp b/src/library/trackset/basetracksetfeature.cpp index 35d7d407351..8994ece86e8 100644 --- a/src/library/trackset/basetracksetfeature.cpp +++ b/src/library/trackset/basetracksetfeature.cpp @@ -5,9 +5,11 @@ BaseTrackSetFeature::BaseTrackSetFeature( Library* pLibrary, UserSettingsPointer pConfig, - const QString& rootViewName) - : LibraryFeature(pLibrary, pConfig), - m_rootViewName(rootViewName) { + const QString& rootViewName, + const QString& iconName) + : LibraryFeature(pLibrary, pConfig, iconName), + m_rootViewName(rootViewName), + m_pSidebarModel(make_parented(this)) { } void BaseTrackSetFeature::activate() { diff --git a/src/library/trackset/basetracksetfeature.h b/src/library/trackset/basetracksetfeature.h index 37a4e8b77f5..3fb75aac987 100644 --- a/src/library/trackset/basetracksetfeature.h +++ b/src/library/trackset/basetracksetfeature.h @@ -1,6 +1,7 @@ #pragma once #include "library/libraryfeature.h" +#include "util/parented_ptr.h" class BaseTrackSetFeature : public LibraryFeature { Q_OBJECT @@ -8,7 +9,8 @@ class BaseTrackSetFeature : public LibraryFeature { public: BaseTrackSetFeature(Library* pLibrary, UserSettingsPointer pConfig, - const QString& rootViewName); + const QString& rootViewName, + const QString& iconName); signals: void analyzeTracks(const QList&); @@ -19,5 +21,5 @@ class BaseTrackSetFeature : public LibraryFeature { protected: const QString m_rootViewName; - TreeItemModel m_childModel; + parented_ptr m_pSidebarModel; }; diff --git a/src/library/trackset/crate/cratefeature.cpp b/src/library/trackset/crate/cratefeature.cpp index e2669811de3..1485fa77213 100644 --- a/src/library/trackset/crate/cratefeature.cpp +++ b/src/library/trackset/crate/cratefeature.cpp @@ -41,15 +41,14 @@ QString formatLabel( CrateFeature::CrateFeature(Library* pLibrary, UserSettingsPointer pConfig) - : BaseTrackSetFeature(pLibrary, pConfig, "CRATEHOME"), - m_cratesIcon(":/images/library/ic_library_crates.svg"), + : BaseTrackSetFeature(pLibrary, pConfig, "CRATEHOME", QStringLiteral("crates")), m_lockedCrateIcon(":/images/library/ic_library_locked_tracklist.svg"), m_pTrackCollection(pLibrary->trackCollectionManager()->internalCollection()), m_crateTableModel(this, pLibrary->trackCollectionManager()) { initActions(); // construct child model - m_childModel.setRootItem(TreeItem::newRoot(this)); + m_pSidebarModel->setRootItem(TreeItem::newRoot(this)); rebuildChildModel(); connectLibrary(pLibrary); @@ -174,10 +173,6 @@ QVariant CrateFeature::title() { return tr("Crates"); } -QIcon CrateFeature::getIcon() { - return m_cratesIcon; -} - QString CrateFeature::formatRootViewHtml() const { QString cratesTitle = tr("Crates"); QString cratesSummary = @@ -279,8 +274,8 @@ void CrateFeature::bindSidebarWidget(WLibrarySidebar* pSidebarWidget) { m_pSidebarWidget = pSidebarWidget; } -TreeItemModel* CrateFeature::getChildModel() { - return &m_childModel; +TreeItemModel* CrateFeature::sidebarModel() const { + return m_pSidebarModel; } void CrateFeature::activateChild(const QModelIndex& index) { @@ -489,11 +484,11 @@ void CrateFeature::slotAutoDjTrackSourceChanged() { QModelIndex CrateFeature::rebuildChildModel(CrateId selectedCrateId) { qDebug() << "CrateFeature::rebuildChildModel()" << selectedCrateId; - TreeItem* pRootItem = m_childModel.getRootItem(); + TreeItem* pRootItem = m_pSidebarModel->getRootItem(); VERIFY_OR_DEBUG_ASSERT(pRootItem != nullptr) { return QModelIndex(); } - m_childModel.removeRows(0, pRootItem->childRows()); + m_pSidebarModel->removeRows(0, pRootItem->childRows()); QList modelRows; modelRows.reserve(m_pTrackCollection->crates().countCrates()); @@ -513,13 +508,13 @@ QModelIndex CrateFeature::rebuildChildModel(CrateId selectedCrateId) { } // Append all the newly created TreeItems in a dynamic way to the childmodel - m_childModel.insertTreeItemRows(modelRows, 0); + m_pSidebarModel->insertTreeItemRows(modelRows, 0); // Update rendering of crates depending on the currently selected track slotTrackSelected(m_pSelectedTrack); if (selectedRow >= 0) { - return m_childModel.index(selectedRow, 0); + return m_pSidebarModel->index(selectedRow, 0); } else { return QModelIndex(); } @@ -538,8 +533,8 @@ void CrateFeature::updateChildModel(const QSet& updatedCrateIds) { continue; } updateTreeItemForCrateSummary( - m_childModel.getItem(index), crateSummary); - m_childModel.triggerRepaint(index); + m_pSidebarModel->getItem(index), crateSummary); + m_pSidebarModel->triggerRepaint(index); } if (m_pSelectedTrack) { // Crates containing the currently selected track might @@ -563,9 +558,9 @@ QModelIndex CrateFeature::indexFromCrateId(CrateId crateId) const { VERIFY_OR_DEBUG_ASSERT(crateId.isValid()) { return QModelIndex(); } - for (int row = 0; row < m_childModel.rowCount(); ++row) { - QModelIndex index = m_childModel.index(row, 0); - TreeItem* pTreeItem = m_childModel.getItem(index); + for (int row = 0; row < m_pSidebarModel->rowCount(); ++row) { + QModelIndex index = m_pSidebarModel->index(row, 0); + TreeItem* pTreeItem = m_pSidebarModel->getItem(index); DEBUG_ASSERT(pTreeItem != nullptr); if (!pTreeItem->hasChildren() && // leaf node (CrateId(pTreeItem->getData()) == crateId)) { @@ -805,7 +800,7 @@ void CrateFeature::htmlLinkClicked(const QUrl& link) { void CrateFeature::slotTrackSelected(TrackPointer pTrack) { m_pSelectedTrack = std::move(pTrack); - TreeItem* pRootItem = m_childModel.getRootItem(); + TreeItem* pRootItem = m_pSidebarModel->getRootItem(); VERIFY_OR_DEBUG_ASSERT(pRootItem != nullptr) { return; } @@ -834,7 +829,7 @@ void CrateFeature::slotTrackSelected(TrackPointer pTrack) { pTreeItem->setBold(crateContainsSelectedTrack); } - m_childModel.triggerRepaint(); + m_pSidebarModel->triggerRepaint(); } void CrateFeature::slotResetSelectedTrack() { diff --git a/src/library/trackset/crate/cratefeature.h b/src/library/trackset/crate/cratefeature.h index 2b1d77c5047..57e2b80e18e 100644 --- a/src/library/trackset/crate/cratefeature.h +++ b/src/library/trackset/crate/cratefeature.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include @@ -30,7 +29,6 @@ class CrateFeature : public BaseTrackSetFeature { ~CrateFeature() override = default; QVariant title() override; - QIcon getIcon() override; bool dropAcceptChild(const QModelIndex& index, const QList& urls, @@ -41,7 +39,7 @@ class CrateFeature : public BaseTrackSetFeature { KeyboardEventFilter* keyboard) override; void bindSidebarWidget(WLibrarySidebar* pSidebarWidget) override; - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; public slots: void activateChild(const QModelIndex& index) override; @@ -98,7 +96,6 @@ class CrateFeature : public BaseTrackSetFeature { QString formatRootViewHtml() const; - const QIcon m_cratesIcon; const QIcon m_lockedCrateIcon; TrackCollection* const m_pTrackCollection; diff --git a/src/library/trackset/playlistfeature.cpp b/src/library/trackset/playlistfeature.cpp index 3d9a42df80a..8cf24cb7735 100644 --- a/src/library/trackset/playlistfeature.cpp +++ b/src/library/trackset/playlistfeature.cpp @@ -42,11 +42,11 @@ PlaylistFeature::PlaylistFeature(Library* pLibrary, UserSettingsPointer pConfig) new PlaylistTableModel(nullptr, pLibrary->trackCollectionManager(), "mixxx.db.model.playlist"), - QStringLiteral("PLAYLISTHOME")), - m_icon(QStringLiteral(":/images/library/ic_library_playlist.svg")) { + QStringLiteral("PLAYLISTHOME"), + QStringLiteral("playlist")) { // construct child model std::unique_ptr pRootItem = TreeItem::newRoot(this); - m_childModel.setRootItem(std::move(pRootItem)); + m_pSidebarModel->setRootItem(std::move(pRootItem)); constructChildModel(kInvalidPlaylistId); } @@ -54,10 +54,6 @@ QVariant PlaylistFeature::title() { return tr("Playlists"); } -QIcon PlaylistFeature::getIcon() { - return m_icon; -} - void PlaylistFeature::onRightClick(const QPoint& globalPos) { m_lastRightClickedIndex = QModelIndex(); QMenu menu(m_pSidebarWidget); @@ -261,11 +257,11 @@ QModelIndex PlaylistFeature::constructChildModel(int selectedId) { } // Append all the newly created TreeItems in a dynamic way to the childmodel - m_childModel.insertTreeItemRows(data_list, 0); + m_pSidebarModel->insertTreeItemRows(data_list, 0); if (selectedRow == -1) { return QModelIndex(); } - return m_childModel.index(selectedRow, 0); + return m_pSidebarModel->index(selectedRow, 0); } void PlaylistFeature::decorateChild(TreeItem* item, int playlistId) { diff --git a/src/library/trackset/playlistfeature.h b/src/library/trackset/playlistfeature.h index 2fe64869d8c..66e1f39638b 100644 --- a/src/library/trackset/playlistfeature.h +++ b/src/library/trackset/playlistfeature.h @@ -25,7 +25,6 @@ class PlaylistFeature : public BasePlaylistFeature { ~PlaylistFeature() override = default; QVariant title() override; - QIcon getIcon() override; bool dropAcceptChild(const QModelIndex& index, const QList& urls, @@ -49,5 +48,4 @@ class PlaylistFeature : public BasePlaylistFeature { private: QString getRootViewHtml() const override; - const QIcon m_icon; }; diff --git a/src/library/trackset/setlogfeature.cpp b/src/library/trackset/setlogfeature.cpp index bc5bdd0f60c..28342aad6f7 100644 --- a/src/library/trackset/setlogfeature.cpp +++ b/src/library/trackset/setlogfeature.cpp @@ -35,9 +35,9 @@ SetlogFeature::SetlogFeature( pLibrary->trackCollectionManager(), "mixxx.db.model.setlog", /*keep deleted tracks*/ true), - QStringLiteral("SETLOGHOME")), - m_playlistId(kInvalidPlaylistId), - m_icon(QStringLiteral(":/images/library/ic_library_history.svg")) { + QStringLiteral("SETLOGHOME"), + QStringLiteral("history")), + m_playlistId(kInvalidPlaylistId) { // clear old empty entries ScopedTransaction transaction(pLibrary->trackCollectionManager() ->internalCollection() @@ -46,7 +46,7 @@ SetlogFeature::SetlogFeature( transaction.commit(); //construct child model - m_childModel.setRootItem(TreeItem::newRoot(this)); + m_pSidebarModel->setRootItem(TreeItem::newRoot(this)); constructChildModel(kInvalidPlaylistId); m_pJoinWithPreviousAction = new QAction(tr("Join with previous (below)"), this); @@ -79,10 +79,6 @@ QVariant SetlogFeature::title() { return tr("History"); } -QIcon SetlogFeature::getIcon() { - return m_icon; -} - void SetlogFeature::bindLibraryWidget( WLibrary* libraryWidget, KeyboardEventFilter* keyboard) { BasePlaylistFeature::bindLibraryWidget(libraryWidget, keyboard); @@ -220,7 +216,7 @@ QModelIndex SetlogFeature::constructChildModel(int selectedId) { } // Append all the newly created TreeItems in a dynamic way to the childmodel - m_childModel.insertTreeItemRows(itemList, 0); + m_pSidebarModel->insertTreeItemRows(itemList, 0); if (selectedId) { return indexFromPlaylistId(selectedId); diff --git a/src/library/trackset/setlogfeature.h b/src/library/trackset/setlogfeature.h index 07731a6b73f..a477a61be25 100644 --- a/src/library/trackset/setlogfeature.h +++ b/src/library/trackset/setlogfeature.h @@ -16,7 +16,6 @@ class SetlogFeature : public BasePlaylistFeature { virtual ~SetlogFeature(); QVariant title() override; - QIcon getIcon() override; void bindLibraryWidget(WLibrary* libraryWidget, KeyboardEventFilter* keyboard) override; @@ -49,5 +48,4 @@ class SetlogFeature : public BasePlaylistFeature { QAction* m_pStartNewPlaylist; int m_playlistId; QPointer m_libraryWidget; - const QIcon m_icon; }; diff --git a/src/library/traktor/traktorfeature.cpp b/src/library/traktor/traktorfeature.cpp index 94760a3b3d2..8a9c716ff6e 100644 --- a/src/library/traktor/traktorfeature.cpp +++ b/src/library/traktor/traktorfeature.cpp @@ -64,9 +64,9 @@ bool TraktorPlaylistModel::isColumnHiddenByDefault(int column) { } TraktorFeature::TraktorFeature(Library* pLibrary, UserSettingsPointer pConfig) - : BaseExternalLibraryFeature(pLibrary, pConfig), - m_cancelImport(false), - m_icon(":/images/library/ic_library_traktor.svg") { + : BaseExternalLibraryFeature(pLibrary, pConfig, QStringLiteral("traktor")), + m_pSidebarModel(make_parented(this)), + m_cancelImport(false) { QString tableName = "traktor_library"; QString idColumn = "id"; QStringList columns; @@ -143,16 +143,12 @@ QVariant TraktorFeature::title() { return m_title; } -QIcon TraktorFeature::getIcon() { - return m_icon; -} - bool TraktorFeature::isSupported() { return (QFile::exists(getTraktorMusicDatabase())); } -TreeItemModel* TraktorFeature::getChildModel() { - return &m_childModel; +TreeItemModel* TraktorFeature::sidebarModel() const { + return m_pSidebarModel; } void TraktorFeature::refreshLibraryModels() { @@ -619,7 +615,7 @@ QString TraktorFeature::getTraktorMusicDatabase() { void TraktorFeature::onTrackCollectionLoaded() { std::unique_ptr root(m_future.result()); if (root) { - m_childModel.setRootItem(std::move(root)); + m_pSidebarModel->setRootItem(std::move(root)); // Tell the traktor track source that it should re-build its index. m_trackSource->buildIndex(); diff --git a/src/library/traktor/traktorfeature.h b/src/library/traktor/traktorfeature.h index b685eb11937..fcb56b14320 100644 --- a/src/library/traktor/traktorfeature.h +++ b/src/library/traktor/traktorfeature.h @@ -35,10 +35,9 @@ class TraktorFeature : public BaseExternalLibraryFeature { virtual ~TraktorFeature(); QVariant title() override; - QIcon getIcon() override; static bool isSupported(); - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; public slots: void activate() override; @@ -61,7 +60,7 @@ class TraktorFeature : public BaseExternalLibraryFeature { void clearTable(const QString& table_name); static QString getTraktorMusicDatabase(); // private fields - TreeItemModel m_childModel; + parented_ptr m_pSidebarModel; // A separate db connection for the worker parsing thread QSqlDatabase m_database; TraktorTrackModel* m_pTraktorTableModel; @@ -74,5 +73,4 @@ class TraktorFeature : public BaseExternalLibraryFeature { QString m_title; QSharedPointer m_trackSource; - QIcon m_icon; }; diff --git a/src/main.cpp b/src/main.cpp index 53f488f98ed..0840fd58c65 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,8 +8,8 @@ #include "coreservices.h" #include "errordialoghandler.h" -#include "mixxx.h" #include "mixxxapplication.h" +#include "mixxxmainwindow.h" #include "sources/soundsourceproxy.h" #include "util/cmdlineargs.h" #include "util/console.h" @@ -79,15 +79,20 @@ int main(int argc, char * argv[]) { // the main thread. Bug #1748636. ErrorDialogHandler::instance(); + MixxxApplication app(argc, argv); + #ifdef __APPLE__ - Sandbox::checkSandboxed(); + // TODO: At this point it is too late to provide the same settings path to all components + // and too early to log errors and give users advises in their system language. + // Calling this from main.cpp before the QApplication is initialized may cause a crash + // due to potential QMessageBox invocations within migrateOldSettings(). + // Solution: Start Mixxx with default settings, migrate the preferences, and then restart + // immediately. if (!args.getSettingsPathSet()) { - args.setSettingsPath(Sandbox::migrateOldSettings()); + CmdlineArgs::Instance().setSettingsPath(Sandbox::migrateOldSettings()); } #endif - MixxxApplication app(argc, argv); - #ifdef __APPLE__ QDir dir(QApplication::applicationDirPath()); // Set the search path for Qt plugins to be in the bundle's PlugIns diff --git a/src/mixer/basetrackplayer.cpp b/src/mixer/basetrackplayer.cpp index 51dfb77f7c0..c9f0aff6fee 100644 --- a/src/mixer/basetrackplayer.cpp +++ b/src/mixer/basetrackplayer.cpp @@ -265,11 +265,17 @@ void BaseTrackPlayerImpl::loadTrack(TrackPointer pTrack) { } if (pLoopCue) { - double loopStart = pLoopCue->getPosition(); - double loopEnd = loopStart + pLoopCue->getLength(); - if (loopStart != kNoTrigger && loopEnd != kNoTrigger && loopStart <= loopEnd) { - m_pLoopInPoint->set(loopStart); - m_pLoopOutPoint->set(loopEnd); + const auto loop = pLoopCue->getStartAndEndPosition(); + if (loop.startPosition.isValid() && loop.endPosition.isValid() && + loop.startPosition <= loop.endPosition) { + // TODO: For all loop cues, both end and start positions should + // be valid and the end position should be greater than the + // start positon. We should use a VERIFY_OR_DEBUG_ASSERT to + // check this. To make this possible, we need to ensure that + // all invalid cues are discarded when saving cues to the + // database first. + m_pLoopInPoint->set(loop.startPosition.toEngineSamplePos()); + m_pLoopOutPoint->set(loop.endPosition.toEngineSamplePos()); } } } else { @@ -290,11 +296,17 @@ TrackPointer BaseTrackPlayerImpl::unloadTrack() { return TrackPointer(); } + PlayerInfo::instance().setTrackInfo(getGroup(), TrackPointer()); + // Save the loops that are currently set in a loop cue. If no loop cue is // currently on the track, then create a new one. - double loopStart = m_pLoopInPoint->get(); - double loopEnd = m_pLoopOutPoint->get(); - if (loopStart != kNoTrigger && loopEnd != kNoTrigger && loopStart <= loopEnd) { + const auto loopStart = + mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid( + m_pLoopInPoint->get()); + const auto loopEnd = + mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid( + m_pLoopOutPoint->get()); + if (loopStart.isValid() && loopEnd.isValid() && loopStart <= loopEnd) { CuePointer pLoopCue; QList cuePoints(m_pLoadedTrack->getCuePoints()); QListIterator it(cuePoints); diff --git a/src/mixer/playerinfo.cpp b/src/mixer/playerinfo.cpp index 93e43db93a9..8d0aa4a31ad 100644 --- a/src/mixer/playerinfo.cpp +++ b/src/mixer/playerinfo.cpp @@ -56,21 +56,23 @@ TrackPointer PlayerInfo::getTrackInfo(const QString& group) { return m_loadedTrackMap.value(group); } -void PlayerInfo::setTrackInfo(const QString& group, const TrackPointer& track) { +void PlayerInfo::setTrackInfo(const QString& group, const TrackPointer& pTrack) { TrackPointer pOld; { // Scope QMutexLocker locker(&m_mutex); pOld = m_loadedTrackMap.value(group); - m_loadedTrackMap.insert(group, track); + m_loadedTrackMap.insert(group, pTrack); } - if (pOld) { - emit trackUnloaded(group, pOld); - } - emit trackLoaded(group, track); + emit trackChanged(group, pTrack, pOld); + + if (pTrack) { + updateCurrentPlayingDeck(); - if (m_currentlyPlayingDeck >= 0 && - group == PlayerManager::groupForDeck(m_currentlyPlayingDeck)) { - emit currentPlayingTrackChanged(track); + int playingDeck = m_currentlyPlayingDeck; + if (playingDeck >= 0 && + group == PlayerManager::groupForDeck(playingDeck)) { + emit currentPlayingTrackChanged(pTrack); + } } } @@ -166,7 +168,13 @@ void PlayerInfo::updateCurrentPlayingDeck() { int oldDeck = m_currentlyPlayingDeck.fetchAndStoreRelease(maxDeck); if (maxDeck != oldDeck) { emit currentPlayingDeckChanged(maxDeck); - emit currentPlayingTrackChanged(getCurrentPlayingTrack()); + // Note: When starting Auto-DJ "play" might be processed before a new + // is track is fully loaded. currentPlayingTrackChanged() is then emitted + // after setTrackInfo(). + TrackPointer pTrack = getCurrentPlayingTrack(); + if (pTrack) { + emit currentPlayingTrackChanged(pTrack); + } } } diff --git a/src/mixer/playerinfo.h b/src/mixer/playerinfo.h index 7fc1035fcc9..c5f7369e5c4 100644 --- a/src/mixer/playerinfo.h +++ b/src/mixer/playerinfo.h @@ -27,8 +27,7 @@ class PlayerInfo : public QObject { signals: void currentPlayingDeckChanged(int deck); void currentPlayingTrackChanged(TrackPointer pTrack); - void trackLoaded(const QString& group, TrackPointer pTrack); - void trackUnloaded(const QString& group, TrackPointer pTrack); + void trackChanged(const QString& group, TrackPointer pNewTrack, TrackPointer pOldTrack); private: class DeckControls { diff --git a/src/mixxx.rc b/src/mixxx.rc index 1c42f218b07..a12730c25fb 100644 --- a/src/mixxx.rc +++ b/src/mixxx.rc @@ -7,7 +7,7 @@ IDI_ICON1 ICON DISCARDABLE "res/images/icons/ic_mixxx.ico" #define VER_PRODUCTNAME_STR "Mixxx\0" #define VER_FILEDESCRIPTION_STR "Mixxx digital DJ software" #define VER_COMPANYNAME_STR "The Mixxx Development Team" -// \xA9 for (c) symbol. The Microsoft Resource Compiler compiler asumes Latin-1 strings +// \xA9 for (c) symbol. The Microsoft Resource Compiler compiler assumes Latin-1 strings #define VER_LEGALCOPYRIGHT_STR "\xA9 2001-" CUR_YEAR " Mixxx Development Team\0" #define VER_ORIGINALFILENAME_STR "Mixxx.exe" diff --git a/src/mixxxapplication.cpp b/src/mixxxapplication.cpp index cf859aedbd9..5d21deedfcb 100644 --- a/src/mixxxapplication.cpp +++ b/src/mixxxapplication.cpp @@ -4,6 +4,7 @@ #include #include +#include "audio/frame.h" #include "audio/types.h" #include "control/controlproxy.h" #include "library/trackset/crate/crateid.h" @@ -97,6 +98,7 @@ void MixxxApplication::registerMetaTypes() { qRegisterMetaType("mixxx::cache_key_t"); qRegisterMetaType("mixxx::Bpm"); qRegisterMetaType("mixxx::Duration"); + qRegisterMetaType("mixxx::audio::FramePos"); qRegisterMetaType>("std::optional"); qRegisterMetaType("mixxx::FileInfo"); } diff --git a/src/mixxx.cpp b/src/mixxxmainwindow.cpp similarity index 99% rename from src/mixxx.cpp rename to src/mixxxmainwindow.cpp index c6790aa29b4..dd9647ecf1b 100644 --- a/src/mixxx.cpp +++ b/src/mixxxmainwindow.cpp @@ -1,4 +1,4 @@ -#include "mixxx.h" +#include "mixxxmainwindow.h" #include #include @@ -18,7 +18,7 @@ #include "effects/builtin/builtinbackend.h" #include "effects/effectsmanager.h" #include "engine/enginemaster.h" -#include "moc_mixxx.cpp" +#include "moc_mixxxmainwindow.cpp" #include "preferences/constants.h" #include "preferences/dialog/dlgprefeq.h" #include "preferences/dialog/dlgpreferences.h" @@ -1072,7 +1072,7 @@ void MixxxMainWindow::rebootMixxxView() { if (wasFullScreen) { slotViewFullScreen(true); } else { - // Programatic placement at this point is very problematic. + // Programmatic placement at this point is very problematic. // The screen() method returns stale data (primary screen) // until the user interacts with mixxx again. Keyboard shortcuts // do not count, moving window, opening menu etc does diff --git a/src/mixxx.h b/src/mixxxmainwindow.h similarity index 100% rename from src/mixxx.h rename to src/mixxxmainwindow.h diff --git a/src/preferences/dialog/dlgprefdeck.cpp b/src/preferences/dialog/dlgprefdeck.cpp index 23fb53a23f4..9e81d0a6499 100644 --- a/src/preferences/dialog/dlgprefdeck.cpp +++ b/src/preferences/dialog/dlgprefdeck.cpp @@ -15,7 +15,7 @@ #include "mixer/basetrackplayer.h" #include "mixer/playerinfo.h" #include "mixer/playermanager.h" -#include "mixxx.h" +#include "mixxxmainwindow.h" #include "moc_dlgprefdeck.cpp" #include "preferences/usersettings.h" #include "util/compatibility.h" @@ -283,53 +283,6 @@ DlgPrefDeck::DlgPrefDeck(QWidget* parent, pControl->set(static_cast(m_keyunlockMode)); } - // - // Rate buttons configuration - // - connect(spinBoxTemporaryRateCoarse, - QOverload::of(&QDoubleSpinBox::valueChanged), - this, - &DlgPrefDeck::slotRateTempCoarseSpinbox); - connect(spinBoxTemporaryRateFine, - QOverload::of(&QDoubleSpinBox::valueChanged), - this, - &DlgPrefDeck::slotRateTempFineSpinbox); - connect(spinBoxPermanentRateCoarse, - QOverload::of(&QDoubleSpinBox::valueChanged), - this, - &DlgPrefDeck::slotRatePermCoarseSpinbox); - connect(spinBoxPermanentRateFine, - QOverload::of(&QDoubleSpinBox::valueChanged), - this, - &DlgPrefDeck::slotRatePermFineSpinbox); - - m_dRateTempCoarse = m_pConfig->getValue(ConfigKey("[Controls]", "RateTempLeft"), - kDefaultTemporaryRateChangeCoarse); - m_dRateTempFine = m_pConfig->getValue(ConfigKey("[Controls]", "RateTempRight"), - kDefaultTemporaryRateChangeFine); - m_dRatePermCoarse = m_pConfig->getValue(ConfigKey("[Controls]", "RatePermLeft"), - kDefaultPermanentRateChangeCoarse); - m_dRatePermFine = m_pConfig->getValue(ConfigKey("[Controls]", "RatePermRight"), - kDefaultPermanentRateChangeFine); - - spinBoxTemporaryRateCoarse->setValue(m_dRateTempCoarse); - spinBoxTemporaryRateFine->setValue(m_dRateTempFine); - spinBoxPermanentRateCoarse->setValue(m_dRatePermCoarse); - spinBoxPermanentRateFine->setValue(m_dRatePermFine); - - RateControl::setTemporaryRateChangeCoarseAmount(m_dRateTempCoarse); - RateControl::setTemporaryRateChangeFineAmount(m_dRateTempFine); - RateControl::setPermanentRateChangeCoarseAmount(m_dRatePermCoarse); - RateControl::setPermanentRateChangeFineAmount(m_dRatePermFine); - - // Rate Ramp Sensitivity - m_iRateRampSensitivity = m_pConfig->getValue(ConfigKey("[Controls]", "RateRampSensitivity"), kDefaultRateRampSensitivity); - SliderRateRampSensitivity->setValue(m_iRateRampSensitivity); - connect(SliderRateRampSensitivity, - &QSlider::valueChanged, - this, - &DlgPrefDeck::slotRateRampSensitivitySlider); - // // Cue Mode // @@ -342,23 +295,9 @@ DlgPrefDeck::DlgPrefDeck(QWidget* parent, MIXXX_MANUAL_CUE_MODES_URL)); // - // Ramping Temporary Rate Change configuration + // Speed / Pitch reset configuration // - // Set Ramp Rate On or Off - connect(radioButtonRateRampModeLinear, - &QRadioButton::toggled, - this, - &DlgPrefDeck::slotRateRampingModeLinearButton); - m_bRateRamping = static_cast( - m_pConfig->getValue(ConfigKey("[Controls]", "RateRamp"), - static_cast(kDefaultRampingMode))); - if (m_bRateRamping == RateControl::RampMode::Linear) { - radioButtonRateRampModeLinear->setChecked(true); - } else { - radioButtonRateRampModeStepping->setChecked(true); - } - // Update "reset speed" and "reset pitch" check boxes // TODO: All defaults should only be set in slotResetToDefaults. int configSPAutoReset = m_pConfig->getValue( @@ -376,6 +315,11 @@ DlgPrefDeck::DlgPrefDeck(QWidget* parent, connect(checkBoxResetSpeed, &QCheckBox::toggled, this, &DlgPrefDeck::slotUpdateSpeedAutoReset); connect(checkBoxResetPitch, &QCheckBox::toggled, this, &DlgPrefDeck::slotUpdatePitchAutoReset); + // + // Ramping Temporary Rate Change configuration + // + + // Rate Ramp Sensitivity slider & spinbox connect(SliderRateRampSensitivity, QOverload::of(&QAbstractSlider::valueChanged), SpinBoxRateRampSensitivity, @@ -384,6 +328,17 @@ DlgPrefDeck::DlgPrefDeck(QWidget* parent, QOverload::of(&QSpinBox::valueChanged), SliderRateRampSensitivity, QOverload::of(&QAbstractSlider::setValue)); + + m_iRateRampSensitivity = + m_pConfig->getValue(ConfigKey("[Controls]", "RateRampSensitivity"), + kDefaultRateRampSensitivity); + SliderRateRampSensitivity->setValue(m_iRateRampSensitivity); + connect(SliderRateRampSensitivity, + &QSlider::valueChanged, + this, + &DlgPrefDeck::slotRateRampSensitivitySlider); + + // Enable/disable permanent rate spinboxes when smooth ramping is selected connect(radioButtonRateRampModeLinear, &QRadioButton::toggled, labelSpeedRampSensitivity, @@ -396,6 +351,7 @@ DlgPrefDeck::DlgPrefDeck(QWidget* parent, &QRadioButton::toggled, SpinBoxRateRampSensitivity, &QWidget::setEnabled); + // Enable/disable temporary rate spinboxes when abrupt ramping is selected connect(radioButtonRateRampModeStepping, &QRadioButton::toggled, labelSpeedTemporary, @@ -408,6 +364,56 @@ DlgPrefDeck::DlgPrefDeck(QWidget* parent, &QRadioButton::toggled, spinBoxTemporaryRateFine, &QWidget::setEnabled); + // Set Ramp Rate On or Off + connect(radioButtonRateRampModeLinear, + &QRadioButton::toggled, + this, + &DlgPrefDeck::slotRateRampingModeLinearButton); + m_bRateRamping = static_cast( + m_pConfig->getValue(ConfigKey("[Controls]", "RateRamp"), + static_cast(kDefaultRampingMode))); + if (m_bRateRamping == RateControl::RampMode::Linear) { + radioButtonRateRampModeLinear->setChecked(true); + } else { + radioButtonRateRampModeStepping->setChecked(true); + } + + // Rate buttons configuration + connect(spinBoxTemporaryRateCoarse, + QOverload::of(&QDoubleSpinBox::valueChanged), + this, + &DlgPrefDeck::slotRateTempCoarseSpinbox); + connect(spinBoxTemporaryRateFine, + QOverload::of(&QDoubleSpinBox::valueChanged), + this, + &DlgPrefDeck::slotRateTempFineSpinbox); + connect(spinBoxPermanentRateCoarse, + QOverload::of(&QDoubleSpinBox::valueChanged), + this, + &DlgPrefDeck::slotRatePermCoarseSpinbox); + connect(spinBoxPermanentRateFine, + QOverload::of(&QDoubleSpinBox::valueChanged), + this, + &DlgPrefDeck::slotRatePermFineSpinbox); + + m_dRateTempCoarse = m_pConfig->getValue(ConfigKey("[Controls]", "RateTempLeft"), + kDefaultTemporaryRateChangeCoarse); + m_dRateTempFine = m_pConfig->getValue(ConfigKey("[Controls]", "RateTempRight"), + kDefaultTemporaryRateChangeFine); + m_dRatePermCoarse = m_pConfig->getValue(ConfigKey("[Controls]", "RatePermLeft"), + kDefaultPermanentRateChangeCoarse); + m_dRatePermFine = m_pConfig->getValue(ConfigKey("[Controls]", "RatePermRight"), + kDefaultPermanentRateChangeFine); + + spinBoxTemporaryRateCoarse->setValue(m_dRateTempCoarse); + spinBoxTemporaryRateFine->setValue(m_dRateTempFine); + spinBoxPermanentRateCoarse->setValue(m_dRatePermCoarse); + spinBoxPermanentRateFine->setValue(m_dRatePermFine); + + RateControl::setTemporaryRateChangeCoarseAmount(m_dRateTempCoarse); + RateControl::setTemporaryRateChangeFineAmount(m_dRateTempFine); + RateControl::setPermanentRateChangeCoarseAmount(m_dRatePermCoarse); + RateControl::setPermanentRateChangeFineAmount(m_dRatePermFine); slotUpdate(); } @@ -433,32 +439,32 @@ void DlgPrefDeck::slotUpdate() { checkBoxCloneDeckOnLoadDoubleTap->setChecked(m_pConfig->getValue( ConfigKey("[Controls]", "CloneDeckOnLoadDoubleTap"), true)); - double deck1RateRange = m_rateRangeControls[0]->get(); - int index = ComboBoxRateRange->findData(static_cast(deck1RateRange * 100.0)); + double rateRange = m_rateRangeControls[0]->get(); + int index = ComboBoxRateRange->findData(static_cast(rateRange * 100.0)); if (index == -1) { - ComboBoxRateRange->addItem(QString::number(deck1RateRange * 100.).append("%"), - deck1RateRange * 100.); + ComboBoxRateRange->addItem(QString::number(rateRange * 100.).append("%"), + rateRange * 100.); } ComboBoxRateRange->setCurrentIndex(index); - double deck1RateDirection = m_rateDirectionControls[0]->get(); - checkBoxInvertSpeedSlider->setChecked(deck1RateDirection == kRateDirectionInverted); + double rateDirection = m_rateDirectionControls[0]->get(); + checkBoxInvertSpeedSlider->setChecked(rateDirection == kRateDirectionInverted); - double deck1CueMode = m_cueControls[0]->get(); - index = ComboBoxCueMode->findData(static_cast(deck1CueMode)); + double cueMode = m_cueControls[0]->get(); + index = ComboBoxCueMode->findData(static_cast(cueMode)); ComboBoxCueMode->setCurrentIndex(index); - KeylockMode deck1KeylockMode = - static_cast(static_cast(m_keylockModeControls[0]->get())); - if (deck1KeylockMode == KeylockMode::LockCurrentKey) { + KeylockMode keylockMode = + static_cast(static_cast(m_keylockModeControls[0]->get())); + if (keylockMode == KeylockMode::LockCurrentKey) { radioButtonCurrentKey->setChecked(true); } else { radioButtonOriginalKey->setChecked(true); } - KeyunlockMode deck1KeyunlockMode = - static_cast(static_cast(m_keyunlockModeControls[0]->get())); - if (deck1KeyunlockMode == KeyunlockMode::KeepLockedKey) { + KeyunlockMode keyunlockMode = + static_cast(static_cast(m_keyunlockModeControls[0]->get())); + if (keyunlockMode == KeyunlockMode::KeepLockedKey) { radioButtonKeepUnlockedKey->setChecked(true); } else { radioButtonResetUnlockedKey->setChecked(true); @@ -480,6 +486,12 @@ void DlgPrefDeck::slotUpdate() { checkBoxResetSpeed->setChecked(false); } + if (m_bRateRamping == RateControl::RampMode::Linear) { + radioButtonRateRampModeLinear->setChecked(true); + } else { + radioButtonRateRampModeStepping->setChecked(true); + } + SliderRateRampSensitivity->setValue( m_pConfig->getValue(ConfigKey("[Controls]", "RateRampSensitivity"), kDefaultRateRampSensitivity)); diff --git a/src/preferences/dialog/dlgprefdeckdlg.ui b/src/preferences/dialog/dlgprefdeckdlg.ui index db19d27b7e5..870de8b6d82 100644 --- a/src/preferences/dialog/dlgprefdeckdlg.ui +++ b/src/preferences/dialog/dlgprefdeckdlg.ui @@ -207,7 +207,7 @@ You can always drag-and-drop tracks on screen to clone a deck. - + Permanent rate change when left-clicking @@ -235,7 +235,7 @@ You can always drag-and-drop tracks on screen to clone a deck. - + Permanent rate change when right-clicking @@ -283,7 +283,7 @@ You can always drag-and-drop tracks on screen to clone a deck. - + false @@ -314,7 +314,7 @@ You can always drag-and-drop tracks on screen to clone a deck. - + Permanent @@ -324,7 +324,7 @@ You can always drag-and-drop tracks on screen to clone a deck. - + @@ -372,7 +372,7 @@ You can always drag-and-drop tracks on screen to clone a deck. - + false @@ -395,7 +395,7 @@ You can always drag-and-drop tracks on screen to clone a deck. - + false @@ -408,7 +408,7 @@ You can always drag-and-drop tracks on screen to clone a deck. - + Pitch bend behavior @@ -428,7 +428,7 @@ You can always drag-and-drop tracks on screen to clone a deck. - + false @@ -473,14 +473,14 @@ You can always drag-and-drop tracks on screen to clone a deck. - + Adjustment buttons: - + true @@ -495,7 +495,7 @@ You can always drag-and-drop tracks on screen to clone a deck. Coarse - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignCenter false @@ -505,7 +505,7 @@ You can always drag-and-drop tracks on screen to clone a deck. - + true @@ -520,7 +520,7 @@ You can always drag-and-drop tracks on screen to clone a deck. Fine - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignCenter false @@ -569,7 +569,7 @@ You can always drag-and-drop tracks on screen to clone a deck. - + Abrupt jump @@ -579,7 +579,7 @@ You can always drag-and-drop tracks on screen to clone a deck. - + Smoothly adjusts deck speed when temporary change buttons are held down @@ -619,13 +619,26 @@ You can always drag-and-drop tracks on screen to clone a deck. + + + + Qt::Vertical + + + + 20 + 15 + + + + - + Qt::Vertical diff --git a/src/preferences/dialog/dlgprefinterface.cpp b/src/preferences/dialog/dlgprefinterface.cpp index 9600fb5ae9c..a7bf2e21375 100644 --- a/src/preferences/dialog/dlgprefinterface.cpp +++ b/src/preferences/dialog/dlgprefinterface.cpp @@ -11,7 +11,7 @@ #include "control/controlobject.h" #include "control/controlproxy.h" #include "defs_urls.h" -#include "mixxx.h" +#include "mixxxmainwindow.h" #include "moc_dlgprefinterface.cpp" #include "preferences/usersettings.h" #include "skin/legacy/legacyskinparser.h" diff --git a/src/preferences/dialog/dlgprefwaveform.cpp b/src/preferences/dialog/dlgprefwaveform.cpp index d1d2e8d35a1..8be6f4ca4e0 100644 --- a/src/preferences/dialog/dlgprefwaveform.cpp +++ b/src/preferences/dialog/dlgprefwaveform.cpp @@ -2,7 +2,7 @@ #include "library/dao/analysisdao.h" #include "library/library.h" -#include "mixxx.h" +#include "mixxxmainwindow.h" #include "moc_dlgprefwaveform.cpp" #include "preferences/waveformsettings.h" #include "util/db/dbconnectionpooled.h" diff --git a/src/skin/qml/qmleffectmanifestparametersmodel.cpp b/src/skin/qml/qmleffectmanifestparametersmodel.cpp new file mode 100644 index 00000000000..69980ccc7b2 --- /dev/null +++ b/src/skin/qml/qmleffectmanifestparametersmodel.cpp @@ -0,0 +1,126 @@ +#include "skin/qml/qmleffectmanifestparametersmodel.h" + +#include + +#include "effects/effectmanifest.h" + +namespace mixxx { +namespace skin { +namespace qml { +namespace { +const QHash kRoleNames = { + {QmlEffectManifestParametersModel::IdRole, "id"}, + {QmlEffectManifestParametersModel::NameRole, "name"}, + {QmlEffectManifestParametersModel::ShortNameRole, "shortName"}, + {QmlEffectManifestParametersModel::DescriptionRole, "description"}, + {QmlEffectManifestParametersModel::ControlHintRole, "controlHint"}, + {QmlEffectManifestParametersModel::ControlKeyRole, "controlKey"}, +}; +} + +QmlEffectManifestParametersModel::QmlEffectManifestParametersModel( + EffectManifestPointer pEffectManifest, + QObject* parent) + : QAbstractListModel(parent), m_pEffectManifest(pEffectManifest) { +} + +QVariant QmlEffectManifestParametersModel::data(const QModelIndex& index, int role) const { + const QList& parameters = m_pEffectManifest->parameters(); + if (index.row() >= parameters.size()) { + return QVariant(); + } + + const EffectManifestParameterPointer pParameter = parameters.at(index.row()); + switch (role) { + case QmlEffectManifestParametersModel::IdRole: + return pParameter->id(); + case QmlEffectManifestParametersModel::NameRole: + return pParameter->name(); + case QmlEffectManifestParametersModel::ShortNameRole: + return pParameter->shortName(); + case QmlEffectManifestParametersModel::DescriptionRole: + return pParameter->description(); + case QmlEffectManifestParametersModel::ControlHintRole: + // TODO: Remove this cast, instead expose the enum directly using + // Q_ENUM after #2618 has been merged. + return static_cast(pParameter->controlHint()); + case QmlEffectManifestParametersModel::ControlKeyRole: { + // FIXME: Unfortunately our effect parameter controls are messed up. + // Even though we only have a single, ordered list of parameters, our + // COs splits up this list into two distinct list (`parameter_N` and + // `button_parameter_M`), and their indices don't match up with the + // original list. + // + // For example, if you have 4 parameters (A: Knob, B: Button, C: Knob, + // D: Knob), one would expect the following control keys: + // parameter1 -> A + // button_parameter2 -> B + // parameter3 -> C + // parameter4 -> D + // + // But in reality, this will lead to the following control keys: + // parameter1 -> A + // button_parameter1 -> B + // parameter2 -> C + // parameter3 -> D + // + // This makes it extremely hard to show the parameters in the correct + // order, because you also need to know how many parameters of the same + // type are in that list. + // + // Due to backwards compatibility, we cannot fix this. This attempts to + // solve this problem by letting the user fetch the appropriate key + // from the model. + if (pParameter->controlHint() == EffectManifestParameter::ControlHint::UNKNOWN) { + return QString(); + } + const bool isButton = pParameter->controlHint() == + EffectManifestParameter::ControlHint::TOGGLE_STEPPING; + int keyNumber = 1; + for (int i = 0; i < index.row(); i++) { + const EffectManifestParameterPointer pPrevParameter = parameters.at(i); + if (pPrevParameter->controlHint() == EffectManifestParameter::ControlHint::UNKNOWN) { + continue; + } + if (isButton == + (pPrevParameter->controlHint() == + EffectManifestParameter::ControlHint:: + TOGGLE_STEPPING)) { + keyNumber++; + } + } + + return (isButton ? QStringLiteral("button_parameter%1") + : QStringLiteral("parameter%1")) + .arg(QString::number(keyNumber)); + } + default: + return QVariant(); + } +} + +int QmlEffectManifestParametersModel::rowCount(const QModelIndex& parent) const { + if (parent.isValid()) { + return 0; + } + + // Add +1 because we also include "no effect" in the model + return m_pEffectManifest->parameters().size(); +} + +QHash QmlEffectManifestParametersModel::roleNames() const { + return kRoleNames; +} + +QVariant QmlEffectManifestParametersModel::get(int row) const { + QModelIndex idx = index(row, 0); + QVariantMap dataMap; + for (auto it = kRoleNames.constBegin(); it != kRoleNames.constEnd(); it++) { + dataMap.insert(it.value(), data(idx, it.key())); + } + return dataMap; +} + +} // namespace qml +} // namespace skin +} // namespace mixxx diff --git a/src/skin/qml/qmleffectmanifestparametersmodel.h b/src/skin/qml/qmleffectmanifestparametersmodel.h new file mode 100644 index 00000000000..bd913fb2219 --- /dev/null +++ b/src/skin/qml/qmleffectmanifestparametersmodel.h @@ -0,0 +1,39 @@ +#pragma once +#include +#include + +#include "effects/effectsmanager.h" + +namespace mixxx { +namespace skin { +namespace qml { + +class QmlEffectManifestParametersModel : public QAbstractListModel { + Q_OBJECT + public: + enum Roles { + IdRole = Qt::UserRole + 1, + NameRole, + ShortNameRole, + DescriptionRole, + ControlHintRole, + ControlKeyRole, + }; + Q_ENUM(Roles) + + explicit QmlEffectManifestParametersModel( + EffectManifestPointer pManifest, + QObject* parent = nullptr); + + QVariant data(const QModelIndex& index, int role) const override; + int rowCount(const QModelIndex& parent) const override; + QHash roleNames() const override; + Q_INVOKABLE QVariant get(int row) const; + + private: + const EffectManifestPointer m_pEffectManifest; +}; + +} // namespace qml +} // namespace skin +} // namespace mixxx diff --git a/src/skin/qml/qmleffectslotproxy.cpp b/src/skin/qml/qmleffectslotproxy.cpp new file mode 100644 index 00000000000..ef1880ff6cf --- /dev/null +++ b/src/skin/qml/qmleffectslotproxy.cpp @@ -0,0 +1,94 @@ +#include "skin/qml/qmleffectslotproxy.h" + +#include +#include + +#include "effects/effectrack.h" +#include "effects/effectslot.h" +#include "skin/qml/qmleffectmanifestparametersmodel.h" + +namespace mixxx { +namespace skin { +namespace qml { + +QmlEffectSlotProxy::QmlEffectSlotProxy(EffectRackPointer pRack, + EffectChainSlotPointer pChainSlot, + EffectSlotPointer pEffectSlot, + QObject* parent) + : QObject(parent), + m_pRack(pRack), + m_pChainSlot(pChainSlot), + m_pEffectSlot(pEffectSlot) { + DEBUG_ASSERT(m_pRack); + DEBUG_ASSERT(m_pChainSlot); + DEBUG_ASSERT(m_pEffectSlot); + connect(m_pEffectSlot.get(), + &EffectSlot::updated, + this, + &QmlEffectSlotProxy::effectIdChanged); + connect(m_pEffectSlot.get(), + &EffectSlot::updated, + this, + &QmlEffectSlotProxy::parametersModelChanged); +} + +int QmlEffectSlotProxy::getRackNumber() const { + return m_pRack->getRackNumber(); +} + +QString QmlEffectSlotProxy::getRackGroup() const { + return m_pRack->getGroup(); +} + +int QmlEffectSlotProxy::getChainSlotNumber() const { + return m_pChainSlot->getChainSlotNumber(); +} + +QString QmlEffectSlotProxy::getChainSlotGroup() const { + return m_pChainSlot->getGroup(); +} + +int QmlEffectSlotProxy::getNumber() const { + return m_pEffectSlot->getEffectSlotNumber(); +} + +QString QmlEffectSlotProxy::getGroup() const { + return m_pEffectSlot->getGroup(); +} + +QString QmlEffectSlotProxy::getEffectId() const { + const EffectPointer pEffect = m_pEffectSlot->getEffect(); + if (!pEffect) { + return QString(); + } + + const EffectManifestPointer pManifest = pEffect->getManifest(); + return pManifest->id(); +} + +void QmlEffectSlotProxy::setEffectId(const QString& effectId) { + m_pRack->maybeLoadEffect( + m_pChainSlot->getChainSlotNumber(), + m_pEffectSlot->getEffectSlotNumber(), + effectId); +} + +QmlEffectManifestParametersModel* QmlEffectSlotProxy::getParametersModel() const { + const EffectPointer pEffect = m_pEffectSlot->getEffect(); + if (!pEffect) { + return nullptr; + } + + const EffectManifestPointer pManifest = pEffect->getManifest(); + VERIFY_OR_DEBUG_ASSERT(pManifest) { + return nullptr; + } + + QmlEffectManifestParametersModel* pModel = new QmlEffectManifestParametersModel(pManifest); + QQmlEngine::setObjectOwnership(pModel, QQmlEngine::JavaScriptOwnership); + return pModel; +} + +} // namespace qml +} // namespace skin +} // namespace mixxx diff --git a/src/skin/qml/qmleffectslotproxy.h b/src/skin/qml/qmleffectslotproxy.h new file mode 100644 index 00000000000..29044657e1c --- /dev/null +++ b/src/skin/qml/qmleffectslotproxy.h @@ -0,0 +1,54 @@ +#pragma once +#include + +#include "effects/effectsmanager.h" + +namespace mixxx { +namespace skin { +namespace qml { + +class QmlEffectManifestParametersModel; + +class QmlEffectSlotProxy : public QObject { + Q_OBJECT + Q_PROPERTY(int rackNumber READ getRackNumber CONSTANT) + Q_PROPERTY(QString rackGroup READ getRackGroup CONSTANT) + Q_PROPERTY(int chainSlotNumber READ getChainSlotNumber CONSTANT) + Q_PROPERTY(QString chainSlotGroup READ getChainSlotGroup CONSTANT) + Q_PROPERTY(int number READ getNumber CONSTANT) + Q_PROPERTY(QString group READ getGroup CONSTANT) + Q_PROPERTY(QString effectId READ getEffectId WRITE setEffectId NOTIFY effectIdChanged) + Q_PROPERTY(mixxx::skin::qml::QmlEffectManifestParametersModel* parametersModel + READ getParametersModel NOTIFY parametersModelChanged) + + public: + explicit QmlEffectSlotProxy(EffectRackPointer pEffectRack, + EffectChainSlotPointer pChainSlot, + EffectSlotPointer pEffectSlot, + QObject* parent = nullptr); + + int getRackNumber() const; + QString getRackGroup() const; + int getChainSlotNumber() const; + QString getChainSlotGroup() const; + int getNumber() const; + QString getGroup() const; + QString getEffectId() const; + QmlEffectManifestParametersModel* getParametersModel() const; + + public slots: + void setEffectId(const QString& effectId); + + signals: + void effectIdChanged(); + void parametersModelChanged(); + + private: + const EffectRackPointer m_pRack; + const EffectChainSlotPointer m_pChainSlot; + const EffectSlotPointer m_pEffectSlot; +}; + +} // namespace qml +} // namespace skin +} // namespace mixxx diff --git a/src/skin/qml/qmleffectsmanagerproxy.cpp b/src/skin/qml/qmleffectsmanagerproxy.cpp new file mode 100644 index 00000000000..17d91b39ecc --- /dev/null +++ b/src/skin/qml/qmleffectsmanagerproxy.cpp @@ -0,0 +1,60 @@ +#include "skin/qml/qmleffectsmanagerproxy.h" + +#include +#include + +#include "effects/effectchainslot.h" +#include "effects/effectrack.h" +#include "skin/qml/qmleffectslotproxy.h" +#include "skin/qml/qmlvisibleeffectsmodel.h" + +namespace mixxx { +namespace skin { +namespace qml { + +QmlEffectsManagerProxy::QmlEffectsManagerProxy( + std::shared_ptr pEffectsManager, QObject* parent) + : QObject(parent), + m_pEffectsManager(pEffectsManager), + m_pVisibleEffectsModel( + new QmlVisibleEffectsModel(pEffectsManager, this)) { +} + +QmlEffectSlotProxy* QmlEffectsManagerProxy::getEffectSlot( + int rackNumber, int unitNumber, int effectNumber) const { + // Subtract 1 from all numbers, because internally our indices are + // zero-based + const int rackIndex = rackNumber - 1; + const auto pRack = m_pEffectsManager->getStandardEffectRack(rackIndex); + if (!pRack) { + qWarning() << "QmlEffectsManagerProxy: Effect Rack" << rackNumber << "not found!"; + return nullptr; + } + + const int unitIndex = unitNumber - 1; + const auto pEffectUnit = pRack->getEffectChainSlot(unitIndex); + if (!pEffectUnit) { + qWarning() << "QmlEffectsManagerProxy: Effect Unit" << unitNumber + << "in Rack" << rackNumber << "not found!"; + return nullptr; + } + + const int effectIndex = effectNumber - 1; + const auto pEffectSlot = pEffectUnit->getEffectSlot(effectIndex); + if (!pEffectSlot) { + qWarning() << "QmlEffectsManagerProxy: Effect Slot" << effectNumber + << "in Unit" << unitNumber << "of Rack" << rackNumber + << "not found!"; + return nullptr; + } + + // Don't set a parent here, so that the QML engine deletes the object when + // the corresponding JS object is garbage collected. + QmlEffectSlotProxy* pEffectSlotProxy = new QmlEffectSlotProxy(pRack, pEffectUnit, pEffectSlot); + QQmlEngine::setObjectOwnership(pEffectSlotProxy, QQmlEngine::JavaScriptOwnership); + return pEffectSlotProxy; +} + +} // namespace qml +} // namespace skin +} // namespace mixxx diff --git a/src/skin/qml/qmleffectsmanagerproxy.h b/src/skin/qml/qmleffectsmanagerproxy.h new file mode 100644 index 00000000000..9b1af880723 --- /dev/null +++ b/src/skin/qml/qmleffectsmanagerproxy.h @@ -0,0 +1,33 @@ +#pragma once +#include + +#include "effects/effectsmanager.h" + +namespace mixxx { +namespace skin { +namespace qml { + +class QmlVisibleEffectsModel; +class QmlEffectSlotProxy; + +class QmlEffectsManagerProxy : public QObject { + Q_OBJECT + Q_PROPERTY(mixxx::skin::qml::QmlVisibleEffectsModel* visibleEffectsModel + MEMBER m_pVisibleEffectsModel CONSTANT); + + public: + explicit QmlEffectsManagerProxy( + std::shared_ptr pEffectsManager, + QObject* parent = nullptr); + + Q_INVOKABLE mixxx::skin::qml::QmlEffectSlotProxy* getEffectSlot( + int rackNumber, int unitNumber, int effectNumber) const; + + private: + const std::shared_ptr m_pEffectsManager; + QmlVisibleEffectsModel* m_pVisibleEffectsModel; +}; + +} // namespace qml +} // namespace skin +} // namespace mixxx diff --git a/src/skin/qml/qmllibraryproxy.cpp b/src/skin/qml/qmllibraryproxy.cpp new file mode 100644 index 00000000000..ba090be3638 --- /dev/null +++ b/src/skin/qml/qmllibraryproxy.cpp @@ -0,0 +1,24 @@ +#include "skin/qml/qmllibraryproxy.h" + +#include + +#include "library/library.h" +#include "library/sidebarmodel.h" + +namespace mixxx { +namespace skin { +namespace qml { + +QmlLibraryProxy::QmlLibraryProxy(std::shared_ptr pLibrary, QObject* parent) + : QObject(parent), + m_pLibrary(pLibrary), + m_pModel(make_parented(m_pLibrary->trackTableModel(), this)) { +} + +QAbstractItemModel* QmlLibraryProxy::getSidebarModel() { + return m_pLibrary->sidebarModel(); +} + +} // namespace qml +} // namespace skin +} // namespace mixxx diff --git a/src/skin/qml/qmllibraryproxy.h b/src/skin/qml/qmllibraryproxy.h new file mode 100644 index 00000000000..cf921ba1e45 --- /dev/null +++ b/src/skin/qml/qmllibraryproxy.h @@ -0,0 +1,35 @@ +#pragma once +#include +#include + +#include "skin/qml/qmllibrarytracklistmodel.h" +#include "util/parented_ptr.h" + +class Library; +class SidebarModel; + +QT_FORWARD_DECLARE_CLASS(QAbstractItemModel); + +namespace mixxx { +namespace skin { +namespace qml { + +class QmlLibraryTrackListModel; + +class QmlLibraryProxy : public QObject { + Q_OBJECT + Q_PROPERTY(mixxx::skin::qml::QmlLibraryTrackListModel* model MEMBER m_pModel CONSTANT) + + public: + explicit QmlLibraryProxy(std::shared_ptr pLibrary, QObject* parent = nullptr); + + Q_INVOKABLE QAbstractItemModel* getSidebarModel(); + + private: + std::shared_ptr m_pLibrary; + parented_ptr m_pModel; +}; + +} // namespace qml +} // namespace skin +} // namespace mixxx diff --git a/src/skin/qml/qmllibrarytracklistmodel.cpp b/src/skin/qml/qmllibrarytracklistmodel.cpp new file mode 100644 index 00000000000..cb2bf36f5bb --- /dev/null +++ b/src/skin/qml/qmllibrarytracklistmodel.cpp @@ -0,0 +1,93 @@ +#include "skin/qml/qmllibrarytracklistmodel.h" + +#include "library/librarytablemodel.h" + +namespace mixxx { +namespace skin { +namespace qml { +namespace { +const QHash kRoleNames = { + {QmlLibraryTrackListModel::TitleRole, "title"}, + {QmlLibraryTrackListModel::ArtistRole, "artist"}, + {QmlLibraryTrackListModel::AlbumRole, "album"}, + {QmlLibraryTrackListModel::AlbumArtistRole, "albumArtist"}, + {QmlLibraryTrackListModel::FileUrlRole, "fileUrl"}, +}; +} + +QmlLibraryTrackListModel::QmlLibraryTrackListModel(LibraryTableModel* pModel, QObject* pParent) + : QIdentityProxyModel(pParent) { + pModel->select(); + setSourceModel(pModel); +} + +QVariant QmlLibraryTrackListModel::data(const QModelIndex& proxyIndex, int role) const { + if (!proxyIndex.isValid()) { + return {}; + } + + VERIFY_OR_DEBUG_ASSERT(checkIndex(proxyIndex)) { + return {}; + } + + const auto pSourceModel = static_cast(sourceModel()); + VERIFY_OR_DEBUG_ASSERT(pSourceModel) { + return {}; + } + + if (proxyIndex.column() > 0) { + return {}; + } + + int column = -1; + switch (role) { + case TitleRole: + column = pSourceModel->fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_TITLE); + break; + case ArtistRole: + column = pSourceModel->fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_ARTIST); + break; + case AlbumRole: + column = pSourceModel->fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_ALBUM); + break; + case AlbumArtistRole: + column = pSourceModel->fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_ALBUMARTIST); + break; + case FileUrlRole: { + column = pSourceModel->fieldIndex(ColumnCache::COLUMN_TRACKLOCATIONSTABLE_LOCATION); + const QString location = QIdentityProxyModel::data( + proxyIndex.siblingAtColumn(column), Qt::DisplayRole) + .toString(); + if (location.isEmpty()) { + return {}; + } + return QUrl::fromLocalFile(location); + } + default: + break; + } + + if (column < 0) { + return {}; + } + + return QIdentityProxyModel::data(proxyIndex.siblingAtColumn(column), Qt::DisplayRole); +} + +int QmlLibraryTrackListModel::columnCount(const QModelIndex& parent) const { + // This is a list model, i.e. no entries have a parent. + VERIFY_OR_DEBUG_ASSERT(!parent.isValid()) { + return 0; + } + + // There is exactly one column. All data is exposed as roles. + return 1; +} + +QHash QmlLibraryTrackListModel::roleNames() const { + return kRoleNames; +} + +} // namespace qml +} // namespace skin +} // namespace mixxx diff --git a/src/skin/qml/qmllibrarytracklistmodel.h b/src/skin/qml/qmllibrarytracklistmodel.h new file mode 100644 index 00000000000..9bf4870fa18 --- /dev/null +++ b/src/skin/qml/qmllibrarytracklistmodel.h @@ -0,0 +1,33 @@ +#pragma once +#include + +class LibraryTableModel; + +namespace mixxx { +namespace skin { +namespace qml { + +class QmlLibraryTrackListModel : public QIdentityProxyModel { + public: + enum Roles { + TitleRole = Qt::UserRole, + ArtistRole, + AlbumRole, + AlbumArtistRole, + FileUrlRole, + }; + Q_ENUM(Roles); + + QmlLibraryTrackListModel(LibraryTableModel* pModel, QObject* pParent = nullptr); + ~QmlLibraryTrackListModel() = default; + + QVariant data(const QModelIndex& index, int role) const override; + int columnCount(const QModelIndex& index = QModelIndex()) const override; + QHash roleNames() const override; +}; + +} // namespace qml +} // namespace skin +} // namespace mixxx + +Q_DECLARE_METATYPE(mixxx::skin::qml::QmlLibraryTrackListModel*) diff --git a/src/skin/qml/qmlplayermanagerproxy.cpp b/src/skin/qml/qmlplayermanagerproxy.cpp index 817cba2d622..4230ecd0c4f 100644 --- a/src/skin/qml/qmlplayermanagerproxy.cpp +++ b/src/skin/qml/qmlplayermanagerproxy.cpp @@ -35,6 +35,12 @@ QObject* QmlPlayerManagerProxy::getPlayer(const QString& group) { [this, group](const QString& trackLocation) { emit loadLocationToPlayer(trackLocation, group); }); + connect(pPlayerProxy, + &QmlPlayerProxy::cloneFromGroup, + this, + [this, group](const QString& sourceGroup) { + m_pPlayerManager->slotCloneDeck(sourceGroup, group); + }); return pPlayerProxy; } diff --git a/src/skin/qml/qmlplayerproxy.cpp b/src/skin/qml/qmlplayerproxy.cpp index bd9823d9f78..49a9f998161 100644 --- a/src/skin/qml/qmlplayerproxy.cpp +++ b/src/skin/qml/qmlplayerproxy.cpp @@ -139,6 +139,7 @@ void QmlPlayerProxy::slotTrackChanged() { emit keyTextChanged(); emit colorChanged(); emit coverArtUrlChanged(); + emit trackLocationUrlChanged(); } PROPERTY_IMPL(QString, artist, getArtist, setArtist) @@ -180,6 +181,15 @@ QUrl QmlPlayerProxy::getCoverArtUrl() const { return AsyncImageProvider::trackLocationToCoverArtUrl(coverInfo.trackLocation); } +QUrl QmlPlayerProxy::getTrackLocationUrl() const { + const TrackPointer pTrack = m_pCurrentTrack; + if (pTrack == nullptr) { + return QUrl(); + } + + return QUrl::fromLocalFile(pTrack->getLocation()); +} + } // namespace qml } // namespace skin } // namespace mixxx diff --git a/src/skin/qml/qmlplayerproxy.h b/src/skin/qml/qmlplayerproxy.h index bcef1b415b9..f912770cdc5 100644 --- a/src/skin/qml/qmlplayerproxy.h +++ b/src/skin/qml/qmlplayerproxy.h @@ -29,6 +29,7 @@ class QmlPlayerProxy : public QObject { Q_PROPERTY(QString keyText READ getKeyText WRITE setKeyText NOTIFY keyTextChanged) Q_PROPERTY(QColor color READ getColor WRITE setColor NOTIFY colorChanged) Q_PROPERTY(QUrl coverArtUrl READ getCoverArtUrl NOTIFY coverArtUrlChanged) + Q_PROPERTY(QUrl trackLocationUrl READ getTrackLocationUrl NOTIFY trackLocationUrlChanged) public: explicit QmlPlayerProxy(BaseTrackPlayer* pTrackPlayer, QObject* parent = nullptr); @@ -48,6 +49,7 @@ class QmlPlayerProxy : public QObject { QString getKeyText() const; QColor getColor() const; QUrl getCoverArtUrl() const; + QUrl getTrackLocationUrl() const; /// Needed for interacting with the raw track player object. BaseTrackPlayer* internalTrackPlayer() const { @@ -81,6 +83,7 @@ class QmlPlayerProxy : public QObject { void trackLoaded(); void trackUnloaded(); void trackChanged(); + void cloneFromGroup(const QString& group); void albumChanged(); void titleChanged(); @@ -96,6 +99,7 @@ class QmlPlayerProxy : public QObject { void keyTextChanged(); void colorChanged(); void coverArtUrlChanged(); + void trackLocationUrlChanged(); void loadTrackFromLocationRequested(const QString& trackLocation); diff --git a/src/skin/qml/qmlskin.cpp b/src/skin/qml/qmlskin.cpp index edf35eb34e0..a87e40d70d5 100644 --- a/src/skin/qml/qmlskin.cpp +++ b/src/skin/qml/qmlskin.cpp @@ -8,8 +8,14 @@ #include "skin/qml/asyncimageprovider.h" #include "skin/qml/qmlconfigproxy.h" #include "skin/qml/qmlcontrolproxy.h" +#include "skin/qml/qmleffectmanifestparametersmodel.h" +#include "skin/qml/qmleffectslotproxy.h" +#include "skin/qml/qmleffectsmanagerproxy.h" +#include "skin/qml/qmllibraryproxy.h" +#include "skin/qml/qmllibrarytracklistmodel.h" #include "skin/qml/qmlplayermanagerproxy.h" #include "skin/qml/qmlplayerproxy.h" +#include "skin/qml/qmlvisibleeffectsmodel.h" #include "skin/qml/qmlwaveformoverview.h" #include "util/assert.h" @@ -128,6 +134,49 @@ QWidget* QmlSkin::loadSkin(QWidget* pParent, qmlRegisterType("Mixxx", 0, 1, "ControlProxy"); qmlRegisterType("Mixxx", 0, 1, "WaveformOverview"); + // Any uncreateable non-singleton types registered here require arguments + // that we don't want to expose to QML directly. Instead, they can be + // retrieved by member properties or methods from the singleton types. + // + // The alternative would be to register their *arguments* in the QML + // system, which would improve nothing, or we had to expose them as + // singletons to that they can be accessed by components instantiated by + // QML, which would also be suboptimal. + + qmlRegisterSingletonType("Mixxx", + 0, + 1, + "EffectsManager", + lambda_to_singleton_type_factory_ptr( + [pCoreServices](QQmlEngine* pEngine, + QJSEngine* pScriptEngine) -> QObject* { + Q_UNUSED(pScriptEngine); + + QmlEffectsManagerProxy* pEffectsManagerProxy = + new QmlEffectsManagerProxy( + pCoreServices->getEffectsManager(), + pEngine); + return pEffectsManagerProxy; + })); + qmlRegisterUncreatableType("Mixxx", + 0, + 1, + "VisibleEffectsModel", + "VisibleEffectsModel objects can't be created directly, please use " + "Mixxx.EffectsManager.visibleEffectsModel"); + qmlRegisterUncreatableType("Mixxx", + 0, + 1, + "EffectManifestParametersModel", + "EffectManifestParametersModel objects can't be created directly, " + "please use Mixxx.EffectsSlot.parametersModel"); + qmlRegisterUncreatableType("Mixxx", + 0, + 1, + "EffectSlotProxy", + "EffectSlotProxy objects can't be created directly, please use " + "Mixxx.EffectsManager.getEffectSlot(rackNumber, unitNumber, effectNumber)"); + qmlRegisterSingletonType("Mixxx", 0, 1, @@ -150,7 +199,7 @@ QWidget* QmlSkin::loadSkin(QWidget* pParent, "Player objects can't be created directly, please use " "Mixxx.PlayerManager.getPlayer(group)"); - qmlRegisterSingletonType("Mixxx", + qmlRegisterSingletonType("Mixxx", 0, 1, "Config", @@ -166,6 +215,27 @@ QWidget* QmlSkin::loadSkin(QWidget* pParent, return pConfigProxy; })); + qmlRegisterUncreatableType("Mixxx", + 0, + 1, + "LibraryTrackListModel", + "LibraryTrackListModel objects can't be created directly, " + "please use Mixxx.Library.model"); + qmlRegisterSingletonType("Mixxx", + 0, + 1, + "Library", + lambda_to_singleton_type_factory_ptr( + [pCoreServices](QQmlEngine* pEngine, + QJSEngine* pScriptEngine) -> QObject* { + Q_UNUSED(pScriptEngine); + + QmlLibraryProxy* pLibraryProxy = new QmlLibraryProxy( + pCoreServices->getLibrary(), + pEngine); + return pLibraryProxy; + })); + QQuickWidget* pWidget = new QQuickWidget(pParent); // Enable multisampling for much nicer rendering of shapes/images diff --git a/src/skin/qml/qmlvisibleeffectsmodel.cpp b/src/skin/qml/qmlvisibleeffectsmodel.cpp new file mode 100644 index 00000000000..ca49643a5e2 --- /dev/null +++ b/src/skin/qml/qmlvisibleeffectsmodel.cpp @@ -0,0 +1,89 @@ +#include "skin/qml/qmlvisibleeffectsmodel.h" + +#include + +#include "effects/effectmanifest.h" +#include "effects/effectsmanager.h" + +namespace mixxx { +namespace skin { +namespace qml { +namespace { +const QHash kRoleNames = { + {Qt::DisplayRole, "display"}, + {Qt::ToolTipRole, "tooltip"}, + {QmlVisibleEffectsModel::EffectIdRole, "effectId"}, +}; +} + +QmlVisibleEffectsModel::QmlVisibleEffectsModel( + std::shared_ptr pEffectsManager, + QObject* parent) + : QAbstractListModel(parent), m_pEffectsManager(pEffectsManager) { + slotVisibleEffectsUpdated(); + connect(m_pEffectsManager.get(), + &EffectsManager::visibleEffectsUpdated, + this, + &QmlVisibleEffectsModel::slotVisibleEffectsUpdated); +} + +void QmlVisibleEffectsModel::slotVisibleEffectsUpdated() { + beginResetModel(); + m_visibleEffectManifests = m_pEffectsManager->getVisibleEffectManifests(); + endResetModel(); +} + +QVariant QmlVisibleEffectsModel::data(const QModelIndex& index, int role) const { + if (index.row() == 0) { + switch (role) { + case Qt::DisplayRole: + return EffectsManager::kNoEffectString; + case Qt::ToolTipRole: + return tr("No effect loaded."); + default: + return QVariant(); + } + } + + if (index.row() > m_visibleEffectManifests.size()) { + return QVariant(); + } + + const EffectManifestPointer pManifest = m_visibleEffectManifests.at(index.row() - 1); + switch (role) { + case Qt::DisplayRole: + return pManifest->displayName(); + case Qt::ToolTipRole: + return pManifest->description(); + case QmlVisibleEffectsModel::EffectIdRole: + return pManifest->id(); + default: + return QVariant(); + } +} + +int QmlVisibleEffectsModel::rowCount(const QModelIndex& parent) const { + if (parent.isValid()) { + return 0; + } + + // Add +1 because we also include "no effect" in the model + return m_visibleEffectManifests.size() + 1; +} + +QHash QmlVisibleEffectsModel::roleNames() const { + return kRoleNames; +} + +QVariant QmlVisibleEffectsModel::get(int row) const { + QModelIndex idx = index(row, 0); + QVariantMap dataMap; + for (auto it = kRoleNames.constBegin(); it != kRoleNames.constEnd(); it++) { + dataMap.insert(it.value(), data(idx, it.key())); + } + return dataMap; +} + +} // namespace qml +} // namespace skin +} // namespace mixxx diff --git a/src/skin/qml/qmlvisibleeffectsmodel.h b/src/skin/qml/qmlvisibleeffectsmodel.h new file mode 100644 index 00000000000..b061471a359 --- /dev/null +++ b/src/skin/qml/qmlvisibleeffectsmodel.h @@ -0,0 +1,38 @@ +#pragma once +#include +#include + +#include "effects/effectsmanager.h" + +namespace mixxx { +namespace skin { +namespace qml { + +class QmlVisibleEffectsModel : public QAbstractListModel { + Q_OBJECT + public: + enum Roles { + EffectIdRole = Qt::UserRole + 1, + }; + Q_ENUM(Roles) + + explicit QmlVisibleEffectsModel( + std::shared_ptr pEffectsManager, + QObject* parent = nullptr); + + QVariant data(const QModelIndex& index, int role) const override; + int rowCount(const QModelIndex& parent) const override; + QHash roleNames() const override; + Q_INVOKABLE QVariant get(int row) const; + + private slots: + void slotVisibleEffectsUpdated(); + + private: + const std::shared_ptr m_pEffectsManager; + QList m_visibleEffectManifests; +}; + +} // namespace qml +} // namespace skin +} // namespace mixxx diff --git a/src/sources/audiosource.h b/src/sources/audiosource.h index 52a60b50e0e..dee01aa3594 100644 --- a/src/sources/audiosource.h +++ b/src/sources/audiosource.h @@ -169,7 +169,7 @@ class AudioSource : public UrlResource, public virtual /*implements*/ IAudioSour /// internal errors of if the format of the content is not /// supported it should return Aborted. /// - /// Returing this error result gives other decoders with a + /// Returning this error result gives other decoders with a /// lower priority the chance to open the same file. /// Example: A SoundSourceProvider has been registered for /// files with a certain extension, but the corresponding diff --git a/src/sources/metadatasourcetaglib.cpp b/src/sources/metadatasourcetaglib.cpp index 607e9881cfd..4458417a203 100644 --- a/src/sources/metadatasourcetaglib.cpp +++ b/src/sources/metadatasourcetaglib.cpp @@ -75,20 +75,29 @@ class AiffFile : public TagLib::RIFF::AIFF::File { } }; -inline QDateTime getMetadataSynchronized(const QFileInfo& fileInfo) { - return fileInfo.lastModified(); +inline QDateTime getSourceSynchronizedAt(const QFileInfo& fileInfo) { + const QDateTime lastModifiedUtc = fileInfo.lastModified().toUTC(); + // Ignore bogus values like 1970-01-01T00:00:00.000 UTC + // that are obviously incorrect and don't provide any + // information. + if (lastModifiedUtc.isValid() && + // Only defined if valid + lastModifiedUtc.toMSecsSinceEpoch() == 0) { + return QDateTime{}; + } + return lastModifiedUtc; } } // anonymous namespace std::pair MetadataSourceTagLib::afterImport(ImportResult importResult) const { - return std::make_pair(importResult, getMetadataSynchronized(QFileInfo(m_fileName))); + return std::make_pair(importResult, getSourceSynchronizedAt(QFileInfo(m_fileName))); } std::pair MetadataSourceTagLib::afterExport(ExportResult exportResult) const { - return std::make_pair(exportResult, getMetadataSynchronized(QFileInfo(m_fileName))); + return std::make_pair(exportResult, getSourceSynchronizedAt(QFileInfo(m_fileName))); } std::pair @@ -630,6 +639,14 @@ class SafelyWritableFile final { // See also: https://bugs.launchpad.net/mixxx/+bug/1815305 DEBUG_ASSERT(m_origFileName.isNull()); DEBUG_ASSERT(m_tempFileName.isNull()); + if (!QFileInfo(origFileName).isWritable()) { + kLogger.warning() + << "Failed to prepare file for writing:" + << origFileName + << "is not writable."; + // Abort constructor + return; + } if (useTemporaryFile) { QString tempFileName = origFileName + kSafelyWritableTempFileSuffix; QFile origFile(origFileName); diff --git a/src/sources/soundsourcecoreaudio.cpp b/src/sources/soundsourcecoreaudio.cpp index 65c6aea76df..26bb254fa88 100644 --- a/src/sources/soundsourcecoreaudio.cpp +++ b/src/sources/soundsourcecoreaudio.cpp @@ -193,7 +193,7 @@ SoundSource::OpenResult SoundSourceCoreAudio::tryOpen( if (m_bFileIsMp3) { // Use the maximum value for MP3 files to ensure that all decoded samples - // are accurate. Otherwise the deocding tests for MP3 files fail! + // are accurate. Otherwise the decoding tests for MP3 files fail! m_seekPrefetchFrames = math_max(m_leadingFrames, kMp3MaxSeekPrefetchFrames); } else { m_seekPrefetchFrames = m_leadingFrames; diff --git a/src/sources/soundsourceflac.cpp b/src/sources/soundsourceflac.cpp index a6624a7e826..4e97e15f0a2 100644 --- a/src/sources/soundsourceflac.cpp +++ b/src/sources/soundsourceflac.cpp @@ -399,16 +399,26 @@ namespace { // https://bugs.launchpad.net/mixxx/+bug/1769717 // https://hydrogenaud.io/index.php/topic,61792.msg559045.html#msg559045 -// We will shift decoded samples left by (32 - m_bitsPerSample) to -// get rid of the garbage in the most significant bits before scaling -// to the range [-CSAMPLE_PEAK, CSAMPLE_PEAK - epsilon] with -// epsilon = 1 / 2 ^ bitsPerSample. -constexpr CSAMPLE kSampleScaleFactor = CSAMPLE_PEAK / +// We multiply the decoded samples by 2 ^ (32 - m_bitsPerSample) to +// get rid of the garbage in the most significant bits which get shifted +// out to the left. The resulting, upscaled integer value is then scaled +// down to the floating point range [-CSAMPLE_PEAK, CSAMPLE_PEAK - epsilon] +// with epsilon = 1 / 2 ^ bitsPerSample. +// +// We have to negate the nominator to compensate for the negative denominator! +// Otherwise the phase would be inverted: https://bugs.launchpad.net/mixxx/+bug/1933001 +constexpr CSAMPLE kSampleScaleFactor = -CSAMPLE_PEAK / (static_cast(1) << std::numeric_limits::digits); inline CSAMPLE convertDecodedSample(FLAC__int32 decodedSample, int bitsPerSample) { - DEBUG_ASSERT(std::numeric_limits::is_signed); - return (decodedSample << ((std::numeric_limits::digits + 1) - bitsPerSample)) * kSampleScaleFactor; + static_assert(std::numeric_limits::is_signed); + static_assert(kSampleScaleFactor > CSAMPLE_ZERO, "preserve phase of decoded signal"); + // Multiples by 2 ^ (32 - bitsPerSample) + const auto upscaleShift = (std::numeric_limits::digits + 1) - bitsPerSample; + const auto upscaledSample = decodedSample << upscaleShift; + // upscaledSample is now a 32-bit signed integer that needs to scaled + // to the range [-CSAMPLE_PEAK, CSAMPLE_PEAK - epsilon] + return upscaledSample * kSampleScaleFactor; } } // anonymous namespace diff --git a/src/sources/soundsourcem4a.cpp b/src/sources/soundsourcem4a.cpp index a1a1c2adbcc..ced4bcfde1d 100644 --- a/src/sources/soundsourcem4a.cpp +++ b/src/sources/soundsourcem4a.cpp @@ -747,7 +747,7 @@ ReadableSampleFrames SoundSourceM4A::readSampleFramesClamped( // Either abort or retry by exiting the inner loop break; } else { - // Reset the retry flag after succesfully decoding a block + // Reset the retry flag after successfully decoding a block retryAfterReopeningDecoder = false; } // Upon a pending retry the inner loop is exited immediately and @@ -759,19 +759,19 @@ ReadableSampleFrames SoundSourceM4A::readSampleFramesClamped( pDecodeBuffer); // verify the in/out parameter // Verify the decoded sample data for consistency - VERIFY_OR_DEBUG_ASSERT(getSignalInfo().getChannelCount() == - decFrameInfo.channels) { - kLogger.critical() << "Corrupt or unsupported AAC file:" - << "Unexpected number of channels" - << decFrameInfo.channels << "<>" - << getSignalInfo().getChannelCount(); + const auto channelCount = mixxx::audio::ChannelCount(decFrameInfo.channels); + VERIFY_OR_DEBUG_ASSERT(getSignalInfo().getChannelCount() == channelCount) { + kLogger.warning() << "Corrupt or unsupported AAC file:" + << "Unexpected number of channels" + << channelCount << "<>" + << getSignalInfo().getChannelCount(); break; // abort } - VERIFY_OR_DEBUG_ASSERT(getSignalInfo().getSampleRate() == - SINT(decFrameInfo.samplerate)) { - kLogger.critical() + const auto sampleRate = mixxx::audio::SampleRate(decFrameInfo.samplerate); + VERIFY_OR_DEBUG_ASSERT(getSignalInfo().getSampleRate() == sampleRate) { + kLogger.warning() << "Corrupt or unsupported AAC file:" - << "Unexpected sample rate" << decFrameInfo.samplerate + << "Unexpected sample rate" << sampleRate << "<>" << getSignalInfo().getSampleRate(); break; // abort } diff --git a/src/sources/soundsourcemediafoundation.cpp b/src/sources/soundsourcemediafoundation.cpp index 5da31ba401a..e398767ca0d 100644 --- a/src/sources/soundsourcemediafoundation.cpp +++ b/src/sources/soundsourcemediafoundation.cpp @@ -52,6 +52,7 @@ const QString SoundSourceProviderMediaFoundation::kDisplayName = const QStringList SoundSourceProviderMediaFoundation::kSupportedFileExtensions = { QStringLiteral("aac"), QStringLiteral("m4a"), + QStringLiteral("m4v"), QStringLiteral("mp4"), }; diff --git a/src/sources/soundsourcemp3.cpp b/src/sources/soundsourcemp3.cpp index 1cee11d94de..844c2d6fd47 100644 --- a/src/sources/soundsourcemp3.cpp +++ b/src/sources/soundsourcemp3.cpp @@ -684,7 +684,8 @@ ReadableSampleFrames SoundSourceMp3::readSampleFramesClamped( DEBUG_ASSERT(isStreamValid(m_madStream)); #ifndef QT_NO_DEBUG_OUTPUT - const SINT madFrameChannelCount = MAD_NCHANNELS(&m_madFrame.header); + const auto madFrameChannelCount = + mixxx::audio::ChannelCount{MAD_NCHANNELS(&m_madFrame.header)}; if (madFrameChannelCount != getSignalInfo().getChannelCount()) { kLogger.warning() << "MP3 frame header with mismatching number of channels" << madFrameChannelCount << "<>" << getSignalInfo().getChannelCount() @@ -696,7 +697,8 @@ ReadableSampleFrames SoundSourceMp3::readSampleFramesClamped( // Once decoded the frame is synthesized to PCM samples mad_synth_frame(&m_madSynth, &m_madFrame); #ifndef QT_NO_DEBUG_OUTPUT - const SINT madSynthSampleRate = m_madSynth.pcm.samplerate; + const auto madSynthSampleRate = + mixxx::audio::SampleRate{m_madSynth.pcm.samplerate}; if (madSynthSampleRate != getSignalInfo().getSampleRate()) { kLogger.warning() << "Reading MP3 data with different sample rate" << madSynthSampleRate << "<>" << getSignalInfo().getSampleRate() diff --git a/src/sources/soundsourceproxy.cpp b/src/sources/soundsourceproxy.cpp index 69d94ea1982..cc773234016 100644 --- a/src/sources/soundsourceproxy.cpp +++ b/src/sources/soundsourceproxy.cpp @@ -539,9 +539,9 @@ bool SoundSourceProxy::updateTrackFromSource( // values if the corresponding file tags are missing. Depending // on the file type some kind of tags might even not be supported // at all and this information would get lost entirely otherwise! - bool metadataSynchronized = false; + bool headerParsed = false; mixxx::TrackMetadata trackMetadata = - m_pTrack->getMetadata(&metadataSynchronized); + m_pTrack->getMetadata(&headerParsed); // Save for later to replace the unreliable and imprecise audio // properties imported from file tags (see below). @@ -559,7 +559,7 @@ bool SoundSourceProxy::updateTrackFromSource( // if the user did not explicitly choose to (re-)import metadata // explicitly from this file. bool mergeExtraMetadataFromSource = false; - if (metadataSynchronized && mode == UpdateTrackFromSourceMode::Once) { + if (headerParsed && mode == UpdateTrackFromSourceMode::Once) { // No (re-)import needed or desired, only merge missing properties mergeExtraMetadataFromSource = true; } else { @@ -592,7 +592,7 @@ bool SoundSourceProxy::updateTrackFromSource( << "from file" << getUrl().toString(); // make sure that the trackMetadata was not messed up due to the failure - trackMetadata = m_pTrack->getMetadata(&metadataSynchronized); + trackMetadata = m_pTrack->getMetadata(&headerParsed); } // Partial import @@ -610,7 +610,7 @@ bool SoundSourceProxy::updateTrackFromSource( } // Full import - if (metadataSynchronized) { + if (headerParsed) { // Metadata has been synchronized successfully at least // once in the past. Only overwrite this information if // new data has actually been imported, otherwise abort diff --git a/src/test/analyzersilence_test.cpp b/src/test/analyzersilence_test.cpp index 9d9eb8192b2..1a3af6ae731 100644 --- a/src/test/analyzersilence_test.cpp +++ b/src/test/analyzersilence_test.cpp @@ -56,16 +56,16 @@ TEST_F(AnalyzerSilenceTest, SilenceTrack) { analyzeTrack(); - CuePosition cue = pTrack->getCuePoint(); - EXPECT_DOUBLE_EQ(0.0, cue.getPosition()); + const mixxx::audio::FramePos cuePosition = pTrack->getMainCuePosition(); + EXPECT_EQ(mixxx::audio::kStartFramePos, cuePosition); CuePointer pIntroCue = pTrack->findCueByType(mixxx::CueType::Intro); - EXPECT_DOUBLE_EQ(0.0, pIntroCue->getPosition()); - EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); + EXPECT_EQ(mixxx::audio::kStartFramePos, pIntroCue->getPosition()); + EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLengthFrames() * kChannelCount); CuePointer pOutroCue = pTrack->findCueByType(mixxx::CueType::Outro); - EXPECT_DOUBLE_EQ(Cue::kNoPosition, pOutroCue->getPosition()); - EXPECT_DOUBLE_EQ(nTrackSampleDataLength, pOutroCue->getLength()); + EXPECT_EQ(mixxx::audio::kInvalidFramePos, pOutroCue->getPosition()); + EXPECT_DOUBLE_EQ(nTrackSampleDataLength, pOutroCue->getLengthFrames() * kChannelCount); } TEST_F(AnalyzerSilenceTest, EndToEndToneTrack) { @@ -77,16 +77,16 @@ TEST_F(AnalyzerSilenceTest, EndToEndToneTrack) { analyzeTrack(); - CuePosition cue = pTrack->getCuePoint(); - EXPECT_DOUBLE_EQ(0.0, cue.getPosition()); + const mixxx::audio::FramePos cuePosition = pTrack->getMainCuePosition(); + EXPECT_EQ(mixxx::audio::kStartFramePos, cuePosition); CuePointer pIntroCue = pTrack->findCueByType(mixxx::CueType::Intro); - EXPECT_DOUBLE_EQ(0.0, pIntroCue->getPosition()); - EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); + EXPECT_EQ(mixxx::audio::kStartFramePos, pIntroCue->getPosition()); + EXPECT_DOUBLE_EQ(0.0 / kChannelCount, pIntroCue->getLengthFrames()); CuePointer pOutroCue = pTrack->findCueByType(mixxx::CueType::Outro); - EXPECT_DOUBLE_EQ(Cue::kNoPosition, pOutroCue->getPosition()); - EXPECT_DOUBLE_EQ(nTrackSampleDataLength, pOutroCue->getLength()); + EXPECT_EQ(mixxx::audio::kInvalidFramePos, pOutroCue->getPosition()); + EXPECT_DOUBLE_EQ(nTrackSampleDataLength / kChannelCount, pOutroCue->getLengthFrames()); } TEST_F(AnalyzerSilenceTest, ToneTrackWithSilence) { @@ -108,16 +108,16 @@ TEST_F(AnalyzerSilenceTest, ToneTrackWithSilence) { analyzeTrack(); - CuePosition cue = pTrack->getCuePoint(); - EXPECT_DOUBLE_EQ(nTrackSampleDataLength / 4, cue.getPosition()); + const mixxx::audio::FramePos cuePosition = pTrack->getMainCuePosition(); + EXPECT_DOUBLE_EQ(nTrackSampleDataLength / 4, cuePosition.toEngineSamplePos()); CuePointer pIntroCue = pTrack->findCueByType(mixxx::CueType::Intro); - EXPECT_DOUBLE_EQ(nTrackSampleDataLength / 4, pIntroCue->getPosition()); - EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); + EXPECT_DOUBLE_EQ(nTrackSampleDataLength / 4, pIntroCue->getPosition().toEngineSamplePos()); + EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLengthFrames()); CuePointer pOutroCue = pTrack->findCueByType(mixxx::CueType::Outro); - EXPECT_DOUBLE_EQ(Cue::kNoPosition, pOutroCue->getPosition()); - EXPECT_DOUBLE_EQ(3 * nTrackSampleDataLength / 4, pOutroCue->getLength()); + EXPECT_EQ(mixxx::audio::kInvalidFramePos, pOutroCue->getPosition()); + EXPECT_DOUBLE_EQ(3 * nTrackSampleDataLength / 4 / kChannelCount, pOutroCue->getLengthFrames()); } TEST_F(AnalyzerSilenceTest, ToneTrackWithSilenceInTheMiddle) { @@ -151,36 +151,41 @@ TEST_F(AnalyzerSilenceTest, ToneTrackWithSilenceInTheMiddle) { analyzeTrack(); - CuePosition cue = pTrack->getCuePoint(); - EXPECT_DOUBLE_EQ(oneFifthOfTrackLength, cue.getPosition()); + const mixxx::audio::FramePos cuePosition = pTrack->getMainCuePosition(); + EXPECT_DOUBLE_EQ(oneFifthOfTrackLength / kChannelCount, cuePosition.value()); CuePointer pIntroCue = pTrack->findCueByType(mixxx::CueType::Intro); - EXPECT_DOUBLE_EQ(oneFifthOfTrackLength, pIntroCue->getPosition()); - EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); + EXPECT_DOUBLE_EQ(oneFifthOfTrackLength, pIntroCue->getPosition().toEngineSamplePos()); + EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLengthFrames()); CuePointer pOutroCue = pTrack->findCueByType(mixxx::CueType::Outro); - EXPECT_DOUBLE_EQ(Cue::kNoPosition, pOutroCue->getPosition()); - EXPECT_DOUBLE_EQ(4 * oneFifthOfTrackLength, pOutroCue->getLength()); + EXPECT_EQ(mixxx::audio::kInvalidFramePos, pOutroCue->getPosition()); + EXPECT_DOUBLE_EQ(4 * oneFifthOfTrackLength, pOutroCue->getLengthFrames() * kChannelCount); } TEST_F(AnalyzerSilenceTest, RespectUserEdits) { // Arbitrary values - const double kManualCuePosition = 0.2 * nTrackSampleDataLength; - const double kManualIntroPosition = 0.1 * nTrackSampleDataLength; - const double kManualOutroPosition = 0.9 * nTrackSampleDataLength; + const auto kManualCuePosition = mixxx::audio::FramePos::fromEngineSamplePos( + 0.2 * nTrackSampleDataLength); + const auto kManualIntroPosition = + mixxx::audio::FramePos::fromEngineSamplePos( + 0.1 * nTrackSampleDataLength); + const auto kManualOutroPosition = + mixxx::audio::FramePos::fromEngineSamplePos( + 0.9 * nTrackSampleDataLength); - pTrack->setCuePoint(CuePosition(kManualCuePosition)); + pTrack->setMainCuePosition(kManualCuePosition); CuePointer pIntroCue = pTrack->createAndAddCue( mixxx::CueType::Intro, Cue::kNoHotCue, kManualIntroPosition, - Cue::kNoPosition); + mixxx::audio::kInvalidFramePos); CuePointer pOutroCue = pTrack->createAndAddCue( mixxx::CueType::Outro, Cue::kNoHotCue, - Cue::kNoPosition, + mixxx::audio::kInvalidFramePos, kManualOutroPosition); // Fill the first half with silence @@ -196,14 +201,14 @@ TEST_F(AnalyzerSilenceTest, RespectUserEdits) { analyzeTrack(); - CuePosition cue = pTrack->getCuePoint(); - EXPECT_DOUBLE_EQ(kManualCuePosition, cue.getPosition()); + mixxx::audio::FramePos cuePosition = pTrack->getMainCuePosition(); + EXPECT_EQ(kManualCuePosition, cuePosition); - EXPECT_DOUBLE_EQ(kManualIntroPosition, pIntroCue->getPosition()); - EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); + EXPECT_EQ(kManualIntroPosition, pIntroCue->getPosition()); + EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLengthFrames()); - EXPECT_DOUBLE_EQ(Cue::kNoPosition, pOutroCue->getPosition()); - EXPECT_DOUBLE_EQ(kManualOutroPosition, pOutroCue->getLength()); + EXPECT_EQ(mixxx::audio::kInvalidFramePos, pOutroCue->getPosition()); + EXPECT_DOUBLE_EQ(kManualOutroPosition.value(), pOutroCue->getLengthFrames()); } } // namespace diff --git a/src/test/beatgridtest.cpp b/src/test/beatgridtest.cpp index a685a781d38..6cd074eb3b9 100644 --- a/src/test/beatgridtest.cpp +++ b/src/test/beatgridtest.cpp @@ -26,200 +26,227 @@ TEST(BeatGridTest, Scale) { int sampleRate = 44100; TrackPointer pTrack = newTrack(sampleRate); - double bpm = 60.0; - pTrack->trySetBpm(bpm); + constexpr mixxx::Bpm bpm(60.0); + pTrack->trySetBpm(bpm.value()); - auto pGrid = BeatGrid::makeBeatGrid(pTrack->getSampleRate(), QString(), bpm, 0); + auto pGrid = BeatGrid::makeBeatGrid(pTrack->getSampleRate(), + QString(), + mixxx::Bpm(bpm), + mixxx::audio::kStartFramePos); - EXPECT_DOUBLE_EQ(bpm, pGrid->getBpm()); - pGrid = pGrid->scale(Beats::DOUBLE); - EXPECT_DOUBLE_EQ(2 * bpm, pGrid->getBpm()); + EXPECT_DOUBLE_EQ(bpm.value(), pGrid->getBpm().value()); + pGrid = pGrid->scale(Beats::BpmScale::Double); + EXPECT_DOUBLE_EQ(2 * bpm.value(), pGrid->getBpm().value()); - pGrid = pGrid->scale(Beats::HALVE); - EXPECT_DOUBLE_EQ(bpm, pGrid->getBpm()); + pGrid = pGrid->scale(Beats::BpmScale::Halve); + EXPECT_DOUBLE_EQ(bpm.value(), pGrid->getBpm().value()); - pGrid = pGrid->scale(Beats::TWOTHIRDS); - EXPECT_DOUBLE_EQ(bpm * 2 / 3, pGrid->getBpm()); + pGrid = pGrid->scale(Beats::BpmScale::TwoThirds); + EXPECT_DOUBLE_EQ(bpm.value() * 2 / 3, pGrid->getBpm().value()); - pGrid = pGrid->scale(Beats::THREEHALVES); - EXPECT_DOUBLE_EQ(bpm, pGrid->getBpm()); + pGrid = pGrid->scale(Beats::BpmScale::ThreeHalves); + EXPECT_DOUBLE_EQ(bpm.value(), pGrid->getBpm().value()); - pGrid = pGrid->scale(Beats::THREEFOURTHS); - EXPECT_DOUBLE_EQ(bpm * 3 / 4, pGrid->getBpm()); + pGrid = pGrid->scale(Beats::BpmScale::ThreeFourths); + EXPECT_DOUBLE_EQ(bpm.value() * 3 / 4, pGrid->getBpm().value()); - pGrid = pGrid->scale(Beats::FOURTHIRDS); - EXPECT_DOUBLE_EQ(bpm, pGrid->getBpm()); + pGrid = pGrid->scale(Beats::BpmScale::FourThirds); + EXPECT_DOUBLE_EQ(bpm.value(), pGrid->getBpm().value()); } TEST(BeatGridTest, TestNthBeatWhenOnBeat) { - int sampleRate = 44100; + constexpr int sampleRate = 44100; TrackPointer pTrack = newTrack(sampleRate); - double bpm = 60.1; - const int kFrameSize = 2; + constexpr double bpm = 60.1; pTrack->trySetBpm(bpm); - double beatLength = (60.0 * sampleRate / bpm) * kFrameSize; + constexpr mixxx::audio::FrameDiff_t beatLengthFrames = 60.0 * sampleRate / bpm; - auto pGrid = BeatGrid::makeBeatGrid(pTrack->getSampleRate(), QString(), bpm, 0); + auto pGrid = BeatGrid::makeBeatGrid(pTrack->getSampleRate(), + QString(), + mixxx::Bpm(bpm), + mixxx::audio::kStartFramePos); // Pretend we're on the 20th beat; - double position = beatLength * 20; + constexpr mixxx::audio::FramePos position(beatLengthFrames * 20); - // The spec dictates that a value of 0 is always invalid and returns -1 - EXPECT_EQ(-1, pGrid->findNthBeat(position, 0)); + // The spec dictates that a value of 0 is always invalid and returns an invalid position + EXPECT_FALSE(pGrid->findNthBeat(position, 0).isValid()); // findNthBeat should return exactly the current beat if we ask for 1 or // -1. For all other values, it should return n times the beat length. for (int i = 1; i < 20; ++i) { - EXPECT_NEAR(position + beatLength * (i - 1), pGrid->findNthBeat(position, i), kMaxBeatError); - EXPECT_NEAR(position + beatLength * (-i + 1), pGrid->findNthBeat(position, -i), kMaxBeatError); + EXPECT_NEAR((position + beatLengthFrames * (i - 1)).value(), + pGrid->findNthBeat(position, i).value(), + kMaxBeatError); + EXPECT_NEAR((position + beatLengthFrames * (-i + 1)).value(), + pGrid->findNthBeat(position, -i).value(), + kMaxBeatError); } // Also test prev/next beat calculation. - double prevBeat, nextBeat; + mixxx::audio::FramePos prevBeat, nextBeat; pGrid->findPrevNextBeats(position, &prevBeat, &nextBeat, true); - EXPECT_NEAR(position, prevBeat, kMaxBeatError); - EXPECT_NEAR(position + beatLength, nextBeat, kMaxBeatError); + EXPECT_NEAR(position.value(), prevBeat.value(), kMaxBeatError); + EXPECT_NEAR((position + beatLengthFrames).value(), nextBeat.value(), kMaxBeatError); - // Also test prev/next beat calculation without snaping tolerance + // Also test prev/next beat calculation without snapping tolerance pGrid->findPrevNextBeats(position, &prevBeat, &nextBeat, false); - EXPECT_NEAR(position, prevBeat, kMaxBeatError); - EXPECT_NEAR(position + beatLength, nextBeat, kMaxBeatError); + EXPECT_NEAR(position.value(), prevBeat.value(), kMaxBeatError); + EXPECT_NEAR((position + beatLengthFrames).value(), nextBeat.value(), kMaxBeatError); // Both previous and next beat should return the current position. - EXPECT_NEAR(position, pGrid->findNextBeat(position), kMaxBeatError); - EXPECT_NEAR(position, pGrid->findPrevBeat(position), kMaxBeatError); + EXPECT_NEAR(position.value(), pGrid->findNextBeat(position).value(), kMaxBeatError); + EXPECT_NEAR(position.value(), pGrid->findPrevBeat(position).value(), kMaxBeatError); } TEST(BeatGridTest, TestNthBeatWhenOnBeat_BeforeEpsilon) { - int sampleRate = 44100; + constexpr int sampleRate = 44100; TrackPointer pTrack = newTrack(sampleRate); - double bpm = 60.1; - const int kFrameSize = 2; + constexpr double bpm = 60.1; pTrack->trySetBpm(bpm); - double beatLength = (60.0 * sampleRate / bpm) * kFrameSize; + constexpr double beatLengthFrames = 60.0 * sampleRate / bpm; - auto pGrid = BeatGrid::makeBeatGrid(pTrack->getSampleRate(), QString(), bpm, 0); + auto pGrid = BeatGrid::makeBeatGrid(pTrack->getSampleRate(), + QString(), + mixxx::Bpm(bpm), + mixxx::audio::kStartFramePos); // Pretend we're just before the 20th beat. - const double kClosestBeat = 20 * beatLength; - double position = kClosestBeat - beatLength * 0.005; + constexpr mixxx::audio::FramePos kClosestBeat(20 * beatLengthFrames); + const mixxx::audio::FramePos position(kClosestBeat - beatLengthFrames * 0.005); - // The spec dictates that a value of 0 is always invalid and returns -1 - EXPECT_EQ(-1, pGrid->findNthBeat(position, 0)); + // The spec dictates that a value of 0 is always invalid and returns an invalid position + EXPECT_FALSE(pGrid->findNthBeat(position, 0).isValid()); // findNthBeat should return exactly the current beat if we ask for 1 or // -1. For all other values, it should return n times the beat length. for (int i = 1; i < 20; ++i) { - EXPECT_NEAR(kClosestBeat + beatLength * (i - 1), pGrid->findNthBeat(position, i), kMaxBeatError); - EXPECT_NEAR(kClosestBeat + beatLength * (-i + 1), pGrid->findNthBeat(position, -i), kMaxBeatError); + EXPECT_NEAR((kClosestBeat + beatLengthFrames * (i - 1)).value(), + pGrid->findNthBeat(position, i).value(), + kMaxBeatError); + EXPECT_NEAR((kClosestBeat + beatLengthFrames * (-i + 1)).value(), + pGrid->findNthBeat(position, -i).value(), + kMaxBeatError); } // Also test prev/next beat calculation. - double prevBeat, nextBeat; + mixxx::audio::FramePos prevBeat, nextBeat; pGrid->findPrevNextBeats(position, &prevBeat, &nextBeat, true); - EXPECT_NEAR(kClosestBeat, prevBeat, kMaxBeatError); - EXPECT_NEAR(kClosestBeat + beatLength, nextBeat, kMaxBeatError); + EXPECT_NEAR(kClosestBeat.value(), prevBeat.value(), kMaxBeatError); + EXPECT_NEAR((kClosestBeat + beatLengthFrames).value(), nextBeat.value(), kMaxBeatError); - // Also test prev/next beat calculation without snaping tolerance + // Also test prev/next beat calculation without snapping tolerance pGrid->findPrevNextBeats(position, &prevBeat, &nextBeat, false); - EXPECT_NEAR(kClosestBeat - beatLength, prevBeat, kMaxBeatError); - EXPECT_NEAR(kClosestBeat, nextBeat, kMaxBeatError); + EXPECT_NEAR((kClosestBeat - beatLengthFrames).value(), prevBeat.value(), kMaxBeatError); + EXPECT_NEAR(kClosestBeat.value(), nextBeat.value(), kMaxBeatError); // Both previous and next beat should return the closest beat. - EXPECT_NEAR(kClosestBeat, pGrid->findNextBeat(position), kMaxBeatError); - EXPECT_NEAR(kClosestBeat, pGrid->findPrevBeat(position), kMaxBeatError); + EXPECT_NEAR(kClosestBeat.value(), pGrid->findNextBeat(position).value(), kMaxBeatError); + EXPECT_NEAR(kClosestBeat.value(), pGrid->findPrevBeat(position).value(), kMaxBeatError); } TEST(BeatGridTest, TestNthBeatWhenOnBeat_AfterEpsilon) { - int sampleRate = 44100; + constexpr int sampleRate = 44100; TrackPointer pTrack = newTrack(sampleRate); - double bpm = 60.1; - const int kFrameSize = 2; + constexpr double bpm = 60.1; pTrack->trySetBpm(bpm); - double beatLength = (60.0 * sampleRate / bpm) * kFrameSize; + constexpr double beatLengthFrames = 60.0 * sampleRate / bpm; - auto pGrid = BeatGrid::makeBeatGrid(pTrack->getSampleRate(), QString(), bpm, 0); + auto pGrid = BeatGrid::makeBeatGrid(pTrack->getSampleRate(), + QString(), + mixxx::Bpm(bpm), + mixxx::audio::kStartFramePos); // Pretend we're just before the 20th beat. - const double kClosestBeat = 20 * beatLength; - double position = kClosestBeat + beatLength * 0.005; + constexpr mixxx::audio::FramePos kClosestBeat(20 * beatLengthFrames); + const mixxx::audio::FramePos position(kClosestBeat + beatLengthFrames * 0.005); - // The spec dictates that a value of 0 is always invalid and returns -1 - EXPECT_EQ(-1, pGrid->findNthBeat(position, 0)); + // The spec dictates that a value of 0 is always invalid and returns an invalid position + EXPECT_FALSE(pGrid->findNthBeat(position, 0).isValid()); // findNthBeat should return exactly the current beat if we ask for 1 or // -1. For all other values, it should return n times the beat length. for (int i = 1; i < 20; ++i) { - EXPECT_NEAR(kClosestBeat + beatLength * (i - 1), pGrid->findNthBeat(position, i), kMaxBeatError); - EXPECT_NEAR(kClosestBeat + beatLength * (-i + 1), pGrid->findNthBeat(position, -i), kMaxBeatError); + EXPECT_NEAR((kClosestBeat + beatLengthFrames * (i - 1)).value(), + pGrid->findNthBeat(position, i).value(), + kMaxBeatError); + EXPECT_NEAR((kClosestBeat + beatLengthFrames * (-i + 1)).value(), + pGrid->findNthBeat(position, -i).value(), + kMaxBeatError); } // Also test prev/next beat calculation. - double prevBeat, nextBeat; + mixxx::audio::FramePos prevBeat, nextBeat; pGrid->findPrevNextBeats(position, &prevBeat, &nextBeat, true); - EXPECT_NEAR(kClosestBeat, prevBeat, kMaxBeatError); - EXPECT_NEAR(kClosestBeat + beatLength, nextBeat, kMaxBeatError); + EXPECT_NEAR(kClosestBeat.value(), prevBeat.value(), kMaxBeatError); + EXPECT_NEAR((kClosestBeat + beatLengthFrames).value(), nextBeat.value(), kMaxBeatError); - // Also test prev/next beat calculation without snaping tolerance + // Also test prev/next beat calculation without snapping tolerance pGrid->findPrevNextBeats(position, &prevBeat, &nextBeat, false); - EXPECT_NEAR(kClosestBeat, prevBeat, kMaxBeatError); - EXPECT_NEAR(kClosestBeat + beatLength, nextBeat, kMaxBeatError); + EXPECT_NEAR(kClosestBeat.value(), prevBeat.value(), kMaxBeatError); + EXPECT_NEAR((kClosestBeat + beatLengthFrames).value(), nextBeat.value(), kMaxBeatError); // Both previous and next beat should return the closest beat. - EXPECT_NEAR(kClosestBeat, pGrid->findNextBeat(position), kMaxBeatError); - EXPECT_NEAR(kClosestBeat, pGrid->findPrevBeat(position), kMaxBeatError); + EXPECT_NEAR(kClosestBeat.value(), pGrid->findNextBeat(position).value(), kMaxBeatError); + EXPECT_NEAR(kClosestBeat.value(), pGrid->findPrevBeat(position).value(), kMaxBeatError); } TEST(BeatGridTest, TestNthBeatWhenNotOnBeat) { - int sampleRate = 44100; + constexpr int sampleRate = 44100; TrackPointer pTrack = newTrack(sampleRate); - double bpm = 60.1; - const int kFrameSize = 2; - pTrack->trySetBpm(bpm); - double beatLength = (60.0 * sampleRate / bpm) * kFrameSize; + constexpr mixxx::Bpm bpm(60.1); + pTrack->trySetBpm(bpm.value()); + const mixxx::audio::FrameDiff_t beatLengthFrames = 60.0 * sampleRate / bpm.value(); - auto pGrid = BeatGrid::makeBeatGrid(pTrack->getSampleRate(), QString(), bpm, 0); + auto pGrid = BeatGrid::makeBeatGrid(pTrack->getSampleRate(), + QString(), + bpm, + mixxx::audio::kStartFramePos); // Pretend we're half way between the 20th and 21st beat - double previousBeat = beatLength * 20.0; - double nextBeat = beatLength * 21.0; - double position = (nextBeat + previousBeat) / 2.0; + const mixxx::audio::FramePos previousBeat(beatLengthFrames * 20.0); + const mixxx::audio::FramePos nextBeat(beatLengthFrames * 21.0); + const mixxx::audio::FramePos position = previousBeat + (nextBeat - previousBeat) / 2.0; - // The spec dictates that a value of 0 is always invalid and returns -1 - EXPECT_EQ(-1, pGrid->findNthBeat(position, 0)); + // The spec dictates that a value of 0 is always invalid and returns an invalid position + EXPECT_FALSE(pGrid->findNthBeat(position, 0).isValid()); // findNthBeat should return multiples of beats starting from the next or // previous beat, depending on whether N is positive or negative. for (int i = 1; i < 20; ++i) { - EXPECT_NEAR(nextBeat + beatLength*(i-1), pGrid->findNthBeat(position, i), kMaxBeatError); - EXPECT_NEAR(previousBeat + beatLength*(-i+1), pGrid->findNthBeat(position, -i), kMaxBeatError); + EXPECT_NEAR((nextBeat + beatLengthFrames * (i - 1)).value(), + pGrid->findNthBeat(position, i).value(), + kMaxBeatError); + EXPECT_NEAR((previousBeat + beatLengthFrames * (-i + 1)).value(), + pGrid->findNthBeat(position, -i).value(), + kMaxBeatError); } // Also test prev/next beat calculation - double foundPrevBeat, foundNextBeat; + mixxx::audio::FramePos foundPrevBeat, foundNextBeat; pGrid->findPrevNextBeats(position, &foundPrevBeat, &foundNextBeat, true); - EXPECT_NEAR(previousBeat, foundPrevBeat, kMaxBeatError); - EXPECT_NEAR(nextBeat, foundNextBeat, kMaxBeatError); + EXPECT_NEAR(previousBeat.value(), foundPrevBeat.value(), kMaxBeatError); + EXPECT_NEAR(nextBeat.value(), foundNextBeat.value(), kMaxBeatError); - // Also test prev/next beat calculation without snaping tolerance + // Also test prev/next beat calculation without snapping tolerance pGrid->findPrevNextBeats(position, &foundPrevBeat, &foundNextBeat, false); - EXPECT_NEAR(previousBeat, foundPrevBeat, kMaxBeatError); - EXPECT_NEAR(nextBeat, foundNextBeat, kMaxBeatError); + EXPECT_NEAR(previousBeat.value(), foundPrevBeat.value(), kMaxBeatError); + EXPECT_NEAR(nextBeat.value(), foundNextBeat.value(), kMaxBeatError); } TEST(BeatGridTest, FromMetadata) { int sampleRate = 44100; TrackPointer pTrack = newTrack(sampleRate); - double bpm = 60.1; - ASSERT_TRUE(pTrack->trySetBpm(bpm)); - EXPECT_DOUBLE_EQ(pTrack->getBpm(), bpm); + constexpr mixxx::Bpm bpm(60.1); + ASSERT_TRUE(pTrack->trySetBpm(bpm.value())); + EXPECT_DOUBLE_EQ(pTrack->getBpm(), bpm.value()); auto pBeats = pTrack->getBeats(); - EXPECT_DOUBLE_EQ(pBeats->getBpm(), bpm); + EXPECT_DOUBLE_EQ(pBeats->getBpm().value(), bpm.value()); // Invalid bpm resets the bpm ASSERT_TRUE(pTrack->trySetBpm(-60.1)); diff --git a/src/test/beatmaptest.cpp b/src/test/beatmaptest.cpp index 73253ff6715..6cbe84dbb50 100644 --- a/src/test/beatmaptest.cpp +++ b/src/test/beatmaptest.cpp @@ -23,18 +23,14 @@ class BeatMapTest : public testing::Test { mixxx::Duration::fromSeconds(180)); } - double getBeatLengthFrames(double bpm) { - return (60.0 * m_iSampleRate / bpm); + mixxx::audio::FrameDiff_t getBeatLengthFrames(mixxx::Bpm bpm) { + return (60.0 * m_iSampleRate / bpm.value()); } - double getBeatLengthSamples(double bpm) { - return getBeatLengthFrames(bpm) * m_iFrameSize; - } - - QVector createBeatVector(double first_beat, - unsigned int num_beats, - double beat_length) { - QVector beats; + QVector createBeatVector(mixxx::audio::FramePos first_beat, + unsigned int num_beats, + mixxx::audio::FrameDiff_t beat_length) { + QVector beats; for (unsigned int i = 0; i < num_beats; ++i) { beats.append(first_beat + i * beat_length); } @@ -47,103 +43,104 @@ class BeatMapTest : public testing::Test { }; TEST_F(BeatMapTest, Scale) { - const double bpm = 60.0; - m_pTrack->trySetBpm(bpm); - double beatLengthFrames = getBeatLengthFrames(bpm); - double startOffsetFrames = 7; + constexpr mixxx::Bpm bpm(60.0); + m_pTrack->trySetBpm(bpm.value()); + mixxx::audio::FrameDiff_t beatLengthFrames = getBeatLengthFrames(bpm); + const auto startOffsetFrames = mixxx::audio::FramePos(7); const int numBeats = 100; // Note beats must be in frames, not samples. - QVector beats = createBeatVector(startOffsetFrames, numBeats, beatLengthFrames); + QVector beats = + createBeatVector(startOffsetFrames, numBeats, beatLengthFrames); auto pMap = BeatMap::makeBeatMap(m_pTrack->getSampleRate(), QString(), beats); - EXPECT_DOUBLE_EQ(bpm, pMap->getBpm()); - pMap = pMap->scale(Beats::DOUBLE); - EXPECT_DOUBLE_EQ(2 * bpm, pMap->getBpm()); + EXPECT_DOUBLE_EQ(bpm.value(), pMap->getBpm().value()); + pMap = pMap->scale(Beats::BpmScale::Double); + EXPECT_DOUBLE_EQ(2 * bpm.value(), pMap->getBpm().value()); - pMap = pMap->scale(Beats::HALVE); - EXPECT_DOUBLE_EQ(bpm, pMap->getBpm()); + pMap = pMap->scale(Beats::BpmScale::Halve); + EXPECT_DOUBLE_EQ(bpm.value(), pMap->getBpm().value()); - pMap = pMap->scale(Beats::TWOTHIRDS); - EXPECT_DOUBLE_EQ(bpm * 2 / 3, pMap->getBpm()); + pMap = pMap->scale(Beats::BpmScale::TwoThirds); + EXPECT_DOUBLE_EQ(bpm.value() * 2 / 3, pMap->getBpm().value()); - pMap = pMap->scale(Beats::THREEHALVES); - EXPECT_DOUBLE_EQ(bpm, pMap->getBpm()); + pMap = pMap->scale(Beats::BpmScale::ThreeHalves); + EXPECT_DOUBLE_EQ(bpm.value(), pMap->getBpm().value()); - pMap = pMap->scale(Beats::THREEFOURTHS); - EXPECT_DOUBLE_EQ(bpm * 3 / 4, pMap->getBpm()); + pMap = pMap->scale(Beats::BpmScale::ThreeFourths); + EXPECT_DOUBLE_EQ(bpm.value() * 3 / 4, pMap->getBpm().value()); - pMap = pMap->scale(Beats::FOURTHIRDS); - EXPECT_DOUBLE_EQ(bpm, pMap->getBpm()); + pMap = pMap->scale(Beats::BpmScale::FourThirds); + EXPECT_DOUBLE_EQ(bpm.value(), pMap->getBpm().value()); } TEST_F(BeatMapTest, TestNthBeat) { - const double bpm = 60.0; - m_pTrack->trySetBpm(bpm); - double beatLengthFrames = getBeatLengthFrames(bpm); - double startOffsetFrames = 7; - double beatLengthSamples = getBeatLengthSamples(bpm); - double startOffsetSamples = startOffsetFrames * 2; + constexpr mixxx::Bpm bpm(60.0); + m_pTrack->trySetBpm(bpm.value()); + mixxx::audio::FrameDiff_t beatLengthFrames = getBeatLengthFrames(bpm); + const auto startOffsetFrames = mixxx::audio::FramePos(7); const int numBeats = 100; // Note beats must be in frames, not samples. - QVector beats = createBeatVector(startOffsetFrames, numBeats, beatLengthFrames); + QVector beats = + createBeatVector(startOffsetFrames, numBeats, beatLengthFrames); auto pMap = BeatMap::makeBeatMap(m_pTrack->getSampleRate(), QString(), beats); // Check edge cases - double firstBeat = startOffsetSamples + beatLengthSamples * 0; - double lastBeat = startOffsetSamples + beatLengthSamples * (numBeats - 1); + const mixxx::audio::FramePos firstBeat = startOffsetFrames + beatLengthFrames * 0; + const mixxx::audio::FramePos lastBeat = startOffsetFrames + beatLengthFrames * (numBeats - 1); EXPECT_EQ(lastBeat, pMap->findNthBeat(lastBeat, 1)); EXPECT_EQ(lastBeat, pMap->findNextBeat(lastBeat)); - EXPECT_EQ(-1, pMap->findNthBeat(lastBeat, 2)); + EXPECT_FALSE(pMap->findNthBeat(lastBeat, 2).isValid()); EXPECT_EQ(firstBeat, pMap->findNthBeat(firstBeat, -1)); EXPECT_EQ(firstBeat, pMap->findPrevBeat(firstBeat)); - EXPECT_EQ(-1, pMap->findNthBeat(firstBeat, -2)); + EXPECT_FALSE(pMap->findNthBeat(firstBeat, -2).isValid()); - double prevBeat, nextBeat; + mixxx::audio::FramePos prevBeat, nextBeat; pMap->findPrevNextBeats(lastBeat, &prevBeat, &nextBeat, true); EXPECT_EQ(lastBeat, prevBeat); - EXPECT_EQ(-1, nextBeat); + EXPECT_FALSE(nextBeat.isValid()); pMap->findPrevNextBeats(firstBeat, &prevBeat, &nextBeat, true); EXPECT_EQ(firstBeat, prevBeat); - EXPECT_EQ(firstBeat + beatLengthSamples, nextBeat); + EXPECT_EQ(firstBeat + beatLengthFrames, nextBeat); } TEST_F(BeatMapTest, TestNthBeatWhenOnBeat) { - const double bpm = 60.0; - m_pTrack->trySetBpm(bpm); - double beatLengthFrames = getBeatLengthFrames(bpm); - double startOffsetFrames = 7; - double beatLengthSamples = getBeatLengthSamples(bpm); - double startOffsetSamples = startOffsetFrames * 2; + constexpr mixxx::Bpm bpm(60.0); + m_pTrack->trySetBpm(bpm.value()); + mixxx::audio::FrameDiff_t beatLengthFrames = getBeatLengthFrames(bpm); + const auto startOffsetFrames = mixxx::audio::FramePos(7); const int numBeats = 100; // Note beats must be in frames, not samples. - QVector beats = createBeatVector(startOffsetFrames, numBeats, beatLengthFrames); + QVector beats = + createBeatVector(startOffsetFrames, numBeats, beatLengthFrames); auto pMap = BeatMap::makeBeatMap(m_pTrack->getSampleRate(), QString(), beats); // Pretend we're on the 20th beat; const int curBeat = 20; - double position = startOffsetSamples + beatLengthSamples * curBeat; + const mixxx::audio::FramePos position = startOffsetFrames + beatLengthFrames * curBeat; - // The spec dictates that a value of 0 is always invalid and returns -1 - EXPECT_EQ(-1, pMap->findNthBeat(position, 0)); + // The spec dictates that a value of 0 is always invalid and returns an invalid position + EXPECT_FALSE(pMap->findNthBeat(position, 0).isValid()); // findNthBeat should return exactly the current beat if we ask for 1 or // -1. For all other values, it should return n times the beat length. for (int i = 1; i < curBeat; ++i) { - EXPECT_DOUBLE_EQ(position + beatLengthSamples*(i-1), pMap->findNthBeat(position, i)); - EXPECT_DOUBLE_EQ(position + beatLengthSamples*(-i+1), pMap->findNthBeat(position, -i)); + EXPECT_DOUBLE_EQ((position + beatLengthFrames * (i - 1)).value(), + pMap->findNthBeat(position, i).value()); + EXPECT_DOUBLE_EQ((position + beatLengthFrames * (-i + 1)).value(), + pMap->findNthBeat(position, -i).value()); } // Also test prev/next beat calculation. - double prevBeat, nextBeat; + mixxx::audio::FramePos prevBeat, nextBeat; pMap->findPrevNextBeats(position, &prevBeat, &nextBeat, true); EXPECT_EQ(position, prevBeat); - EXPECT_EQ(position + beatLengthSamples, nextBeat); + EXPECT_EQ(position + beatLengthFrames, nextBeat); - // Also test prev/next beat calculation without snaping tolerance + // Also test prev/next beat calculation without snapping tolerance pMap->findPrevNextBeats(position, &prevBeat, &nextBeat, false); EXPECT_EQ(position, prevBeat); - EXPECT_EQ(position + beatLengthSamples, nextBeat); + EXPECT_EQ(position + beatLengthFrames, nextBeat); // Both previous and next beat should return the current position. EXPECT_EQ(position, pMap->findNextBeat(position)); @@ -151,41 +148,42 @@ TEST_F(BeatMapTest, TestNthBeatWhenOnBeat) { } TEST_F(BeatMapTest, TestNthBeatWhenOnBeat_BeforeEpsilon) { - const double bpm = 60.0; - m_pTrack->trySetBpm(bpm); - double beatLengthFrames = getBeatLengthFrames(bpm); - double startOffsetFrames = 7; - double beatLengthSamples = getBeatLengthSamples(bpm); - double startOffsetSamples = startOffsetFrames * 2; + constexpr mixxx::Bpm bpm(60.0); + m_pTrack->trySetBpm(bpm.value()); + mixxx::audio::FrameDiff_t beatLengthFrames = getBeatLengthFrames(bpm); + const auto startOffsetFrames = mixxx::audio::FramePos(7); const int numBeats = 100; // Note beats must be in frames, not samples. - QVector beats = createBeatVector(startOffsetFrames, numBeats, beatLengthFrames); + QVector beats = + createBeatVector(startOffsetFrames, numBeats, beatLengthFrames); auto pMap = BeatMap::makeBeatMap(m_pTrack->getSampleRate(), QString(), beats); // Pretend we're just before the 20th beat; const int curBeat = 20; - const double kClosestBeat = startOffsetSamples + curBeat * beatLengthSamples; - double position = kClosestBeat - beatLengthSamples * 0.005; + const mixxx::audio::FramePos kClosestBeat = startOffsetFrames + curBeat * beatLengthFrames; + const mixxx::audio::FramePos position = kClosestBeat - beatLengthFrames * 0.005; // The spec dictates that a value of 0 is always invalid and returns -1 - EXPECT_EQ(-1, pMap->findNthBeat(position, 0)); + EXPECT_FALSE(pMap->findNthBeat(position, 0).isValid()); // findNthBeat should return exactly the current beat if we ask for 1 or // -1. For all other values, it should return n times the beat length. for (int i = 1; i < curBeat; ++i) { - EXPECT_DOUBLE_EQ(kClosestBeat + beatLengthSamples*(i-1), pMap->findNthBeat(position, i)); - EXPECT_DOUBLE_EQ(kClosestBeat + beatLengthSamples*(-i+1), pMap->findNthBeat(position, -i)); + EXPECT_DOUBLE_EQ((kClosestBeat + beatLengthFrames * (i - 1)).value(), + pMap->findNthBeat(position, i).value()); + EXPECT_DOUBLE_EQ((kClosestBeat + beatLengthFrames * (-i + 1)).value(), + pMap->findNthBeat(position, -i).value()); } // Also test prev/next beat calculation - double prevBeat, nextBeat; + mixxx::audio::FramePos prevBeat, nextBeat; pMap->findPrevNextBeats(position, &prevBeat, &nextBeat, true); EXPECT_EQ(kClosestBeat, prevBeat); - EXPECT_EQ(kClosestBeat + beatLengthSamples, nextBeat); + EXPECT_EQ(kClosestBeat + beatLengthFrames, nextBeat); - // Also test prev/next beat calculation without snaping tolerance + // Also test prev/next beat calculation without snapping tolerance pMap->findPrevNextBeats(position, &prevBeat, &nextBeat, false); - EXPECT_EQ(kClosestBeat - beatLengthSamples, prevBeat); + EXPECT_EQ(kClosestBeat - beatLengthFrames, prevBeat); EXPECT_EQ(kClosestBeat, nextBeat); // Both previous and next beat should return the closest beat. @@ -195,44 +193,45 @@ TEST_F(BeatMapTest, TestNthBeatWhenOnBeat_BeforeEpsilon) { } TEST_F(BeatMapTest, TestNthBeatWhenOnBeat_AfterEpsilon) { - const double bpm = 60.0; - m_pTrack->trySetBpm(bpm); - double beatLengthFrames = getBeatLengthFrames(bpm); - double startOffsetFrames = 7; - double beatLengthSamples = getBeatLengthSamples(bpm); - double startOffsetSamples = startOffsetFrames * 2; + constexpr mixxx::Bpm bpm(60.0); + m_pTrack->trySetBpm(bpm.value()); + mixxx::audio::FrameDiff_t beatLengthFrames = getBeatLengthFrames(bpm); + const auto startOffsetFrames = mixxx::audio::FramePos(7); const int numBeats = 100; // Note beats must be in frames, not samples. - QVector beats = createBeatVector(startOffsetFrames, numBeats, beatLengthFrames); + QVector beats = + createBeatVector(startOffsetFrames, numBeats, beatLengthFrames); auto pMap = BeatMap::makeBeatMap(m_pTrack->getSampleRate(), QString(), beats); // Pretend we're just after the 20th beat; const int curBeat = 20; - const double kClosestBeat = startOffsetSamples + curBeat * beatLengthSamples; - double position = kClosestBeat + beatLengthSamples * 0.005; + const mixxx::audio::FramePos kClosestBeat = startOffsetFrames + curBeat * beatLengthFrames; + const mixxx::audio::FramePos position = kClosestBeat + beatLengthFrames * 0.005; // The spec dictates that a value of 0 is always invalid and returns -1 - EXPECT_EQ(-1, pMap->findNthBeat(position, 0)); + EXPECT_FALSE(pMap->findNthBeat(position, 0).isValid()); EXPECT_EQ(kClosestBeat, pMap->findClosestBeat(position)); // findNthBeat should return exactly the current beat if we ask for 1 or // -1. For all other values, it should return n times the beat length. for (int i = 1; i < curBeat; ++i) { - EXPECT_DOUBLE_EQ(kClosestBeat + beatLengthSamples*(i-1), pMap->findNthBeat(position, i)); - EXPECT_DOUBLE_EQ(kClosestBeat + beatLengthSamples*(-i+1), pMap->findNthBeat(position, -i)); + EXPECT_DOUBLE_EQ((kClosestBeat + beatLengthFrames * (i - 1)).value(), + pMap->findNthBeat(position, i).value()); + EXPECT_DOUBLE_EQ((kClosestBeat + beatLengthFrames * (-i + 1)).value(), + pMap->findNthBeat(position, -i).value()); } // Also test prev/next beat calculation. - double prevBeat, nextBeat; + mixxx::audio::FramePos prevBeat, nextBeat; pMap->findPrevNextBeats(position, &prevBeat, &nextBeat, true); EXPECT_EQ(kClosestBeat, prevBeat); - EXPECT_EQ(kClosestBeat + beatLengthSamples, nextBeat); + EXPECT_EQ(kClosestBeat + beatLengthFrames, nextBeat); // Also test prev/next beat calculation without snapping tolerance pMap->findPrevNextBeats(position, &prevBeat, &nextBeat, false); EXPECT_EQ(kClosestBeat, prevBeat); - EXPECT_EQ(kClosestBeat + beatLengthSamples, nextBeat); + EXPECT_EQ(kClosestBeat + beatLengthFrames, nextBeat); // Both previous and next beat should return the closest beat. EXPECT_EQ(kClosestBeat, pMap->findNextBeat(position)); @@ -240,56 +239,55 @@ TEST_F(BeatMapTest, TestNthBeatWhenOnBeat_AfterEpsilon) { } TEST_F(BeatMapTest, TestNthBeatWhenNotOnBeat) { - const double bpm = 60.0; - m_pTrack->trySetBpm(bpm); - double beatLengthFrames = getBeatLengthFrames(bpm); - double startOffsetFrames = 7; - double beatLengthSamples = getBeatLengthSamples(bpm); - double startOffsetSamples = startOffsetFrames * 2; + constexpr mixxx::Bpm bpm(60.0); + m_pTrack->trySetBpm(bpm.value()); + mixxx::audio::FrameDiff_t beatLengthFrames = getBeatLengthFrames(bpm); + const auto startOffsetFrames = mixxx::audio::FramePos(7); const int numBeats = 100; // Note beats must be in frames, not samples. - QVector beats = createBeatVector(startOffsetFrames, numBeats, beatLengthFrames); + QVector beats = + createBeatVector(startOffsetFrames, numBeats, beatLengthFrames); auto pMap = BeatMap::makeBeatMap(m_pTrack->getSampleRate(), QString(), beats); // Pretend we're half way between the 20th and 21st beat - double previousBeat = startOffsetSamples + beatLengthSamples * 20.0; - double nextBeat = startOffsetSamples + beatLengthSamples * 21.0; - double position = (nextBeat + previousBeat) / 2.0; + const mixxx::audio::FramePos previousBeat = startOffsetFrames + beatLengthFrames * 20.0; + const mixxx::audio::FramePos nextBeat = startOffsetFrames + beatLengthFrames * 21.0; + const mixxx::audio::FramePos position = previousBeat + (nextBeat - previousBeat) / 2.0; // The spec dictates that a value of 0 is always invalid and returns -1 - EXPECT_EQ(-1, pMap->findNthBeat(position, 0)); + EXPECT_FALSE(pMap->findNthBeat(position, 0).isValid()); // findNthBeat should return multiples of beats starting from the next or // previous beat, depending on whether N is positive or negative. for (int i = 1; i < 20; ++i) { - EXPECT_DOUBLE_EQ(nextBeat + beatLengthSamples*(i-1), - pMap->findNthBeat(position, i)); - EXPECT_DOUBLE_EQ(previousBeat - beatLengthSamples*(i-1), - pMap->findNthBeat(position, -i)); + EXPECT_DOUBLE_EQ((nextBeat + beatLengthFrames * (i - 1)).value(), + pMap->findNthBeat(position, i).value()); + EXPECT_DOUBLE_EQ((previousBeat - beatLengthFrames * (i - 1)).value(), + pMap->findNthBeat(position, -i).value()); } // Also test prev/next beat calculation - double foundPrevBeat, foundNextBeat; + mixxx::audio::FramePos foundPrevBeat, foundNextBeat; pMap->findPrevNextBeats(position, &foundPrevBeat, &foundNextBeat, true); EXPECT_EQ(previousBeat, foundPrevBeat); EXPECT_EQ(nextBeat, foundNextBeat); - // Also test prev/next beat calculation without snaping tolerance + // Also test prev/next beat calculation without snapping tolerance pMap->findPrevNextBeats(position, &foundPrevBeat, &foundNextBeat, false); EXPECT_EQ(previousBeat, foundPrevBeat); EXPECT_EQ(nextBeat, foundNextBeat); } TEST_F(BeatMapTest, TestBpmAround) { - const double filebpm = 60.0; - double approx_beat_length = getBeatLengthSamples(filebpm); - m_pTrack->trySetBpm(filebpm); + constexpr mixxx::Bpm filebpm(60.0); + double approx_beat_length = getBeatLengthFrames(filebpm); + m_pTrack->trySetBpm(filebpm.value()); const int numBeats = 64; - QVector beats; - double beat_pos = 0; - for (unsigned int i = 0, bpm=60; i < numBeats; ++i, ++bpm) { - double beat_length = getBeatLengthFrames(bpm); + QVector beats; + mixxx::audio::FramePos beat_pos = mixxx::audio::kStartFramePos; + for (unsigned int i = 0, bpmValue = 60; i < numBeats; ++i, ++bpmValue) { + const mixxx::audio::FrameDiff_t beat_length = getBeatLengthFrames(mixxx::Bpm(bpmValue)); beats.append(beat_pos); beat_pos += beat_length; } @@ -299,19 +297,33 @@ TEST_F(BeatMapTest, TestBpmAround) { // The average of the first 8 beats should be different than the average // of the last 8 beats. EXPECT_DOUBLE_EQ(63.937645572318047, - pMap->getBpmAroundPosition(4 * approx_beat_length, 4)); + pMap->getBpmAroundPosition( + mixxx::audio::kStartFramePos + 4 * approx_beat_length, + 4) + .value()); EXPECT_DOUBLE_EQ(118.96668932698844, - pMap->getBpmAroundPosition(60 * approx_beat_length, 4)); + pMap->getBpmAroundPosition( + mixxx::audio::kStartFramePos + 60 * approx_beat_length, + 4) + .value()); // Also test at the beginning and end of the track EXPECT_DOUBLE_EQ(62.937377309576974, - pMap->getBpmAroundPosition(0, 4)); + pMap->getBpmAroundPosition(mixxx::audio::kStartFramePos, 4).value()); EXPECT_DOUBLE_EQ(118.96668932698844, - pMap->getBpmAroundPosition(65 * approx_beat_length, 4)); + pMap->getBpmAroundPosition( + mixxx::audio::kStartFramePos + 65 * approx_beat_length, + 4) + .value()); // Try a really, really short track - beats = createBeatVector(10, 3, getBeatLengthFrames(filebpm)); + constexpr auto startFramePos = mixxx::audio::FramePos(10); + beats = createBeatVector(startFramePos, 3, approx_beat_length); pMap = BeatMap::makeBeatMap(m_pTrack->getSampleRate(), QString(), beats); - EXPECT_DOUBLE_EQ(filebpm, pMap->getBpmAroundPosition(1 * approx_beat_length, 4)); + EXPECT_DOUBLE_EQ(filebpm.value(), + pMap->getBpmAroundPosition( + mixxx::audio::kStartFramePos + 1 * approx_beat_length, + 4) + .value()); } } // namespace diff --git a/src/test/beatstranslatetest.cpp b/src/test/beatstranslatetest.cpp index dbbdefdb8c1..f476aecf3db 100644 --- a/src/test/beatstranslatetest.cpp +++ b/src/test/beatstranslatetest.cpp @@ -7,21 +7,23 @@ class BeatsTranslateTest : public MockedEngineBackendTest { TEST_F(BeatsTranslateTest, SimpleTranslateMatch) { // Set up BeatGrids for decks 1 and 2. - const double bpm = 60.0; - const double firstBeat = 0.0; + const auto bpm = mixxx::Bpm(60.0); + constexpr auto firstBeat = mixxx::audio::kStartFramePos; auto grid1 = mixxx::BeatGrid::makeBeatGrid( m_pTrack1->getSampleRate(), QString(), bpm, firstBeat); m_pTrack1->trySetBeats(grid1); - ASSERT_DOUBLE_EQ(firstBeat, grid1->findClosestBeat(0)); + ASSERT_DOUBLE_EQ(firstBeat.value(), + grid1->findClosestBeat(mixxx::audio::kStartFramePos).value()); auto grid2 = mixxx::BeatGrid::makeBeatGrid( m_pTrack2->getSampleRate(), QString(), bpm, firstBeat); m_pTrack2->trySetBeats(grid2); - ASSERT_DOUBLE_EQ(firstBeat, grid2->findClosestBeat(0)); + ASSERT_DOUBLE_EQ(firstBeat.value(), + grid2->findClosestBeat(mixxx::audio::kStartFramePos).value()); // Seek deck 1 forward a bit. - const double delta = 2222.0; - m_pChannel1->getEngineBuffer()->slotControlSeekAbs(delta); + const double deltaFrames = 1111.0; + m_pChannel1->getEngineBuffer()->slotControlSeekAbs(deltaFrames * 2.0); ProcessBuffer(); EXPECT_TRUE(m_pChannel1->getEngineBuffer()->getVisualPlayPos() > 0); @@ -33,8 +35,8 @@ TEST_F(BeatsTranslateTest, SimpleTranslateMatch) { // doesn't get set naturally, but this will do for now. auto pBpm1 = std::make_unique(m_sGroup1, "bpm"); auto pBpm2 = std::make_unique(m_sGroup1, "bpm"); - pBpm1->set(bpm); - pBpm2->set(bpm); + pBpm1->set(bpm.value()); + pBpm2->set(bpm.value()); ProcessBuffer(); // Push the button on deck 2. @@ -43,9 +45,9 @@ TEST_F(BeatsTranslateTest, SimpleTranslateMatch) { pTranslateMatchAlignment->set(1.0); ProcessBuffer(); - // Deck 1 is +delta away from its closest beat (which is at 0). - // Deck 2 was left at 0. We translated grid 2 so that it is also +delta - // away from its closest beat, so that beat should be at -delta. + // Deck 1 is +deltaFrames away from its closest beat (which is at 0). + // Deck 2 was left at 0. We translated grid 2 so that it is also +deltaFrames + // away from its closest beat, so that beat should be at -deltaFrames. mixxx::BeatsPointer beats = m_pTrack2->getBeats(); - ASSERT_DOUBLE_EQ(-delta, beats->findClosestBeat(0)); + ASSERT_DOUBLE_EQ(-deltaFrames, beats->findClosestBeat(mixxx::audio::kStartFramePos).value()); } diff --git a/src/test/bpmcontrol_test.cpp b/src/test/bpmcontrol_test.cpp index 997edf79ec2..18750d7fc38 100644 --- a/src/test/bpmcontrol_test.cpp +++ b/src/test/bpmcontrol_test.cpp @@ -33,11 +33,12 @@ TEST_F(BpmControlTest, BeatContext_BeatGrid) { mixxx::audio::Bitrate(), mixxx::Duration::fromSeconds(180)); - const double bpm = 60.0; + const auto bpm = mixxx::Bpm(60.0); const int kFrameSize = 2; - const double expectedBeatLength = (60.0 * sampleRate / bpm) * kFrameSize; + const double expectedBeatLength = (60.0 * sampleRate / bpm.value()) * kFrameSize; - const mixxx::BeatsPointer pBeats = BeatFactory::makeBeatGrid(pTrack->getSampleRate(), bpm, 0); + const mixxx::BeatsPointer pBeats = BeatFactory::makeBeatGrid( + pTrack->getSampleRate(), bpm, mixxx::audio::kStartFramePos); // On a beat. double prevBeat, nextBeat, beatLength, beatPercentage; diff --git a/src/test/bpmtest.cpp b/src/test/bpmtest.cpp new file mode 100644 index 00000000000..6152bf5fecb --- /dev/null +++ b/src/test/bpmtest.cpp @@ -0,0 +1,38 @@ +#include + +#include + +#include "track/bpm.h" + +class BpmTest : public testing::Test { +}; + +TEST_F(BpmTest, TestBpmComparisonOperators) { + EXPECT_EQ(mixxx::Bpm(120), mixxx::Bpm(120)); + EXPECT_EQ(mixxx::Bpm(120), mixxx::Bpm(60) * 2); + EXPECT_EQ(mixxx::Bpm(120), mixxx::Bpm(240) / 2); + + EXPECT_LT(mixxx::Bpm(120.0), mixxx::Bpm(130.0)); + EXPECT_LE(mixxx::Bpm(120.0), mixxx::Bpm(130.0)); + EXPECT_LE(mixxx::Bpm(120.0), mixxx::Bpm(120.0)); + + EXPECT_GT(mixxx::Bpm(130.0), mixxx::Bpm(120.0)); + EXPECT_GE(mixxx::Bpm(130.0), mixxx::Bpm(120.0)); + EXPECT_GE(mixxx::Bpm(130.0), mixxx::Bpm(130.0)); + + // Verify that invalid values are equal to each other, regardless of their + // actual value. + EXPECT_EQ(mixxx::Bpm(mixxx::Bpm::kValueUndefined), mixxx::Bpm()); + EXPECT_EQ(mixxx::Bpm(0.0), mixxx::Bpm()); + EXPECT_EQ(mixxx::Bpm(-120.0), mixxx::Bpm()); + EXPECT_EQ(mixxx::Bpm(-120.0), mixxx::Bpm(0.0)); + EXPECT_EQ(mixxx::Bpm(-120.0), mixxx::Bpm(-100.0)); + + // Here, both values are invalid and therefore equal, so both <= and >= returns true. + EXPECT_LE(mixxx::Bpm(-120.0), mixxx::Bpm(-100.0)); + EXPECT_GE(mixxx::Bpm(-120.0), mixxx::Bpm(-100.0)); + + // Verify that valid and invalid values are not equal + EXPECT_NE(mixxx::Bpm(120.0), mixxx::Bpm()); + EXPECT_NE(mixxx::Bpm(120.0), mixxx::Bpm(-120.0)); +} diff --git a/src/test/coverartutils_test.cpp b/src/test/coverartutils_test.cpp index 59c8a9b2fc1..8bf8635dfea 100644 --- a/src/test/coverartutils_test.cpp +++ b/src/test/coverartutils_test.cpp @@ -59,6 +59,11 @@ TEST_F(CoverArtUtilTest, extractEmbeddedCover) { kTestDir.absoluteFilePath("cover-test-itunes-12.7.0-alac.m4a"), referencePNGImage); } + if (isSupportedFileExtension("m4v")) { + extractEmbeddedCover( + kTestDir.absoluteFilePath("cover-test.m4v"), referencePNGImage); + } + if (isSupportedFileExtension("mp3")) { // PNG extractEmbeddedCover( diff --git a/src/test/cue_test.cpp b/src/test/cue_test.cpp index 9707ae2e530..fb92e184b0e 100644 --- a/src/test/cue_test.cpp +++ b/src/test/cue_test.cpp @@ -12,8 +12,8 @@ TEST(CueTest, NewCueIsDirty) { const auto cue = Cue( mixxx::CueType::HotCue, 1, - 0.0, - Cue::kNoPosition); + mixxx::audio::kStartFramePos, + mixxx::audio::kInvalidFramePos); EXPECT_TRUE(cue.isDirty()); } diff --git a/src/test/cuecontrol_test.cpp b/src/test/cuecontrol_test.cpp index 2b8c1f6eb04..8b3457b8bf6 100644 --- a/src/test/cuecontrol_test.cpp +++ b/src/test/cuecontrol_test.cpp @@ -55,8 +55,9 @@ class CueControlTest : public BaseSignalPathTest { return m_pChannel1->getEngineBuffer()->m_pCueControl->getSampleOfTrack().current; } - void setCurrentSample(double sample) { - m_pChannel1->getEngineBuffer()->queueNewPlaypos(sample, EngineBuffer::SEEK_STANDARD); + void setCurrentSample(double samplePosition) { + const auto position = mixxx::audio::FramePos::fromEngineSamplePos(samplePosition); + m_pChannel1->getEngineBuffer()->queueNewPlaypos(position, EngineBuffer::SEEK_STANDARD); ProcessBuffer(); } @@ -397,8 +398,8 @@ TEST_F(CueControlTest, IntroCue_SetStartEnd_ClearStartEnd) { CuePointer pCue = pTrack->findCueByType(mixxx::CueType::Intro); EXPECT_NE(nullptr, pCue); if (pCue != nullptr) { - EXPECT_DOUBLE_EQ(100.0, pCue->getPosition()); - EXPECT_DOUBLE_EQ(0.0, pCue->getLength()); + EXPECT_DOUBLE_EQ(100.0, pCue->getPosition().toEngineSamplePos()); + EXPECT_DOUBLE_EQ(0.0, pCue->getLengthFrames() * mixxx::kEngineChannelCount); } // Set intro end cue @@ -413,8 +414,8 @@ TEST_F(CueControlTest, IntroCue_SetStartEnd_ClearStartEnd) { pCue = pTrack->findCueByType(mixxx::CueType::Intro); EXPECT_NE(nullptr, pCue); if (pCue != nullptr) { - EXPECT_DOUBLE_EQ(100.0, pCue->getPosition()); - EXPECT_DOUBLE_EQ(400.0, pCue->getLength()); + EXPECT_DOUBLE_EQ(100.0, pCue->getPosition().toEngineSamplePos()); + EXPECT_DOUBLE_EQ(400.0, pCue->getLengthFrames() * mixxx::kEngineChannelCount); } // Clear intro start cue @@ -428,8 +429,8 @@ TEST_F(CueControlTest, IntroCue_SetStartEnd_ClearStartEnd) { pCue = pTrack->findCueByType(mixxx::CueType::Intro); EXPECT_NE(nullptr, pCue); if (pCue != nullptr) { - EXPECT_DOUBLE_EQ(Cue::kNoPosition, pCue->getPosition()); - EXPECT_DOUBLE_EQ(500.0, pCue->getLength()); + EXPECT_EQ(mixxx::audio::kInvalidFramePos, pCue->getPosition()); + EXPECT_DOUBLE_EQ(500.0, pCue->getLengthFrames() * mixxx::kEngineChannelCount); } // Clear intro end cue @@ -458,8 +459,8 @@ TEST_F(CueControlTest, OutroCue_SetStartEnd_ClearStartEnd) { CuePointer pCue = pTrack->findCueByType(mixxx::CueType::Outro); EXPECT_NE(nullptr, pCue); if (pCue != nullptr) { - EXPECT_DOUBLE_EQ(750.0, pCue->getPosition()); - EXPECT_DOUBLE_EQ(0.0, pCue->getLength()); + EXPECT_DOUBLE_EQ(750.0, pCue->getPosition().toEngineSamplePos()); + EXPECT_DOUBLE_EQ(0.0, pCue->getLengthFrames() * mixxx::kEngineChannelCount); } // Set outro end cue @@ -474,8 +475,8 @@ TEST_F(CueControlTest, OutroCue_SetStartEnd_ClearStartEnd) { pCue = pTrack->findCueByType(mixxx::CueType::Outro); EXPECT_NE(nullptr, pCue); if (pCue != nullptr) { - EXPECT_DOUBLE_EQ(750.0, pCue->getPosition()); - EXPECT_DOUBLE_EQ(250.0, pCue->getLength()); + EXPECT_DOUBLE_EQ(750.0, pCue->getPosition().toEngineSamplePos()); + EXPECT_DOUBLE_EQ(250.0, pCue->getLengthFrames() * mixxx::kEngineChannelCount); } // Clear outro start cue @@ -489,8 +490,8 @@ TEST_F(CueControlTest, OutroCue_SetStartEnd_ClearStartEnd) { pCue = pTrack->findCueByType(mixxx::CueType::Outro); EXPECT_NE(nullptr, pCue); if (pCue != nullptr) { - EXPECT_DOUBLE_EQ(Cue::kNoPosition, pCue->getPosition()); - EXPECT_DOUBLE_EQ(1000.0, pCue->getLength()); + EXPECT_EQ(mixxx::audio::kInvalidFramePos, pCue->getPosition()); + EXPECT_DOUBLE_EQ(1000.0, pCue->getLengthFrames() * mixxx::kEngineChannelCount); } // Clear outro end cue diff --git a/src/test/enginebuffertest.cpp b/src/test/enginebuffertest.cpp index bce375dac5c..d0eb53f966c 100644 --- a/src/test/enginebuffertest.cpp +++ b/src/test/enginebuffertest.cpp @@ -241,8 +241,8 @@ TEST_F(EngineBufferE2ETest, ScratchTest) { // to the other. ControlObject::set(ConfigKey(m_sGroup1, "scratch2_enable"), 1.0); ControlObject::set(ConfigKey(m_sGroup1, "scratch2"), 1.1); - m_pChannel1->getEngineBuffer()->queueNewPlaypos(450, - EngineBuffer::SEEK_EXACT); + m_pChannel1->getEngineBuffer()->queueNewPlaypos( + mixxx::audio::FramePos(225), EngineBuffer::SEEK_EXACT); ProcessBuffer(); ControlObject::set(ConfigKey(m_sGroup1, "scratch2"), -1.1); ProcessBuffer(); @@ -354,8 +354,8 @@ TEST_F(EngineBufferE2ETest, SeekTest) { ControlObject::set(ConfigKey(m_sGroup1, "rate"), 0.0); ControlObject::set(ConfigKey(m_sGroup1, "play"), 1.0); ProcessBuffer(); - m_pChannel1->getEngineBuffer()->queueNewPlaypos(1000, - EngineBuffer::SEEK_EXACT); + m_pChannel1->getEngineBuffer()->queueNewPlaypos( + mixxx::audio::FramePos(500), EngineBuffer::SEEK_EXACT); ProcessBuffer(); assertBufferMatchesReference(m_pEngineMaster->masterBuffer(), kProcessBufferSize, "SeekTest"); @@ -406,7 +406,7 @@ TEST_F(EngineBufferE2ETest, CueGotoAndPlayTest) { ControlObject::set(ConfigKey(m_sGroup1, "quantize"), 1.0); ControlObject::set(ConfigKey(m_sGroup1, "cue_point"), 0.0); m_pChannel1->getEngineBuffer()->queueNewPlaypos( - 1000, EngineBuffer::SEEK_EXACT); + mixxx::audio::FramePos(500), EngineBuffer::SEEK_EXACT); ProcessBuffer(); ControlObject::set(ConfigKey(m_sGroup1, "cue_gotoandplay"), 1.0); ProcessBuffer(); @@ -430,7 +430,7 @@ TEST_F(EngineBufferE2ETest, CueGotoAndPlayDenon) { // enable Denon mode Bug #1504934 ControlObject::set(ConfigKey(m_sGroup1, "cue_mode"), 2.0); // CUE_MODE_DENON m_pChannel1->getEngineBuffer()->queueNewPlaypos( - 1000, EngineBuffer::SEEK_EXACT); + mixxx::audio::FramePos(500), EngineBuffer::SEEK_EXACT); ProcessBuffer(); double cueBefore = ControlObject::get(ConfigKey(m_sGroup1, "cue_point")); ControlObject::set(ConfigKey(m_sGroup1, "cue_gotoandplay"), 1.0); diff --git a/src/test/enginesynctest.cpp b/src/test/enginesynctest.cpp index 99e5bb7935a..7f1dfff05c1 100644 --- a/src/test/enginesynctest.cpp +++ b/src/test/enginesynctest.cpp @@ -244,9 +244,11 @@ TEST_F(EngineSyncTest, SetLeaderSuccess) { TEST_F(EngineSyncTest, ExplicitLeaderPersists) { // If we set an explicit leader, enabling sync or pressing play on other decks // doesn't cause the leader to move around. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 120, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(120), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 124, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(124), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); auto pButtonLeaderSync1 = @@ -276,11 +278,14 @@ TEST_F(EngineSyncTest, ExplicitLeaderPersists) { TEST_F(EngineSyncTest, SetLeaderWhilePlaying) { // Make sure we don't get two leader lights if we change leaders while playing. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 120, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(120), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 124, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(124), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); - mixxx::BeatsPointer pBeats3 = BeatFactory::makeBeatGrid(m_pTrack3->getSampleRate(), 128, 0.0); + mixxx::BeatsPointer pBeats3 = BeatFactory::makeBeatGrid( + m_pTrack3->getSampleRate(), mixxx::Bpm(128), mixxx::audio::kStartFramePos); m_pTrack3->trySetBeats(pBeats3); auto pButtonLeaderSync1 = @@ -310,7 +315,8 @@ TEST_F(EngineSyncTest, SetLeaderWhilePlaying) { TEST_F(EngineSyncTest, SetEnabledBecomesLeader) { // If we set the first channel with a valid tempo to follower, it should be leader. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 80, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(80), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); auto pButtonLeaderSync1 = std::make_unique(m_sGroup1, "sync_mode"); @@ -336,10 +342,12 @@ TEST_F(EngineSyncTest, DisableInternalLeaderWhilePlaying) { EXPECT_TRUE(isExplicitLeader(m_sInternalClockGroup)); // Make sure both decks are playing. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 80, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(80), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); ControlObject::getControl(ConfigKey(m_sGroup1, "play"))->set(1.0); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 80, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(80), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ControlObject::getControl(ConfigKey(m_sGroup2, "play"))->set(1.0); ProcessBuffer(); @@ -355,13 +363,15 @@ TEST_F(EngineSyncTest, DisableInternalLeaderWhilePlaying) { TEST_F(EngineSyncTest, DisableSyncOnLeader) { // Channel 1 follower, channel 2 leader. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 130, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(130), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); auto pButtonSyncMode1 = std::make_unique(m_sGroup1, "sync_mode"); pButtonSyncMode1->slotSet(SYNC_FOLLOWER); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 130, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(130), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); // Set deck two to explicit leader. auto pButtonSyncLeader2 = @@ -399,7 +409,8 @@ TEST_F(EngineSyncTest, InternalLeaderSetFollowerSliderMoves) { pButtonLeaderSyncInternal->slotSet(1); // Set the file bpm of channel 1 to 80 bpm. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 80, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(80), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); auto pButtonLeaderSync1 = @@ -417,7 +428,8 @@ TEST_F(EngineSyncTest, AnySyncDeckSliderStays) { // If there exists a sync deck, even if it's not playing, don't change the // leader BPM if a new deck enables sync. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 80, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(80), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); auto pButtonSyncEnabled1 = std::make_unique(m_sGroup1, "sync_enabled"); @@ -428,7 +440,8 @@ TEST_F(EngineSyncTest, AnySyncDeckSliderStays) { ControlObject::getControl(ConfigKey(m_sInternalClockGroup, "bpm")) ->get()); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 100, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(100), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); auto pButtonSyncEnabled2 = std::make_unique(m_sGroup2, "sync_enabled"); @@ -452,11 +465,13 @@ TEST_F(EngineSyncTest, InternalClockFollowsFirstPlayingDeck) { std::make_unique(m_sGroup2, "sync_enabled"); // Set up decks so they can be playing, and start deck 1. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 100, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(100), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); ControlObject::set(ConfigKey(m_sGroup1, "rate"), getRateSliderValue(1.0)); ControlObject::set(ConfigKey(m_sGroup1, "play"), 1.0); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 130, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(130), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ControlObject::set(ConfigKey(m_sGroup2, "rate"), getRateSliderValue(1.0)); ControlObject::set(ConfigKey(m_sGroup2, "play"), 0.0); @@ -522,10 +537,12 @@ TEST_F(EngineSyncTest, SetExplicitLeaderByLights) { std::make_unique(m_sGroup2, "sync_leader"); // Set the file bpm of channel 1 to 160bpm. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 160, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(160), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); // Set the file bpm of channel 2 to 150bpm. - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 150, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(150), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ControlObject::set(ConfigKey(m_sGroup1, "play"), 1.0); @@ -603,7 +620,8 @@ TEST_F(EngineSyncTest, RateChangeTest) { ProcessBuffer(); // Set the file bpm of channel 1 to 160bpm. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 160, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(160), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); EXPECT_DOUBLE_EQ( 160.0, ControlObject::get(ConfigKey(m_sGroup1, "file_bpm"))); @@ -622,7 +640,8 @@ TEST_F(EngineSyncTest, RateChangeTest) { 192.0, ControlObject::get(ConfigKey(m_sInternalClockGroup, "bpm"))); // Set the file bpm of channel 2 to 120bpm. - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 120, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(120), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); EXPECT_DOUBLE_EQ( 120.0, ControlObject::get(ConfigKey(m_sGroup2, "file_bpm"))); @@ -644,13 +663,15 @@ TEST_F(EngineSyncTest, RateChangeTestWeirdOrder) { ProcessBuffer(); // Set the file bpm of channel 1 to 160bpm. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 160, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(160), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); EXPECT_DOUBLE_EQ( 160.0, ControlObject::get(ConfigKey(m_sInternalClockGroup, "bpm"))); // Set the file bpm of channel 2 to 120bpm. - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 120, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(120), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); // Set the rate slider of channel 1 to 1.2. @@ -668,13 +689,15 @@ TEST_F(EngineSyncTest, RateChangeTestWeirdOrder) { TEST_F(EngineSyncTest, RateChangeTestOrder3) { // Set the file bpm of channel 1 to 160bpm. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 160, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(160), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); EXPECT_DOUBLE_EQ( 160.0, ControlObject::get(ConfigKey(m_sGroup1, "file_bpm"))); // Set the file bpm of channel 2 to 120bpm. - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 120, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(120), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); EXPECT_DOUBLE_EQ( 120.0, ControlObject::get(ConfigKey(m_sGroup2, "file_bpm"))); @@ -714,11 +737,13 @@ TEST_F(EngineSyncTest, FollowerRateChange) { ProcessBuffer(); // Set the file bpm of channel 1 to 160bpm. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 160, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(160), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); // Set the file bpm of channel 2 to 120bpm. - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 120, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(120), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); // Set the rate slider of channel 1 to 1.2. @@ -760,13 +785,15 @@ TEST_F(EngineSyncTest, InternalRateChangeTest) { EXPECT_TRUE(isFollower(m_sGroup2)); // Set the file bpm of channel 1 to 160bpm. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 160, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(160), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); EXPECT_DOUBLE_EQ(160.0, ControlObject::getControl(ConfigKey(m_sGroup1, "file_bpm"))->get()); // Set the file bpm of channel 2 to 120bpm. - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 120, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(120), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); EXPECT_DOUBLE_EQ(120.0, ControlObject::getControl(ConfigKey(m_sGroup2, "file_bpm"))->get()); @@ -812,9 +839,11 @@ TEST_F(EngineSyncTest, InternalRateChangeTest) { TEST_F(EngineSyncTest, LeaderStopSliderCheck) { // If the leader is playing, and stop is pushed, the sliders should stay the same. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 120, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(120), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 128, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(128), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); auto pButtonLeaderSync1 = @@ -856,7 +885,8 @@ TEST_F(EngineSyncTest, EnableOneDeckInitsLeader) { ProcessBuffer(); // Set up the deck to play. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 130, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(130), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); ControlObject::getControl(ConfigKey(m_sGroup1, "rate")) ->set(getRateSliderValue(1.0)); @@ -883,7 +913,8 @@ TEST_F(EngineSyncTest, EnableOneDeckInitsLeader) { ConfigKey(m_sInternalClockGroup, "beat_distance"))); // Enable second deck, bpm and beat distance should still match original setting. - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 140, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(140), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ControlObject::getControl(ConfigKey(m_sGroup2, "rate")) ->set(getRateSliderValue(1.0)); @@ -911,9 +942,11 @@ TEST_F(EngineSyncTest, MomentarySyncAlgorithmTwo) { m_pConfig->set(ConfigKey("[BPM]", "sync_lock_algorithm"), ConfigValue(EngineSync::PREFER_LOCK_BPM)); - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 120, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(120), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 128, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(128), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ControlObject::getControl(ConfigKey(m_sGroup2, "play"))->set(1.0); @@ -931,7 +964,8 @@ TEST_F(EngineSyncTest, MomentarySyncAlgorithmTwo) { TEST_F(EngineSyncTest, EnableOneDeckInitializesLeader) { // Enabling sync on a deck causes it to be leader, and sets bpm and clock. // Set the deck to play. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 130, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(130), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); ControlObject::getControl(ConfigKey(m_sGroup1, "rate")) ->set(getRateSliderValue(1.0)); @@ -1121,7 +1155,8 @@ TEST_F(EngineSyncTest, EnableOneDeckSliderUpdates) { auto pButtonSyncEnabled1 = std::make_unique(m_sGroup1, "sync_enabled"); - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 130, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(130), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); ControlObject::getControl(ConfigKey(m_sGroup1, "rate")) ->set(getRateSliderValue(1.0)); @@ -1148,11 +1183,13 @@ TEST_F(EngineSyncTest, SyncToNonSyncDeck) { auto pButtonSyncEnabled2 = std::make_unique(m_sGroup2, "sync_enabled"); - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 130, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(130), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); ProcessBuffer(); ControlObject::set(ConfigKey(m_sGroup1, "rate"), getRateSliderValue(1.0)); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 100, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(100), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ControlObject::getControl(ConfigKey(m_sGroup2, "rate")) ->set(getRateSliderValue(1.0)); @@ -1232,11 +1269,13 @@ TEST_F(EngineSyncTest, MomentarySyncDependsOnPlayingStates) { std::make_unique(m_sGroup2, "sync_enabled"); // Set up decks so they can be playing, and start deck 1. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 100, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(100), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); ControlObject::set(ConfigKey(m_sGroup1, "rate"), getRateSliderValue(1.0)); ControlObject::set(ConfigKey(m_sGroup1, "play"), 1.0); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 130, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(130), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ControlObject::set(ConfigKey(m_sGroup2, "rate"), getRateSliderValue(1.0)); ControlObject::set(ConfigKey(m_sGroup2, "play"), 1.0); @@ -1306,7 +1345,8 @@ TEST_F(EngineSyncTest, EjectTrackSyncRemains) { std::make_unique(m_sGroup2, "sync_enabled"); auto pButtonEject1 = std::make_unique(m_sGroup1, "eject"); - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 120, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(120), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); pButtonSyncEnabled1->set(1.0); ProcessBuffer(); @@ -1331,7 +1371,8 @@ TEST_F(EngineSyncTest, EjectTrackSyncRemains) { m_pMixerDeck1->loadFakeTrack(false, 128.0); EXPECT_DOUBLE_EQ(128.0, ControlObject::getControl(ConfigKey(m_sGroup1, "bpm"))->get()); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 135, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(135), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); pButtonSyncEnabled2->set(1.0); ProcessBuffer(); @@ -1351,14 +1392,16 @@ TEST_F(EngineSyncTest, EjectTrackSyncRemains) { TEST_F(EngineSyncTest, FileBpmChangesDontAffectLeader) { // If filebpm changes, don't treat it like a rate change unless it's the leader. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 100, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(100), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); auto pButtonSyncEnabled1 = std::make_unique(m_sGroup1, "sync_enabled"); pButtonSyncEnabled1->set(1.0); ProcessBuffer(); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 120, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(120), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); auto pButtonSyncEnabled2 = std::make_unique(m_sGroup2, "sync_enabled"); @@ -1369,7 +1412,8 @@ TEST_F(EngineSyncTest, FileBpmChangesDontAffectLeader) { EXPECT_TRUE(isFollower(m_sGroup2)); // Update the leader's beats -- update the internal clock - pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 160, 0.0); + pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(160), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); EXPECT_DOUBLE_EQ( 160.0, ControlObject::get(ConfigKey(m_sInternalClockGroup, "bpm"))); @@ -1377,7 +1421,8 @@ TEST_F(EngineSyncTest, FileBpmChangesDontAffectLeader) { EXPECT_TRUE(isSoftLeader(m_sGroup1)); // Update follower beats -- don't update internal clock. - pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 140, 0.0); + pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(140), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); EXPECT_DOUBLE_EQ( 160.0, ControlObject::get(ConfigKey(m_sInternalClockGroup, "bpm"))); @@ -1389,7 +1434,8 @@ TEST_F(EngineSyncTest, ExplicitLeaderPostProcessed) { auto pButtonLeaderSync1 = std::make_unique(m_sGroup1, "sync_mode"); pButtonLeaderSync1->slotSet(SYNC_LEADER_EXPLICIT); - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 160, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(160), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); ProcessBuffer(); ControlObject::getControl(ConfigKey(m_sGroup1, "play"))->set(1.0); @@ -1403,7 +1449,8 @@ TEST_F(EngineSyncTest, ExplicitLeaderPostProcessed) { TEST_F(EngineSyncTest, ZeroBPMRateAdjustIgnored) { // If a track isn't loaded (0 bpm), but the deck has sync enabled, // don't pay attention to rate changes. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 0, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(0), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); auto pButtonSyncEnabled1 = std::make_unique(m_sGroup1, "sync_enabled"); @@ -1412,7 +1459,8 @@ TEST_F(EngineSyncTest, ZeroBPMRateAdjustIgnored) { ->set(getRateSliderValue(1.0)); ProcessBuffer(); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 120, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(120), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); auto pButtonSyncEnabled2 = std::make_unique(m_sGroup2, "sync_enabled"); @@ -1450,7 +1498,8 @@ TEST_F(EngineSyncTest, DISABLED_BeatDistanceBeforeStart) { // If the start position is before zero, we should still initialize the beat distance // correctly. Unfortunately, this currently doesn't work. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 128, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(128), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); ControlObject::set(ConfigKey(m_sGroup1, "playposition"), -.05); ControlObject::getControl(ConfigKey(m_sGroup1, "sync_mode")) @@ -1466,9 +1515,11 @@ TEST_F(EngineSyncTest, DISABLED_BeatDistanceBeforeStart) { TEST_F(EngineSyncTest, ZeroLatencyRateChangeNoQuant) { // Confirm that a rate change in an explicit leader is instantly communicated // to followers. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 128, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(128), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 160, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(160), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); // Make Channel2 leader to weed out any channel ordering issues. @@ -1514,9 +1565,11 @@ TEST_F(EngineSyncTest, ZeroLatencyRateChangeNoQuant) { TEST_F(EngineSyncTest, ZeroLatencyRateChangeQuant) { // Confirm that a rate change in an explicit leader is instantly communicated // to followers. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 128, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(128), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 160, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(160), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ControlObject::getControl(ConfigKey(m_sGroup1, "quantize"))->set(1.0); @@ -1567,9 +1620,11 @@ TEST_F(EngineSyncTest, ZeroLatencyRateChangeQuant) { TEST_F(EngineSyncTest, ZeroLatencyRateDiffQuant) { // Confirm that a rate change in an explicit leader is instantly communicated // to followers. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 128, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(128), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 160, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(160), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ControlObject::getControl(ConfigKey(m_sGroup2, "quantize"))->set(1.0); @@ -1621,9 +1676,11 @@ TEST_F(EngineSyncTest, ZeroLatencyRateDiffQuant) { // need to check. The Sync feature is unfortunately brittle. // This test exercises https://bugs.launchpad.net/mixxx/+bug/1884324 TEST_F(EngineSyncTest, ActivatingSyncDoesNotCauseDrifting) { - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 150, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(150), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 150, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(150), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ControlObject::getControl(ConfigKey(m_sGroup1, "quantize"))->set(0.0); @@ -1665,9 +1722,11 @@ TEST_F(EngineSyncTest, ActivatingSyncDoesNotCauseDrifting) { } TEST_F(EngineSyncTest, HalfDoubleBpmTest) { - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 70, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(70), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 140, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(140), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); // Mixxx will choose the first playing deck to be leader. Let's start deck 2 first. @@ -1762,9 +1821,11 @@ TEST_F(EngineSyncTest, HalfDoubleBpmTest) { TEST_F(EngineSyncTest, HalfDoubleThenPlay) { // If a deck plays that had its multiplier set, we need to reset the // internal clock. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 80, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(80), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 175, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(175), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ControlObject::getControl(ConfigKey(m_sGroup1, "rate")) ->set(getRateSliderValue(1.0)); @@ -1885,9 +1946,11 @@ TEST_F(EngineSyncTest, HalfDoubleThenPlay) { TEST_F(EngineSyncTest, HalfDoubleInternalClockTest) { // If we set the file_bpm CO's directly, the correct signals aren't fired. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 70, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(70), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 140, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(140), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ControlObject::getControl(ConfigKey(m_sGroup1, "quantize"))->set(1.0); @@ -1906,9 +1969,11 @@ TEST_F(EngineSyncTest, HalfDoubleInternalClockTest) { } namespace { -QVector createBeatVector( - double first_beat, unsigned int num_beats, double beat_length) { - QVector beats; +QVector createBeatVector( + mixxx::audio::FramePos first_beat, + unsigned int num_beats, + mixxx::audio::FrameDiff_t beat_length) { + QVector beats; for (unsigned int i = 0; i < num_beats; ++i) { beats.append(first_beat + i * beat_length); } @@ -1918,16 +1983,16 @@ QVector createBeatVector( TEST_F(EngineSyncTest, HalfDoubleConsistency) { // half-double matching should be consistent - double beatLengthFrames = 60.0 * 44100 / 90.0; - double startOffsetFrames = 0; + mixxx::audio::FrameDiff_t beatLengthFrames = 60.0 * 44100 / 90.0; + constexpr auto startOffsetFrames = mixxx::audio::kStartFramePos; const int numBeats = 100; - QVector beats1 = + QVector beats1 = createBeatVector(startOffsetFrames, numBeats, beatLengthFrames); auto pBeats1 = mixxx::BeatMap::makeBeatMap(m_pTrack1->getSampleRate(), QString(), beats1); m_pTrack1->trySetBeats(pBeats1); beatLengthFrames = 60.0 * 44100 / 145.0; - QVector beats2 = + QVector beats2 = createBeatVector(startOffsetFrames, numBeats, beatLengthFrames); auto pBeats2 = mixxx::BeatMap::makeBeatMap(m_pTrack2->getSampleRate(), QString(), beats2); m_pTrack2->trySetBeats(pBeats2); @@ -1958,9 +2023,11 @@ TEST_F(EngineSyncTest, HalfDoubleEachOther) { // Confirm that repeated sync with both decks leads to the same // Half/Double decision. // This test demonstrates https://bugs.launchpad.net/mixxx/+bug/1921962 - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 144, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(144), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 105, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(105), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); // Threshold 1.414 sqrt(2); @@ -1985,7 +2052,8 @@ TEST_F(EngineSyncTest, HalfDoubleEachOther) { // 105 / 75 = 1.40 // expect 75 BPM - mixxx::BeatsPointer pBeats1b = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 150, 0.0); + mixxx::BeatsPointer pBeats1b = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(150), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1b); EXPECT_DOUBLE_EQ(150.0, @@ -2006,7 +2074,8 @@ TEST_F(EngineSyncTest, HalfDoubleEachOther) { TEST_F(EngineSyncTest, SetFileBpmUpdatesLocalBpm) { ControlObject::getControl(ConfigKey(m_sGroup1, "beat_distance"))->set(0.2); - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 130, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(130), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); EXPECT_EQ( 130.0, m_pEngineSync->getSyncableForGroup(m_sGroup1)->getBaseBpm()); @@ -2018,14 +2087,16 @@ TEST_F(EngineSyncTest, SyncPhaseToPlayingNonSyncDeck) { auto pButtonSyncEnabled1 = std::make_unique(m_sGroup1, "sync_enabled"); - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 130, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(130), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); ControlObject::getControl(ConfigKey(m_sGroup1, "quantize"))->set(1.0); auto pButtonSyncEnabled2 = std::make_unique(m_sGroup2, "sync_enabled"); ControlObject::set(ConfigKey(m_sGroup2, "rate_ratio"), 1.0); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 100, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(100), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); // Set the sync deck playing with nothing else active. @@ -2108,7 +2179,8 @@ TEST_F(EngineSyncTest, SyncPhaseToPlayingNonSyncDeck) { std::make_unique(m_sGroup3, "sync_enabled"); ControlObject::set(ConfigKey(m_sGroup3, "beat_distance"), 0.6); ControlObject::set(ConfigKey(m_sGroup2, "rate_ratio"), 1.0); - mixxx::BeatsPointer pBeats3 = BeatFactory::makeBeatGrid(m_pTrack3->getSampleRate(), 140, 0.0); + mixxx::BeatsPointer pBeats3 = BeatFactory::makeBeatGrid( + m_pTrack3->getSampleRate(), mixxx::Bpm(140), mixxx::audio::kStartFramePos); m_pTrack3->trySetBeats(pBeats3); // This will sync to the first deck here and not the second (lp1784185) pButtonSyncEnabled3->set(1.0); @@ -2153,9 +2225,11 @@ TEST_F(EngineSyncTest, UserTweakBeatDistance) { // If a deck has a user tweak, and another deck stops such that the first // is used to reseed the leader beat distance, make sure the user offset // is reset. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 128, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(128), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 128, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(128), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ControlObject::getControl(ConfigKey(m_sGroup1, "quantize"))->set(1.0); @@ -2207,9 +2281,10 @@ TEST_F(EngineSyncTest, UserTweakPreservedInSeek) { // This is about 128 bpm, but results in nice round numbers of samples. const double kDivisibleBpm = 44100.0 / 344.0; mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( - m_pTrack1->getSampleRate(), kDivisibleBpm, 0.0); + m_pTrack1->getSampleRate(), mixxx::Bpm(kDivisibleBpm), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 130, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(130), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ControlObject::getControl(ConfigKey(m_sGroup2, "sync_enabled"))->set(1); @@ -2287,9 +2362,10 @@ TEST_F(EngineSyncTest, FollowerUserTweakPreservedInLeaderChange) { // This is about 128 bpm, but results in nice round numbers of samples. const double kDivisibleBpm = 44100.0 / 344.0; mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( - m_pTrack1->getSampleRate(), kDivisibleBpm, 0.0); + m_pTrack1->getSampleRate(), mixxx::Bpm(kDivisibleBpm), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 130, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(130), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ControlObject::getControl(ConfigKey(m_sGroup1, "sync_leader"))->set(1); @@ -2339,9 +2415,10 @@ TEST_F(EngineSyncTest, LeaderUserTweakPreservedInLeaderChange) { // This is about 128 bpm, but results in nice round numbers of samples. const double kDivisibleBpm = 44100.0 / 344.0; mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( - m_pTrack1->getSampleRate(), kDivisibleBpm, 0.0); + m_pTrack1->getSampleRate(), mixxx::Bpm(kDivisibleBpm), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 130, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(130), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ControlObject::getControl(ConfigKey(m_sGroup1, "sync_leader"))->set(1); @@ -2386,7 +2463,8 @@ TEST_F(EngineSyncTest, LeaderUserTweakPreservedInLeaderChange) { } TEST_F(EngineSyncTest, LeaderBpmNeverZero) { - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 128, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(128), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); auto pButtonSyncEnabled1 = std::make_unique(m_sGroup1, "sync_enabled"); @@ -2401,7 +2479,8 @@ TEST_F(EngineSyncTest, ZeroBpmNaturalRate) { // If a track has a zero bpm and a bad beatgrid, make sure the rate // doesn't end up something crazy when sync is enabled.. // Maybe the beatgrid ended up at zero also. - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 0.0, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(0.0), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); auto pButtonSyncEnabled1 = std::make_unique(m_sGroup1, "sync_enabled"); @@ -2420,11 +2499,13 @@ TEST_F(EngineSyncTest, QuantizeImpliesSyncPhase) { auto pButtonBeatsync1 = std::make_unique(m_sGroup1, "beatsync"); auto pButtonBeatsyncPhase1 = std::make_unique(m_sGroup1, "beatsync_phase"); - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 130, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(130), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); ControlObject::set(ConfigKey(m_sGroup2, "rate"), getRateSliderValue(1.0)); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 100, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(100), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ProcessBuffer(); @@ -2516,7 +2597,8 @@ TEST_F(EngineSyncTest, QuantizeImpliesSyncPhase) { TEST_F(EngineSyncTest, SeekStayInPhase) { ControlObject::set(ConfigKey(m_sGroup1, "quantize"), 1.0); - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 130, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(130), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); ControlObject::set(ConfigKey(m_sGroup1, "play"), 1.0); @@ -2538,7 +2620,8 @@ TEST_F(EngineSyncTest, SeekStayInPhase) { ControlObject::set(ConfigKey(m_sGroup1, "play"), 0.0); ProcessBuffer(); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 130, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(130), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ControlObject::set(ConfigKey(m_sGroup1, "play"), 1.0); @@ -2560,7 +2643,8 @@ TEST_F(EngineSyncTest, SeekStayInPhase) { TEST_F(EngineSyncTest, SyncWithoutBeatgrid) { // this tests bug lp1783020, notresetting rate when other deck has no beatgrid - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 128, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(128), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); m_pTrack2->trySetBeats(mixxx::BeatsPointer()); @@ -2578,11 +2662,13 @@ TEST_F(EngineSyncTest, SyncWithoutBeatgrid) { } TEST_F(EngineSyncTest, QuantizeHotCueActivate) { - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 130, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(130), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); auto pHotCue2Activate = std::make_unique(m_sGroup2, "hotcue_1_activate"); - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 100, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(100), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); @@ -2618,7 +2704,7 @@ TEST_F(EngineSyncTest, QuantizeHotCueActivate) { pHotCue2Activate->set(1.0); ProcessBuffer(); - // Beat_distance is the distance to the previous beat wich has already passed. + // Beat_distance is the distance to the previous beat which has already passed. // We compare here the distance to the next beat (1 - beat_distance) and // scale it by the different tempos. EXPECT_NEAR( @@ -2643,7 +2729,8 @@ TEST_F(EngineSyncTest, ChangeBeatGrid) { auto pButtonSyncEnabled2 = std::make_unique(m_sGroup2, "sync_enabled"); // set beatgrid for deck 1 - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 130, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(130), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); pButtonSyncEnabled1->set(1.0); ControlObject::set(ConfigKey(m_sGroup1, "play"), 1.0); @@ -2676,7 +2763,8 @@ TEST_F(EngineSyncTest, ChangeBeatGrid) { EXPECT_TRUE(isFollower(m_sGroup2)); // Load a new beatgrid during playing, this happens when the analyser is finished. - mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 140, 0.0); + mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(140), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2); ProcessBuffer(); @@ -2700,7 +2788,8 @@ TEST_F(EngineSyncTest, ChangeBeatGrid) { EXPECT_TRUE(isSoftLeader(m_sGroup2)); // Load a new beatgrid again, this happens when the user adjusts the beatgrid - mixxx::BeatsPointer pBeats2n = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 75, 0.0); + mixxx::BeatsPointer pBeats2n = BeatFactory::makeBeatGrid( + m_pTrack2->getSampleRate(), mixxx::Bpm(75), mixxx::audio::kStartFramePos); m_pTrack2->trySetBeats(pBeats2n); ProcessBuffer(); @@ -2715,7 +2804,8 @@ TEST_F(EngineSyncTest, ChangeBeatGrid) { TEST_F(EngineSyncTest, BeatMapQuantizePlay) { // This test demonstates https://bugs.launchpad.net/mixxx/+bug/1874918 - mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid(m_pTrack1->getSampleRate(), 120, 0.0); + mixxx::BeatsPointer pBeats1 = BeatFactory::makeBeatGrid( + m_pTrack1->getSampleRate(), mixxx::Bpm(120), mixxx::audio::kStartFramePos); m_pTrack1->trySetBeats(pBeats1); constexpr auto kSampleRate = mixxx::audio::SampleRate(44100); @@ -2723,8 +2813,11 @@ TEST_F(EngineSyncTest, BeatMapQuantizePlay) { auto pBeats2 = mixxx::BeatMap::makeBeatMap(kSampleRate, QString(), // Add two beats at 120 Bpm - QVector({static_cast(kSampleRate) / 2, - static_cast(kSampleRate)})); + QVector( + {mixxx::audio::FramePos( + static_cast(kSampleRate) / 2), + mixxx::audio::FramePos( + static_cast(kSampleRate))})); m_pTrack2->trySetBeats(pBeats2); ControlObject::set(ConfigKey(m_sGroup1, "quantize"), 1.0); diff --git a/src/test/frametest.cpp b/src/test/frametest.cpp new file mode 100644 index 00000000000..1abd9ca3245 --- /dev/null +++ b/src/test/frametest.cpp @@ -0,0 +1,67 @@ +#include + +#include + +#include "audio/frame.h" + +class FrameTest : public testing::Test { +}; + +TEST_F(FrameTest, TestFramePosValid) { + EXPECT_TRUE(mixxx::audio::FramePos(100).isValid()); + EXPECT_TRUE(mixxx::audio::FramePos(2000).isValid()); + EXPECT_TRUE(mixxx::audio::FramePos(-1).isValid()); + EXPECT_TRUE(mixxx::audio::FramePos(99999).isValid()); + EXPECT_TRUE(mixxx::audio::FramePos(-99999).isValid()); + EXPECT_TRUE(mixxx::audio::FramePos(128.5).isValid()); + EXPECT_TRUE(mixxx::audio::FramePos(135.67).isValid()); + // Denormals + EXPECT_TRUE(mixxx::audio::FramePos(0.0).isValid()); + EXPECT_TRUE(mixxx::audio::FramePos(std::numeric_limits::min() / 2.0).isValid()); + EXPECT_FALSE(mixxx::audio::FramePos(std::numeric_limits::infinity()).isValid()); + // NaN + EXPECT_FALSE(mixxx::audio::FramePos().isValid()); + EXPECT_FALSE(mixxx::audio::FramePos(std::numeric_limits::quiet_NaN()).isValid()); + EXPECT_FALSE(mixxx::audio::FramePos(std::numeric_limits::signaling_NaN()).isValid()); +} + +TEST_F(FrameTest, TestFramePosFractional) { + EXPECT_FALSE(mixxx::audio::FramePos(100).isFractional()); + EXPECT_FALSE(mixxx::audio::FramePos(2000).isFractional()); + EXPECT_FALSE(mixxx::audio::FramePos(0).isFractional()); + EXPECT_FALSE(mixxx::audio::FramePos(-1).isFractional()); + EXPECT_FALSE(mixxx::audio::FramePos(99999).isFractional()); + EXPECT_FALSE(mixxx::audio::FramePos(-99999).isFractional()); + EXPECT_TRUE(mixxx::audio::FramePos(128.5).isFractional()); + EXPECT_TRUE(mixxx::audio::FramePos(135.67).isFractional()); +} + +TEST_F(FrameTest, TestFramePosEquality) { + EXPECT_EQ(mixxx::audio::FramePos(0), mixxx::audio::FramePos(0)); + EXPECT_EQ(mixxx::audio::FramePos(-100), mixxx::audio::FramePos(-100)); + EXPECT_EQ(mixxx::audio::FramePos(100), mixxx::audio::FramePos(100)); + EXPECT_EQ(mixxx::audio::FramePos(50) * 2, mixxx::audio::FramePos(100)); + + EXPECT_NE(mixxx::audio::FramePos(100), mixxx::audio::FramePos(200)); + EXPECT_NE(mixxx::audio::FramePos(100), mixxx::audio::FramePos()); + EXPECT_NE(mixxx::audio::FramePos(0), mixxx::audio::FramePos()); + + // Check that invalid positions are equal to each other + EXPECT_EQ(mixxx::audio::FramePos(), mixxx::audio::kInvalidFramePos); + EXPECT_EQ(mixxx::audio::FramePos(), + mixxx::audio::FramePos(mixxx::audio::FramePos::kInvalidValue)); + EXPECT_EQ(mixxx::audio::FramePos(), + mixxx::audio::FramePos(std::numeric_limits< + mixxx::audio::FramePos::value_t>::quiet_NaN())); + EXPECT_EQ(mixxx::audio::FramePos(), + mixxx::audio::FramePos(std::numeric_limits< + mixxx::audio::FramePos::value_t>::infinity())); + EXPECT_EQ(mixxx::audio::FramePos(), + mixxx::audio::FramePos( + -std::numeric_limits< + mixxx::audio::FramePos::value_t>::infinity())); + EXPECT_EQ(mixxx::audio::FramePos(std::numeric_limits< + mixxx::audio::FramePos::value_t>::quiet_NaN()), + mixxx::audio::FramePos(std::numeric_limits< + mixxx::audio::FramePos::value_t>::infinity())); +} diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index c45c951d528..d92b3e966b5 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -82,8 +82,9 @@ class HotcueControlTest : public BaseSignalPathTest { return m_pChannel1->getEngineBuffer()->m_pCueControl->getSampleOfTrack().current; } - void setCurrentSamplePosition(double sample) { - m_pChannel1->getEngineBuffer()->queueNewPlaypos(sample, EngineBuffer::SEEK_STANDARD); + void setCurrentSamplePosition(double samplePosition) { + const auto position = mixxx::audio::FramePos::fromEngineSamplePos(samplePosition); + m_pChannel1->getEngineBuffer()->queueNewPlaypos(position, EngineBuffer::SEEK_STANDARD); ProcessBuffer(); } diff --git a/src/test/id3-test-data/cover-test.m4v b/src/test/id3-test-data/cover-test.m4v new file mode 100644 index 00000000000..6a59ff510c9 Binary files /dev/null and b/src/test/id3-test-data/cover-test.m4v differ diff --git a/src/test/looping_control_test.cpp b/src/test/looping_control_test.cpp index 7f0dcb1fde8..57947e7209e 100644 --- a/src/test/looping_control_test.cpp +++ b/src/test/looping_control_test.cpp @@ -69,8 +69,9 @@ class LoopingControlTest : public MockedEngineBackendTest { return m_pLoopEnabled->get() > 0.0; } - void seekToSampleAndProcess(double new_pos) { - m_pChannel1->getEngineBuffer()->queueNewPlaypos(new_pos, EngineBuffer::SEEK_STANDARD); + void seekToSampleAndProcess(double samplePosition) { + const auto position = mixxx::audio::FramePos::fromEngineSamplePos(samplePosition); + m_pChannel1->getEngineBuffer()->queueNewPlaypos(position, EngineBuffer::SEEK_STANDARD); ProcessBuffer(); } @@ -536,8 +537,7 @@ TEST_F(LoopingControlTest, LoopMoveTest) { EXPECT_EQ(44110, m_pChannel1->getEngineBuffer()->m_pLoopingControl->getSampleOfTrack().current); // Move backward so that the current position is outside the new location of the loop - m_pChannel1->getEngineBuffer()->queueNewPlaypos(44300, EngineBuffer::SEEK_STANDARD); - ProcessBuffer(); + seekToSampleAndProcess(44300); m_pButtonBeatMoveBackward->set(1.0); m_pButtonBeatMoveBackward->set(0.0); ProcessBuffer(); @@ -565,8 +565,7 @@ TEST_F(LoopingControlTest, LoopMoveTest) { kLoopPositionMaxAbsError); // Move backward so that the current position is outside the new location of the loop - m_pChannel1->getEngineBuffer()->queueNewPlaypos(500, EngineBuffer::SEEK_STANDARD); - ProcessBuffer(); + seekToSampleAndProcess(500); m_pButtonBeatMoveBackward->set(1.0); m_pButtonBeatMoveBackward->set(0.0); ProcessBuffer(); diff --git a/src/test/metadatatest.cpp b/src/test/metadatatest.cpp index 83856e9f7fb..0b8f082b592 100644 --- a/src/test/metadatatest.cpp +++ b/src/test/metadatatest.cpp @@ -48,7 +48,7 @@ class MetadataTest : public testing::Test { mixxx::TrackMetadata trackMetadata; mixxx::taglib::id3v2::importTrackMetadataFromTag(&trackMetadata, tag); - EXPECT_DOUBLE_EQ(expectedValue, trackMetadata.getTrackInfo().getBpm().getValue()); + EXPECT_DOUBLE_EQ(expectedValue, trackMetadata.getTrackInfo().getBpm().value()); } }; diff --git a/src/test/seratobeatgridtest.cpp b/src/test/seratobeatgridtest.cpp index 2f507d4451f..5887cb2ef15 100644 --- a/src/test/seratobeatgridtest.cpp +++ b/src/test/seratobeatgridtest.cpp @@ -113,10 +113,11 @@ TEST_F(SeratoBeatGridTest, ParseEmptyDataFLAC) { TEST_F(SeratoBeatGridTest, SerializeBeatgrid) { // Create a const beatgrid at 120 BPM - constexpr double bpm = 120.0; + constexpr mixxx::Bpm bpm(120.0); const auto sampleRate = mixxx::audio::SampleRate(44100); EXPECT_EQ(sampleRate.isValid(), true); - const auto pBeats = mixxx::BeatGrid::makeBeatGrid(sampleRate, QString("Test"), bpm, 0); + const auto pBeats = mixxx::BeatGrid::makeBeatGrid( + sampleRate, QString("Test"), bpm, mixxx::audio::kStartFramePos); const auto signalInfo = mixxx::audio::SignalInfo(mixxx::audio::ChannelCount(2), sampleRate); const auto duration = mixxx::Duration::fromSeconds(300); @@ -125,22 +126,22 @@ TEST_F(SeratoBeatGridTest, SerializeBeatgrid) { seratoBeatGrid.setBeats(pBeats, signalInfo, duration, 0); EXPECT_EQ(seratoBeatGrid.nonTerminalMarkers().size(), 0); EXPECT_NE(seratoBeatGrid.terminalMarker(), nullptr); - EXPECT_FLOAT_EQ(seratoBeatGrid.terminalMarker()->bpm(), static_cast(bpm)); + EXPECT_FLOAT_EQ(seratoBeatGrid.terminalMarker()->bpm(), static_cast(bpm.value())); } TEST_F(SeratoBeatGridTest, SerializeBeatMap) { // Create a non-const beatmap constexpr double timingOffsetMillis = -10; - constexpr int bpm = 120; + constexpr mixxx::Bpm bpm(120); const auto sampleRate = mixxx::audio::SampleRate(44100); const auto signalInfo = mixxx::audio::SignalInfo(mixxx::audio::ChannelCount(2), sampleRate); const auto duration = mixxx::Duration::fromSeconds(300); - const double framesPerMinute = signalInfo.getSampleRate() * 60; - const double framesPerBeat = framesPerMinute / bpm; - const double initialFrameOffset = framesPerBeat / 2; + const mixxx::audio::FrameDiff_t framesPerMinute = signalInfo.getSampleRate() * 60; + const mixxx::audio::FrameDiff_t framesPerBeat = framesPerMinute / bpm.value(); + const mixxx::audio::FrameDiff_t initialFrameOffset = framesPerBeat / 2; - QVector beatPositionsFrames; - double beatPositionFrames = initialFrameOffset; + QVector beatPositionsFrames; + mixxx::audio::FramePos beatPositionFrames = mixxx::audio::FramePos(initialFrameOffset); constexpr int kNumBeats120BPM = 4; qInfo() << "Step 1: Add" << kNumBeats120BPM << "beats at 100 bpm to the beatgrid"; @@ -156,9 +157,8 @@ TEST_F(SeratoBeatGridTest, SerializeBeatMap) { sampleRate, QString("Test"), beatPositionsFrames); // Check that the first section's BPM is 100 EXPECT_EQ(pBeats->getBpmAroundPosition( - signalInfo.frames2samples( - static_cast(initialFrameOffset + - framesPerBeat * kNumBeats120BPM / 2)), + mixxx::audio::FramePos(initialFrameOffset + + framesPerBeat * kNumBeats120BPM / 2), 1), bpm); @@ -166,17 +166,19 @@ TEST_F(SeratoBeatGridTest, SerializeBeatMap) { seratoBeatGrid.setBeats(pBeats, signalInfo, duration, timingOffsetMillis); EXPECT_EQ(seratoBeatGrid.nonTerminalMarkers().size(), 0); EXPECT_NE(seratoBeatGrid.terminalMarker(), nullptr); - EXPECT_FLOAT_EQ(seratoBeatGrid.terminalMarker()->bpm(), static_cast(bpm)); + EXPECT_FLOAT_EQ(seratoBeatGrid.terminalMarker()->bpm(), static_cast(bpm.value())); // Check if the beats can be re-imported losslessly mixxx::SeratoBeatsImporter beatsImporter( seratoBeatGrid.nonTerminalMarkers(), seratoBeatGrid.terminalMarker()); - QVector importedBeatPositionsFrames = + const QVector importedBeatPositionsFrames = beatsImporter.importBeatsAndApplyTimingOffset(timingOffsetMillis, signalInfo); ASSERT_EQ(beatPositionsFrames.size(), importedBeatPositionsFrames.size()); for (int i = 0; i < beatPositionsFrames.size(); i++) { - EXPECT_NEAR(beatPositionsFrames[i], importedBeatPositionsFrames[i], kEpsilon); + EXPECT_NEAR(beatPositionsFrames[i].value(), + importedBeatPositionsFrames[i].value(), + kEpsilon); } } @@ -193,17 +195,15 @@ TEST_F(SeratoBeatGridTest, SerializeBeatMap) { sampleRate, QString("Test"), beatPositionsFrames); // Check that the first section'd BPM is 100 EXPECT_EQ(pBeats->getBpmAroundPosition( - signalInfo.frames2samples( - static_cast(initialFrameOffset + - framesPerBeat * kNumBeats120BPM / 2)), + mixxx::audio::FramePos(initialFrameOffset + + framesPerBeat * kNumBeats120BPM / 2), 1), bpm); // Check that the second section'd BPM is 50 EXPECT_EQ(pBeats->getBpmAroundPosition( - signalInfo.frames2samples( - static_cast(initialFrameOffset + - framesPerBeat * kNumBeats120BPM + - framesPerBeat * kNumBeats60BPM / 2)), + mixxx::audio::FramePos(initialFrameOffset + + framesPerBeat * kNumBeats120BPM + + framesPerBeat * kNumBeats60BPM / 2), 1), bpm / 2); @@ -214,17 +214,20 @@ TEST_F(SeratoBeatGridTest, SerializeBeatMap) { ASSERT_EQ(seratoBeatGrid.nonTerminalMarkers()[1]->beatsTillNextMarker(), kNumBeats60BPM - 1); EXPECT_NE(seratoBeatGrid.terminalMarker(), nullptr); - EXPECT_FLOAT_EQ(seratoBeatGrid.terminalMarker()->bpm(), static_cast(bpm / 2)); + EXPECT_FLOAT_EQ(seratoBeatGrid.terminalMarker()->bpm(), + static_cast(bpm.value() / 2)); // Check if the beats can be re-imported losslessly mixxx::SeratoBeatsImporter beatsImporter( seratoBeatGrid.nonTerminalMarkers(), seratoBeatGrid.terminalMarker()); - QVector importedBeatPositionsFrames = + const QVector importedBeatPositionsFrames = beatsImporter.importBeatsAndApplyTimingOffset(timingOffsetMillis, signalInfo); ASSERT_EQ(beatPositionsFrames.size(), importedBeatPositionsFrames.size()); for (int i = 0; i < beatPositionsFrames.size(); i++) { - EXPECT_NEAR(beatPositionsFrames[i], importedBeatPositionsFrames[i], kEpsilon); + EXPECT_NEAR(beatPositionsFrames[i].value(), + importedBeatPositionsFrames[i].value(), + kEpsilon); } } @@ -243,25 +246,22 @@ TEST_F(SeratoBeatGridTest, SerializeBeatMap) { sampleRate, QString("Test"), beatPositionsFrames); // Check that the first section's BPM is 100 EXPECT_EQ(pBeats->getBpmAroundPosition( - signalInfo.frames2samples( - static_cast(initialFrameOffset + - framesPerBeat * kNumBeats120BPM / 2)), + mixxx::audio::FramePos(initialFrameOffset + + framesPerBeat * kNumBeats120BPM / 2), 1), bpm); // Check that the second section's BPM is 50 EXPECT_EQ(pBeats->getBpmAroundPosition( - signalInfo.frames2samples( - static_cast(initialFrameOffset + - framesPerBeat * kNumBeats120BPM + - framesPerBeat * kNumBeats60BPM / 2)), + mixxx::audio::FramePos(initialFrameOffset + + framesPerBeat * kNumBeats120BPM + + framesPerBeat * kNumBeats60BPM / 2), 1), bpm / 2); // Check that the third section's BPM is 100 EXPECT_EQ(pBeats->getBpmAroundPosition( - signalInfo.frames2samples(static_cast( - initialFrameOffset + + mixxx::audio::FramePos(initialFrameOffset + framesPerBeat * kNumBeats120BPM * 1.5 + - framesPerBeat * kNumBeats60BPM)), + framesPerBeat * kNumBeats60BPM), 1), bpm / 2); @@ -272,17 +272,19 @@ TEST_F(SeratoBeatGridTest, SerializeBeatMap) { ASSERT_EQ(seratoBeatGrid.nonTerminalMarkers()[1]->beatsTillNextMarker(), kNumBeats60BPM); ASSERT_EQ(seratoBeatGrid.nonTerminalMarkers()[2]->beatsTillNextMarker(), kNumBeats60BPM); EXPECT_NE(seratoBeatGrid.terminalMarker(), nullptr); - EXPECT_FLOAT_EQ(seratoBeatGrid.terminalMarker()->bpm(), static_cast(bpm)); + EXPECT_FLOAT_EQ(seratoBeatGrid.terminalMarker()->bpm(), static_cast(bpm.value())); // Check if the beats can be re-imported losslessly mixxx::SeratoBeatsImporter beatsImporter( seratoBeatGrid.nonTerminalMarkers(), seratoBeatGrid.terminalMarker()); - QVector importedBeatPositionsFrames = + const QVector importedBeatPositionsFrames = beatsImporter.importBeatsAndApplyTimingOffset(timingOffsetMillis, signalInfo); ASSERT_EQ(beatPositionsFrames.size(), importedBeatPositionsFrames.size()); for (int i = 0; i < beatPositionsFrames.size(); i++) { - EXPECT_NEAR(beatPositionsFrames[i], importedBeatPositionsFrames[i], kEpsilon); + EXPECT_NEAR(beatPositionsFrames[i].value(), + importedBeatPositionsFrames[i].value(), + kEpsilon); } } } diff --git a/src/test/trackupdate_test.cpp b/src/test/trackupdate_test.cpp index d413c922210..3b4b0f4709d 100644 --- a/src/test/trackupdate_test.cpp +++ b/src/test/trackupdate_test.cpp @@ -30,7 +30,7 @@ class TrackUpdateTest : public MixxxTest, SoundSourceProviderRegistration { static TrackPointer newTestTrackParsed() { auto pTrack = newTestTrack(); EXPECT_TRUE(SoundSourceProxy(pTrack).updateTrackFromSource()); - EXPECT_TRUE(pTrack->isMetadataSynchronized()); + EXPECT_TRUE(pTrack->isSourceSynchronized()); EXPECT_TRUE(hasTrackMetadata(pTrack)); EXPECT_TRUE(hasCoverArt(pTrack)); pTrack->markClean(); @@ -66,7 +66,7 @@ TEST_F(TrackUpdateTest, parseModifiedCleanOnce) { const auto coverInfoAfter = pTrack->getCoverInfo(); // Verify that the track has not been modified - ASSERT_TRUE(pTrack->isMetadataSynchronized()); + ASSERT_TRUE(pTrack->isSourceSynchronized()); ASSERT_FALSE(pTrack->isDirty()); ASSERT_EQ(trackMetadataBefore, trackMetadataAfter); ASSERT_EQ(coverInfoBefore, coverInfoAfter); @@ -86,7 +86,7 @@ TEST_F(TrackUpdateTest, parseModifiedCleanAgainSkipCover) { const auto coverInfoAfter = pTrack->getCoverInfo(); // Updated - EXPECT_TRUE(pTrack->isMetadataSynchronized()); + EXPECT_TRUE(pTrack->isSourceSynchronized()); EXPECT_TRUE(pTrack->isDirty()); EXPECT_NE(trackMetadataBefore, trackMetadataAfter); EXPECT_EQ(coverInfoBefore, coverInfoAfter); @@ -110,7 +110,7 @@ TEST_F(TrackUpdateTest, parseModifiedCleanAgainUpdateCover) { const auto coverInfoAfter = pTrack->getCoverInfo(); // Updated - EXPECT_TRUE(pTrack->isMetadataSynchronized()); + EXPECT_TRUE(pTrack->isSourceSynchronized()); EXPECT_TRUE(pTrack->isDirty()); EXPECT_NE(trackMetadataBefore, trackMetadataAfter); EXPECT_NE(coverInfoBefore, coverInfoAfter); @@ -129,7 +129,7 @@ TEST_F(TrackUpdateTest, parseModifiedDirtyAgain) { const auto coverInfoAfter = pTrack->getCoverInfo(); // Updated - EXPECT_TRUE(pTrack->isMetadataSynchronized()); + EXPECT_TRUE(pTrack->isSourceSynchronized()); EXPECT_TRUE(pTrack->isDirty()); EXPECT_NE(trackMetadataBefore, trackMetadataAfter); EXPECT_EQ(coverInfoBefore, coverInfoAfter); diff --git a/src/track/beatfactory.cpp b/src/track/beatfactory.cpp index 6f7fa038522..d79b797c922 100644 --- a/src/track/beatfactory.cpp +++ b/src/track/beatfactory.cpp @@ -33,9 +33,9 @@ mixxx::BeatsPointer BeatFactory::loadBeatsFromByteArray( mixxx::BeatsPointer BeatFactory::makeBeatGrid( mixxx::audio::SampleRate sampleRate, - double dBpm, - double dFirstBeatSample) { - return mixxx::BeatGrid::makeBeatGrid(sampleRate, QString(), dBpm, dFirstBeatSample); + mixxx::Bpm bpm, + mixxx::audio::FramePos firstBeatFramePos) { + return mixxx::BeatGrid::makeBeatGrid(sampleRate, QString(), bpm, firstBeatFramePos); } // static @@ -77,7 +77,7 @@ QString BeatFactory::getPreferredSubVersion( } mixxx::BeatsPointer BeatFactory::makePreferredBeats( - const QVector& beats, + const QVector& beats, const QHash& extraVersionInfo, bool fixedTempo, mixxx::audio::SampleRate sampleRate) { @@ -85,8 +85,8 @@ mixxx::BeatsPointer BeatFactory::makePreferredBeats( const QString subVersion = getPreferredSubVersion(extraVersionInfo); #ifdef DEBUG_PRINT_BEATS - for (double beat : beats) { - qDebug().noquote() << QString::number(beat, 'g', 8); + for (mixxx::audio::FramePos beat : beats) { + qDebug().noquote() << QString::number(beat.value(), 'g', 8); } #endif @@ -95,20 +95,21 @@ mixxx::BeatsPointer BeatFactory::makePreferredBeats( #ifdef DEBUG_PRINT_BEATS for (auto& region : constantRegions) { - qDebug().noquote() << QString::number(region.firstBeat, 'g', 8) + qDebug().noquote() << QString::number(region.firstBeat.value(), 'g', 8) << QString::number(region.beatLength, 'g', 8); } #endif if (version == BEAT_GRID_2_VERSION) { - double firstBeat = 0; - double constBPM = BeatUtils::makeConstBpm(constantRegions, sampleRate, &firstBeat); + mixxx::audio::FramePos firstBeat = mixxx::audio::kStartFramePos; + const mixxx::Bpm constBPM = BeatUtils::makeConstBpm( + constantRegions, sampleRate, &firstBeat); firstBeat = BeatUtils::adjustPhase(firstBeat, constBPM, sampleRate, beats); auto pGrid = mixxx::BeatGrid::makeBeatGrid( - sampleRate, subVersion, constBPM, firstBeat * 2); + sampleRate, subVersion, constBPM, firstBeat); return pGrid; } else if (version == BEAT_MAP_VERSION) { - QVector ironedBeats = BeatUtils::getBeats(constantRegions); + QVector ironedBeats = BeatUtils::getBeats(constantRegions); auto pBeatMap = mixxx::BeatMap::makeBeatMap(sampleRate, subVersion, ironedBeats); return pBeatMap; } else { diff --git a/src/track/beatfactory.h b/src/track/beatfactory.h index 6d0fa57eb65..b2b71b2a7d0 100644 --- a/src/track/beatfactory.h +++ b/src/track/beatfactory.h @@ -2,8 +2,10 @@ #include +#include "audio/frame.h" #include "audio/types.h" #include "track/beats.h" +#include "track/bpm.h" class Track; @@ -16,8 +18,8 @@ class BeatFactory { const QByteArray& beatsSerialized); static mixxx::BeatsPointer makeBeatGrid( mixxx::audio::SampleRate sampleRate, - double dBpm, - double dFirstBeatSample); + mixxx::Bpm bpm, + mixxx::audio::FramePos firstBeatFramePos); static QString getPreferredVersion(bool fixedTempo); @@ -25,7 +27,7 @@ class BeatFactory { const QHash& extraVersionInfo); static mixxx::BeatsPointer makePreferredBeats( - const QVector& beats, + const QVector& beats, const QHash& extraVersionInfo, bool fixedTempo, mixxx::audio::SampleRate sampleRate); diff --git a/src/track/beatgrid.cpp b/src/track/beatgrid.cpp index a5c85cc2d38..a50f4ea4bb3 100644 --- a/src/track/beatgrid.cpp +++ b/src/track/beatgrid.cpp @@ -23,71 +23,76 @@ namespace mixxx { class BeatGridIterator : public BeatIterator { public: - BeatGridIterator(double dBeatLength, double dFirstBeat, double dEndSample) - : m_dBeatLength(dBeatLength), - m_dCurrentSample(dFirstBeat), - m_dEndSample(dEndSample) { + BeatGridIterator(audio::FrameDiff_t beatLengthFrames, + audio::FramePos firstBeatPosition, + audio::FramePos endPosition) + : m_beatLengthFrames(beatLengthFrames), + m_endPosition(endPosition), + m_currentPosition(firstBeatPosition) { } bool hasNext() const override { - return m_dBeatLength > 0 && m_dCurrentSample <= m_dEndSample; + return m_beatLengthFrames > 0 && m_currentPosition <= m_endPosition; } - double next() override { - double beat = m_dCurrentSample; - m_dCurrentSample += m_dBeatLength; - return beat; + audio::FramePos next() override { + const audio::FramePos beatPosition = m_currentPosition; + m_currentPosition += m_beatLengthFrames; + return beatPosition; } private: - double m_dBeatLength; - double m_dCurrentSample; - double m_dEndSample; + const audio::FrameDiff_t m_beatLengthFrames; + const audio::FramePos m_endPosition; + audio::FramePos m_currentPosition; }; BeatGrid::BeatGrid( audio::SampleRate sampleRate, const QString& subVersion, const mixxx::track::io::BeatGrid& grid, - double beatLength) + audio::FrameDiff_t beatLengthFrames) : m_subVersion(subVersion), m_sampleRate(sampleRate), m_grid(grid), - m_dBeatLength(beatLength) { + m_beatLengthFrames(beatLengthFrames) { // BeatGrid should live in the same thread as the track it is associated // with. } -BeatGrid::BeatGrid(const BeatGrid& other, const mixxx::track::io::BeatGrid& grid, double beatLength) +BeatGrid::BeatGrid(const BeatGrid& other, + const mixxx::track::io::BeatGrid& grid, + audio::FrameDiff_t beatLengthFrames) : m_subVersion(other.m_subVersion), m_sampleRate(other.m_sampleRate), m_grid(grid), - m_dBeatLength(beatLength) { + m_beatLengthFrames(beatLengthFrames) { } BeatGrid::BeatGrid(const BeatGrid& other) - : BeatGrid(other, other.m_grid, other.m_dBeatLength) { + : BeatGrid(other, other.m_grid, other.m_beatLengthFrames) { } // static BeatsPointer BeatGrid::makeBeatGrid( audio::SampleRate sampleRate, const QString& subVersion, - double dBpm, - double dFirstBeatSample) { - if (dBpm < 0) { - dBpm = 0.0; + mixxx::Bpm bpm, + mixxx::audio::FramePos firstBeatPosition) { + // FIXME: Should this be a debug assertion? + if (!bpm.isValid() || !firstBeatPosition.isValid()) { + return nullptr; } mixxx::track::io::BeatGrid grid; - grid.mutable_bpm()->set_bpm(dBpm); + grid.mutable_bpm()->set_bpm(bpm.value()); grid.mutable_first_beat()->set_frame_position( - static_cast(dFirstBeatSample / kFrameSize)); + static_cast(firstBeatPosition.value())); // Calculate beat length as sample offsets - double beatLength = (60.0 * sampleRate / dBpm) * kFrameSize; + const audio::FrameDiff_t beatLengthFrames = 60.0 * sampleRate / bpm.value(); - return BeatsPointer(new BeatGrid(sampleRate, subVersion, grid, beatLength)); + return BeatsPointer(new BeatGrid(sampleRate, subVersion, grid, beatLengthFrames)); } // static @@ -97,8 +102,8 @@ BeatsPointer BeatGrid::makeBeatGrid( const QByteArray& byteArray) { mixxx::track::io::BeatGrid grid; if (grid.ParseFromArray(byteArray.constData(), byteArray.length())) { - double beatLength = (60.0 * sampleRate / grid.bpm().bpm()) * kFrameSize; - return BeatsPointer(new BeatGrid(sampleRate, subVersion, grid, beatLength)); + const audio::FrameDiff_t beatLengthFrames = (60.0 * sampleRate / grid.bpm().bpm()); + return BeatsPointer(new BeatGrid(sampleRate, subVersion, grid, beatLengthFrames)); } // Legacy fallback for BeatGrid-1.0 @@ -106,9 +111,10 @@ BeatsPointer BeatGrid::makeBeatGrid( return BeatsPointer(new BeatGrid(sampleRate, QString(), grid, 0)); } const BeatGridData* blob = reinterpret_cast(byteArray.constData()); + const auto firstBeat = mixxx::audio::FramePos(blob->firstBeat); + const auto bpm = mixxx::Bpm(blob->bpm); - // We serialize into frame offsets but use sample offsets at runtime - return makeBeatGrid(sampleRate, subVersion, blob->bpm, blob->firstBeat * kFrameSize); + return makeBeatGrid(sampleRate, subVersion, bpm, firstBeat); } QByteArray BeatGrid::toByteArray() const { @@ -117,12 +123,12 @@ QByteArray BeatGrid::toByteArray() const { return QByteArray(output.data(), static_cast(output.length())); } -double BeatGrid::firstBeatSample() const { - return m_grid.first_beat().frame_position() * kFrameSize; +audio::FramePos BeatGrid::firstBeatPosition() const { + return audio::FramePos(m_grid.first_beat().frame_position()); } -double BeatGrid::bpm() const { - return m_grid.bpm().bpm(); +mixxx::Bpm BeatGrid::bpm() const { + return mixxx::Bpm(m_grid.bpm().bpm()); } QString BeatGrid::getVersion() const { @@ -135,44 +141,50 @@ QString BeatGrid::getSubVersion() const { // internal use only bool BeatGrid::isValid() const { - return m_sampleRate.isValid() && bpm() > 0; + return m_sampleRate.isValid() && bpm().isValid() && firstBeatPosition().isValid(); } // This could be implemented in the Beats Class itself. // If necessary, the child class can redefine it. -double BeatGrid::findNextBeat(double dSamples) const { - return findNthBeat(dSamples, +1); +audio::FramePos BeatGrid::findNextBeat(audio::FramePos position) const { + return findNthBeat(position, 1); } // This could be implemented in the Beats Class itself. // If necessary, the child class can redefine it. -double BeatGrid::findPrevBeat(double dSamples) const { - return findNthBeat(dSamples, -1); +audio::FramePos BeatGrid::findPrevBeat(audio::FramePos position) const { + return findNthBeat(position, -1); } // This is an internal call. This could be implemented in the Beats Class itself. -double BeatGrid::findClosestBeat(double dSamples) const { +audio::FramePos BeatGrid::findClosestBeat(audio::FramePos position) const { if (!isValid()) { - return -1; + return audio::kInvalidFramePos; + } + audio::FramePos prevBeatPosition; + audio::FramePos nextBeatPosition; + findPrevNextBeats(position, &prevBeatPosition, &nextBeatPosition, true); + if (!prevBeatPosition.isValid()) { + // If both positions are invalid, we correctly return an invalid position. + return nextBeatPosition; } - double prevBeat; - double nextBeat; - findPrevNextBeats(dSamples, &prevBeat, &nextBeat, true); - if (prevBeat == -1) { - // If both values are -1, we correctly return -1. - return nextBeat; - } else if (nextBeat == -1) { - return prevBeat; + + if (!nextBeatPosition.isValid()) { + return prevBeatPosition; } - return (nextBeat - dSamples > dSamples - prevBeat) ? prevBeat : nextBeat; + + // Both position are valid, return the closest position. + return (nextBeatPosition - position > position - prevBeatPosition) + ? prevBeatPosition + : nextBeatPosition; } -double BeatGrid::findNthBeat(double dSamples, int n) const { +audio::FramePos BeatGrid::findNthBeat(audio::FramePos position, int n) const { if (!isValid() || n == 0) { - return -1; + return audio::kInvalidFramePos; } - double beatFraction = (dSamples - firstBeatSample()) / m_dBeatLength; + double beatFraction = (position - firstBeatPosition()) / m_beatLengthFrames; double prevBeat = floor(beatFraction); double nextBeat = ceil(beatFraction); @@ -194,38 +206,34 @@ double BeatGrid::findNthBeat(double dSamples, int n) const { nextBeat = prevBeat; } - double dClosestBeat; + audio::FramePos closestBeatPosition; if (n > 0) { // We're going forward, so use ceil to round up to the next multiple of // m_dBeatLength - dClosestBeat = nextBeat * m_dBeatLength + firstBeatSample(); + closestBeatPosition = firstBeatPosition() + nextBeat * m_beatLengthFrames; n = n - 1; } else { // We're going backward, so use floor to round down to the next multiple // of m_dBeatLength - dClosestBeat = prevBeat * m_dBeatLength + firstBeatSample(); + closestBeatPosition = firstBeatPosition() + prevBeat * m_beatLengthFrames; n = n + 1; } - double dResult = dClosestBeat + n * m_dBeatLength; - return dResult; + const audio::FramePos result = closestBeatPosition + n * m_beatLengthFrames; + return result; } -bool BeatGrid::findPrevNextBeats(double dSamples, - double* dpPrevBeatSamples, - double* dpNextBeatSamples, +bool BeatGrid::findPrevNextBeats(audio::FramePos position, + audio::FramePos* prevBeatPosition, + audio::FramePos* nextBeatPosition, bool snapToNearBeats) const { - double dFirstBeatSample; - double dBeatLength; if (!isValid()) { - *dpPrevBeatSamples = -1.0; - *dpNextBeatSamples = -1.0; + *prevBeatPosition = audio::kInvalidFramePos; + *nextBeatPosition = audio::kInvalidFramePos; return false; } - dFirstBeatSample = firstBeatSample(); - dBeatLength = m_dBeatLength; - double beatFraction = (dSamples - dFirstBeatSample) / dBeatLength; + double beatFraction = (position - firstBeatPosition()) / m_beatLengthFrames; double prevBeat = floor(beatFraction); double nextBeat = ceil(beatFraction); @@ -244,86 +252,90 @@ bool BeatGrid::findPrevNextBeats(double dSamples, // And nextBeat needs to be incremented. ++nextBeat; } - *dpPrevBeatSamples = prevBeat * dBeatLength + dFirstBeatSample; - *dpNextBeatSamples = nextBeat * dBeatLength + dFirstBeatSample; + *prevBeatPosition = firstBeatPosition() + prevBeat * m_beatLengthFrames; + *nextBeatPosition = firstBeatPosition() + nextBeat * m_beatLengthFrames; return true; } -std::unique_ptr BeatGrid::findBeats(double startSample, double stopSample) const { - if (!isValid() || startSample > stopSample) { +std::unique_ptr BeatGrid::findBeats( + audio::FramePos startPosition, audio::FramePos endPosition) const { + // FIXME: Should this be a VERIFY_OR_DEBUG_ASSERT? + if (!isValid() || !startPosition.isValid() || !endPosition.isValid() || + startPosition > endPosition) { return std::unique_ptr(); } - //qDebug() << "BeatGrid::findBeats startSample" << startSample << "stopSample" - // << stopSample << "beatlength" << m_dBeatLength << "BPM" << bpm(); - double curBeat = findNextBeat(startSample); - if (curBeat == -1.0) { + const audio::FramePos startBeatPosition = findNextBeat(startPosition); + if (!startBeatPosition.isValid()) { return std::unique_ptr(); } - return std::make_unique(m_dBeatLength, curBeat, stopSample); + return std::make_unique(m_beatLengthFrames, startBeatPosition, endPosition); } -bool BeatGrid::hasBeatInRange(double startSample, double stopSample) const { - if (!isValid() || startSample > stopSample) { +bool BeatGrid::hasBeatInRange(audio::FramePos startPosition, audio::FramePos endPosition) const { + // FIXME: Should this be a VERIFY_OR_DEBUG_ASSERT? + if (!isValid() || !startPosition.isValid() || !endPosition.isValid() || + startPosition > endPosition) { return false; } - double curBeat = findNextBeat(startSample); - if (curBeat != -1.0 && curBeat <= stopSample) { + const audio::FramePos currentPosition = findNextBeat(startPosition); + if (currentPosition.isValid() && currentPosition <= endPosition) { return true; } return false; } -double BeatGrid::getBpm() const { +mixxx::Bpm BeatGrid::getBpm() const { if (!isValid()) { - return mixxx::Bpm::kValueUndefined; + return {}; } return bpm(); } // Note: Also called from the engine thread -double BeatGrid::getBpmAroundPosition(double curSample, int n) const { - Q_UNUSED(curSample); +mixxx::Bpm BeatGrid::getBpmAroundPosition(audio::FramePos position, int n) const { + Q_UNUSED(position); Q_UNUSED(n); if (!isValid()) { - return -1; + return {}; } return bpm(); } -BeatsPointer BeatGrid::translate(double dNumSamples) const { +BeatsPointer BeatGrid::translate(audio::FrameDiff_t offset) const { if (!isValid()) { return BeatsPointer(new BeatGrid(*this)); } mixxx::track::io::BeatGrid grid = m_grid; - double newFirstBeatFrames = (firstBeatSample() + dNumSamples) / kFrameSize; + const audio::FramePos newFirstBeatPosition = firstBeatPosition() + offset; grid.mutable_first_beat()->set_frame_position( - static_cast(newFirstBeatFrames)); + static_cast( + newFirstBeatPosition.toLowerFrameBoundary().value())); - return BeatsPointer(new BeatGrid(*this, grid, m_dBeatLength)); + return BeatsPointer(new BeatGrid(*this, grid, m_beatLengthFrames)); } -BeatsPointer BeatGrid::scale(enum BPMScale scale) const { +BeatsPointer BeatGrid::scale(BpmScale scale) const { mixxx::track::io::BeatGrid grid = m_grid; - double bpm = grid.bpm().bpm(); + auto bpm = mixxx::Bpm(grid.bpm().bpm()); switch (scale) { - case DOUBLE: + case BpmScale::Double: bpm *= 2; break; - case HALVE: + case BpmScale::Halve: bpm *= 1.0 / 2; break; - case TWOTHIRDS: + case BpmScale::TwoThirds: bpm *= 2.0 / 3; break; - case THREEFOURTHS: + case BpmScale::ThreeFourths: bpm *= 3.0 / 4; break; - case FOURTHIRDS: + case BpmScale::FourThirds: bpm *= 4.0 / 3; break; - case THREEHALVES: + case BpmScale::ThreeHalves: bpm *= 3.0 / 2; break; default: @@ -331,23 +343,23 @@ BeatsPointer BeatGrid::scale(enum BPMScale scale) const { return BeatsPointer(new BeatGrid(*this)); } - if (bpm > getMaxBpm()) { + if (!bpm.isValid()) { return BeatsPointer(new BeatGrid(*this)); } bpm = BeatUtils::roundBpmWithinRange(bpm - kBpmScaleRounding, bpm, bpm + kBpmScaleRounding); - grid.mutable_bpm()->set_bpm(bpm); - double beatLength = (60.0 * m_sampleRate / bpm) * kFrameSize; + grid.mutable_bpm()->set_bpm(bpm.value()); + double beatLength = (60.0 * m_sampleRate / bpm.value()) * kFrameSize; return BeatsPointer(new BeatGrid(*this, grid, beatLength)); } -BeatsPointer BeatGrid::setBpm(double dBpm) { - if (dBpm > getMaxBpm()) { - dBpm = getMaxBpm(); +BeatsPointer BeatGrid::setBpm(mixxx::Bpm bpm) { + VERIFY_OR_DEBUG_ASSERT(bpm.isValid()) { + return nullptr; } mixxx::track::io::BeatGrid grid = m_grid; - grid.mutable_bpm()->set_bpm(dBpm); - double beatLength = (60.0 * m_sampleRate / dBpm) * kFrameSize; + grid.mutable_bpm()->set_bpm(bpm.value()); + double beatLength = (60.0 * m_sampleRate / bpm.value()) * kFrameSize; return BeatsPointer(new BeatGrid(*this, grid, beatLength)); } diff --git a/src/track/beatgrid.h b/src/track/beatgrid.h index 8397fd7afdb..2a7779d34ec 100644 --- a/src/track/beatgrid.h +++ b/src/track/beatgrid.h @@ -20,8 +20,8 @@ class BeatGrid final : public Beats { static BeatsPointer makeBeatGrid( audio::SampleRate sampleRate, const QString& subVersion, - double dBpm, - double dFirstBeatSample); + mixxx::Bpm bpm, + mixxx::audio::FramePos firstBeatPos); static BeatsPointer makeBeatGrid( audio::SampleRate sampleRate, @@ -43,18 +43,19 @@ class BeatGrid final : public Beats { // Beat calculations //////////////////////////////////////////////////////////////////////////// - double findNextBeat(double dSamples) const override; - double findPrevBeat(double dSamples) const override; - bool findPrevNextBeats(double dSamples, - double* dpPrevBeatSamples, - double* dpNextBeatSamples, + audio::FramePos findNextBeat(audio::FramePos position) const override; + audio::FramePos findPrevBeat(audio::FramePos position) const override; + bool findPrevNextBeats(audio::FramePos position, + audio::FramePos* prevBeatPosition, + audio::FramePos* nextBeatPosition, bool snapToNearBeats) const override; - double findClosestBeat(double dSamples) const override; - double findNthBeat(double dSamples, int n) const override; - std::unique_ptr findBeats(double startSample, double stopSample) const override; - bool hasBeatInRange(double startSample, double stopSample) const override; - double getBpm() const override; - double getBpmAroundPosition(double curSample, int n) const override; + audio::FramePos findClosestBeat(audio::FramePos position) const override; + audio::FramePos findNthBeat(audio::FramePos position, int n) const override; + std::unique_ptr findBeats(audio::FramePos startPosition, + audio::FramePos endPosition) const override; + bool hasBeatInRange(audio::FramePos startPosition, audio::FramePos endPosition) const override; + mixxx::Bpm getBpm() const override; + mixxx::Bpm getBpmAroundPosition(audio::FramePos position, int n) const override; audio::SampleRate getSampleRate() const override { return m_sampleRate; @@ -64,9 +65,9 @@ class BeatGrid final : public Beats { // Beat mutations //////////////////////////////////////////////////////////////////////////// - BeatsPointer translate(double dNumSamples) const override; - BeatsPointer scale(enum BPMScale scale) const override; - BeatsPointer setBpm(double dBpm) override; + BeatsPointer translate(audio::FrameDiff_t offset) const override; + BeatsPointer scale(BpmScale scale) const override; + BeatsPointer setBpm(mixxx::Bpm bpm) override; private: BeatGrid( @@ -78,8 +79,8 @@ class BeatGrid final : public Beats { BeatGrid(const BeatGrid& other, const mixxx::track::io::BeatGrid& grid, double beatLength); BeatGrid(const BeatGrid& other); - double firstBeatSample() const; - double bpm() const; + audio::FramePos firstBeatPosition() const; + mixxx::Bpm bpm() const; // For internal use only. bool isValid() const; @@ -91,7 +92,7 @@ class BeatGrid final : public Beats { // Data storage for BeatGrid const mixxx::track::io::BeatGrid m_grid; // The length of a beat in samples - const double m_dBeatLength; + const audio::FrameDiff_t m_beatLengthFrames; }; } // namespace mixxx diff --git a/src/track/beatmap.cpp b/src/track/beatmap.cpp index f68af39bfcf..06e46475051 100644 --- a/src/track/beatmap.cpp +++ b/src/track/beatmap.cpp @@ -20,15 +20,16 @@ using mixxx::track::io::Beat; namespace { -constexpr int kFrameSize = 2; constexpr int kMinNumberOfBeats = 2; // a map needs at least two beats to have a tempo -inline double samplesToFrames(const double samples) { - return floor(samples / kFrameSize); -} - -inline double framesToSamples(const int frames) { - return frames * kFrameSize; +inline Beat beatFromFramePos(mixxx::audio::FramePos beatPosition) { + DEBUG_ASSERT(beatPosition.isValid()); + // Because the protobuf Beat object stores integers internally, all + // fractional positions are lost. + DEBUG_ASSERT(!beatPosition.isFractional()); + Beat beat; + beat.set_frame_position(static_cast(beatPosition.value())); + return beat; } bool BeatLessThan(const Beat& beat1, const Beat& beat2) { @@ -128,17 +129,17 @@ void scaleFourth(BeatList* pBeats) { } } -double calculateNominalBpm(const BeatList& beats, mixxx::audio::SampleRate sampleRate) { - QVector beatvect; +mixxx::Bpm calculateNominalBpm(const BeatList& beats, mixxx::audio::SampleRate sampleRate) { + QVector beatvect; beatvect.reserve(beats.size()); for (const auto& beat : beats) { if (beat.enabled()) { - beatvect.append(beat.frame_position()); + beatvect.append(mixxx::audio::FramePos(beat.frame_position())); } } if (beatvect.size() < 2) { - return -1; + return {}; } return BeatUtils::calculateBpm(beatvect, mixxx::audio::SampleRate(sampleRate)); @@ -163,8 +164,8 @@ class BeatMapIterator : public BeatIterator { return m_currentBeat != m_endBeat; } - double next() override { - double beat = framesToSamples(m_currentBeat->frame_position()); + audio::FramePos next() override { + const auto beat = mixxx::audio::FramePos(m_currentBeat->frame_position()); ++m_currentBeat; while (m_currentBeat != m_endBeat && !m_currentBeat->enabled()) { ++m_currentBeat; @@ -181,14 +182,14 @@ BeatMap::BeatMap( audio::SampleRate sampleRate, const QString& subVersion, BeatList beats, - double nominalBpm) + mixxx::Bpm nominalBpm) : m_subVersion(subVersion), m_sampleRate(sampleRate), m_nominalBpm(nominalBpm), m_beats(std::move(beats)) { } -BeatMap::BeatMap(const BeatMap& other, BeatList beats, double nominalBpm) +BeatMap::BeatMap(const BeatMap& other, BeatList beats, mixxx::Bpm nominalBpm) : m_subVersion(other.m_subVersion), m_sampleRate(other.m_sampleRate), m_nominalBpm(nominalBpm), @@ -204,7 +205,7 @@ BeatsPointer BeatMap::makeBeatMap( audio::SampleRate sampleRate, const QString& subVersion, const QByteArray& byteArray) { - double nominalBpm = 0.0; + auto nominalBpm = mixxx::Bpm(); BeatList beatList; track::io::BeatMap map; @@ -225,25 +226,31 @@ BeatsPointer BeatMap::makeBeatMap( BeatsPointer BeatMap::makeBeatMap( audio::SampleRate sampleRate, const QString& subVersion, - const QVector& beats) { + const QVector& beats) { BeatList beatList; - double previous_beatpos = -1; - Beat beat; + mixxx::audio::FramePos previousBeatPos = mixxx::audio::kInvalidFramePos; - foreach (double beatpos, beats) { - // beatpos is in frames. Do not accept fractional frames. - beatpos = floor(beatpos); - if (beatpos <= previous_beatpos || beatpos < 0) { - qDebug() << "BeatMap::createFromVector: beats not in increasing order or negative"; - qDebug() << "discarding beat " << beatpos; - } else { - beat.set_frame_position(static_cast(beatpos)); - beatList.append(beat); - previous_beatpos = beatpos; + for (const mixxx::audio::FramePos& originalBeatPos : beats) { + VERIFY_OR_DEBUG_ASSERT(originalBeatPos.isValid()) { + qWarning() << "BeatMap::makeBeatMap: Beats is invalid, discarding beat"; + continue; } + + // Do not accept fractional frames. + const auto beatPos = mixxx::audio::FramePos(std::floor(originalBeatPos.value())); + if (previousBeatPos.isValid() && beatPos <= previousBeatPos) { + qWarning() << "BeatMap::makeBeatMap: Beats not in increasing " + "order, discarding beat " + << beatPos; + continue; + } + + Beat beat = beatFromFramePos(beatPos); + beatList.append(beat); + previousBeatPos = beatPos; } - double nominalBpm = calculateNominalBpm(beatList, sampleRate); + const auto nominalBpm = calculateNominalBpm(beatList, sampleRate); return BeatsPointer(new BeatMap(sampleRate, subVersion, beatList, nominalBpm)); } @@ -273,38 +280,42 @@ bool BeatMap::isValid() const { return m_sampleRate.isValid() && m_beats.size() >= kMinNumberOfBeats; } -double BeatMap::findNextBeat(double dSamples) const { - return findNthBeat(dSamples, 1); +audio::FramePos BeatMap::findNextBeat(audio::FramePos position) const { + return findNthBeat(position, 1); } -double BeatMap::findPrevBeat(double dSamples) const { - return findNthBeat(dSamples, -1); +audio::FramePos BeatMap::findPrevBeat(audio::FramePos position) const { + return findNthBeat(position, -1); } -double BeatMap::findClosestBeat(double dSamples) const { +audio::FramePos BeatMap::findClosestBeat(audio::FramePos position) const { if (!isValid()) { - return -1; - } - double prevBeat; - double nextBeat; - findPrevNextBeats(dSamples, &prevBeat, &nextBeat, true); - if (prevBeat == -1) { - // If both values are -1, we correctly return -1. - return nextBeat; - } else if (nextBeat == -1) { - return prevBeat; - } - return (nextBeat - dSamples > dSamples - prevBeat) ? prevBeat : nextBeat; + return audio::kInvalidFramePos; + } + audio::FramePos prevBeatPosition; + audio::FramePos nextBeatPosition; + findPrevNextBeats(position, &prevBeatPosition, &nextBeatPosition, true); + if (!prevBeatPosition.isValid()) { + // If both positions are invalid, we correctly return an invalid position. + return nextBeatPosition; + } + + if (!nextBeatPosition.isValid()) { + return prevBeatPosition; + } + + // Both position are valid, return the closest position. + return (nextBeatPosition - position > position - prevBeatPosition) + ? prevBeatPosition + : nextBeatPosition; } -double BeatMap::findNthBeat(double dSamples, int n) const { +audio::FramePos BeatMap::findNthBeat(audio::FramePos position, int n) const { if (!isValid() || n == 0) { - return -1; + return audio::kInvalidFramePos; } - Beat beat; - // Reduce sample offset to a frame offset. - beat.set_frame_position(static_cast(samplesToFrames(dSamples))); + Beat beat = beatFromFramePos(position); // it points at the first occurrence of beat or the next largest beat BeatList::const_iterator it = @@ -358,8 +369,7 @@ double BeatMap::findNthBeat(double dSamples, int n) const { continue; } if (n == 1) { - // Return a sample offset - return framesToSamples(next_beat->frame_position()); + return mixxx::audio::FramePos(next_beat->frame_position()); } --n; } @@ -367,8 +377,7 @@ double BeatMap::findNthBeat(double dSamples, int n) const { for (; true; --previous_beat) { if (previous_beat->enabled()) { if (n == -1) { - // Return a sample offset - return framesToSamples(previous_beat->frame_position()); + return mixxx::audio::FramePos(previous_beat->frame_position()); } ++n; } @@ -379,22 +388,20 @@ double BeatMap::findNthBeat(double dSamples, int n) const { } } } - return -1; + return audio::kInvalidFramePos; } -bool BeatMap::findPrevNextBeats(double dSamples, - double* dpPrevBeatSamples, - double* dpNextBeatSamples, +bool BeatMap::findPrevNextBeats(audio::FramePos position, + audio::FramePos* prevBeatPosition, + audio::FramePos* nextBeatPosition, bool snapToNearBeats) const { - if (!isValid()) { - *dpPrevBeatSamples = -1; - *dpNextBeatSamples = -1; + *prevBeatPosition = audio::kInvalidFramePos; + *nextBeatPosition = audio::kInvalidFramePos; + if (!isValid() || !position.isValid()) { return false; } - Beat beat; - // Reduce sample offset to a frame offset. - beat.set_frame_position(static_cast(samplesToFrames(dSamples))); + Beat beat = beatFromFramePos(position); // it points at the first occurrence of beat or the next largest beat BeatList::const_iterator it = @@ -443,20 +450,17 @@ bool BeatMap::findPrevNextBeats(double dSamples, next_beat = on_beat + 1; } - *dpPrevBeatSamples = -1; - *dpNextBeatSamples = -1; - for (; next_beat != m_beats.end(); ++next_beat) { if (!next_beat->enabled()) { continue; } - *dpNextBeatSamples = framesToSamples(next_beat->frame_position()); + *nextBeatPosition = mixxx::audio::FramePos(next_beat->frame_position()); break; } if (previous_beat != m_beats.end()) { for (; true; --previous_beat) { if (previous_beat->enabled()) { - *dpPrevBeatSamples = framesToSamples(previous_beat->frame_position()); + *prevBeatPosition = mixxx::audio::FramePos(previous_beat->frame_position()); break; } @@ -466,28 +470,26 @@ bool BeatMap::findPrevNextBeats(double dSamples, } } } - return *dpPrevBeatSamples != -1 && *dpNextBeatSamples != -1; + return prevBeatPosition->isValid() && nextBeatPosition->isValid(); } -std::unique_ptr BeatMap::findBeats(double startSample, double stopSample) const { - //startSample and stopSample are sample offsets, converting them to - //frames - if (!isValid() || startSample > stopSample) { +std::unique_ptr BeatMap::findBeats( + audio::FramePos startPosition, audio::FramePos endPosition) const { + // FIXME: Should this be a VERIFY_OR_DEBUG_ASSERT? + if (!isValid() || !startPosition.isValid() || !endPosition.isValid() || + startPosition > endPosition) { return std::unique_ptr(); } - Beat startBeat, stopBeat; - startBeat.set_frame_position( - static_cast(samplesToFrames(startSample))); - stopBeat.set_frame_position(static_cast(samplesToFrames(stopSample))); + Beat startBeat = beatFromFramePos(startPosition); + Beat endBeat = beatFromFramePos(endPosition); BeatList::const_iterator curBeat = std::lower_bound(m_beats.constBegin(), m_beats.constEnd(), startBeat, BeatLessThan); BeatList::const_iterator lastBeat = - std::upper_bound(m_beats.constBegin(), m_beats.constEnd(), - stopBeat, BeatLessThan); + std::upper_bound(m_beats.constBegin(), m_beats.constEnd(), endBeat, BeatLessThan); if (curBeat >= lastBeat) { return std::unique_ptr(); @@ -495,62 +497,61 @@ std::unique_ptr BeatMap::findBeats(double startSample, double stop return std::make_unique(curBeat, lastBeat); } -bool BeatMap::hasBeatInRange(double startSample, double stopSample) const { - if (!isValid() || startSample > stopSample) { +bool BeatMap::hasBeatInRange(audio::FramePos startPosition, audio::FramePos endPosition) const { + // FIXME: Should this be a VERIFY_OR_DEBUG_ASSERT? + if (!isValid() || !startPosition.isValid() || !endPosition.isValid() || + startPosition > endPosition) { return false; } - double curBeat = findNextBeat(startSample); - if (curBeat <= stopSample) { + audio::FramePos beatPosition = findNextBeat(startPosition); + if (beatPosition <= endPosition) { return true; } return false; } -double BeatMap::getBpm() const { +mixxx::Bpm BeatMap::getBpm() const { if (!isValid()) { - return mixxx::Bpm::kValueUndefined; + return {}; } return m_nominalBpm; } // Note: Also called from the engine thread -double BeatMap::getBpmAroundPosition(double curSample, int n) const { +mixxx::Bpm BeatMap::getBpmAroundPosition(audio::FramePos position, int n) const { if (!isValid()) { - return -1; + return {}; } // To make sure we are always counting n beats, iterate backward to the // lower bound, then iterate forward from there to the upper bound. // a value of -1 indicates we went off the map -- count from the beginning. - double lowerSample = findNthBeat(curSample, -n); - if (lowerSample == -1) { - lowerSample = framesToSamples(m_beats.first().frame_position()); + audio::FramePos lowerFrame = findNthBeat(position, -n); + if (!lowerFrame.isValid()) { + lowerFrame = mixxx::audio::FramePos(m_beats.first().frame_position()); } // If we hit the end of the beat map, recalculate the lower bound. - double upperSample = findNthBeat(lowerSample, n * 2); - if (upperSample == -1) { - upperSample = framesToSamples(m_beats.last().frame_position()); - lowerSample = findNthBeat(upperSample, n * -2); + audio::FramePos upperFrame = findNthBeat(lowerFrame, n * 2); + if (!upperFrame.isValid()) { + upperFrame = mixxx::audio::FramePos(m_beats.last().frame_position()); + lowerFrame = findNthBeat(upperFrame, n * -2); // Super edge-case -- the track doesn't have n beats! Do the best // we can. - if (lowerSample == -1) { - lowerSample = framesToSamples(m_beats.first().frame_position()); + if (!lowerFrame.isValid()) { + lowerFrame = mixxx::audio::FramePos(m_beats.first().frame_position()); } } - double lowerFrame = samplesToFrames(lowerSample); - double upperFrame = samplesToFrames(upperSample); - VERIFY_OR_DEBUG_ASSERT(lowerFrame < upperFrame) { - return -1; + return {}; } const int kFrameEpsilon = m_sampleRate / 20; int numberOfBeats = 0; for (const auto& beat : m_beats) { - double pos = beat.frame_position() + kFrameEpsilon; + const auto pos = mixxx::audio::FramePos(beat.frame_position() + kFrameEpsilon); if (pos > upperFrame) { break; } @@ -559,22 +560,25 @@ double BeatMap::getBpmAroundPosition(double curSample, int n) const { } } - return BeatUtils::calculateAverageBpm(numberOfBeats, m_sampleRate, lowerFrame, upperFrame); + return BeatUtils::calculateAverageBpm( + numberOfBeats, m_sampleRate, lowerFrame, upperFrame); } -BeatsPointer BeatMap::translate(double dNumSamples) const { +BeatsPointer BeatMap::translate(audio::FrameDiff_t offset) const { // Converting to frame offset if (!isValid()) { return BeatsPointer(new BeatMap(*this)); } BeatList beats = m_beats; - double dNumFrames = samplesToFrames(dNumSamples); for (BeatList::iterator it = beats.begin(); it != beats.end();) { - double newpos = it->frame_position() + dNumFrames; - if (newpos >= 0) { - it->set_frame_position(static_cast(newpos)); + const auto oldPosition = mixxx::audio::FramePos(it->frame_position()); + mixxx::audio::FramePos newPosition = oldPosition + offset; + + // FIXME: Don't we allow negative positions? + if (newPosition >= mixxx::audio::kStartFramePos) { + it->set_frame_position(static_cast(newPosition.value())); ++it; } else { it = beats.erase(it); @@ -584,40 +588,40 @@ BeatsPointer BeatMap::translate(double dNumSamples) const { return BeatsPointer(new BeatMap(*this, beats, m_nominalBpm)); } -BeatsPointer BeatMap::scale(enum BPMScale scale) const { +BeatsPointer BeatMap::scale(BpmScale scale) const { if (!isValid() || m_beats.isEmpty()) { return BeatsPointer(new BeatMap(*this)); } BeatList beats = m_beats; switch (scale) { - case DOUBLE: + case BpmScale::Double: // introduce a new beat into every gap scaleDouble(&beats); break; - case HALVE: + case BpmScale::Halve: // remove every second beat scaleHalve(&beats); break; - case TWOTHIRDS: + case BpmScale::TwoThirds: // introduce a new beat into every gap scaleDouble(&beats); // remove every second and third beat scaleThird(&beats); break; - case THREEFOURTHS: + case BpmScale::ThreeFourths: // introduce two beats into every gap scaleTriple(&beats); // remove every second third and forth beat scaleFourth(&beats); break; - case FOURTHIRDS: + case BpmScale::FourThirds: // introduce three beats into every gap scaleQuadruple(&beats); // remove every second third and forth beat scaleThird(&beats); break; - case THREEHALVES: + case BpmScale::ThreeHalves: // introduce two beats into every gap scaleTriple(&beats); // remove every second beat @@ -628,12 +632,12 @@ BeatsPointer BeatMap::scale(enum BPMScale scale) const { return BeatsPointer(new BeatMap(*this)); } - double bpm = calculateNominalBpm(beats, m_sampleRate); + mixxx::Bpm bpm = calculateNominalBpm(beats, m_sampleRate); return BeatsPointer(new BeatMap(*this, beats, bpm)); } -BeatsPointer BeatMap::setBpm(double dBpm) { - Q_UNUSED(dBpm); +BeatsPointer BeatMap::setBpm(mixxx::Bpm bpm) { + Q_UNUSED(bpm); DEBUG_ASSERT(!"BeatMap::setBpm() not implemented"); return BeatsPointer(new BeatMap(*this)); diff --git a/src/track/beatmap.h b/src/track/beatmap.h index a51e313609d..d597efce2ca 100644 --- a/src/track/beatmap.h +++ b/src/track/beatmap.h @@ -31,7 +31,7 @@ class BeatMap final : public Beats { static BeatsPointer makeBeatMap( audio::SampleRate sampleRate, const QString& subVersion, - const QVector& beats); + const QVector& beats); Beats::CapabilitiesFlags getCapabilities() const override { return BEATSCAP_TRANSLATE | BEATSCAP_SCALE | BEATSCAP_ADDREMOVE | @@ -46,19 +46,20 @@ class BeatMap final : public Beats { // Beat calculations //////////////////////////////////////////////////////////////////////////// - double findNextBeat(double dSamples) const override; - double findPrevBeat(double dSamples) const override; - bool findPrevNextBeats(double dSamples, - double* dpPrevBeatSamples, - double* dpNextBeatSamples, + audio::FramePos findNextBeat(audio::FramePos position) const override; + audio::FramePos findPrevBeat(audio::FramePos position) const override; + bool findPrevNextBeats(audio::FramePos position, + audio::FramePos* prevBeatPosition, + audio::FramePos* nextBeatPosition, bool snapToNearBeats) const override; - double findClosestBeat(double dSamples) const override; - double findNthBeat(double dSamples, int n) const override; - std::unique_ptr findBeats(double startSample, double stopSample) const override; - bool hasBeatInRange(double startSample, double stopSample) const override; + audio::FramePos findClosestBeat(audio::FramePos position) const override; + audio::FramePos findNthBeat(audio::FramePos position, int n) const override; + std::unique_ptr findBeats(audio::FramePos startPosition, + audio::FramePos endPosition) const override; + bool hasBeatInRange(audio::FramePos startPosition, audio::FramePos endPosition) const override; - double getBpm() const override; - double getBpmAroundPosition(double curSample, int n) const override; + mixxx::Bpm getBpm() const override; + mixxx::Bpm getBpmAroundPosition(audio::FramePos position, int n) const override; audio::SampleRate getSampleRate() const override { return m_sampleRate; @@ -68,17 +69,17 @@ class BeatMap final : public Beats { // Beat mutations //////////////////////////////////////////////////////////////////////////// - BeatsPointer translate(double dNumSamples) const override; - BeatsPointer scale(enum BPMScale scale) const override; - BeatsPointer setBpm(double dBpm) override; + BeatsPointer translate(audio::FrameDiff_t offset) const override; + BeatsPointer scale(BpmScale scale) const override; + BeatsPointer setBpm(mixxx::Bpm bpm) override; private: BeatMap(audio::SampleRate sampleRate, const QString& subVersion, BeatList beats, - double nominalBpm); + mixxx::Bpm nominalBpm); // Constructor to update the beat map - BeatMap(const BeatMap& other, BeatList beats, double nominalBpm); + BeatMap(const BeatMap& other, BeatList beats, mixxx::Bpm nominalBpm); BeatMap(const BeatMap& other); // For internal use only. @@ -86,7 +87,7 @@ class BeatMap final : public Beats { const QString m_subVersion; const audio::SampleRate m_sampleRate; - const double m_nominalBpm; + const mixxx::Bpm m_nominalBpm; const BeatList m_beats; }; diff --git a/src/track/beats.cpp b/src/track/beats.cpp index d8911f01a99..2c62fd3dad7 100644 --- a/src/track/beats.cpp +++ b/src/track/beats.cpp @@ -2,54 +2,56 @@ namespace mixxx { -int Beats::numBeatsInRange(double dStartSample, double dEndSample) const { - double dLastCountedBeat = 0.0; - int iBeatsCounter; - for (iBeatsCounter = 1; dLastCountedBeat < dEndSample; iBeatsCounter++) { - dLastCountedBeat = findNthBeat(dStartSample, iBeatsCounter); - if (dLastCountedBeat == -1) { +int Beats::numBeatsInRange(audio::FramePos startPosition, audio::FramePos endPosition) const { + audio::FramePos lastPosition = audio::kStartFramePos; + int i = 1; + while (lastPosition < endPosition) { + lastPosition = findNthBeat(startPosition, i); + if (!lastPosition.isValid()) { break; } + i++; } - return iBeatsCounter - 2; + return i - 2; }; -double Beats::findNBeatsFromSample(double fromSample, double beats) const { - double nthBeat; - double prevBeat; - double nextBeat; +audio::FramePos Beats::findNBeatsFromPosition(audio::FramePos position, double beats) const { + audio::FramePos prevBeatPosition; + audio::FramePos nextBeatPosition; - if (!findPrevNextBeats(fromSample, &prevBeat, &nextBeat, true)) { - return fromSample; + if (!findPrevNextBeats(position, &prevBeatPosition, &nextBeatPosition, true)) { + return position; } - double fromFractionBeats = (fromSample - prevBeat) / (nextBeat - prevBeat); - double beatsFromPrevBeat = fromFractionBeats + beats; + const audio::FrameDiff_t fromFractionBeats = (position - prevBeatPosition) / + (nextBeatPosition - prevBeatPosition); + const audio::FrameDiff_t beatsFromPrevBeat = fromFractionBeats + beats; - int fullBeats = static_cast(beatsFromPrevBeat); - double fractionBeats = beatsFromPrevBeat - fullBeats; + const int fullBeats = static_cast(beatsFromPrevBeat); + const audio::FrameDiff_t fractionBeats = beatsFromPrevBeat - fullBeats; // Add the length between this beat and the fullbeats'th beat // to the end position + audio::FramePos nthBeatPosition; if (fullBeats > 0) { - nthBeat = findNthBeat(nextBeat, fullBeats); + nthBeatPosition = findNthBeat(nextBeatPosition, fullBeats); } else { - nthBeat = findNthBeat(prevBeat, fullBeats - 1); + nthBeatPosition = findNthBeat(prevBeatPosition, fullBeats - 1); } - if (nthBeat == -1) { - return fromSample; + if (!nthBeatPosition.isValid()) { + return position; } // Add the fraction of the beat if (fractionBeats != 0) { - nextBeat = findNthBeat(nthBeat, 2); - if (nextBeat == -1) { - return fromSample; + nextBeatPosition = findNthBeat(nthBeatPosition, 2); + if (!nextBeatPosition.isValid()) { + return position; } - nthBeat += (nextBeat - nthBeat) * fractionBeats; + nthBeatPosition += (nextBeatPosition - nthBeatPosition) * fractionBeats; } - return nthBeat; + return nthBeatPosition; }; } // namespace mixxx diff --git a/src/track/beats.h b/src/track/beats.h index 73aaa4f72e7..048d19c2556 100644 --- a/src/track/beats.h +++ b/src/track/beats.h @@ -5,14 +5,12 @@ #include #include +#include "audio/frame.h" #include "audio/types.h" +#include "track/bpm.h" #include "util/memory.h" #include "util/types.h" -namespace { - double kMaxBpm = 500; -} - namespace mixxx { class Beats; @@ -22,46 +20,53 @@ class BeatIterator { public: virtual ~BeatIterator() = default; virtual bool hasNext() const = 0; - virtual double next() = 0; + virtual audio::FramePos next() = 0; }; -// Beats is the base class for BPM and beat management classes. It -// provides a specification of all methods a beat-manager class must provide, as -// well as a capability model for representing optional features. +/// Beats is the base class for BPM and beat management classes. It provides a +/// specification of all methods a beat-manager class must provide, as well as +/// a capability model for representing optional features. class Beats { public: virtual ~Beats() = default; enum Capabilities { - BEATSCAP_NONE = 0x0000, - BEATSCAP_ADDREMOVE = 0x0001, // Add or remove a single beat - BEATSCAP_TRANSLATE = 0x0002, // Move all beat markers earlier or later - BEATSCAP_SCALE = 0x0004, // Scale beat distance by a fixed ratio - BEATSCAP_MOVEBEAT = 0x0008, // Move a single Beat - BEATSCAP_SETBPM = 0x0010 // Set new bpm, beat grid only + BEATSCAP_NONE = 0x0000, + /// Add or remove a single beat + BEATSCAP_ADDREMOVE = 0x0001, + /// Move all beat markers earlier or later + BEATSCAP_TRANSLATE = 0x0002, + /// Scale beat distance by a fixed ratio + BEATSCAP_SCALE = 0x0004, + /// Move a single Beat + BEATSCAP_MOVEBEAT = 0x0008, + /// Set new bpm, beat grid only + BEATSCAP_SETBPM = 0x0010 }; - typedef int CapabilitiesFlags; // Allows us to do ORing - - enum BPMScale { - DOUBLE, - HALVE, - TWOTHIRDS, - THREEFOURTHS, - FOURTHIRDS, - THREEHALVES, + /// Allows us to do ORing + typedef int CapabilitiesFlags; + + enum class BpmScale { + Double, + Halve, + TwoThirds, + ThreeFourths, + FourThirds, + ThreeHalves, }; + /// Retrieve the capabilities supported by the beats implementation. virtual Beats::CapabilitiesFlags getCapabilities() const = 0; - // Serialization + /// Serialize beats to QByteArray. virtual QByteArray toByteArray() const = 0; - // A string representing the version of the beat-processing code that - // produced this Beats instance. Used by BeatsFactory for associating a - // given serialization with the version that produced it. + /// A string representing the version of the beat-processing code that + /// produced this Beats instance. Used by BeatsFactory for associating a + /// given serialization with the version that produced it. virtual QString getVersion() const = 0; - // A sub-version can be used to represent the preferences used to generate - // the beats object. + /// A sub-version can be used to represent the preferences used to generate + /// the beats object. virtual QString getSubVersion() const = 0; //////////////////////////////////////////////////////////////////////////// @@ -73,86 +78,92 @@ class Beats { // TODO: We may want to implement these with common code that returns // the triple of closest, next, and prev. - // Starting from sample dSamples, return the sample of the next beat in the - // track, or -1 if none exists. If dSamples refers to the location of a - // beat, dSamples is returned. - virtual double findNextBeat(double dSamples) const = 0; - - // Starting from sample dSamples, return the sample of the previous beat in - // the track, or -1 if none exists. If dSamples refers to the location of - // beat, dSamples is returned. - virtual double findPrevBeat(double dSamples) const = 0; - - // Starting from sample dSamples, fill the samples of the previous beat - // and next beat. Either can be -1 if none exists. If dSamples refers - // to the location of the beat, the first value is dSamples, and the second - // value is the next beat position. Non- -1 values are guaranteed to be - // even. Returns false if *at least one* sample is -1. (Can return false - // with one beat successfully filled) - virtual bool findPrevNextBeats(double dSamples, - double* dpPrevBeatSamples, - double* dpNextBeatSamples, + /// Starting from frame position `position`, return the frame position of + /// the next beat in the track, or an invalid position if none exists. If + /// `position` refers to the location of a beat, `position` is returned. + virtual audio::FramePos findNextBeat(audio::FramePos position) const = 0; + + /// Starting from frame position `position`, return the frame position of + /// the previous beat in the track, or an invalid position if none exists. + /// If `position` refers to the location of beat, `position` is returned. + virtual audio::FramePos findPrevBeat(audio::FramePos position) const = 0; + + /// Starting from frame position `position`, fill the frame position of the + /// previous beat and next beat. Either can be invalid if none exists. If + /// `position` refers to the location of the beat, the first value is + /// `position`, and the second value is the next beat position. Returns + /// `false` if *at least one* position is invalid. + virtual bool findPrevNextBeats(audio::FramePos position, + audio::FramePos* prevBeatPosition, + audio::FramePos* nextBeatPosition, bool snapToNearBeats) const = 0; - // Starting from sample dSamples, return the sample of the closest beat in - // the track, or -1 if none exists. Non- -1 values are guaranteed to be - // even. - virtual double findClosestBeat(double dSamples) const = 0; - - // Find the Nth beat from sample dSamples. Works with both positive and - // negative values of n. Calling findNthBeat with n=0 is invalid. Calling - // findNthBeat with n=1 or n=-1 is equivalent to calling findNextBeat and - // findPrevBeat, respectively. If dSamples refers to the location of a beat, - // then dSamples is returned. If no beat can be found, returns -1. - virtual double findNthBeat(double dSamples, int n) const = 0; - - int numBeatsInRange(double dStartSample, double dEndSample) const; - - // Find the sample N beats away from dSample. The number of beats may be - // negative and does not need to be an integer. - double findNBeatsFromSample(double fromSample, double beats) const; - - - // Adds to pBeatsList the position in samples of every beat occurring between - // startPosition and endPosition. BeatIterator must be iterated while - // holding a strong references to the Beats object to ensure that the Beats - // object is not deleted. Caller takes ownership of the returned BeatIterator; - virtual std::unique_ptr findBeats(double startSample, double stopSample) const = 0; - - // Return whether or not a sample lies between startPosition and endPosition - virtual bool hasBeatInRange(double startSample, double stopSample) const = 0; - - // Return the average BPM over the entire track if the BPM is - // valid, otherwise returns -1 - virtual double getBpm() const = 0; - - // Return the average BPM over the range of n*2 beats centered around - // curSample. (An n of 4 results in an averaging of 8 beats). Invalid - // BPM returns -1. - virtual double getBpmAroundPosition(double curSample, int n) const = 0; - - virtual double getMaxBpm() const { - return kMaxBpm; + /// Return the frame position of the first beat in the track, or an invalid + /// position if none exists. + audio::FramePos firstBeat() const { + return findNextBeat(mixxx::audio::kStartFramePos); } + /// Starting from frame position `position`, return the frame position of + /// the closest beat in the track, or an invalid positon if none exists. + virtual audio::FramePos findClosestBeat(audio::FramePos position) const = 0; + + /// Find the Nth beat from frame position `position`. Works with both + /// positive and negative values of n. Calling findNthBeat with `n=0` is + /// invalid and always returns an invalid frame position. Calling + /// findNthBeat with `n=1` or `n=-1` is equivalent to calling + /// `findNextBeat` and `findPrevBeat`, respectively. If `position` refers + /// to the location of a beat, then `position` is returned. If no beat can + /// be found, returns an invalid frame position. + virtual audio::FramePos findNthBeat(audio::FramePos position, int n) const = 0; + + int numBeatsInRange(audio::FramePos startPosition, audio::FramePos endPosition) const; + + /// Find the frame position N beats away from `position`. The number of beats may be + /// negative and does not need to be an integer. + audio::FramePos findNBeatsFromPosition(audio::FramePos position, double beats) const; + + /// Reutns an iterator that yields frame position of every beat occurring + /// between `startPosition` and `endPosition`. `BeatIterator` must be iterated + /// while holding a strong references to the `Beats` object to ensure that + /// the `Beats` object is not deleted. Caller takes ownership of the returned + /// `BeatIterator`. + virtual std::unique_ptr findBeats( + audio::FramePos startPosition, + audio::FramePos endPosition) const = 0; + + /// Return whether or not a beat exists between `startPosition` and `endPosition`. + virtual bool hasBeatInRange(audio::FramePos startPosition, + audio::FramePos endPosition) const = 0; + + /// Return the average BPM over the entire track if the BPM is valid, + /// otherwise returns -1 + virtual mixxx::Bpm getBpm() const = 0; + + /// Return the average BPM over the range of n*2 beats centered around + /// frame position `position`. For example, n=4 results in an averaging of 8 beats. + /// The returned Bpm value may be invalid. + virtual mixxx::Bpm getBpmAroundPosition(audio::FramePos position, int n) const = 0; + virtual audio::SampleRate getSampleRate() const = 0; //////////////////////////////////////////////////////////////////////////// // Beat mutations //////////////////////////////////////////////////////////////////////////// - // Translate all beats in the song by dNumSamples samples. Beats that lie - // before the start of the track or after the end of the track are not - // removed. Beats instance must have the capability BEATSCAP_TRANSLATE. - virtual BeatsPointer translate(double dNumSamples) const = 0; + /// Translate all beats in the song by `offset` frames. Beats that lie + /// before the start of the track or after the end of the track are *not* + /// removed. The `Beats` instance must have the capability + /// `BEATSCAP_TRANSLATE`. + virtual BeatsPointer translate(audio::FrameDiff_t offset) const = 0; - // Scale the position of every beat in the song by dScalePercentage. Beats - // class must have the capability BEATSCAP_SCALE. - virtual BeatsPointer scale(enum BPMScale scale) const = 0; + /// Scale the position of every beat in the song by `scale`. The `Beats` + /// class must have the capability `BEATSCAP_SCALE`. + virtual BeatsPointer scale(BpmScale scale) const = 0; - // Adjust the beats so the global average BPM matches dBpm. Beats class must - // have the capability BEATSCAP_SET. - virtual BeatsPointer setBpm(double dBpm) = 0; + /// Adjust the beats so the global average BPM matches `bpm`. The `Beats` + /// class must have the capability `BEATSCAP_SET`. + virtual BeatsPointer setBpm(mixxx::Bpm bpm) = 0; }; } // namespace mixxx diff --git a/src/track/beatsimporter.h b/src/track/beatsimporter.h index 0b58b374334..402889fba24 100644 --- a/src/track/beatsimporter.h +++ b/src/track/beatsimporter.h @@ -3,6 +3,7 @@ #include #include +#include "audio/frame.h" #include "audio/streaminfo.h" namespace mixxx { @@ -17,7 +18,7 @@ class BeatsImporter { /// Determines the timing offset and returns a Vector of frame positions /// to use as input for the BeatMap constructor - virtual QVector importBeatsAndApplyTimingOffset( + virtual QVector importBeatsAndApplyTimingOffset( const QString& filePath, const audio::StreamInfo& streamInfo) = 0; }; diff --git a/src/track/beatutils.cpp b/src/track/beatutils.cpp index 68f0962f1c2..bae1e12a4d4 100644 --- a/src/track/beatutils.cpp +++ b/src/track/beatutils.cpp @@ -6,7 +6,6 @@ #include #include -#include "track/bpm.h" #include "util/math.h" namespace { @@ -23,23 +22,23 @@ constexpr int kMinRegionBeatCount = 16; } // namespace -double BeatUtils::calculateAverageBpm(int numberOfBeats, +mixxx::Bpm BeatUtils::calculateAverageBpm(int numberOfBeats, mixxx::audio::SampleRate sampleRate, - double lowerFrame, - double upperFrame) { - double frames = upperFrame - lowerFrame; + mixxx::audio::FramePos lowerFrame, + mixxx::audio::FramePos upperFrame) { + mixxx::audio::FrameDiff_t frames = upperFrame - lowerFrame; DEBUG_ASSERT(frames > 0); if (numberOfBeats < 1) { - return 0; + return {}; } - return 60.0 * numberOfBeats * sampleRate / frames; + return mixxx::Bpm(60.0 * numberOfBeats * sampleRate / frames); } -double BeatUtils::calculateBpm( - const QVector& beats, +mixxx::Bpm BeatUtils::calculateBpm( + const QVector& beats, mixxx::audio::SampleRate sampleRate) { if (beats.size() < 2) { - return 0; + return {}; } // If we don't have enough beats for our regular approach, just divide the # @@ -54,7 +53,7 @@ double BeatUtils::calculateBpm( } QVector BeatUtils::retrieveConstRegions( - const QVector& coarseBeats, + const QVector& coarseBeats, mixxx::audio::SampleRate sampleRate) { // The QM Beat detector has a step size of 512 frames @ 44100 Hz. This means that // Single beats have has a jitter of +- 12 ms around the actual position. @@ -78,23 +77,23 @@ QVector BeatUtils::retrieveConstRegions( return constantRegions; } - double maxPhaseError = kMaxSecsPhaseError * sampleRate; - double maxPhaseErrorSum = kMaxSecsPhaseErrorSum * sampleRate; + const mixxx::audio::FrameDiff_t maxPhaseError = kMaxSecsPhaseError * sampleRate; + const mixxx::audio::FrameDiff_t maxPhaseErrorSum = kMaxSecsPhaseErrorSum * sampleRate; int leftIndex = 0; int rightIndex = coarseBeats.size() - 1; while (leftIndex < coarseBeats.size() - 1) { DEBUG_ASSERT(rightIndex > leftIndex); - double meanBeatLength = + mixxx::audio::FrameDiff_t meanBeatLength = (coarseBeats[rightIndex] - coarseBeats[leftIndex]) / (rightIndex - leftIndex); int outliersCount = 0; - double ironedBeat = coarseBeats[leftIndex]; - double phaseErrorSum = 0; + mixxx::audio::FramePos ironedBeat = coarseBeats[leftIndex]; + mixxx::audio::FrameDiff_t phaseErrorSum = 0; int i = leftIndex + 1; for (; i <= rightIndex; ++i) { ironedBeat += meanBeatLength; - double phaseError = ironedBeat - coarseBeats[i]; + const mixxx::audio::FrameDiff_t phaseError = ironedBeat - coarseBeats[i]; phaseErrorSum += phaseError; if (fabs(phaseError) > maxPhaseError) { outliersCount++; @@ -112,15 +111,17 @@ QVector BeatUtils::retrieveConstRegions( if (i > rightIndex) { // Verify that the first an the last beat are not correction beats in the same direction // This would bend meanBeatLength unfavorably away from the optimum. - double regionBorderError = 0; + mixxx::audio::FrameDiff_t regionBorderError = 0; if (rightIndex > leftIndex + 2) { - double firstBeatLength = coarseBeats[leftIndex + 1] - coarseBeats[leftIndex]; - double lastBeatLength = coarseBeats[rightIndex] - coarseBeats[rightIndex - 1]; + const mixxx::audio::FrameDiff_t firstBeatLength = + coarseBeats[leftIndex + 1] - coarseBeats[leftIndex]; + const mixxx::audio::FrameDiff_t lastBeatLength = + coarseBeats[rightIndex] - coarseBeats[rightIndex - 1]; regionBorderError = fabs(firstBeatLength + lastBeatLength - (2 * meanBeatLength)); } if (regionBorderError < maxPhaseError / 2) { // We have found a constant enough region. - double firstBeat = coarseBeats[leftIndex]; + const mixxx::audio::FramePos firstBeat = coarseBeats[leftIndex]; // store the regions for the later stages constantRegions.append({firstBeat, meanBeatLength}); // continue with the next region. @@ -139,15 +140,15 @@ QVector BeatUtils::retrieveConstRegions( } // static -double BeatUtils::makeConstBpm( +mixxx::Bpm BeatUtils::makeConstBpm( const QVector& constantRegions, mixxx::audio::SampleRate sampleRate, - double* pFirstBeat) { + mixxx::audio::FramePos* pFirstBeat) { // We assume here the track was recorded with an unhear-able static metronome. // This metronome is likely at a full BPM. // The track may has intros, outros and bridges without detectable beats. // In these regions the detected beat might is floating around and is just wrong. - // The track may also has regions with different Rythm giving Instruments. They + // The track may also has regions with different Rhythm giving Instruments. They // have a different shape of onsets and introduce a static beat offset. // The track may also have break beats or other issues that makes the detector // hook onto a beat that is by an integer fraction off the original metronome. @@ -161,10 +162,11 @@ double BeatUtils::makeConstBpm( // this functions are based on frames. int midRegionIndex = 0; - double longestRegionLength = 0; - double longestRegionBeatLength = 0; + mixxx::audio::FrameDiff_t longestRegionLength = 0; + mixxx::audio::FrameDiff_t longestRegionBeatLength = 0; for (int i = 0; i < constantRegions.size() - 1; ++i) { - double length = constantRegions[i + 1].firstBeat - constantRegions[i].firstBeat; + mixxx::audio::FrameDiff_t length = + constantRegions[i + 1].firstBeat - constantRegions[i].firstBeat; if (length > longestRegionLength) { longestRegionLength = length; longestRegionBeatLength = constantRegions[i].beatLength; @@ -175,39 +177,43 @@ double BeatUtils::makeConstBpm( if (longestRegionLength == 0) { // no betas, we default to - return 128; + return mixxx::Bpm(128); } int longestRegionNumberOfBeats = static_cast( (longestRegionLength / longestRegionBeatLength) + 0.5); - double longestRegionBeatLengthMin = longestRegionBeatLength - + mixxx::audio::FrameDiff_t longestRegionBeatLengthMin = longestRegionBeatLength - ((kMaxSecsPhaseError * sampleRate) / longestRegionNumberOfBeats); - double longestRegionBeatLengthMax = longestRegionBeatLength + + mixxx::audio::FrameDiff_t longestRegionBeatLengthMax = longestRegionBeatLength + ((kMaxSecsPhaseError * sampleRate) / longestRegionNumberOfBeats); int startRegionIndex = midRegionIndex; // Find a region at the beginning of the track with a similar tempo and phase for (int i = 0; i < midRegionIndex; ++i) { - const double length = constantRegions[i + 1].firstBeat - constantRegions[i].firstBeat; + const mixxx::audio::FrameDiff_t length = + constantRegions[i + 1].firstBeat - constantRegions[i].firstBeat; const int numberOfBeats = static_cast((length / constantRegions[i].beatLength) + 0.5); if (numberOfBeats < kMinRegionBeatCount) { // Request short regions, too unstable. continue; } - const double thisRegionBeatLengthMin = constantRegions[i].beatLength - + const mixxx::audio::FrameDiff_t thisRegionBeatLengthMin = constantRegions[i].beatLength - ((kMaxSecsPhaseError * sampleRate) / numberOfBeats); - const double thisRegionBeatLengthMax = constantRegions[i].beatLength + + const mixxx::audio::FrameDiff_t thisRegionBeatLengthMax = constantRegions[i].beatLength + ((kMaxSecsPhaseError * sampleRate) / numberOfBeats); // check if the tempo of the longest region is part of the rounding range of this region if (longestRegionBeatLength > thisRegionBeatLengthMin && longestRegionBeatLength < thisRegionBeatLengthMax) { // Now check if both regions are at the same phase. - const double newLongestRegionLength = constantRegions[midRegionIndex + 1].firstBeat - + const mixxx::audio::FrameDiff_t newLongestRegionLength = + constantRegions[midRegionIndex + 1].firstBeat - constantRegions[i].firstBeat; - double beatLengthMin = math_max(longestRegionBeatLengthMin, thisRegionBeatLengthMin); - double beatLengthMax = math_min(longestRegionBeatLengthMax, thisRegionBeatLengthMax); + mixxx::audio::FrameDiff_t beatLengthMin = math_max( + longestRegionBeatLengthMin, thisRegionBeatLengthMin); + mixxx::audio::FrameDiff_t beatLengthMax = math_min( + longestRegionBeatLengthMax, thisRegionBeatLengthMax); const int maxNumberOfBeats = static_cast(round(newLongestRegionLength / beatLengthMin)); @@ -219,7 +225,7 @@ double BeatUtils::makeConstBpm( continue; } const int numberOfBeats = minNumberOfBeats; - const double newBeatLength = newLongestRegionLength / numberOfBeats; + const mixxx::audio::FrameDiff_t newBeatLength = newLongestRegionLength / numberOfBeats; if (newBeatLength > longestRegionBeatLengthMin && newBeatLength < longestRegionBeatLengthMax) { longestRegionLength = newLongestRegionLength; @@ -237,23 +243,27 @@ double BeatUtils::makeConstBpm( // Find a region at the end of the track with similar tempo and phase for (int i = constantRegions.size() - 2; i > midRegionIndex; --i) { - const double length = constantRegions[i + 1].firstBeat - constantRegions[i].firstBeat; + const mixxx::audio::FrameDiff_t length = + constantRegions[i + 1].firstBeat - constantRegions[i].firstBeat; const int numberOfBeats = static_cast((length / constantRegions[i].beatLength) + 0.5); if (numberOfBeats < kMinRegionBeatCount) { continue; } - const double thisRegionBeatLengthMin = constantRegions[i].beatLength - + const mixxx::audio::FrameDiff_t thisRegionBeatLengthMin = constantRegions[i].beatLength - ((kMaxSecsPhaseError * sampleRate) / numberOfBeats); - const double thisRegionBeatLengthMax = constantRegions[i].beatLength + + const mixxx::audio::FrameDiff_t thisRegionBeatLengthMax = constantRegions[i].beatLength + ((kMaxSecsPhaseError * sampleRate) / numberOfBeats); if (longestRegionBeatLength > thisRegionBeatLengthMin && longestRegionBeatLength < thisRegionBeatLengthMax) { // Now check if both regions are at the same phase. - const double newLongestRegionLength = constantRegions[i + 1].firstBeat - + const mixxx::audio::FrameDiff_t newLongestRegionLength = + constantRegions[i + 1].firstBeat - constantRegions[startRegionIndex].firstBeat; - double minBeatLength = math_max(longestRegionBeatLengthMin, thisRegionBeatLengthMin); - double maxBeatLength = math_min(longestRegionBeatLengthMax, thisRegionBeatLengthMax); + mixxx::audio::FrameDiff_t minBeatLength = math_max( + longestRegionBeatLengthMin, thisRegionBeatLengthMin); + mixxx::audio::FrameDiff_t maxBeatLength = math_min( + longestRegionBeatLengthMax, thisRegionBeatLengthMax); const int maxNumberOfBeats = static_cast(round(newLongestRegionLength / minBeatLength)); @@ -265,7 +275,7 @@ double BeatUtils::makeConstBpm( continue; } const int numberOfBeats = minNumberOfBeats; - const double newBeatLength = newLongestRegionLength / numberOfBeats; + const mixxx::audio::FrameDiff_t newBeatLength = newLongestRegionLength / numberOfBeats; if (newBeatLength > longestRegionBeatLengthMin && newBeatLength < longestRegionBeatLengthMax) { longestRegionLength = newLongestRegionLength; @@ -289,13 +299,13 @@ double BeatUtils::makeConstBpm( // Create a const region region form the first beat of the first region to the last beat of the last region. - const double minRoundBpm = 60.0 * sampleRate / longestRegionBeatLengthMax; - const double maxRoundBpm = 60.0 * sampleRate / longestRegionBeatLengthMin; - const double centerBpm = 60.0 * sampleRate / longestRegionBeatLength; + const mixxx::Bpm minRoundBpm = mixxx::Bpm(60.0 * sampleRate / longestRegionBeatLengthMax); + const mixxx::Bpm maxRoundBpm = mixxx::Bpm(60.0 * sampleRate / longestRegionBeatLengthMin); + const mixxx::Bpm centerBpm = mixxx::Bpm(60.0 * sampleRate / longestRegionBeatLength); //qDebug() << "minRoundBpm" << minRoundBpm; //qDebug() << "maxRoundBpm" << maxRoundBpm; - const double roundBpm = roundBpmWithinRange(minRoundBpm, centerBpm, maxRoundBpm); + const mixxx::Bpm roundBpm = roundBpmWithinRange(minRoundBpm, centerBpm, maxRoundBpm); if (pFirstBeat) { // Move the first beat as close to the start of the track as we can. This is @@ -303,17 +313,19 @@ double BeatUtils::makeConstBpm( // bpm adjustments are made. // This is a temporary fix, ideally the anchor point for the BPM grid should // be the first proper downbeat, or perhaps the CUE point. - const double roundedBeatLength = 60.0 * sampleRate / roundBpm; - *pFirstBeat = fmod(constantRegions[startRegionIndex].firstBeat, - roundedBeatLength); + const double roundedBeatLength = 60.0 * sampleRate / roundBpm.value(); + *pFirstBeat = mixxx::audio::FramePos( + fmod(constantRegions[startRegionIndex].firstBeat.value(), + roundedBeatLength)); } return roundBpm; } // static -double BeatUtils::roundBpmWithinRange(double minBpm, double centerBpm, double maxBpm) { +mixxx::Bpm BeatUtils::roundBpmWithinRange( + mixxx::Bpm minBpm, mixxx::Bpm centerBpm, mixxx::Bpm maxBpm) { // First try to snap to a full integer BPM - double snapBpm = round(centerBpm); + auto snapBpm = mixxx::Bpm(round(centerBpm.value())); if (snapBpm > minBpm && snapBpm < maxBpm) { // Success return snapBpm; @@ -324,23 +336,23 @@ double BeatUtils::roundBpmWithinRange(double minBpm, double centerBpm, double ma if (roundBpmWidth > 0.5) { // 0.5 BPM are only reasonable if the double value is not insane // or the 2/3 value is not too small. - if (centerBpm < 85.0) { + if (centerBpm < mixxx::Bpm(85.0)) { // this cane be actually up to 175 BPM // allow halve BPM values - return round(centerBpm * 2) / 2; - } else if (centerBpm > 127.0) { + return mixxx::Bpm(round(centerBpm.value() * 2) / 2); + } else if (centerBpm > mixxx::Bpm(127.0)) { // optimize for 2/3 going down to 85 - return round(centerBpm / 3 * 2) * 3 / 2; + return mixxx::Bpm(round(centerBpm.value() / 3 * 2) * 3 / 2); } } if (roundBpmWidth > 1.0 / 12) { // this covers all sorts of 1/2 2/3 and 3/4 multiplier - return round(centerBpm * 12) / 12; + return mixxx::Bpm(round(centerBpm.value() * 12) / 12); } else { // We are here if we have more that ~75 beats and ~30 s // try to snap to a 1/12 Bpm - snapBpm = round(centerBpm * 12) / 12; + snapBpm = mixxx::Bpm(round(centerBpm.value() * 12) / 12); if (snapBpm > minBpm && snapBpm < maxBpm) { // Success return snapBpm; @@ -352,10 +364,11 @@ double BeatUtils::roundBpmWithinRange(double minBpm, double centerBpm, double ma } // static -QVector BeatUtils::getBeats(const QVector& constantRegions) { - QVector beats; +QVector BeatUtils::getBeats( + const QVector& constantRegions) { + QVector beats; for (int i = 0; i < constantRegions.size() - 1; ++i) { - double beat = constantRegions[i].firstBeat; + mixxx::audio::FramePos beat = constantRegions[i].firstBeat; constexpr double epsilon = 100; // Protection against tiny beats due rounding while (beat < constantRegions[i + 1].firstBeat - epsilon) { beats.append(beat); @@ -369,17 +382,18 @@ QVector BeatUtils::getBeats(const QVector& const } // static -double BeatUtils::adjustPhase( - double firstBeat, - double bpm, +mixxx::audio::FramePos BeatUtils::adjustPhase( + mixxx::audio::FramePos firstBeat, + mixxx::Bpm bpm, mixxx::audio::SampleRate sampleRate, - const QVector& beats) { - const double beatLength = 60 * sampleRate / bpm; - const double startOffset = fmod(firstBeat, beatLength); - double offsetAdjust = 0; + const QVector& beats) { + const double beatLength = 60 * sampleRate / bpm.value(); + const mixxx::audio::FramePos startOffset = + mixxx::audio::FramePos(fmod(firstBeat.value(), beatLength)); + mixxx::audio::FrameDiff_t offsetAdjust = 0; double offsetAdjustCount = 0; for (const auto& beat : beats) { - double offset = fmod(beat - startOffset, beatLength); + mixxx::audio::FrameDiff_t offset = fmod(beat - startOffset, beatLength); if (offset > beatLength / 2) { offset -= beatLength; } diff --git a/src/track/beatutils.h b/src/track/beatutils.h index 5a4df420e1d..698c7848e5b 100644 --- a/src/track/beatutils.h +++ b/src/track/beatutils.h @@ -2,40 +2,43 @@ #include +#include "audio/frame.h" #include "audio/types.h" +#include "track/bpm.h" #include "util/math.h" class BeatUtils { public: struct ConstRegion { - double firstBeat; - double beatLength; + mixxx::audio::FramePos firstBeat; + mixxx::audio::FrameDiff_t beatLength; }; - static double calculateBpm(const QVector& beats, + static mixxx::Bpm calculateBpm(const QVector& beats, mixxx::audio::SampleRate sampleRate); static QVector retrieveConstRegions( - const QVector& coarseBeats, + const QVector& coarseBeats, mixxx::audio::SampleRate sampleRate); - static double calculateAverageBpm(int numberOfBeats, + static mixxx::Bpm calculateAverageBpm(int numberOfBeats, mixxx::audio::SampleRate sampleRate, - double lowerFrame, - double upperFrame); + mixxx::audio::FramePos lowerFrame, + mixxx::audio::FramePos upperFrame); - static double makeConstBpm( + static mixxx::Bpm makeConstBpm( const QVector& constantRegions, mixxx::audio::SampleRate sampleRate, - double* pFirstBeat); + mixxx::audio::FramePos* pFirstBeat); - static double adjustPhase( - double firstBeat, - double bpm, + static mixxx::audio::FramePos adjustPhase( + mixxx::audio::FramePos firstBeat, + mixxx::Bpm bpm, mixxx::audio::SampleRate sampleRate, - const QVector& beats); + const QVector& beats); - static QVector getBeats(const QVector& constantRegions); + static QVector getBeats(const QVector& constantRegions); - static double roundBpmWithinRange(double minBpm, double centerBpm, double maxBpm); + static mixxx::Bpm roundBpmWithinRange( + mixxx::Bpm minBpm, mixxx::Bpm centerBpm, mixxx::Bpm maxBpm); }; diff --git a/src/track/bpm.h b/src/track/bpm.h index 9ca47c6cb82..93800ce2b2e 100644 --- a/src/track/bpm.h +++ b/src/track/bpm.h @@ -2,6 +2,7 @@ #include +#include "util/fpclassify.h" #include "util/math.h" namespace mixxx { @@ -11,13 +12,13 @@ class Bpm final { public: static constexpr double kValueUndefined = 0.0; static constexpr double kValueMin = 0.0; // lower bound (exclusive) - static constexpr double kValueMax = 300.0; // higher bound (inclusive) + static constexpr double kValueMax = 500.0; // higher bound (inclusive) - Bpm() - : Bpm(kValueUndefined) { + constexpr Bpm() + : Bpm(kValueUndefined) { } - explicit Bpm(double value) - : m_value(value) { + explicit constexpr Bpm(double value) + : m_value(value) { } static double normalizeValue(double value); @@ -37,13 +38,16 @@ class Bpm final { } static bool isValidValue(double value) { - return kValueMin < value; + return util_isfinite(value) && kValueMin < value; } - bool hasValue() const { + bool isValid() const { return isValidValue(m_value); } - double getValue() const { + double value() const { + VERIFY_OR_DEBUG_ASSERT(isValid()) { + return kValueUndefined; + } return m_value; } void setValue(double value) { @@ -68,14 +72,25 @@ class Bpm final { bool compareEq( const Bpm& bpm, Comparison cmp = Comparison::Default) const { + if (!isValid() && !bpm.isValid()) { + // Both values are invalid and thus equal. + return true; + } + + if (isValid() != bpm.isValid()) { + // One value is valid, one is not. + return false; + } + + // At this point both values are valid switch (cmp) { case Comparison::Integer: - return Bpm::valueToInteger(getValue()) == Bpm::valueToInteger(bpm.getValue()); + return Bpm::valueToInteger(value()) == Bpm::valueToInteger(bpm.value()); case Comparison::String: - return Bpm::valueToString(getValue()) == Bpm::valueToString(bpm.getValue()); + return Bpm::valueToString(value()) == Bpm::valueToString(bpm.value()); case Comparison::Default: default: - return getValue() == bpm.getValue(); + return value() == bpm.value(); } } @@ -83,25 +98,100 @@ class Bpm final { return displayValueText(m_value); } + Bpm& operator+=(double increment) { + DEBUG_ASSERT(isValid()); + m_value += increment; + return *this; + } + + Bpm& operator-=(double decrement) { + DEBUG_ASSERT(isValid()); + m_value -= decrement; + return *this; + } + + Bpm& operator*=(double multiple) { + DEBUG_ASSERT(isValid()); + m_value *= multiple; + return *this; + } + + Bpm& operator/=(double divisor) { + DEBUG_ASSERT(isValid()); + m_value /= divisor; + return *this; + } + private: double m_value; }; -inline -bool operator==(const Bpm& lhs, const Bpm& rhs) { - return lhs.compareEq(rhs); +/// Bpm can be added to a double +inline Bpm operator+(Bpm bpm, double bpmDiff) { + return Bpm(bpm.value() + bpmDiff); } -inline -bool operator!=(const Bpm& lhs, const Bpm& rhs) { - return !(lhs == rhs); +/// Bpm can be subtracted from a double +inline Bpm operator-(Bpm bpm, double bpmDiff) { + return Bpm(bpm.value() - bpmDiff); +} + +/// Two Bpm values can be subtracted to get a double +inline double operator-(Bpm bpm1, Bpm bpm2) { + return bpm1.value() - bpm2.value(); +} + +// Adding two Bpm is not allowed, because it makes no sense semantically. + +/// Bpm can be multiplied or divided by a double +inline Bpm operator*(Bpm bpm, double multiple) { + return Bpm(bpm.value() * multiple); } -inline -QDebug operator<<(QDebug dbg, const Bpm& arg) { - return dbg << arg.getValue(); +inline Bpm operator/(Bpm bpm, double divisor) { + return Bpm(bpm.value() / divisor); } +/// Bpm can be divided by another Bpm to get a ratio (represented as a double). +inline double operator/(Bpm bpm, Bpm otherBpm) { + return bpm.value() / otherBpm.value(); +} + +inline bool operator==(Bpm bpm1, Bpm bpm2) { + if (!bpm1.isValid() && !bpm2.isValid()) { + return true; + } + return bpm1.isValid() && bpm2.isValid() && bpm1.value() == bpm2.value(); +} + +inline bool operator!=(Bpm bpm1, Bpm bpm2) { + return !(bpm1 == bpm2); +} + +inline bool operator<(Bpm bpm1, Bpm bpm2) { + return bpm1.value() < bpm2.value(); +} + +inline bool operator<=(Bpm bpm1, Bpm bpm2) { + return (bpm1 == bpm2) || bpm1 < bpm2; +} + +inline bool operator>(Bpm bpm1, Bpm bpm2) { + return bpm2 < bpm1; +} + +inline bool operator>=(Bpm bpm1, Bpm bpm2) { + return bpm2 <= bpm1; +} + +inline QDebug operator<<(QDebug dbg, Bpm arg) { + if (arg.isValid()) { + dbg.nospace() << "Bpm(" << arg.value() << ")"; + } else { + dbg << "Bpm(Invalid)"; + } + return dbg; +} } Q_DECLARE_TYPEINFO(mixxx::Bpm, Q_MOVABLE_TYPE); diff --git a/src/track/cue.cpp b/src/track/cue.cpp index 81d2b8cdb71..bb63a77a1c2 100644 --- a/src/track/cue.cpp +++ b/src/track/cue.cpp @@ -3,6 +3,7 @@ #include #include +#include "audio/frame.h" #include "engine/engine.h" #include "moc_cue.cpp" #include "util/assert.h" @@ -11,30 +12,31 @@ namespace { -inline std::optional positionSamplesToMillis( - double positionSamples, +inline std::optional positionFramesToMillis( + mixxx::audio::FramePos position, mixxx::audio::SampleRate sampleRate) { VERIFY_OR_DEBUG_ASSERT(sampleRate.isValid()) { return std::nullopt; } - if (positionSamples == Cue::kNoPosition) { + if (!position.isValid()) { return std::nullopt; } // Try to avoid rounding errors - return (positionSamples * 1000) / (sampleRate * mixxx::kEngineChannelCount); + return (position.value() * 1000) / sampleRate; } -inline double positionMillisToSamples( +inline mixxx::audio::FramePos positionMillisToFrames( std::optional positionMillis, mixxx::audio::SampleRate sampleRate) { VERIFY_OR_DEBUG_ASSERT(sampleRate.isValid()) { - return Cue::kNoPosition; + return mixxx::audio::kInvalidFramePos; } + if (!positionMillis) { - return Cue::kNoPosition; + return mixxx::audio::kInvalidFramePos; } - // Try to avoid rounding errors - return (*positionMillis * sampleRate * mixxx::kEngineChannelCount) / 1000; + + return mixxx::audio::FramePos((*positionMillis * sampleRate) / 1000); } } // namespace @@ -48,27 +50,25 @@ void CuePointer::deleteLater(Cue* pCue) { Cue::Cue( DbId id, mixxx::CueType type, - double position, - double length, + mixxx::audio::FramePos position, + mixxx::audio::FrameDiff_t length, int hotCue, const QString& label, mixxx::RgbColor color) : m_bDirty(false), // clear flag after loading from database m_dbId(id), m_type(type), - m_sampleStartPosition(position), + m_startPosition(position), m_iHotCue(hotCue), m_label(label), m_color(color) { DEBUG_ASSERT(m_dbId.isValid()); if (length != 0) { - if (position != Cue::kNoPosition) { - m_sampleEndPosition = position + length; + if (position.isValid()) { + m_endPosition = position + length; } else { - m_sampleEndPosition = length; + m_endPosition = mixxx::audio::kStartFramePos + length; } - } else { - m_sampleEndPosition = Cue::kNoPosition; } } @@ -78,12 +78,12 @@ Cue::Cue( bool setDirty) : m_bDirty(setDirty), m_type(cueInfo.getType()), - m_sampleStartPosition( - positionMillisToSamples( + m_startPosition( + positionMillisToFrames( cueInfo.getStartPositionMillis(), sampleRate)), - m_sampleEndPosition( - positionMillisToSamples( + m_endPosition( + positionMillisToFrames( cueInfo.getEndPositionMillis(), sampleRate)), m_iHotCue(cueInfo.getHotCueIndex() ? *cueInfo.getHotCueIndex() : kNoHotCue), @@ -96,12 +96,12 @@ Cue::Cue( Cue::Cue( mixxx::CueType type, int hotCueIndex, - double sampleStartPosition, - double sampleEndPosition) + mixxx::audio::FramePos startPosition, + mixxx::audio::FramePos endPosition) : m_bDirty(true), // not yet in database, needs to be saved m_type(type), - m_sampleStartPosition(sampleStartPosition), - m_sampleEndPosition(sampleEndPosition), + m_startPosition(startPosition), + m_endPosition(endPosition), m_iHotCue(hotCueIndex), m_color(mixxx::PredefinedColorPalettes::kDefaultCueColor) { DEBUG_ASSERT(!m_dbId.isValid()); @@ -112,8 +112,8 @@ mixxx::CueInfo Cue::getCueInfo( QMutexLocker lock(&m_mutex); return mixxx::CueInfo( m_type, - positionSamplesToMillis(m_sampleStartPosition, sampleRate), - positionSamplesToMillis(m_sampleEndPosition, sampleRate), + positionFramesToMillis(m_startPosition, sampleRate), + positionFramesToMillis(m_endPosition, sampleRate), m_iHotCue == kNoHotCue ? std::nullopt : std::make_optional(m_iHotCue), m_label, m_color); @@ -151,43 +151,43 @@ void Cue::setType(mixxx::CueType type) { emit updated(); } -double Cue::getPosition() const { +mixxx::audio::FramePos Cue::getPosition() const { QMutexLocker lock(&m_mutex); - return m_sampleStartPosition; + return m_startPosition; } -void Cue::setStartPosition(double samplePosition) { +void Cue::setStartPosition(mixxx::audio::FramePos position) { QMutexLocker lock(&m_mutex); - if (m_sampleStartPosition == samplePosition) { + if (m_startPosition == position) { return; } - m_sampleStartPosition = samplePosition; + m_startPosition = position; m_bDirty = true; lock.unlock(); emit updated(); } -void Cue::setEndPosition(double samplePosition) { +void Cue::setEndPosition(mixxx::audio::FramePos position) { QMutexLocker lock(&m_mutex); - if (m_sampleEndPosition == samplePosition) { + if (m_endPosition == position) { return; } - m_sampleEndPosition = samplePosition; + m_endPosition = position; m_bDirty = true; lock.unlock(); emit updated(); } void Cue::setStartAndEndPosition( - double sampleStartPosition, - double sampleEndPosition) { + mixxx::audio::FramePos startPosition, + mixxx::audio::FramePos endPosition) { QMutexLocker lock(&m_mutex); - if (m_sampleStartPosition == sampleStartPosition && - m_sampleEndPosition == sampleEndPosition) { + if (m_startPosition == startPosition && + m_endPosition == endPosition) { return; } - m_sampleStartPosition = sampleStartPosition; - m_sampleEndPosition = sampleEndPosition; + m_startPosition = startPosition; + m_endPosition = endPosition; m_bDirty = true; lock.unlock(); emit updated(); @@ -195,31 +195,31 @@ void Cue::setStartAndEndPosition( Cue::StartAndEndPositions Cue::getStartAndEndPosition() const { QMutexLocker lock(&m_mutex); - return {m_sampleStartPosition, m_sampleEndPosition}; + return {m_startPosition, m_endPosition}; } -void Cue::shiftPositionFrames(double frameOffset) { +void Cue::shiftPositionFrames(mixxx::audio::FrameDiff_t frameOffset) { QMutexLocker lock(&m_mutex); - if (m_sampleStartPosition != kNoPosition) { - m_sampleStartPosition += frameOffset * mixxx::kEngineChannelCount; + if (m_startPosition.isValid()) { + m_startPosition += frameOffset; } - if (m_sampleEndPosition != kNoPosition) { - m_sampleEndPosition += frameOffset * mixxx::kEngineChannelCount; + if (m_endPosition.isValid()) { + m_endPosition += frameOffset; } m_bDirty = true; lock.unlock(); emit updated(); } -double Cue::getLength() const { +mixxx::audio::FrameDiff_t Cue::getLengthFrames() const { QMutexLocker lock(&m_mutex); - if (m_sampleEndPosition == Cue::kNoPosition) { + if (!m_endPosition.isValid()) { return 0; } - if (m_sampleStartPosition == Cue::kNoPosition) { - return m_sampleEndPosition; + if (!m_startPosition.isValid()) { + return m_endPosition.value(); } - return m_sampleEndPosition - m_sampleStartPosition; + return m_endPosition - m_startPosition; } int Cue::getHotCue() const { @@ -269,9 +269,9 @@ void Cue::setDirty(bool dirty) { m_bDirty = dirty; } -double Cue::getEndPosition() const { +mixxx::audio::FramePos Cue::getEndPosition() const { QMutexLocker lock(&m_mutex); - return m_sampleEndPosition; + return m_endPosition; } bool operator==(const CuePosition& lhs, const CuePosition& rhs) { diff --git a/src/track/cue.h b/src/track/cue.h index 77e946ec5c2..1b469661af4 100644 --- a/src/track/cue.h +++ b/src/track/cue.h @@ -6,6 +6,7 @@ #include #include // static_assert +#include "audio/frame.h" #include "audio/types.h" #include "track/cueinfo.h" #include "util/color/rgbcolor.h" @@ -28,8 +29,8 @@ class Cue : public QObject { "Conflicting definitions of invalid and first hot cue index"); struct StartAndEndPositions { - double startPosition; - double endPosition; + mixxx::audio::FramePos startPosition; + mixxx::audio::FramePos endPosition; }; Cue() = delete; @@ -44,8 +45,8 @@ class Cue : public QObject { Cue( DbId id, mixxx::CueType type, - double position, - double length, + mixxx::audio::FramePos position, + mixxx::audio::FrameDiff_t length, int hotCue, const QString& label, mixxx::RgbColor color); @@ -54,8 +55,8 @@ class Cue : public QObject { Cue( mixxx::CueType type, int hotCueIndex, - double sampleStartPosition, - double sampleEndPosition); + mixxx::audio::FramePos startPosition, + mixxx::audio::FramePos endPosition); ~Cue() override = default; @@ -65,17 +66,32 @@ class Cue : public QObject { mixxx::CueType getType() const; void setType(mixxx::CueType type); - double getPosition() const; - void setStartPosition( - double samplePosition); - void setEndPosition( - double samplePosition); + mixxx::audio::FramePos getPosition() const; + void setStartPosition(mixxx::audio::FramePos position); + void setStartPosition(double samplePosition) { + setStartPosition(mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid(samplePosition)); + } + void setEndPosition(mixxx::audio::FramePos position); + void setEndPosition(double samplePosition) { + setEndPosition(mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid(samplePosition)); + } + void setStartAndEndPosition( + mixxx::audio::FramePos startPosition, + mixxx::audio::FramePos endPosition); void setStartAndEndPosition( double sampleStartPosition, - double sampleEndPosition); - void shiftPositionFrames(double frameOffset); + double sampleEndPosition) { + const auto startPosition = + mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid( + sampleStartPosition); + const auto endPosition = + mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid( + sampleEndPosition); + setStartAndEndPosition(startPosition, endPosition); + } + void shiftPositionFrames(mixxx::audio::FrameDiff_t frameOffset); - double getLength() const; + mixxx::audio::FrameDiff_t getLengthFrames() const; int getHotCue() const; @@ -85,7 +101,7 @@ class Cue : public QObject { mixxx::RgbColor getColor() const; void setColor(mixxx::RgbColor color); - double getEndPosition() const; + mixxx::audio::FramePos getEndPosition() const; StartAndEndPositions getStartAndEndPosition() const; @@ -105,8 +121,8 @@ class Cue : public QObject { bool m_bDirty; DbId m_dbId; mixxx::CueType m_type; - double m_sampleStartPosition; - double m_sampleEndPosition; + mixxx::audio::FramePos m_startPosition; + mixxx::audio::FramePos m_endPosition; const int m_iHotCue; QString m_label; mixxx::RgbColor m_color; @@ -115,6 +131,10 @@ class Cue : public QObject { friend class CueDAO; }; +static_assert(mixxx::audio::FramePos::kLegacyInvalidEnginePosition == + Cue::kNoPosition, + "Invalid engine position value mismatch"); + class CuePointer : public std::shared_ptr { public: CuePointer() = default; diff --git a/src/track/serato/beatgrid.cpp b/src/track/serato/beatgrid.cpp index 85d8bae2e5c..a5161ef856c 100644 --- a/src/track/serato/beatgrid.cpp +++ b/src/track/serato/beatgrid.cpp @@ -437,10 +437,9 @@ void SeratoBeatGrid::setBeats(BeatsPointer pBeats, // in the track, therefore we calculate the track duration in samples and // round up. This value might be longer than the actual track, but that's // okay because we want to make sure we get all beats. - const SINT trackDurationSamples = signalInfo.frames2samples( - static_cast(signalInfo.secs2frames( - std::ceil(duration.toDoubleSeconds())))); - auto pBeatsIterator = pBeats->findBeats(0, trackDurationSamples); + const auto trackEndPosition = audio::FramePos( + signalInfo.secs2frames(std::ceil(duration.toDoubleSeconds()))); + auto pBeatsIterator = pBeats->findBeats(audio::kStartFramePos, trackEndPosition); // This might be null if the track doesn't contain any beats if (!pBeatsIterator || !pBeatsIterator->hasNext()) { @@ -450,38 +449,37 @@ void SeratoBeatGrid::setBeats(BeatsPointer pBeats, return; } - const double beatgridFrameOffset = signalInfo.samples2framesFractional(pBeatsIterator->next()); - double currentBeatPositionFrames = 0; - double previousBeatPositionFrames = 0; - double previousDeltaFrames = -1; + const audio::FrameDiff_t beatgridFrameOffset = pBeatsIterator->next().value(); + audio::FramePos currentBeatPositionFrames = audio::kStartFramePos; + audio::FramePos previousBeatPositionFrames = audio::kStartFramePos; + audio::FrameDiff_t previousDeltaFrames = -1; QList nonTerminalMarkers; { const double positionSecs = signalInfo.frames2secsFractional( - currentBeatPositionFrames + beatgridFrameOffset); + currentBeatPositionFrames.value() + beatgridFrameOffset); nonTerminalMarkers.append( std::make_shared( positionSecs - timingOffsetSecs, 0)); } while (pBeatsIterator->hasNext()) { previousBeatPositionFrames = currentBeatPositionFrames; - currentBeatPositionFrames = - signalInfo.samples2framesFractional(pBeatsIterator->next()) - - beatgridFrameOffset; + currentBeatPositionFrames = pBeatsIterator->next() - beatgridFrameOffset; // Calculate the delta between the current beat and the previous beat. // If the distance is the same as the distance between the previous // beat and the beat before that, we can just increment // `beatsSinceLastMarker`. If not, we need to add a new marker. - const double currentDeltaFrames = currentBeatPositionFrames - previousBeatPositionFrames; + const audio::FrameDiff_t currentDeltaFrames = + currentBeatPositionFrames - previousBeatPositionFrames; if (previousDeltaFrames < 0) { previousDeltaFrames = currentDeltaFrames; } - const double differenceBetweenCurrentAndPreviousDelta = + const audio::FrameDiff_t differenceBetweenCurrentAndPreviousDelta = abs(currentDeltaFrames - previousDeltaFrames); if (differenceBetweenCurrentAndPreviousDelta >= kEpsilon) { const double positionSecs = signalInfo.frames2secsFractional( - previousBeatPositionFrames + beatgridFrameOffset); + previousBeatPositionFrames.value() + beatgridFrameOffset); nonTerminalMarkers.append( std::make_shared( positionSecs - timingOffsetSecs, 1)); @@ -505,16 +503,14 @@ void SeratoBeatGrid::setBeats(BeatsPointer pBeats, } // Finally, create the terminal marker. - const double currentBeatPositionFramesWithOffset = + const audio::FramePos currentBeatPositionFramesWithOffset = currentBeatPositionFrames + beatgridFrameOffset; const double positionSecs = signalInfo.frames2secsFractional( - currentBeatPositionFramesWithOffset); - const double bpm = pBeats->getBpmAroundPosition( - signalInfo.getChannelCount() * currentBeatPositionFramesWithOffset, - 1); + currentBeatPositionFramesWithOffset.value()); + const mixxx::Bpm bpm = pBeats->getBpmAroundPosition(currentBeatPositionFramesWithOffset, 1); setTerminalMarker(std::make_shared( - positionSecs - timingOffsetSecs, bpm)); + positionSecs - timingOffsetSecs, static_cast(bpm.value()))); setNonTerminalMarkers(nonTerminalMarkers); } diff --git a/src/track/serato/beatsimporter.cpp b/src/track/serato/beatsimporter.cpp index 96725283d5f..364408107ad 100644 --- a/src/track/serato/beatsimporter.cpp +++ b/src/track/serato/beatsimporter.cpp @@ -22,7 +22,7 @@ bool SeratoBeatsImporter::isEmpty() const { return !m_pTerminalMarker; }; -QVector SeratoBeatsImporter::importBeatsAndApplyTimingOffset( +QVector SeratoBeatsImporter::importBeatsAndApplyTimingOffset( const QString& filePath, const audio::StreamInfo& streamInfo) { const audio::SignalInfo& signalInfo = streamInfo.getSignalInfo(); const double timingOffsetMillis = SeratoTags::guessTimingOffsetMillis( @@ -31,13 +31,13 @@ QVector SeratoBeatsImporter::importBeatsAndApplyTimingOffset( return importBeatsAndApplyTimingOffset(timingOffsetMillis, signalInfo); } -QVector SeratoBeatsImporter::importBeatsAndApplyTimingOffset( +QVector SeratoBeatsImporter::importBeatsAndApplyTimingOffset( double timingOffsetMillis, const audio::SignalInfo& signalInfo) { VERIFY_OR_DEBUG_ASSERT(!isEmpty()) { return {}; } - QVector beats; + QVector beats; double beatPositionMillis = 0; // Calculate beat positions for non-terminal markers for (int i = 0; i < m_nonTerminalMarkers.size(); ++i) { @@ -62,8 +62,8 @@ QVector SeratoBeatsImporter::importBeatsAndApplyTimingOffset( beats.reserve(beats.size() + pMarker->beatsTillNextMarker()); for (quint32 j = 0; j < pMarker->beatsTillNextMarker(); ++j) { - beats.append(signalInfo.millis2frames( - beatPositionMillis + timingOffsetMillis)); + beats.append(mixxx::audio::FramePos(signalInfo.millis2frames( + beatPositionMillis + timingOffsetMillis))); beatPositionMillis += beatLengthMillis; } } @@ -99,8 +99,8 @@ QVector SeratoBeatsImporter::importBeatsAndApplyTimingOffset( // Now fill the range with beats until the end is reached. Add a half beat // length, to make sure that the last beat is actually included. while (beatPositionMillis <= (rangeEndBeatPositionMillis + beatLengthMillis / 2)) { - beats.append(signalInfo.millis2frames( - beatPositionMillis + timingOffsetMillis)); + beats.append(mixxx::audio::FramePos(signalInfo.millis2frames( + beatPositionMillis + timingOffsetMillis))); beatPositionMillis += beatLengthMillis; } diff --git a/src/track/serato/beatsimporter.h b/src/track/serato/beatsimporter.h index 71a0ee7e00c..26c3ec5450a 100644 --- a/src/track/serato/beatsimporter.h +++ b/src/track/serato/beatsimporter.h @@ -18,14 +18,14 @@ class SeratoBeatsImporter : public BeatsImporter { ~SeratoBeatsImporter() override = default; bool isEmpty() const override; - QVector importBeatsAndApplyTimingOffset( + QVector importBeatsAndApplyTimingOffset( const QString& filePath, const audio::StreamInfo& streamInfo) override; private: FRIEND_TEST(SeratoBeatGridTest, SerializeBeatMap); - QVector importBeatsAndApplyTimingOffset( + QVector importBeatsAndApplyTimingOffset( double timingOffsetMillis, const audio::SignalInfo& signalInfo); QList m_nonTerminalMarkers; diff --git a/src/track/serato/markers2.h b/src/track/serato/markers2.h index 96917a77565..f38e3ca59c4 100644 --- a/src/track/serato/markers2.h +++ b/src/track/serato/markers2.h @@ -381,7 +381,7 @@ class SeratoMarkers2 final { m_lastBase64ByteFLAC('A') { } - /// Parse a binary Serato repesentation of the "Markers2" data from a + /// Parse a binary Serato representation of the "Markers2" data from a /// `QByteArray` and write the results to the `SeratoMarkers2` instance. /// The `fileType` parameter determines the exact format of the data being /// used. @@ -390,7 +390,7 @@ class SeratoMarkers2 final { const QByteArray& outerData, taglib::FileType fileType); - /// Create a binary Serato repesentation of the "Markers2" data suitable + /// Create a binary Serato representation of the "Markers2" data suitable /// for `fileType` and dump it into a `QByteArray`. The content of that /// byte array can be used for round-trip tests or written to the /// appropriate tag to make it accessible to Serato. diff --git a/src/track/taglib/trackmetadata_common.h b/src/track/taglib/trackmetadata_common.h index 69d62f32704..8dacf929e1e 100644 --- a/src/track/taglib/trackmetadata_common.h +++ b/src/track/taglib/trackmetadata_common.h @@ -71,8 +71,11 @@ inline TagLib::String uuidToTString( inline QString formatBpm( const TrackMetadata& trackMetadata) { - return Bpm::valueToString( - trackMetadata.getTrackInfo().getBpm().getValue()); + const Bpm bpm = trackMetadata.getTrackInfo().getBpm(); + if (!bpm.isValid()) { + return {}; + } + return Bpm::valueToString(bpm.value()); } bool parseBpm( diff --git a/src/track/taglib/trackmetadata_file.cpp b/src/track/taglib/trackmetadata_file.cpp index d2e92cc4983..53f88dd7cab 100644 --- a/src/track/taglib/trackmetadata_file.cpp +++ b/src/track/taglib/trackmetadata_file.cpp @@ -55,7 +55,7 @@ FileType getFileTypeFromFileName( if (QStringLiteral("mp3") == fileExt) { return FileType::MP3; } - if (QStringLiteral("m4a") == fileExt) { + if ((QStringLiteral("m4a") == fileExt) || (QStringLiteral("m4v") == fileExt)) { return FileType::MP4; } if (QStringLiteral("flac") == fileExt) { diff --git a/src/track/taglib/trackmetadata_id3v2.cpp b/src/track/taglib/trackmetadata_id3v2.cpp index b80ba16c8b4..8a219b1417b 100644 --- a/src/track/taglib/trackmetadata_id3v2.cpp +++ b/src/track/taglib/trackmetadata_id3v2.cpp @@ -561,12 +561,12 @@ inline QImage loadImageFromPictureFrame( inline QString formatBpmInteger( const TrackMetadata& trackMetadata) { - if (!trackMetadata.getTrackInfo().getBpm().hasValue()) { + if (!trackMetadata.getTrackInfo().getBpm().isValid()) { return QString(); } return QString::number( Bpm::valueToInteger( - trackMetadata.getTrackInfo().getBpm().getValue())); + trackMetadata.getTrackInfo().getBpm().value())); } } // anonymous namespace @@ -795,7 +795,7 @@ void importTrackMetadataFromTag( if (!bpmFrames.isEmpty()) { parseBpm(pTrackMetadata, firstNonEmptyFrameToQString(bpmFrames)); - double bpmValue = pTrackMetadata->getTrackInfo().getBpm().getValue(); + double bpmValue = pTrackMetadata->getTrackInfo().getBpm().value(); // Some software use (or used) to write decimated values without comma, // so the number reads as 1352 or 14525 when it is 135.2 or 145.25 if (bpmValue < Bpm::kValueMin || bpmValue > 1000 * Bpm::kValueMax) { diff --git a/src/track/taglib/trackmetadata_mp4.cpp b/src/track/taglib/trackmetadata_mp4.cpp index c98a5680d5c..75e370c77d2 100644 --- a/src/track/taglib/trackmetadata_mp4.cpp +++ b/src/track/taglib/trackmetadata_mp4.cpp @@ -381,10 +381,10 @@ bool exportTrackMetadataIntoTag( writeAtom(pTag, "\251grp", toTString(trackMetadata.getTrackInfo().getGrouping())); // Write both BPM fields (just in case) - if (trackMetadata.getTrackInfo().getBpm().hasValue()) { + if (trackMetadata.getTrackInfo().getBpm().isValid()) { // 16-bit integer value const int tmpoValue = - Bpm::valueToInteger(trackMetadata.getTrackInfo().getBpm().getValue()); + Bpm::valueToInteger(trackMetadata.getTrackInfo().getBpm().value()); pTag->setItem("tmpo", tmpoValue); } else { pTag->removeItem("tmpo"); diff --git a/src/track/track.cpp b/src/track/track.cpp index 3c630bff404..fd6d56ad985 100644 --- a/src/track/track.cpp +++ b/src/track/track.cpp @@ -135,7 +135,7 @@ void Track::relocate( void Track::replaceMetadataFromSource( mixxx::TrackMetadata importedMetadata, - const QDateTime& metadataSynchronized) { + const QDateTime& sourceSynchronizedAt) { // Information stored in Serato tags is imported separately after // importing the metadata (see below). The Serato tags BLOB itself // is updated together with the metadata. @@ -164,19 +164,19 @@ void Track::replaceMetadataFromSource( m_record.getMetadata().getTrackInfo().getReplayGain(); bool modified = m_record.replaceMetadataFromSource( std::move(importedMetadata), - metadataSynchronized); + sourceSynchronizedAt); const auto newReplayGain = m_record.getMetadata().getTrackInfo().getReplayGain(); // Need to set BPM after sample rate since beat grid creation depends on // knowing the sample rate. Bug #1020438. auto beatsAndBpmModified = false; - if (!m_pBeats || !mixxx::Bpm::isValidValue(m_pBeats->getBpm())) { + if (importedBpm.isValid() && (!m_pBeats || !m_pBeats->getBpm().isValid())) { // Only use the imported BPM if the current beat grid is either // missing or not valid! The BPM value in the metadata might be // imprecise (normalized or rounded), e.g. ID3v2 only supports // integer values. - beatsAndBpmModified = trySetBpmWhileLocked(importedBpm.getValue()); + beatsAndBpmModified = trySetBpmWhileLocked(importedBpm.value()); } modified |= beatsAndBpmModified; @@ -245,10 +245,10 @@ bool Track::mergeExtraMetadataFromSource( } mixxx::TrackMetadata Track::getMetadata( - bool* pMetadataSynchronized) const { + bool* pSourceSynchronized) const { const QMutexLocker locked(&m_qMutex); - if (pMetadataSynchronized) { - *pMetadataSynchronized = m_record.getMetadataSynchronized(); + if (pSourceSynchronized) { + *pSourceSynchronized = m_record.isSourceSynchronized(); } return m_record.getMetadata(); } @@ -288,7 +288,7 @@ bool Track::replaceRecord( } else { // Setting the bpm manually may in turn update the beat grid bpmUpdatedFlag = trySetBpmWhileLocked( - newRecord.getMetadata().getTrackInfo().getBpm().getValue()); + newRecord.getMetadata().getTrackInfo().getBpm().value()); } // The bpm in m_record has already been updated. Read it and copy it into // the new record to ensure it will be consistent with the new beat grid. @@ -338,29 +338,36 @@ mixxx::Bpm Track::getBpmWhileLocked() const { } bool Track::trySetBpmWhileLocked(double bpmValue) { - if (!mixxx::Bpm::isValidValue(bpmValue)) { + const auto bpm = mixxx::Bpm(bpmValue); + if (!bpm.isValid()) { // If the user sets the BPM to an invalid value, we assume // they want to clear the beatgrid. return trySetBeatsWhileLocked(nullptr); } else if (!m_pBeats) { // No beat grid available -> create and initialize - double cue = m_record.getCuePoint().getPosition(); - auto pBeats = BeatFactory::makeBeatGrid(getSampleRate(), bpmValue, cue); + mixxx::audio::FramePos cuePosition = m_record.getMainCuePosition(); + if (!cuePosition.isValid()) { + cuePosition = mixxx::audio::kStartFramePos; + } + auto pBeats = BeatFactory::makeBeatGrid(getSampleRate(), + bpm, + cuePosition); return trySetBeatsWhileLocked(std::move(pBeats)); } else if ((m_pBeats->getCapabilities() & mixxx::Beats::BEATSCAP_SETBPM) && - m_pBeats->getBpm() != bpmValue) { + m_pBeats->getBpm() != bpm) { // Continue with the regular cases if (kLogger.debugEnabled()) { kLogger.debug() << "Updating BPM:" << getLocation(); } - return trySetBeatsWhileLocked(m_pBeats->setBpm(bpmValue)); + return trySetBeatsWhileLocked(m_pBeats->setBpm(bpm)); } return false; } double Track::getBpm() const { const QMutexLocker lock(&m_qMutex); - return getBpmWhileLocked().getValue(); + const mixxx::Bpm bpm = getBpmWhileLocked(); + return bpm.isValid() ? bpm.value() : mixxx::Bpm::kValueUndefined; } bool Track::trySetBpm(double bpmValue) { @@ -395,7 +402,7 @@ bool Track::trySetBeatsWhileLocked( mixxx::BeatsPointer pBeats, bool lockBpmAfterSet) { if (m_pBeats && m_record.getBpmLocked()) { - // Track has already a valid and locked beats object, abbort. + // Track has already a valid and locked beats object, abort. qDebug() << "Track beats is already set and BPM-locked. Discard the new beats"; return false; } @@ -461,16 +468,23 @@ void Track::emitChangedSignalsForAllMetadata() { emit keyChanged(); } -void Track::setMetadataSynchronized(bool metadataSynchronized) { +bool Track::isSourceSynchronized() const { + QMutexLocker lock(&m_qMutex); + return m_record.isSourceSynchronized(); +} + +void Track::setSourceSynchronizedAt(const QDateTime& sourceSynchronizedAt) { + DEBUG_ASSERT(!sourceSynchronizedAt.isValid() || + sourceSynchronizedAt.timeSpec() == Qt::UTC); QMutexLocker lock(&m_qMutex); - if (compareAndSet(m_record.ptrMetadataSynchronized(), metadataSynchronized)) { + if (compareAndSet(m_record.ptrSourceSynchronizedAt(), sourceSynchronizedAt)) { markDirtyAndUnlock(&lock); } } -bool Track::isMetadataSynchronized() const { +QDateTime Track::getSourceSynchronizedAt() const { QMutexLocker lock(&m_qMutex); - return m_record.getMetadataSynchronized(); + return m_record.getSourceSynchronizedAt(); } QString Track::getInfo() const { @@ -851,18 +865,17 @@ void Track::setWaveformSummary(ConstWaveformPointer pWaveform) { emit waveformSummaryUpdated(); } -void Track::setCuePoint(CuePosition cue) { +void Track::setMainCuePosition(mixxx::audio::FramePos position) { QMutexLocker lock(&m_qMutex); - if (!compareAndSet(m_record.ptrCuePoint(), cue)) { + if (!compareAndSet(m_record.ptrMainCuePosition(), position)) { // Nothing changed. return; } // Store the cue point as main cue CuePointer pLoadCue = findCueByType(mixxx::CueType::MainCue); - double position = cue.getPosition(); - if (position != -1.0) { + if (position.isValid()) { if (pLoadCue) { pLoadCue->setStartPosition(position); } else { @@ -870,7 +883,7 @@ void Track::setCuePoint(CuePosition cue) { mixxx::CueType::MainCue, Cue::kNoHotCue, position, - Cue::kNoPosition)); + mixxx::audio::kInvalidFramePos)); // While this method could be called from any thread, // associated Cue objects should always live on the // same thread as their host, namely this->thread(). @@ -908,9 +921,9 @@ void Track::analysisFinished() { emit analyzed(); } -CuePosition Track::getCuePoint() const { +mixxx::audio::FramePos Track::getMainCuePosition() const { QMutexLocker lock(&m_qMutex); - return m_record.getCuePoint(); + return m_record.getMainCuePosition(); } void Track::slotCueUpdated() { @@ -921,13 +934,13 @@ void Track::slotCueUpdated() { CuePointer Track::createAndAddCue( mixxx::CueType type, int hotCueIndex, - double sampleStartPosition, - double sampleEndPosition) { + mixxx::audio::FramePos startPosition, + mixxx::audio::FramePos endPosition) { CuePointer pCue(new Cue( type, hotCueIndex, - sampleStartPosition, - sampleEndPosition)); + startPosition, + endPosition)); // While this method could be called from any thread, // associated Cue objects should always live on the // same thread as their host, namely this->thread(). @@ -977,7 +990,7 @@ void Track::removeCue(const CuePointer& pCue) { disconnect(pCue.get(), nullptr, this, nullptr); m_cuePoints.removeOne(pCue); if (pCue->getType() == mixxx::CueType::MainCue) { - m_record.setCuePoint(CuePosition()); + m_record.setMainCuePosition(mixxx::audio::kStartFramePos); } markDirtyAndUnlock(&lock); emit cuesUpdated(); @@ -996,7 +1009,7 @@ void Track::removeCuesOfType(mixxx::CueType type) { dirty = true; } } - if (compareAndSet(m_record.ptrCuePoint(), CuePosition())) { + if (compareAndSet(m_record.ptrMainCuePosition(), mixxx::audio::kStartFramePos)) { dirty = true; } if (dirty) { @@ -1176,7 +1189,7 @@ bool Track::setCuePointsWhileLocked(const QList& cuePoints) { this, &Track::slotCueUpdated); if (pCue->getType() == mixxx::CueType::MainCue) { - m_record.setCuePoint(CuePosition(pCue->getPosition())); + m_record.setMainCuePosition(pCue->getPosition()); } } return true; @@ -1430,12 +1443,11 @@ ExportTrackMetadataResult Track::exportMetadata( // be called after all references to the object have been dropped. // But it doesn't hurt much, so let's play it safe ;) QMutexLocker lock(&m_qMutex); - // TODO(XXX): m_record.getMetadataSynchronized() currently is a - // boolean flag, but it should become a time stamp in the future. - // We could take this time stamp and the file's last modification - // time stamp into account and might decide to skip importing - // the metadata again. - if (!m_bMarkedForMetadataExport && !m_record.getMetadataSynchronized()) { + // TODO(XXX): Use sourceSynchronizedAt to decide if metadata + // should be (re-)imported before exporting it. The file might + // have been updated by external applications. Overwriting + // this modified metadata might not be intended. + if (!m_bMarkedForMetadataExport && !m_record.isSourceSynchronized()) { // If the metadata has never been imported from file tags it // must be exported explicitly once. This ensures that we don't // overwrite existing file tags with completely different @@ -1577,10 +1589,7 @@ ExportTrackMetadataResult Track::exportMetadata( // This information (flag or time stamp) is stored in the database. // The database update will follow immediately after returning from // this operation! - // TODO(XXX): Replace bool with QDateTime - DEBUG_ASSERT(!trackMetadataExported.second.isNull()); - //pTrack->setMetadataSynchronized(trackMetadataExported.second); - m_record.setMetadataSynchronized(!trackMetadataExported.second.isNull()); + m_record.updateSourceSynchronizedAt(trackMetadataExported.second); if (kLogger.debugEnabled()) { kLogger.debug() << "Exported track metadata:" @@ -1619,7 +1628,7 @@ void Track::setAudioProperties( QMutexLocker lock(&m_qMutex); // These properties are stored separately in the database // and are also imported from file tags. They will be - // overriden by the actual properties from the audio + // overridden by the actual properties from the audio // source later. DEBUG_ASSERT(!m_record.hasStreamInfoFromSource()); if (compareAndSet( diff --git a/src/track/track.h b/src/track/track.h index 10a66c5533a..f5386de827a 100644 --- a/src/track/track.h +++ b/src/track/track.h @@ -72,6 +72,7 @@ class Track : public QObject { STORED false NOTIFY durationChanged) Q_PROPERTY(QString info READ getInfo STORED false NOTIFY infoChanged) Q_PROPERTY(QString titleInfo READ getTitleInfo STORED false NOTIFY infoChanged) + Q_PROPERTY(QDateTime sourceSynchronizedAt READ getSourceSynchronizedAt STORED false) mixxx::FileAccess getFileAccess() const { // Copying QFileInfo is thread-safe due to implicit sharing, @@ -148,9 +149,18 @@ class Track : public QObject { mixxx::ReplayGain getReplayGain() const; // Indicates if the metadata has been parsed from file tags. - bool isMetadataSynchronized() const; - // Only used by a free function in TrackDAO! - void setMetadataSynchronized(bool metadataSynchronized); + bool isSourceSynchronized() const; + + void setHeaderParsedFromTrackDAO(bool headerParsed) { + // Always operating on a newly created, exclusive instance! No need + // to lock the mutex. + DEBUG_ASSERT(!m_record.m_headerParsed); + m_record.m_headerParsed = headerParsed; + } + + // The date/time of the last import or export of metadata + void setSourceSynchronizedAt(const QDateTime& sourceSynchronizedAt); + QDateTime getSourceSynchronizedAt() const; void setDateAdded(const QDateTime& dateAdded); QDateTime getDateAdded() const; @@ -252,12 +262,20 @@ class Track : public QObject { ConstWaveformPointer getWaveformSummary() const; void setWaveformSummary(ConstWaveformPointer pWaveform); - // Get the track's main cue point - CuePosition getCuePoint() const; + /// Get the track's main cue point + mixxx::audio::FramePos getMainCuePosition() const; + CuePosition getCuePoint() const { + return getMainCuePosition().toEngineSamplePosMaybeInvalid(); + }; // Set the track's main cue point - void setCuePoint(CuePosition cue); + void setMainCuePosition(mixxx::audio::FramePos position); + void setCuePoint(CuePosition position) { + setMainCuePosition( + mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid( + position.getPosition())); + } /// Shift all cues by a constant offset - void shiftCuePositionsMillis(double milliseconds); + void shiftCuePositionsMillis(mixxx::audio::FrameDiff_t milliseconds); // Call when analysis is done. void analysisFinished(); @@ -265,8 +283,20 @@ class Track : public QObject { CuePointer createAndAddCue( mixxx::CueType type, int hotCueIndex, - double sampleStartPosition, - double sampleEndPosition); + mixxx::audio::FramePos startPosition, + mixxx::audio::FramePos endPosition); + CuePointer createAndAddCue( + mixxx::CueType type, + int hotCueIndex, + double startPositionSamples, + double endPositionSamples) { + return createAndAddCue(type, + hotCueIndex, + mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid( + startPositionSamples), + mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid( + endPositionSamples)); + } CuePointer findCueByType(mixxx::CueType type) const; // NOTE: Cannot be used for hotcues. CuePointer findCueById(DbId id) const; void removeCue(const CuePointer& pCue); @@ -336,10 +366,10 @@ class Track : public QObject { /// with file tags, either by importing or exporting the metadata. void replaceMetadataFromSource( mixxx::TrackMetadata importedMetadata, - const QDateTime& metadataSynchronized); + const QDateTime& sourceSynchronizedAt); mixxx::TrackMetadata getMetadata( - bool* pMetadataSynchronized = nullptr) const; + bool* pHeaderParsed = nullptr) const; mixxx::TrackRecord getRecord( bool* pDirty = nullptr) const; diff --git a/src/track/trackrecord.cpp b/src/track/trackrecord.cpp index a1e7b82f877..f8f2a47a352 100644 --- a/src/track/trackrecord.cpp +++ b/src/track/trackrecord.cpp @@ -15,9 +15,10 @@ const Logger kLogger("TrackRecord"); TrackRecord::TrackRecord(TrackId id) : m_id(std::move(id)), - m_metadataSynchronized(false), + m_mainCuePosition(mixxx::audio::kStartFramePos), m_rating(0), - m_bpmLocked(false) { + m_bpmLocked(false), + m_headerParsed(false) { } void TrackRecord::setKeys(const Keys& keys) { @@ -107,24 +108,66 @@ bool copyIfNotEmpty( } // anonymous namespace +bool TrackRecord::updateSourceSynchronizedAt( + const QDateTime& sourceSynchronizedAt) { + VERIFY_OR_DEBUG_ASSERT(sourceSynchronizedAt.isValid()) { + // Cannot be reset after it has been set at least once. + // This is required to prevent unintended and repeated + // reimporting of metadata from file tags. + return false; + } + if (getSourceSynchronizedAt() == sourceSynchronizedAt) { + return false; // unchanged + } + if (getSourceSynchronizedAt().isValid() && + getSourceSynchronizedAt() > sourceSynchronizedAt) { + kLogger.warning() + << "Backdating source synchronization time from" + << getSourceSynchronizedAt() + << "to" + << sourceSynchronizedAt; + } + setSourceSynchronizedAt(sourceSynchronizedAt); + m_headerParsed = sourceSynchronizedAt.isValid(); + DEBUG_ASSERT(isSourceSynchronized()); + return true; +} + +bool TrackRecord::isSourceSynchronized() const { + // This method cannot be used to update m_headerParsed + // after modifying m_sourceSynchronizedAt during a short + // moment of inconsistency. Otherwise the debug assertion + // triggers! + DEBUG_ASSERT(m_headerParsed || + !getSourceSynchronizedAt().isValid()); + if (getSourceSynchronizedAt().isValid()) { + return true; + } + // Legacy fallback: The property sourceSynchronizedAt has been + // added later. Files that have been added before that time + // and that have never been re-imported will only have that + // legacy flag set while sourceSynchronizedAt is still invalid. + return m_headerParsed; +} + bool TrackRecord::replaceMetadataFromSource( TrackMetadata&& importedMetadata, - const QDateTime& metadataSynchronized) { + const QDateTime& sourceSynchronizedAt) { + VERIFY_OR_DEBUG_ASSERT(sourceSynchronizedAt.isValid()) { + return false; + } + DEBUG_ASSERT(sourceSynchronizedAt.timeSpec() == Qt::UTC); + if (m_streamInfoFromSource) { + // Preserve precise stream info if available, i.e. discard the + // audio properties that are also stored as track metadata. + importedMetadata.updateStreamInfoFromSource(*m_streamInfoFromSource); + } bool modified = false; if (getMetadata() != importedMetadata) { setMetadata(std::move(importedMetadata)); modified = true; } - // Only set the metadata synchronized flag (column `header_parsed` - // in the database) from false to true, but never reset it back to - // false. Otherwise file tags would be re-imported and overwrite - // the metadata stored in the database, e.g. after retrieving metadata - // from MusicBrainz! - // TODO: In the future this flag should become a time stamp - // to detect updates of files and then decide based on time - // stamps if file tags need to be re-imported. - if (!getMetadataSynchronized() && !metadataSynchronized.isNull()) { - setMetadataSynchronized(true); + if (updateSourceSynchronizedAt(sourceSynchronizedAt)) { modified = true; } return modified; @@ -273,16 +316,17 @@ bool operator==(const TrackRecord& lhs, const TrackRecord& rhs) { return lhs.getMetadata() == rhs.getMetadata() && lhs.getCoverInfo() == rhs.getCoverInfo() && lhs.getId() == rhs.getId() && - lhs.getMetadataSynchronized() == rhs.getMetadataSynchronized() && + lhs.getSourceSynchronizedAt() == rhs.getSourceSynchronizedAt() && lhs.getDateAdded() == rhs.getDateAdded() && lhs.getFileType() == rhs.getFileType() && lhs.getUrl() == rhs.getUrl() && lhs.getPlayCounter() == rhs.getPlayCounter() && lhs.getColor() == rhs.getColor() && - lhs.getCuePoint() == rhs.getCuePoint() && + lhs.getMainCuePosition() == rhs.getMainCuePosition() && lhs.getBpmLocked() == rhs.getBpmLocked() && lhs.getKeys() == rhs.getKeys() && - lhs.getRating() == rhs.getRating(); + lhs.getRating() == rhs.getRating() && + lhs.m_headerParsed == rhs.m_headerParsed; } } // namespace mixxx diff --git a/src/track/trackrecord.h b/src/track/trackrecord.h index 354a41ef02b..67aa74efadc 100644 --- a/src/track/trackrecord.h +++ b/src/track/trackrecord.h @@ -1,15 +1,13 @@ #pragma once +#include "library/coverart.h" #include "proto/keys.pb.h" - -#include "track/trackid.h" #include "track/cue.h" #include "track/keys.h" #include "track/keyutils.h" -#include "track/trackmetadata.h" #include "track/playcounter.h" - -#include "library/coverart.h" +#include "track/trackid.h" +#include "track/trackmetadata.h" #include "util/color/rgbcolor.h" @@ -39,19 +37,13 @@ class TrackRecord final { // has been inserted or is loaded from the library DB. MIXXX_DECL_PROPERTY(TrackId, id, Id) - // TODO(uklotz): Change data type from bool to QDateTime - // // Both import and export of metadata can be tracked by a single time // stamp, the direction doesn't matter. The value should be set to the // modification time stamp provided by the metadata source. This would // enable us to update the metadata of all tracks in the database after // the external metadata has been modified, i.e. if the corresponding // files have been modified. - // - // Requires a database update! We could reuse the 'header_parsed' column. - // During migration the boolean value will be substituted with either a - // default time stamp 1970-01-01 00:00:00.000 or NULL respectively. - MIXXX_DECL_PROPERTY(bool /*QDateTime*/, metadataSynchronized, MetadataSynchronized) + MIXXX_DECL_PROPERTY(QDateTime, sourceSynchronizedAt, SourceSynchronizedAt) MIXXX_DECL_PROPERTY(CoverInfoRelative, coverInfo, CoverInfo) @@ -60,7 +52,7 @@ class TrackRecord final { MIXXX_DECL_PROPERTY(QString, url, Url) MIXXX_DECL_PROPERTY(PlayCounter, playCounter, PlayCounter) MIXXX_DECL_PROPERTY(RgbColor::optional_t, color, Color) - MIXXX_DECL_PROPERTY(CuePosition, cuePoint, CuePoint) + MIXXX_DECL_PROPERTY(mixxx::audio::FramePos, mainCuePosition, MainCuePosition) MIXXX_DECL_PROPERTY(int, rating, Rating) MIXXX_DECL_PROPERTY(bool, bpmLocked, BpmLocked) @@ -117,9 +109,11 @@ class TrackRecord final { const QString& keyText, track::io::key::Source keySource); + bool isSourceSynchronized() const; bool replaceMetadataFromSource( TrackMetadata&& importedMetadata, - const QDateTime& metadataSynchronized); + const QDateTime& sourceSynchronizedAt); + // Merge the current metadata with new and additional properties // imported from the file. Since these properties are not (yet) // stored in the library or have been added later all existing @@ -148,13 +142,19 @@ class TrackRecord final { return m_streamInfoFromSource; } -private: + private: + // TODO: Remove this dependency + friend class ::Track; + + bool updateSourceSynchronizedAt( + const QDateTime& sourceSynchronizedAt); + Keys m_keys; // TODO: Use TrackMetadata as single source of truth and do not // store this information redundantly. // - // PROPOSAL (as implememted by https://gitlab.com/uklotzde/aoide-rs): + // PROPOSAL (as implemented by https://gitlab.com/uklotzde/aoide-rs): // This redesign requires to track the status of some or all track // metadata (which includes the stream info properties) by a set of // bitflags: @@ -173,6 +173,8 @@ class TrackRecord final { // Stale metadata should be re-imported depending on the other flags. std::optional m_streamInfoFromSource; + bool m_headerParsed; // deprecated, replaced by sourceSynchronizedAt + /// Equality comparison /// /// Exception: The member m_streamInfoFromSource must not be considered diff --git a/src/util/cmdlineargs.cpp b/src/util/cmdlineargs.cpp index 224907ca178..3f7b38b5c91 100644 --- a/src/util/cmdlineargs.cpp +++ b/src/util/cmdlineargs.cpp @@ -63,7 +63,11 @@ bool parseLogLevel( } } // namespace -bool CmdlineArgs::parse(int& argc, char** argv) { +bool CmdlineArgs::parse(int argc, char** argv) { + if (argc == 1) { + // Mixxx was run with the binary name only, nothing to do + return true; + } QStringList arguments; arguments.reserve(argc); for (int a = 0; a < argc; ++a) { @@ -71,115 +75,146 @@ bool CmdlineArgs::parse(int& argc, char** argv) { } QCommandLineParser parser; - parser.setApplicationDescription(QCoreApplication::translate("main", - "Mixxx is an open source DJ software. For more information, " - "see " MIXXX_MANUAL_COMMANDLINEOPTIONS_URL - "\n." - "CamelCase arguments are deprecated and will be removed in 2.5")); parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); + parser.setApplicationDescription( + QCoreApplication::translate("CmdlineArgs", + "Mixxx is an open source DJ software. For more " + "information, see: ") + + MIXXX_MANUAL_COMMANDLINEOPTIONS_URL); + // add options - const QCommandLineOption fullscreen(QStringList() << "f" - << "full-screen" - << "fullScreen", - QCoreApplication::translate("main", "Starts Mixxx in full-screen mode")); - parser.addOption(fullscreen); + const QCommandLineOption fullScreen( + QStringList({QStringLiteral("f"), QStringLiteral("full-screen")}), + QCoreApplication::translate( + "CmdlineArgs", "Starts Mixxx in full-screen mode")); + QCommandLineOption fullScreenDeprecated(QStringLiteral("fullScreen")); + fullScreenDeprecated.setFlags(QCommandLineOption::HiddenFromHelp); + parser.addOption(fullScreen); + parser.addOption(fullScreenDeprecated); const QCommandLineOption locale(QStringLiteral("locale"), - QCoreApplication::translate("main", + QCoreApplication::translate("CmdlineArgs", "Use a custom locale for loading translations. (e.g " - "'fr')")); + "'fr')"), + QStringLiteral("locale")); parser.addOption(locale); // An option with a value - const QCommandLineOption settingsPath(QStringList() << "settings-path" - << "settingsPath", - QCoreApplication::translate("main", + const QCommandLineOption settingsPath(QStringLiteral("settings-path"), + QCoreApplication::translate("CmdlineArgs", "Top-level directory where Mixxx should look for settings. " "Default is:") + - getSettingsPath().toLocal8Bit().constData(), + getSettingsPath(), + QStringLiteral("path")); + QCommandLineOption settingsPathDeprecated( QStringLiteral("settingsPath")); + settingsPathDeprecated.setFlags(QCommandLineOption::HiddenFromHelp); + settingsPathDeprecated.setValueName(settingsPath.valueName()); parser.addOption(settingsPath); + parser.addOption(settingsPathDeprecated); - QCommandLineOption resourcePath(QStringList() << "resource-path" - << "resourcePath", - QCoreApplication::translate("main", + QCommandLineOption resourcePath(QStringLiteral("resource-path"), + QCoreApplication::translate("CmdlineArgs", "Top-level directory where Mixxx should look for its " "resource files such as MIDI mappings, overriding the " "default installation location."), + QStringLiteral("path")); + QCommandLineOption resourcePathDeprecated( QStringLiteral("resourcePath")); + resourcePathDeprecated.setFlags(QCommandLineOption::HiddenFromHelp); + resourcePathDeprecated.setValueName(resourcePath.valueName()); parser.addOption(resourcePath); - - const QCommandLineOption timelinePath(QStringList() << "timeline-path" - << "timelinePath", - QCoreApplication::translate("main", "Path the timeline is written to")); + parser.addOption(resourcePathDeprecated); + + const QCommandLineOption timelinePath(QStringLiteral("timeline-path"), + QCoreApplication::translate("CmdlineArgs", + "Path the debug statistics time line is written to"), + QStringLiteral("path")); + QCommandLineOption timelinePathDeprecated( + QStringLiteral("timelinePath"), timelinePath.description()); + timelinePathDeprecated.setFlags(QCommandLineOption::HiddenFromHelp); + timelinePathDeprecated.setValueName(timelinePath.valueName()); parser.addOption(timelinePath); + parser.addOption(timelinePathDeprecated); - const QCommandLineOption controllerDebug(QStringList() << "controller-debug" - << "controllerDebug" - << "midi-debug" - << "midiDebug", - QCoreApplication::translate("main", + const QCommandLineOption controllerDebug(QStringLiteral("controller-debug"), + QCoreApplication::translate("CmdlineArgs", "Causes Mixxx to display/log all of the controller data it " "receives and script functions it loads")); + QCommandLineOption controllerDebugDeprecated( + QStringList({QStringLiteral("controllerDebug"), + QStringLiteral("midiDebug")})); + controllerDebugDeprecated.setFlags(QCommandLineOption::HiddenFromHelp); parser.addOption(controllerDebug); + parser.addOption(controllerDebugDeprecated); const QCommandLineOption developer(QStringLiteral("developer"), - QCoreApplication::translate("main", + QCoreApplication::translate("CmdlineArgs", "Enables developer-mode. Includes extra log info, stats on " "performance, and a Developer tools menu.")); parser.addOption(developer); - const QCommandLineOption safeMode(QStringList() << "safe-mode" - << "safeMode", - QCoreApplication::translate("main", + const QCommandLineOption safeMode(QStringLiteral("safe-mode"), + QCoreApplication::translate("CmdlineArgs", "Enables safe-mode. Disables OpenGL waveforms, and " "spinning vinyl widgets. Try this option if Mixxx is " "crashing on startup.")); + QCommandLineOption safeModeDeprecated(QStringLiteral("safeMode"), safeMode.description()); + safeModeDeprecated.setFlags(QCommandLineOption::HiddenFromHelp); parser.addOption(safeMode); + parser.addOption(safeModeDeprecated); const QCommandLineOption color(QStringLiteral("color"), - QCoreApplication::translate("main", + QCoreApplication::translate("CmdlineArgs", "[auto|always|never] Use colors on the console output."), QStringLiteral("color"), QStringLiteral("auto")); parser.addOption(color); - const QCommandLineOption logLevel(QStringList() << "log-level" - << "logLevel", - QCoreApplication::translate("main", + const QCommandLineOption logLevel(QStringLiteral("log-level"), + QCoreApplication::translate("CmdlineArgs", "Sets the verbosity of command line logging.\n" "critical - Critical/Fatal only\n" "warning - Above + Warnings\n" "info - Above + Informational messages\n" "debug - Above + Debug/Developer messages\n" "trace - Above + Profiling messages"), - QStringLiteral("logLevel")); + QStringLiteral("level")); + QCommandLineOption logLevelDeprecated(QStringLiteral("logLevel"), logLevel.description()); + logLevelDeprecated.setFlags(QCommandLineOption::HiddenFromHelp); + logLevelDeprecated.setValueName(logLevel.valueName()); parser.addOption(logLevel); + parser.addOption(logLevelDeprecated); - const QCommandLineOption logFlushLevel(QStringList() << "log-flush-level" - << "logFlushLevel", - QCoreApplication::translate("main", + const QCommandLineOption logFlushLevel(QStringLiteral("log-flush-level"), + QCoreApplication::translate("CmdlineArgs", "Sets the the logging level at which the log buffer is " - "flushed to mixxx.log. LEVEL is one of the values defined " - "at --logLevel above."), - QStringLiteral("logFlushLevel")); + "flushed to mixxx.log. is one of the values defined " + "at --log-level above."), + QStringLiteral("level")); + QCommandLineOption logFlushLevelDeprecated( + QStringLiteral("logFlushLevel"), logLevel.description()); + logFlushLevelDeprecated.setFlags(QCommandLineOption::HiddenFromHelp); + logFlushLevelDeprecated.setValueName(logFlushLevel.valueName()); parser.addOption(logFlushLevel); + parser.addOption(logFlushLevelDeprecated); -#ifdef MIXXX_BUILD_DEBUG - QCommandLineOption debugAssertBreak(QStringList() << "debug-assert-break" - << "debugAssertBreak", - QCoreApplication::translate("main", + QCommandLineOption debugAssertBreak(QStringLiteral("debug-assert-break"), + QCoreApplication::translate("CmdlineArgs", "Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to " "false. Under a debugger you can continue afterwards.")); + QCommandLineOption debugAssertBreakDeprecated( + QStringLiteral("debugAssertBreak"), debugAssertBreak.description()); + debugAssertBreakDeprecated.setFlags(QCommandLineOption::HiddenFromHelp); parser.addOption(debugAssertBreak); -#endif + parser.addOption(debugAssertBreakDeprecated); const QCommandLineOption helpOption = parser.addHelpOption(); const QCommandLineOption versionOption = parser.addVersionOption(); parser.addPositionalArgument(QStringLiteral("file"), - QCoreApplication::translate("main", + QCoreApplication::translate("CmdlineArgs", "Load the specified music file(s) at start-up. Each file " "you specify will be loaded into the next virtual deck.")); @@ -204,7 +239,7 @@ bool CmdlineArgs::parse(int& argc, char** argv) { return false; } - m_startInFullscreen = parser.isSet(fullscreen); + m_startInFullscreen = parser.isSet(fullScreen) || parser.isSet(fullScreenDeprecated); if (parser.isSet(locale)) { m_locale = parser.value(locale); @@ -216,26 +251,43 @@ bool CmdlineArgs::parse(int& argc, char** argv) { m_settingsPath.append("/"); } m_settingsPathSet = true; + } else if (parser.isSet(settingsPathDeprecated)) { + m_settingsPath = parser.value(settingsPathDeprecated); + if (!m_settingsPath.endsWith("/")) { + m_settingsPath.append("/"); + } + m_settingsPathSet = true; } if (parser.isSet(resourcePath)) { m_resourcePath = parser.value(resourcePath); + } else if (parser.isSet(resourcePathDeprecated)) { + m_resourcePath = parser.value(resourcePathDeprecated); } - m_midiDebug = parser.isSet(controllerDebug); - m_developer = parser.isSet(developer); - m_safeMode = parser.isSet(safeMode); + if (parser.isSet(timelinePath)) { + m_timelinePath = parser.value(timelinePath); + } else if (parser.isSet(timelinePathDeprecated)) { + m_timelinePath = parser.value(timelinePathDeprecated); + } -#ifdef MIXXX_BUILD_DEBUG - m_debugAssertBreak = parser.isSet(debugAssertBreak); -#endif + m_midiDebug = parser.isSet(controllerDebug) || parser.isSet(controllerDebugDeprecated); + m_developer = parser.isSet(developer); + m_safeMode = parser.isSet(safeMode) || parser.isSet(safeModeDeprecated); + m_debugAssertBreak = parser.isSet(debugAssertBreak) || parser.isSet(debugAssertBreakDeprecated); m_musicFiles = parser.positionalArguments(); if (parser.isSet(logLevel)) { if (!parseLogLevel(parser.value(logLevel), &m_logLevel)) { - fputs("\nlogLevel argument wasn't 'trace', 'debug', 'info', 'warning', or 'critical'! Mixxx will only output\n\ -warnings and errors to the console unless this is set properly.\n", + fputs("\nlog-level wasn't 'trace', 'debug', 'info', 'warning', or 'critical'!\n" + "Mixxx will only print warnings and critical messages to the console.\n", + stdout); + } + } else if (parser.isSet(logLevelDeprecated)) { + if (!parseLogLevel(parser.value(logLevelDeprecated), &m_logLevel)) { + fputs("\nlogLevel wasn't 'trace', 'debug', 'info', 'warning', or 'critical'!\n" + "Mixxx will only print warnings and critical messages to the console.\n", stdout); } } else { @@ -244,6 +296,20 @@ warnings and errors to the console unless this is set properly.\n", } } + if (parser.isSet(logFlushLevel)) { + if (!parseLogLevel(parser.value(logFlushLevel), &m_logFlushLevel)) { + fputs("\nlog-flush-level wasn't 'trace', 'debug', 'info', 'warning', or 'critical'!\n" + "Mixxx will only flush output after a critical message.\n", + stdout); + } + } else if (parser.isSet(logFlushLevelDeprecated)) { + if (!parseLogLevel(parser.value(logFlushLevelDeprecated), &m_logFlushLevel)) { + fputs("\nlogFlushLevel wasn't 'trace', 'debug', 'info', 'warning', or 'critical'!\n" + "Mixxx will only flush output after a critical message.\n", + stdout); + } + } + // set colors if (parser.value(color).compare(QLatin1String("auto"), Qt::CaseInsensitive) == 0) { // see https://no-color.org/ @@ -265,7 +331,7 @@ warnings and errors to the console unless this is set properly.\n", } else if (parser.value(color).compare(QLatin1String("never"), Qt::CaseInsensitive) == 0) { m_useColors = false; } else { - qWarning() << "Unknown setting for color, ignoring"; + fputs("Unknown argument for for color.\n", stdout); } return true; diff --git a/src/util/cmdlineargs.h b/src/util/cmdlineargs.h index 046351052c2..b02615062be 100644 --- a/src/util/cmdlineargs.h +++ b/src/util/cmdlineargs.h @@ -21,7 +21,7 @@ class CmdlineArgs final { return cla; } - bool parse(int& argc, char** argv); + bool parse(int argc, char** argv); const QList& getMusicFiles() const { return m_musicFiles; } bool getStartInFullscreen() const { return m_startInFullscreen; } diff --git a/src/util/db/sqlite.cpp b/src/util/db/sqlite.cpp index 46f9e8e4152..fae53bde223 100644 --- a/src/util/db/sqlite.cpp +++ b/src/util/db/sqlite.cpp @@ -4,7 +4,7 @@ namespace { -/// Date/time formate generated by SQLite CURRENT_TIMESTAMP (UTC) that is +/// Date/time format generated by SQLite CURRENT_TIMESTAMP (UTC) that is /// used for library.last_played_at and PlalistTracks.pl_datetime_added. /// QStringBuilder cannot be used to compose this constant at compile time! const QString kGeneratedTimestampFormat = diff --git a/src/util/fileinfo.h b/src/util/fileinfo.h index e16845d7689..9703b1bcfeb 100644 --- a/src/util/fileinfo.h +++ b/src/util/fileinfo.h @@ -26,7 +26,7 @@ namespace mixxx { /// All single-argument are declared as explicit to prevent implicit conversions. /// /// Implementation note: Inheriting from QFileInfo would violate the -/// Liskov Substition Principle. It is also invalid, because QFileInfo +/// Liskov Substution Principle. It is also invalid, because QFileInfo /// has a non-virtual destructor and we cannot override non-virtual /// member functions. class FileInfo final { @@ -99,7 +99,7 @@ class FileInfo final { } /// Check that the given QFileInfo is context-insensitive to avoid - /// implicitly acccessing any transient working directory when + /// implicitly accessing any transient working directory when /// resolving relative paths. We need to exclude these unintended /// side-effects! static bool hasLocation(const QFileInfo& fileInfo) { diff --git a/src/util/parented_ptr.h b/src/util/parented_ptr.h index 7213fac565f..dd5d4ba2a7e 100644 --- a/src/util/parented_ptr.h +++ b/src/util/parented_ptr.h @@ -28,7 +28,7 @@ class parented_ptr final { } ~parented_ptr() noexcept { - DEBUG_ASSERT(!m_ptr || m_ptr->parent()); + DEBUG_ASSERT(!m_ptr || static_cast(m_ptr)->parent()); } // Delete copy constructor and copy assignment operator diff --git a/src/util/qt.h b/src/util/qt.h index f674d6d7ddb..303893ae278 100644 --- a/src/util/qt.h +++ b/src/util/qt.h @@ -39,7 +39,7 @@ inline QString escapeTextPropertyWithoutShortcuts(QString text) { /// Prevents directly dereferencing the internal pointer. The internal /// pointer in QPointer might be reset and become a nullptr at any time /// when the referenced QObject lives in a different thread. This -/// behavior could cause spurious crahses due to race conditions. +/// behavior could cause spurious crashes due to race conditions. template class SafeQPointer final { public: diff --git a/src/util/sample.cpp b/src/util/sample.cpp index eb744f83593..18c3eece7cd 100644 --- a/src/util/sample.cpp +++ b/src/util/sample.cpp @@ -17,7 +17,7 @@ typedef qint32 int32_t; // This also utilizes AVX registers when compiled for a recent 64-bit CPU // using scons optimize=native. // "SINT i" is the preferred loop index type that should allow vectorization in -// general. Unfortunatly there are expetions where "int i" is required for some reasons. +// general. Unfortunately there are exceptions where "int i" is required for some reasons. namespace { diff --git a/src/util/sandbox.cpp b/src/util/sandbox.cpp index b971606097a..245d7a3ad9d 100644 --- a/src/util/sandbox.cpp +++ b/src/util/sandbox.cpp @@ -90,48 +90,50 @@ bool Sandbox::canAccessDir(const QDir& dir) { bool Sandbox::askForAccess(mixxx::FileInfo* pFileInfo) { // We always want read/write access because we wouldn't want to have to // re-ask for access in the future if we need to write. - if (canAccess(pFileInfo)) { + if (sDebug) { + qDebug() << "Sandbox: Requesting user access to" << pFileInfo; + } + if (!enabled()) { + // Pretend we have access. return true; } - const QString canonicalLocation = pFileInfo->canonicalLocation(); - if (canonicalLocation.isEmpty()) { - // File does not exist + if (!pFileInfo->exists()) { + // We cannot grant access to a not existing file return false; } - if (sDebug) { - qDebug() << "Sandbox: Requesting user access to" << canonicalLocation; + if (canAccess(pFileInfo)) { + return true; } + + const QString location = pFileInfo->location(); const QString fileName = pFileInfo->fileName(); const QString title = QObject::tr("Mixxx Needs Access to: %1").arg(fileName); - QMessageBox::question(nullptr, + QMessageBox::information(nullptr, title, QObject::tr( - "Due to Mac Sandboxing, we need your permission to access " - "this file:" + "Your permission is required to access " + "the following location:" "\n\n%1\n\n" "After clicking OK, you will see a file picker. " - "To give Mixxx permission, you must select '%2' to " - "proceed. " - "If you do not want to grant Mixxx access click Cancel on " - "the file picker. " - "We're sorry for this inconvenience.\n\n" - "To abort this action, press Cancel on the file dialog.") - .arg(canonicalLocation, fileName)); + "Please select '%2' to proceed or click Cancel if " + "you don't want to grant Mixxx access and abort " + "this action.") + .arg(location, fileName)); mixxx::FileInfo resultInfo; while (true) { QString result; if (pFileInfo->isFile()) { - result = QFileDialog::getOpenFileName(nullptr, title, canonicalLocation); + result = QFileDialog::getOpenFileName(nullptr, title, location); } else if (pFileInfo->isDir()) { - result = QFileDialog::getExistingDirectory(nullptr, title, canonicalLocation); + result = QFileDialog::getExistingDirectory(nullptr, title, location); } if (result.isNull()) { if (sDebug) { - qDebug() << "Sandbox: User rejected access to" << canonicalLocation; + qDebug() << "Sandbox: User rejected access to" << location; } return false; } @@ -147,7 +149,7 @@ bool Sandbox::askForAccess(mixxx::FileInfo* pFileInfo) { if (sDebug) { qDebug() << "User selected the wrong file."; } - QMessageBox::question( + QMessageBox::information( nullptr, title, QObject::tr("You selected the wrong file. To grant Mixxx access, " "please select the file '%1'. If you do not want to " "continue, press Cancel.") diff --git a/src/waveform/renderers/waveformmark.h b/src/waveform/renderers/waveformmark.h index bef85b1e29c..60de168e5a3 100644 --- a/src/waveform/renderers/waveformmark.h +++ b/src/waveform/renderers/waveformmark.h @@ -85,7 +85,7 @@ class WaveformMark { return m_labelColor; } - // Check if a point (in image co-ordinates) lies on drawn image. + // Check if a point (in image coordinates) lies on drawn image. bool contains(QPoint point, Qt::Orientation orientation) const; QColor m_textColor; diff --git a/src/waveform/renderers/waveformrenderbeat.cpp b/src/waveform/renderers/waveformrenderbeat.cpp index e9b3227caf5..5af17988373 100644 --- a/src/waveform/renderers/waveformrenderbeat.cpp +++ b/src/waveform/renderers/waveformrenderbeat.cpp @@ -57,8 +57,8 @@ void WaveformRenderBeat::draw(QPainter* painter, QPaintEvent* /*event*/) { // << "lastDisplayedPosition" << lastDisplayedPosition; std::unique_ptr it(trackBeats->findBeats( - firstDisplayedPosition * trackSamples, - lastDisplayedPosition * trackSamples)); + mixxx::audio::FramePos::fromEngineSamplePos(firstDisplayedPosition * trackSamples), + mixxx::audio::FramePos::fromEngineSamplePos(lastDisplayedPosition * trackSamples))); // if no beat do not waste time saving/restoring painter if (!it || !it->hasNext()) { @@ -80,7 +80,7 @@ void WaveformRenderBeat::draw(QPainter* painter, QPaintEvent* /*event*/) { int beatCount = 0; while (it->hasNext()) { - double beatPosition = it->next(); + double beatPosition = it->next().toEngineSamplePos(); double xBeatPoint = m_waveformRenderer->transformSamplePositionInRendererWorld(beatPosition); diff --git a/src/waveform/renderers/waveformrendermark.cpp b/src/waveform/renderers/waveformrendermark.cpp index 0077ec60b80..0347951fe77 100644 --- a/src/waveform/renderers/waveformrendermark.cpp +++ b/src/waveform/renderers/waveformrendermark.cpp @@ -66,7 +66,7 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { const double sampleEndPosition = pMark->getSampleEndPosition(); if (m_waveformRenderer->getOrientation() == Qt::Horizontal) { // Pixmaps are expected to have the mark stroke at the center, - // and preferrably have an odd width in order to have the stroke + // and preferably have an odd width in order to have the stroke // exactly at the sample position. const int markHalfWidth = static_cast(pMark->m_image.width() / 2.0 / @@ -226,7 +226,7 @@ void WaveformRenderMark::generateMarkImage(WaveformMarkPointer pMark) { image.convertToFormat(QImage::Format_ARGB32_Premultiplied); //WImageStore::correctImageColors(&pMark->m_image); // Set the pixel/device ratio AFTER loading the image in order to get - // a truely scaled source image. + // a truly scaled source image. // See https://doc.qt.io/qt-5/qimage.html#setDevicePixelRatio // Also, without this some Qt-internal issue results in an offset // image when calculating the center line of pixmaps in draw(). diff --git a/src/widget/wcuemenupopup.cpp b/src/widget/wcuemenupopup.cpp index 243998400c1..0686b1abe7f 100644 --- a/src/widget/wcuemenupopup.cpp +++ b/src/widget/wcuemenupopup.cpp @@ -83,13 +83,11 @@ void WCueMenuPopup::setTrackAndCue(TrackPointer pTrack, const CuePointer& pCue) QString positionText = ""; Cue::StartAndEndPositions pos = m_pCue->getStartAndEndPosition(); - if (pos.startPosition != Cue::kNoPosition) { - double startPositionSeconds = pos.startPosition / - m_pTrack->getSampleRate() / mixxx::kEngineChannelCount; + if (pos.startPosition.isValid()) { + double startPositionSeconds = pos.startPosition.value() / m_pTrack->getSampleRate(); positionText = mixxx::Duration::formatTime(startPositionSeconds, mixxx::Duration::Precision::CENTISECONDS); - if (pos.endPosition != Cue::kNoPosition) { - double endPositionSeconds = pos.endPosition / - m_pTrack->getSampleRate() / mixxx::kEngineChannelCount; + if (pos.endPosition.isValid()) { + double endPositionSeconds = pos.endPosition.value() / m_pTrack->getSampleRate(); positionText = QString("%1 - %2").arg( positionText, mixxx::Duration::formatTime(endPositionSeconds, mixxx::Duration::Precision::CENTISECONDS) diff --git a/src/widget/wpushbutton.cpp b/src/widget/wpushbutton.cpp index e23f167125b..a7cda9946eb 100644 --- a/src/widget/wpushbutton.cpp +++ b/src/widget/wpushbutton.cpp @@ -423,8 +423,8 @@ bool WPushButton::event(QEvent* e) { restyleAndRepaint(); } else if (e->type() == QEvent::Leave) { if (m_bPressed) { - // A Leave event is send instead of a mouseReleaseEvent() - // fake it to get not stucked in pressed state + // A Leave event is sent instead of a mouseReleaseEvent() + // fake it to not get stuck in pressed state QMouseEvent mouseEvent = QMouseEvent( QEvent::MouseButtonRelease, QPointF(), diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index f0f9c1ff645..9fb3fee4aa0 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -315,22 +315,22 @@ void WTrackMenu::createActions() { m_pBpmThreeHalvesAction = new QAction(tr("3/2 BPM"), m_pBPMMenu); connect(m_pBpmDoubleAction, &QAction::triggered, this, [this] { - slotScaleBpm(mixxx::Beats::DOUBLE); + slotScaleBpm(mixxx::Beats::BpmScale::Double); }); connect(m_pBpmHalveAction, &QAction::triggered, this, [this] { - slotScaleBpm(mixxx::Beats::HALVE); + slotScaleBpm(mixxx::Beats::BpmScale::Halve); }); connect(m_pBpmTwoThirdsAction, &QAction::triggered, this, [this] { - slotScaleBpm(mixxx::Beats::TWOTHIRDS); + slotScaleBpm(mixxx::Beats::BpmScale::TwoThirds); }); connect(m_pBpmThreeFourthsAction, &QAction::triggered, this, [this] { - slotScaleBpm(mixxx::Beats::THREEFOURTHS); + slotScaleBpm(mixxx::Beats::BpmScale::ThreeFourths); }); connect(m_pBpmFourThirdsAction, &QAction::triggered, this, [this] { - slotScaleBpm(mixxx::Beats::FOURTHIRDS); + slotScaleBpm(mixxx::Beats::BpmScale::FourThirds); }); connect(m_pBpmThreeHalvesAction, &QAction::triggered, this, [this] { - slotScaleBpm(mixxx::Beats::THREEHALVES); + slotScaleBpm(mixxx::Beats::BpmScale::ThreeHalves); }); m_pBpmResetAction = new QAction(tr("Reset BPM"), m_pBPMMenu); @@ -1192,7 +1192,7 @@ namespace { class ScaleBpmTrackPointerOperation : public mixxx::TrackPointerOperation { public: - explicit ScaleBpmTrackPointerOperation(mixxx::Beats::BPMScale bpmScale) + explicit ScaleBpmTrackPointerOperation(mixxx::Beats::BpmScale bpmScale) : m_bpmScale(bpmScale) { } @@ -1209,17 +1209,16 @@ class ScaleBpmTrackPointerOperation : public mixxx::TrackPointerOperation { pTrack->trySetBeats(pBeats->scale(m_bpmScale)); } - const mixxx::Beats::BPMScale m_bpmScale; + const mixxx::Beats::BpmScale m_bpmScale; }; } // anonymous namespace -void WTrackMenu::slotScaleBpm(int scale) { +void WTrackMenu::slotScaleBpm(mixxx::Beats::BpmScale scale) { const auto progressLabelText = tr("Scaling BPM of %n track(s)", "", getTrackCount()); const auto trackOperator = - ScaleBpmTrackPointerOperation( - static_cast(scale)); + ScaleBpmTrackPointerOperation(scale); applyTrackPointerOperation( progressLabelText, &trackOperator); diff --git a/src/widget/wtrackmenu.h b/src/widget/wtrackmenu.h index 71f5c841f0c..ced9c065546 100644 --- a/src/widget/wtrackmenu.h +++ b/src/widget/wtrackmenu.h @@ -9,6 +9,7 @@ #include "library/dao/playlistdao.h" #include "library/trackprocessing.h" #include "preferences/usersettings.h" +#include "track/beats.h" #include "track/trackref.h" #include "util/color/rgbcolor.h" #include "util/parented_ptr.h" @@ -102,7 +103,7 @@ class WTrackMenu : public QMenu { // BPM void slotLockBpm(); void slotUnlockBpm(); - void slotScaleBpm(int); + void slotScaleBpm(mixxx::Beats::BpmScale scale); // Info and metadata void slotShowDlgTagFetcher(); diff --git a/tools/debian_buildenv.sh b/tools/debian_buildenv.sh index 013f154b997..b58a1b6d7ef 100755 --- a/tools/debian_buildenv.sh +++ b/tools/debian_buildenv.sh @@ -3,12 +3,10 @@ # shellcheck disable=SC1091 set -o pipefail -COMMAND=$1 -shift - -case "$COMMAND" in +case "$1" in name) - echo "No build environment needed for Ubuntu, please install dependencies using apt." >&2 + echo "No build environment name required for Debian based distros." >&2 + echo "This script installs the build dependencies via apt using the \"setup\" option." >&2 ;; setup) @@ -40,6 +38,8 @@ case "$COMMAND" in sudo apt-get install -y --no-install-recommends -- \ ccache \ cmake \ + clazy \ + clang-tidy \ debhelper \ devscripts \ docbook-to-man \ @@ -74,6 +74,7 @@ case "$COMMAND" in libsqlite3-dev \ libssl-dev \ libtag1-dev \ + libudev-dev \ libupower-glib-dev \ libusb-1.0-0-dev \ libwavpack-dev \ @@ -87,4 +88,13 @@ case "$COMMAND" in qml-module-qt-labs-qmlmodels \ qml-module-qtquick-shapes \ "${PACKAGES_EXTRA[@]}" + ;; + *) + echo "Usage: $0 [options]" + echo "" + echo "options:" + echo " help Displays this help." + echo " name Displays the name of the required build environment." + echo " setup Installs the build environment." + ;; esac diff --git a/tools/deploy.py b/tools/deploy.py index 7b2861480cd..910833c7222 100644 --- a/tools/deploy.py +++ b/tools/deploy.py @@ -81,7 +81,7 @@ def git_info(info, path="."): def splitext(filename): """ - Split filename into name without extenstion and file extension. + Split filename into name without extension and file extension. This includes a workaround for ".tar.gz" files. """ diff --git a/tools/githelper.py b/tools/githelper.py index da0f6456173..e995ebcf689 100644 --- a/tools/githelper.py +++ b/tools/githelper.py @@ -169,7 +169,7 @@ def get_changed_lines( yield lineobj # If we reach this part, the line does not contain a diff filename or a - # hunk header and does not belog to a hunk. This means that this line + # hunk header and does not belong to a hunk. This means that this line # will be ignored implicitly. # Make sure we really parsed all lines from the last hunk diff --git a/tools/macos_buildenv.sh b/tools/macos_buildenv.sh index 41553136397..51c4a2e1ed3 100755 --- a/tools/macos_buildenv.sh +++ b/tools/macos_buildenv.sh @@ -8,9 +8,6 @@ if [ -z "${GITHUB_ENV}" ] && ! $(return 0 2>/dev/null); then exit 1 fi -COMMAND=$1 -shift 1 - realpath() { OLDPWD="${PWD}" cd "$1" || exit 1 @@ -28,7 +25,7 @@ read -r -d'\n' BUILDENV_NAME BUILDENV_SHA256 < "${MIXXX_ROOT}/packaging/macos/bu [ -z "$BUILDENV_BASEPATH" ] && BUILDENV_BASEPATH="${MIXXX_ROOT}/buildenv" -case "$COMMAND" in +case "$1" in name) if [ -n "${GITHUB_ENV}" ]; then echo "BUILDENV_NAME=$BUILDENV_NAME" >> "${GITHUB_ENV}" @@ -123,4 +120,12 @@ case "$COMMAND" in echo_exported_variables fi ;; + *) + echo "Usage: source macos_buildenv.sh [options]" + echo "" + echo "options:" + echo " help Displays this help." + echo " name Displays the name of the required build environment." + echo " setup Installs the build environment." + ;; esac diff --git a/tools/unzip.ps1 b/tools/unzip.ps1 new file mode 100644 index 00000000000..c2ccca21f80 --- /dev/null +++ b/tools/unzip.ps1 @@ -0,0 +1,63 @@ +function unzipTo { + param ( + [string]$archiveFilePath, + [string]$destinationPath + ) + + # Ensure absolute paths. Convert from relative if needed + if ($archiveFilePath -notlike '?:\*') { + $archiveFilePath = [System.IO.Path]::Combine($PWD, $archiveFilePath) + } + + if ($destinationPath -notlike '?:\*') { + $destinationPath = [System.IO.Path]::Combine($PWD, $destinationPath) + } + + # Test supported features. + if ($PSVersionTable.PSVersion.Major -ge 3) { + # Powershell 3 (Windows 8). This needs .NET framework 4.5, available in Windows 8 + + + Add-Type -AssemblyName System.IO.Compression + Add-Type -AssemblyName System.IO.Compression.FileSystem + + $archiveFile = [System.IO.File]::Open($archiveFilePath, [System.IO.FileMode]::Open) + $archive = [System.IO.Compression.ZipArchive]::new($archiveFile) + + # If the directory exists, unzip item by itep to force the extraction. Else it would fail if file already exists. + if (Test-Path $destinationPath) { + foreach ($item in $archive.Entries) { + $destinationItemPath = [System.IO.Path]::Combine($destinationPath, $item.FullName) + + if ($destinationItemPath -like '*/') { + New-Item $destinationItemPath -Force -ItemType Directory > $null + } else { + New-Item $destinationItemPath -Force -ItemType File > $null + + [System.IO.Compression.ZipFileExtensions]::ExtractToFile($item, $destinationItemPath, $true) + } + } + } else { + # On, no folder present, use the simpler method. + [System.IO.Compression.ZipFileExtensions]::ExtractToDirectory($archive, $destinationPath) + } + } + else { + # We are on powerwhell 2. We try using the system. Note that this requires Windows 7 since it uses the Explorer zip capability. + # Note also that this is slow for big files. + New-Item -ItemType directory -Path $destinationPath -Force + + $shell = New-Object -ComObject Shell.Application + $zip = $shell.Namespace($archiveFilePath) + $shell.Namespace($destinationPath).CopyHere($zip.items()) + } + # This is as slow as the Shell.Application.CopyHere, so the System.IO.ExtractToDirectory is favoured + #if ($PSVersionTable.PSVersion.Major -ge 5) { + # # Powershell 5 (Windows 10). Expand-Archive supported + # Expand-Archive -Path $archiveFilePath -DestinationPath $destinationPath + #} +} + +$arg1, $arg2 = $args + +unzipTo $arg1 $arg2 diff --git a/tools/windows_buildenv.bat b/tools/windows_buildenv.bat index 8d03e7d5308..6d60b6e9705 100644 --- a/tools/windows_buildenv.bat +++ b/tools/windows_buildenv.bat @@ -33,6 +33,9 @@ IF "%~1"=="" ( CALL :COMMAND_%1 ) +REM Make These permanent, not local to the batch script. +ENDLOCAL & SET "VCPKG_ROOT=%VCPKG_ROOT%" & SET "VCPKG_DEFAULT_TRIPLET=%VCPKG_DEFAULT_TRIPLET%" & SET "X_VCPKG_APPLOCAL_DEPS_INSTALL=%X_VCPKG_APPLOCAL_DEPS_INSTALL%" & SET "CMAKE_GENERATOR=%CMAKE_GENERATOR%" + EXIT /B 0 :COMMAND_name @@ -46,72 +49,102 @@ EXIT /B 0 CALL :READ_ENVNAME SET BUILDENV_NAME=%RETVAL% SET BUILDENV_PATH=%BUILDENV_BASEPATH%\%BUILDENV_NAME% - SET CMAKE_TOOLCHAIN_FILE=%BUILDENV_PATH%\scripts\buildsystems\vcpkg.cmake IF NOT EXIST %BUILDENV_BASEPATH% ( - ECHO ### Create subdirectory buildenv ### + ECHO ^Creating "buildenv" directory... MD %BUILDENV_BASEPATH% ) IF NOT EXIST %BUILDENV_PATH% ( - ECHO ### Download prebuild build environment ### SET BUILDENV_URL=https://downloads.mixxx.org/dependencies/2.3/Windows/!BUILDENV_NAME!.zip IF NOT EXIST !BUILDENV_PATH!.zip ( - ECHO ### Download prebuild build environment from !BUILDENV_URL! to !BUILDENV_PATH!.zip ### + ECHO ^Download prebuilt build environment from "!BUILDENV_URL!" to "!BUILDENV_PATH!.zip"... BITSADMIN /transfer buildenvjob /download /priority normal !BUILDENV_URL! !BUILDENV_PATH!.zip REM TODO: verify download using sha256sum? + ECHO ^Download complete. + ) else ( + ECHO ^Using cached archive at "!BUILDENV_PATH!.zip". + ) + + CALL :DETECT_SEVENZIP + IF !RETVAL!=="" ( + ECHO ^Unpacking "!BUILDENV_PATH!.zip" using powershell... + CALL :UNZIP_POWERSHELL "!BUILDENV_PATH!.zip" "!BUILDENV_BASEPATH!" + ) ELSE ( + ECHO ^Unpacking "!BUILDENV_PATH!.zip" using 7z... + CALL :UNZIP_SEVENZIP "!RETVAL!" "!BUILDENV_PATH!.zip" "!BUILDENV_BASEPATH!" + ) + IF NOT EXIST %BUILDENV_PATH% ( + ECHO ^Error: Unpacking failed. The downloaded archive might be broken, consider removing "!BUILDENV_PATH!.zip" to force redownload. + EXIT /B 1 ) - ECHO ### Unpacking !BUILDENV_PATH!.zip ### - CALL :UNZIP "!BUILDENV_PATH!.zip" "!BUILDENV_BASEPATH!" - ECHO ### Unpacking complete. ### + + ECHO ^Unpacking complete. DEL /f /q %BUILDENV_PATH%.zip ) - ECHO ### Build environment path: !BUILDENV_PATH! ### - ENDLOCAL + ECHO ^Build environment path: !BUILDENV_PATH! - SET PATH=!BUILDENV_PATH!\bin;!PATH! - SET CMAKE_PREFIX_PATH=!BUILDENV_PATH! + SET "VCPKG_ROOT=!BUILDENV_PATH!" + SET "VCPKG_DEFAULT_TRIPLET=x64-windows" + SET "X_VCPKG_APPLOCAL_DEPS_INSTALL=ON" + SET "CMAKE_GENERATOR=Ninja" - ECHO ^Environent Variables: - ECHO ^- PATH=!PATH! - ECHO ^CMake Configuration: - ECHO ^- CMAKE_PREFIX_PATH=!CMAKE_PREFIX_PATH! + ECHO ^Environment Variables: + ECHO ^- VCPKG_ROOT='!VCPKG_ROOT!' + ECHO ^- VCPKG_DEFAULT_TRIPLET='!VCPKG_DEFAULT_TRIPLET!' + ECHO ^- X_VCPKG_APPLOCAL_DEPS_INSTALL='!X_VCPKG_APPLOCAL_DEPS_INSTALL!' + ECHO ^- CMAKE_GENERATOR='!CMAKE_GENERATOR!' IF DEFINED GITHUB_ENV ( - ECHO CMAKE_ARGS_EXTRA=-DX_VCPKG_APPLOCAL_DEPS_INSTALL=ON -DCMAKE_TOOLCHAIN_FILE=!CMAKE_TOOLCHAIN_FILE! -DVCPKG_TARGET_TRIPLET=x64-windows>>!GITHUB_ENV! - ECHO PATH=!PATH!>>!GITHUB_ENV! - ) else ( + ECHO VCPKG_ROOT=!VCPKG_ROOT!>>!GITHUB_ENV! + ECHO VCPKG_DEFAULT_TRIPLET=!VCPKG_DEFAULT_TRIPLET!>>!GITHUB_ENV! + ECHO X_VCPKG_APPLOCAL_DEPS_INSTALL=!X_VCPKG_APPLOCAL_DEPS_INSTALL!>>!GITHUB_ENV! + ECHO CMAKE_GENERATOR=!CMAKE_GENERATOR!>>!GITHUB_ENV! + ) ELSE ( + ECHO ^Generating "CMakeSettings.json"... CALL :GENERATE_CMakeSettings_JSON IF NOT EXIST %BUILD_ROOT% ( - ECHO ### Create subdirectory build ### + ECHO ^Creating subdirectory "build"... MD %BUILD_ROOT% ) IF NOT EXIST %INSTALL_ROOT% ( - ECHO ### Create subdirectory install ### + ECHO ^Creating subdirectory "install"... MD %INSTALL_ROOT% ) ) GOTO :EOF -:UNZIP - SET vbs="%temp%\_.vbs" - IF EXIST %vbs% del /f /q %vbs% - >%vbs% echo Set fso = CreateObject("Scripting.FileSystemObject") - >>%vbs% echo If NOT fso.FolderExists(%2) Then - >>%vbs% echo fso.CreateFolder(%2) - >>%vbs% echo End If - >>%vbs% echo Set objShell = CreateObject("Shell.Application") - >>%vbs% echo Set FilesInZip=objShell.NameSpace(%1).items - >>%vbs% echo objShell.NameSpace(%2).CopyHere(FilesInZip) - >>%vbs% echo Set fso = Nothing - >>%vbs% echo Set objShell = Nothing - cscript //nologo %vbs% - IF EXIST %vbs% DEL /f /q %vbs% - GOTO :EOF +:DETECT_SEVENZIP + SET SEVENZIP_PATH=7z.exe + !SEVENZIP_PATH! --help >NUL 2>NUL + IF errorlevel 1 ( + SET SEVENZIP_PATH="c:\Program Files\7-Zip\7z.exe" + !SEVENZIP_PATH! --help >NUL 2>NUL + IF errorlevel 1 ( + SET SEVENZIP_PATH="c:\Program Files (x86)\7-Zip\7z.exe" + !SEVENZIP_PATH! --help >NUL 2>NUL + if errorlevel 1 ( + SET SEVENZIP_PATH= + ) + ) + ) + SET RETVAL="!SEVENZIP_PATH!" + GOTO :EOF + + +:UNZIP_SEVENZIP <7zippath> + %1 x -o"%3" "%2" + GOTO :EOF + + +:UNZIP_POWERSHELL + SET SCRIPTDIR=%~dp0 + powershell -executionpolicy bypass -File "%SCRIPTDIR%\unzip.ps1" %1 %2 + GOTO :EOF :REALPATH @@ -120,23 +153,23 @@ EXIT /B 0 :READ_ENVNAME - ECHO ### Read name of prebuild environment from: %MIXXX_ROOT%\packaging\windows\build_environment ### + ECHO Reading name of prebuild environment from "%MIXXX_ROOT%\packaging\windows\build_environment" SET /P BUILDENV_NAME=<%MIXXX_ROOT%\packaging\windows\build_environment SET BUILDENV_NAME=!BUILDENV_NAME:PLATFORM=%PLATFORM%! SET BUILDENV_NAME=!BUILDENV_NAME:CONFIGURATION=%CONFIGURATION%! SET RETVAL=%BUILDENV_NAME% - ECHO "%RETVAL%" + ECHO Environment name: %RETVAL% GOTO :EOF :GENERATE_CMakeSettings_JSON REM Generate CMakeSettings.json which is read by MS Visual Studio to determine the supported CMake build environments SET CMakeSettings=%MIXXX_ROOT%\CMakeSettings.json IF EXIST %CMakeSettings% ( - ECHO ### CMakeSettings.json exist: Rename old file to CMakeSettings__YYYY-MM-DD_HH-MM-SS.json ### FOR /f "delims=" %%a in ('wmic OS Get localdatetime ^| find "."') do set DateTime=%%a - REN %CMakeSettings% CMakeSettings__!DateTime:~0,4!-!DateTime:~4,2!-!DateTime:~6,2!_!DateTime:~8,2!-!DateTime:~10,2!-!DateTime:~12,2!.json + SET CMakeSettingsBackup=CMakeSettings_!DateTime:~0,4!-!DateTime:~4,2!-!DateTime:~6,2!_!DateTime:~8,2!-!DateTime:~10,2!-!DateTime:~12,2!.json + ECHO CMakeSettings.json already exists, creating backup at "!CMakeSettingsBackup!"... + REN %CMakeSettings% !CMakeSettingsBackup! ) - ECHO ### Create new CMakeSettings.json ### CALL :SETANSICONSOLE SET OLDCODEPAGE=%RETVAL%