diff options
67 files changed, 596 insertions, 303 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 4de77ad879..47aa8a0599 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2181,7 +2181,7 @@ endif() # QtKeychain find_package(Qt5Keychain QUIET) -option(QTKEYCHAIN "Secure credentials storage support for Live Broadcasting profiles" OFF) +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.") @@ -2191,20 +2191,8 @@ if(QTKEYCHAIN) target_include_directories(mixxx-lib PUBLIC ${QTKEYCHAIN_INCLUDE_DIRS}) endif() -# USB Bulk controller support +# USB HID or/and Bulk controller support find_package(LibUSB) -cmake_dependent_option(BULK "USB Bulk controller support" ON "LibUSB_FOUND" OFF) -if(BULK) - if(NOT LibUSB_FOUND) - message(FATAL_ERROR "USB Bulk controller support requires libusb 1.0 and its development headers.") - endif() - target_sources(mixxx-lib PRIVATE - src/controllers/bulk/bulkcontroller.cpp - src/controllers/bulk/bulkenumerator.cpp - ) - target_compile_definitions(mixxx-lib PUBLIC __BULK__) - target_link_libraries(mixxx-lib PUBLIC LibUSB::LibUSB) -endif() # USB HID controller support find_package(HIDAPI) @@ -2245,6 +2233,26 @@ if(HID) endif() endif() +# USB Bulk controller support +cmake_dependent_option(BULK "USB Bulk controller support" ON "LibUSB_FOUND" OFF) +if(BULK) + if(NOT LibUSB_FOUND) + message(FATAL_ERROR "USB Bulk controller support requires libusb 1.0 and its development headers.") + endif() + target_sources(mixxx-lib PRIVATE + src/controllers/bulk/bulkcontroller.cpp + src/controllers/bulk/bulkenumerator.cpp + ) + if(NOT HID) + target_sources(mixxx-lib PRIVATE + src/controllers/hid/hidcontrollerpreset.cpp + src/controllers/hid/hidcontrollerpresetfilehandler.cpp + ) + endif() + target_compile_definitions(mixxx-lib PUBLIC __BULK__) + target_link_libraries(mixxx-lib PUBLIC LibUSB::LibUSB) +endif() + # Vinyl Control cmake_dependent_option(VINYLCONTROL "Vinyl Control support" ON "NOT MACAPPSTORE" OFF) if(VINYLCONTROL) diff --git a/build/debian/changelog b/build/debian/changelog index f0ac68b858..fbfc06ea56 100644 --- a/build/debian/changelog +++ b/build/debian/changelog @@ -1,4 +1,4 @@ -mixxx (2.2.3-0ubuntu1) bionic; urgency=medium +mixxx (2.2.4-0ubuntu3) bionic; urgency=medium * Bugfix release diff --git a/build/features.py b/build/features.py index 60f75dbb2d..31d38dd187 100644 --- a/build/features.py +++ b/build/features.py @@ -157,7 +157,8 @@ class Bulk(Feature): 'src/controllers/bulk/bulkenumerator.cpp'] if not int(build.flags['hid']): sources.append( - 'src/controllers/hid/hidcontrollerpresetfilehandler.cpp') + ['src/controllers/hid/hidcontrollerpresetfilehandler.cpp', + 'src/controllers/hid/hidcontrollerpreset.cpp']) return sources @@ -1212,7 +1213,7 @@ class QtKeychain(Feature): return "Secure credentials storage support for Live Broadcasting profiles" def enabled(self, build): - build.flags['qtkeychain'] = util.get_flags(build.env, 'qtkeychain', 0) + build.flags['qtkeychain'] = util.get_flags(build.env, 'qtkeychain', 1) if int(build.flags['qtkeychain']): return True return False diff --git a/src/analyzer/plugins/analyzerqueenmarybeats.cpp b/src/analyzer/plugins/analyzerqueenmarybeats.cpp index 7dbd6048f9..095b61f9c6 100644 --- a/src/analyzer/plugins/analyzerqueenmarybeats.cpp +++ b/src/analyzer/plugins/analyzerqueenmarybeats.cpp @@ -9,9 +9,18 @@ namespace mixxx { namespace { -// stepsize should be equivalent to ~10ms and this constant (11.61ms) make the number -// of samples an exact power of 2 for 22.1k, 44.1k, and very close to, for 96k and 192k -constexpr float kStepSecs = 0.01161; + +// This determines the resolution of the resulting BeatMap. +// ~12 ms (86 Hz) is a fair compromise between accuracy and analysis speed, +// also matching the preferred window/step sizes from BeatTrack VAMP. +// For a 44.1 kHz track, we go in 512 sample steps +// TODO: kStepSecs and the waveform sample rate of 441 +// (defined in AnalyzerWaveform::initialize) do not align well and thus +// generate interference. Currently we are at this odd factor: 441 * 0.01161 = 5.12. +// This should be adjusted to be an integer. +constexpr float kStepSecs = 0.01161; +// 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) { // These are the defaults for the VAMP beat tracker plugin we used in Mixxx @@ -30,7 +39,9 @@ DFConfig makeDetectionFunctionConfig(int stepSize, int windowSize) { } // namespace AnalyzerQueenMaryBeats::AnalyzerQueenMaryBeats() - : m_iSampleRate(0) { + : m_iSampleRate(0), + m_windowSize(0), + m_stepSize(0) { } AnalyzerQueenMaryBeats::~AnalyzerQueenMaryBeats() { @@ -39,9 +50,8 @@ AnalyzerQueenMaryBeats::~AnalyzerQueenMaryBeats() { bool AnalyzerQueenMaryBeats::initialize(int samplerate) { m_detectionResults.clear(); m_iSampleRate = samplerate; - // These are the preferred window/step sizes from the BeatTrack VAMP - m_stepSize = int(m_iSampleRate * kStepSecs + 0.0001); - m_windowSize = m_stepSize * 2; + m_stepSize = m_iSampleRate * kStepSecs; + m_windowSize = MathUtilities::nextPowerOfTwo(m_iSampleRate / kMaximumBinSizeHz); m_pDetectionFunction = std::make_unique<DetectionFunction>( makeDetectionFunctionConfig(m_stepSize, m_windowSize)); qDebug() << "input sample rate is " << m_iSampleRate << ", step size is " << m_stepSize; diff --git a/src/controllers/dlgprefcontrollers.h b/src/controllers/dlgprefcontrollers.h index ce06dfc822..82f1530e80 100644 --- a/src/controllers/dlgprefcontrollers.h +++ b/src/controllers/dlgprefcontrollers.h @@ -28,13 +28,13 @@ class DlgPrefControllers : public DlgPreferencePage, public Ui::DlgPrefControlle public slots: /// Called when the preference dialog (not this page) is shown to the user. - void slotUpdate(); + void slotUpdate() override; /// Called when the user clicks the global "Apply" button. - void slotApply(); + void slotApply() override; /// Called when the user clicks the global "Cancel" button. - void slotCancel(); + void slotCancel() override; /// Called when the user clicks the global "Reset to Defaults" button. - void slotResetToDefaults(); + void slotResetToDefaults() override; private slots: void rescanControllers(); diff --git a/src/controllers/hid/hidcontrollerpreset.h b/src/controllers/hid/hidcontrollerpreset.h index 93108f4304..08aed79722 100644 --- a/src/controllers/hid/hidcontrollerpreset.h +++ b/src/controllers/hid/hidcontrollerpreset.h @@ -10,8 +10,10 @@ /// elements that make it up. class HidControllerPreset : public ControllerPreset { public: - HidControllerPreset() {} - virtual ~HidControllerPreset() {} + HidControllerPreset() { + } + ~HidControllerPreset() override { + } bool savePreset(const QString& fileName) const override; diff --git a/src/controllers/learningutils.cpp b/src/controllers/learningutils.cpp index 4df4710df3..388fc3cc5d 100644 --- a/src/controllers/learningutils.cpp +++ b/src/controllers/learningutils.cpp @@ -244,9 +244,9 @@ MidiInputMappings LearningUtils::guessMidiInputMappings( } } } else if (one_channel && only_cc && stats.controls.size() == 2 && - stats_by_control.begin()->message_count > 10 && - stats_by_control.begin()->message_count == - (stats_by_control.begin() + 1)->message_count) { + stats_by_control.begin()->message_count > 10 && + stats_by_control.begin()->message_count == + (++stats_by_control.begin())->message_count) { // If there are two CC controls with the same number of messages then we // assume this is a 14-bit CC knob. Now we need to determine which // control is the LSB and which is the MSB. @@ -257,7 +257,7 @@ MidiInputMappings LearningUtils::guessMidiInputMappings( // between messages. We expect to see many high/low wrap-arounds for the // LSB. int control1 = *stats.controls.begin(); - int control2 = *(stats.controls.begin() + 1); + int control2 = *(++stats.controls.begin()); int control1_max_abs_diff = (stats_by_control[control1].abs_diff_histogram.end() - 1).key(); diff --git a/src/engine/controls/bpmcontrol.cpp b/src/engine/controls/bpmcontrol.cpp index 0d1bde3af0..c2baca7c26 100644 --- a/src/engine/controls/bpmcontrol.cpp +++ b/src/engine/controls/bpmcontrol.cpp @@ -426,7 +426,8 @@ double BpmControl::calcSyncAdjustment(bool userTweakingSync) { // boundaries too. double syncTargetBeatDistance = m_dSyncTargetBeatDistance.getValue(); - double thisBeatDistance = m_pThisBeatDistance->get(); + // We want the untweaked beat distance, so we have to add the offset here. + double thisBeatDistance = m_pThisBeatDistance->get() + m_dUserOffset.getValue(); double shortest_distance = shortestPercentageChange( syncTargetBeatDistance, thisBeatDistance); @@ -737,7 +738,7 @@ double BpmControl::getBeatMatchPosition( } EngineBuffer* pOtherEngineBuffer = nullptr; - // explicit master always syncs to itself, so set to null + // explicit master always syncs to itself, so keep it null if (getSyncMode() != SYNC_MASTER_EXPLICIT) { pOtherEngineBuffer = pickSyncTarget(); } @@ -762,11 +763,11 @@ double BpmControl::getBeatMatchPosition( dThisPosition > dThisNextBeat || (dThisPrevBeat != -1 && dThisPosition < dThisPrevBeat)) { if (kLogger.traceEnabled()) { - kLogger.trace() << "BpmControl::getNearestPositionInPhase out of date" - << dThisPosition << dThisNextBeat << dThisPrevBeat; + kLogger.trace() << "BpmControl::getBeatMatchPosition out of date" + << dThisPrevBeat << dThisPosition << dThisNextBeat; } // This happens if dThisPosition is the target position of a requested - // seek command + // seek command. Get new prev and next beats for the calculation. getBeatContext( m_pBeats, dThisPosition, @@ -780,6 +781,10 @@ double BpmControl::getBeatMatchPosition( return dThisPosition; } } else { + if (kLogger.traceEnabled()) { + kLogger.trace() << "BpmControl::getBeatMatchPosition up to date" + << dThisPrevBeat << dThisPosition << dThisNextBeat; + } // We are between the previous and next beats so we can try a standard // lookup of the beat length. getBeatContextNoLookup( diff --git a/src/engine/controls/bpmcontrol.h b/src/engine/controls/bpmcontrol.h index bbbc7af404..d191f77ef7 100644 --- a/src/engine/controls/bpmcontrol.h +++ b/src/engine/controls/bpmcontrol.h @@ -39,12 +39,16 @@ class BpmControl : public EngineControl { double getNearestPositionInPhase(double dThisPosition, bool respectLoops, bool playing); double getBeatMatchPosition(double dThisPosition, bool respectLoops, bool playing); double getPhaseOffset(double dThisPosition); + /// getBeatDistance is adjusted to include the user offset so it's + /// transparent to other decks. double getBeatDistance(double dThisPosition) const; void setTargetBeatDistance(double beatDistance); void setInstantaneousBpm(double instantaneousBpm); void resetSyncAdjustment(); double updateLocalBpm(); + /// updateBeatDistance is adjusted to include the user offset so + /// it's transparent to other decks. double updateBeatDistance(); void collectFeatures(GroupFeatureState* pGroupFeatures) const; @@ -163,7 +167,7 @@ class BpmControl : public EngineControl { mixxx::BeatsPointer m_pBeats; FRIEND_TEST(EngineSyncTest, UserTweakBeatDistance); + FRIEND_TEST(EngineSyncTest, UserTweakPreservedInSeek); }; - #endif // BPMCONTROL_H diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index a2aab2004b..e3b58a4c59 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -1198,7 +1198,9 @@ void EngineBuffer::processSeek(bool paused) { double syncPosition = m_pBpmControl->getBeatMatchPosition(position, true, true); position = m_pLoopingControl->getSyncPositionInsideLoop(requestedPosition, syncPosition); if (kLogger.traceEnabled()) { - kLogger.trace() << "EngineBuffer::processSeek seek info: " << m_filepos_play << " " << position; + kLogger.trace() + << "EngineBuffer::processSeek seek info: " << m_filepos_play + << " -> " << position; } } if (position != m_filepos_play) { diff --git a/src/engine/enginebuffer.h b/src/engine/enginebuffer.h index f0a8fb9909..e3ede11099 100644 --- a/src/engine/enginebuffer.h +++ b/src/engine/enginebuffer.h @@ -265,6 +265,7 @@ class EngineBuffer : public EngineObject { FRIEND_TEST(EngineSyncTest, HalfDoubleBpmTest); FRIEND_TEST(EngineSyncTest, HalfDoubleThenPlay); FRIEND_TEST(EngineSyncTest, UserTweakBeatDistance); + FRIEND_TEST(EngineSyncTest, UserTweakPreservedInSeek); FRIEND_TEST(EngineSyncTest, BeatMapQantizePlay); FRIEND_TEST(EngineBufferTest, ScalerNoTransport); EngineSync* m_pEngineSync; diff --git a/src/engine/sync/clock.h b/src/engine/sync/clock.h index b772b2d495..da7de81de4 100644 --- a/src/engine/sync/clock.h +++ b/src/engine/sync/clock.h @@ -3,7 +3,7 @@ class Clock { public: - virtual ~Clock() {} + virtual ~Clock() = default; virtual double getBeatDistance() const = 0; virtual void setMasterBeatDistance(double beatDistance) = 0; diff --git a/src/engine/sync/internalclock.h b/src/engine/sync/internalclock.h index 85814c9a29..085fe7d9c5 100644 --- a/src/engine/sync/internalclock.h +++ b/src/engine/sync/internalclock.h @@ -23,36 +23,36 @@ class InternalClock : public QObject, public Clock, public Syncable { Q_OBJECT public: InternalClock(const char* pGroup, SyncableListener* pEngineSync); - virtual ~InternalClock(); + ~InternalClock() override; - const QString& getGroup() const { + const QString& getGroup() const override { return m_group; } - EngineChannel* getChannel() const { - return NULL; + EngineChannel* getChannel() const override { + return nullptr; } - void setSyncMode(SyncMode mode); - void notifyOnlyPlayingSyncable(); - void requestSync(); - SyncMode getSyncMode() const { + void setSyncMode(SyncMode mode) override; + void notifyOnlyPlayingSyncable() override; + void requestSync() override; + SyncMode getSyncMode() const override { return m_mode; } // The clock is always "playing" in a sense but this specifically refers to // decks so always return false. - bool isPlaying() const { + bool isPlaying() const override { return false; } - double getBeatDistance() const; - void setMasterBeatDistance(double beatDistance); + double getBeatDistance() const override; + void setMasterBeatDistance(double beatDistance) override; - double getBaseBpm() const; - void setMasterBpm(double bpm); - double getBpm() const; - void setInstantaneousBpm(double bpm); - void setMasterParams(double beatDistance, double baseBpm, double bpm); + double getBaseBpm() const override; + void setMasterBpm(double bpm) override; + double getBpm() const override; + void setInstantaneousBpm(double bpm) override; + void setMasterParams(double beatDistance, double baseBpm, double bpm) override; void onCallbackStart(int sampleRate, int bufferSize); void onCallbackEnd(int sampleRate, int bufferSize); diff --git a/src/engine/sync/syncable.h b/src/engine/sync/syncable.h index 3e8a0a1c94..2f3513a191 100644 --- a/src/engine/sync/syncable.h +++ b/src/engine/sync/syncable.h @@ -40,7 +40,7 @@ inline bool isMaster(SyncMode mode) { /// in Master Sync. class Syncable { public: - virtual ~Syncable() { } + virtual ~Syncable() = default; virtual const QString& getGroup() const = 0; virtual EngineChannel* getChannel() const = 0; @@ -99,7 +99,7 @@ class Syncable { /// information about sync change requests. class SyncableListener { public: - virtual ~SyncableListener() {} + virtual ~SyncableListener() = default; // Used by Syncables to tell EngineSync it wants to be enabled in a // specific mode. If the state change is accepted, EngineSync calls diff --git a/src/library/banshee/bansheeplaylistmodel.h b/src/library/banshee/bansheeplaylistmodel.h index d6cad06cf5..f632c04e67 100644 --- a/src/library/banshee/bansheeplaylistmodel.h +++ b/src/library/banshee/bansheeplaylistmodel.h @@ -11,7 +11,7 @@ #include "library/stardelegate.h" #include "library/basesqltablemodel.h" -class BansheePlaylistModel : public BaseSqlTableModel { +class BansheePlaylistModel final : public BaseSqlTableModel { Q_OBJECT public: BansheePlaylistModel(QObject* pParent, TrackCollectionManager* pTrackCollectionManager, BansheeDbConnection* pConnection); diff --git a/src/library/coverart.cpp b/src/library/coverart.cpp index 491dbbe139..85620cdd87 100644 --- a/src/library/coverart.cpp +++ b/src/library/coverart.cpp @@ -1,5 +1,7 @@ #include "library/coverart.h" +#include <QDebugStateSaver> + #include "library/coverartutils.h" #include "util/debug.h" #include "util/logger.h" @@ -83,19 +85,27 @@ QDebug operator<<(QDebug dbg, const CoverInfoRelative& infoRelative) { .arg(coverInfoRelativeToString(infoRelative)); } -QImage CoverInfo::loadImage( +CoverInfo::LoadedImage CoverInfo::loadImage( const SecurityTokenPointer& pTrackLocationToken) const { + LoadedImage loadedImage(LoadedImage::Result::ErrorUnknown); if (type == CoverInfo::METADATA) { VERIFY_OR_DEB |