summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt36
-rw-r--r--build/debian/changelog2
-rw-r--r--build/features.py5
-rw-r--r--src/analyzer/plugins/analyzerqueenmarybeats.cpp24
-rw-r--r--src/controllers/dlgprefcontrollers.h8
-rw-r--r--src/controllers/hid/hidcontrollerpreset.h6
-rw-r--r--src/controllers/learningutils.cpp8
-rw-r--r--src/engine/controls/bpmcontrol.cpp15
-rw-r--r--src/engine/controls/bpmcontrol.h6
-rw-r--r--src/engine/enginebuffer.cpp4
-rw-r--r--src/engine/enginebuffer.h1
-rw-r--r--src/engine/sync/clock.h2
-rw-r--r--src/engine/sync/internalclock.h32
-rw-r--r--src/engine/sync/syncable.h4
-rw-r--r--src/library/banshee/bansheeplaylistmodel.h2
-rw-r--r--src/library/coverart.cpp110
-rw-r--r--src/library/coverart.h55
-rw-r--r--src/library/coverartcache.cpp107
-rw-r--r--src/library/coverartcache.h4
-rw-r--r--src/library/coverartdelegate.h2
-rw-r--r--src/library/dao/playlistdao.cpp2
-rw-r--r--src/library/dlgcoverartfullsize.cpp5
-rw-r--r--src/library/hiddentablemodel.h2
-rw-r--r--src/library/missingtablemodel.h2
-rw-r--r--src/library/playlisttablemodel.h2
-rw-r--r--src/library/songdownloader.cpp9
-rw-r--r--src/library/trackcollection.cpp51
-rw-r--r--src/library/trackcollection.h8
-rw-r--r--src/library/trackcollectionmanager.cpp27
-rw-r--r--src/library/trackcollectionmanager.h4
-rw-r--r--src/library/trackset/crate/cratetablemodel.h2
-rw-r--r--src/mixxx.cpp12
-rw-r--r--src/musicbrainz/tagfetcher.cpp23
-rw-r--r--src/musicbrainz/web/musicbrainzrecordingstask.cpp12
-rw-r--r--src/network/jsonwebtask.cpp16
-rw-r--r--src/network/webtask.cpp14
-rw-r--r--src/preferences/colorpalettesettings.cpp7
-rw-r--r--src/preferences/configobject.cpp4
-rw-r--r--src/preferences/configobject.h2
-rw-r--r--src/preferences/dialog/dlgprefcolors.cpp9
-rw-r--r--src/preferences/dialog/dlgprefcolors.h2
-rw-r--r--src/preferences/dialog/dlgprefrecord.cpp4
-rw-r--r--src/skin/skinloader.cpp2
-rw-r--r--src/soundio/sounddevice.cpp3
-rw-r--r--src/soundio/sounddevice.h2
-rw-r--r--src/soundio/sounddevicenetwork.h3
-rw-r--r--src/soundio/soundmanager.cpp4
-rw-r--r--src/soundio/soundmanager.h2
-rw-r--r--src/soundio/soundmanagerutil.cpp4
-rw-r--r--src/soundio/soundmanagerutil.h7
-rw-r--r--src/sources/audiosource.h2
-rw-r--r--src/sources/metadatasource.h3
-rw-r--r--src/sources/metadatasourcetaglib.cpp3
-rw-r--r--src/sources/soundsourceprovider.h3
-rw-r--r--src/sources/urlresource.h3
-rw-r--r--src/test/coverartcache_test.cpp18
-rw-r--r--src/test/coverartutils_test.cpp2
-rw-r--r--src/test/enginesynctest.cpp59
-rw-r--r--src/track/beats.h4
-rw-r--r--src/track/globaltrackcache.cpp46
-rw-r--r--src/track/globaltrackcache.h39
-rw-r--r--src/util/duration.cpp3
-rw-r--r--src/util/samplebuffer.h2
-rw-r--r--src/util/thread_affinity.h20
-rw-r--r--src/waveform/renderers/waveformmark.cpp7
-rw-r--r--src/waveform/renderers/waveformrendermark.cpp2
-rw-r--r--src/widget/wcoverartlabel.cpp4
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