summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUwe Klotz <uklotz@mixxx.org>2019-09-29 09:53:02 +0200
committerUwe Klotz <uklotz@mixxx.org>2019-09-29 09:53:02 +0200
commit1d882d8b5022005a120e23f20496f8cd9795d45c (patch)
tree5089fa8478860f26ec9e0a3f91f25269285bc76e
parenta1fdea2aef545ee0bd9f25027f0d66f936325cf8 (diff)
parent5998ee24e30361b3d14907d899e191a0aee16a3b (diff)
Merge branch 'master' of git@github.com:mixxxdj/mixxx.git into new-signals-slots-syntax-library
# Conflicts: # src/library/library.cpp # src/library/scanner/libraryscanner.cpp
-rw-r--r--build/depends.py1
-rw-r--r--default.nix16
-rw-r--r--res/controllers/midi-components-0.0.js54
-rw-r--r--src/engine/controls/loopingcontrol.cpp45
-rw-r--r--src/engine/controls/loopingcontrol.h10
-rw-r--r--src/engine/controls/ratecontrol.cpp7
-rw-r--r--src/engine/controls/ratecontrol.h1
-rw-r--r--src/engine/enginebuffer.cpp12
-rw-r--r--src/engine/enginebuffer.h2
-rw-r--r--src/library/dao/directorydao.cpp30
-rw-r--r--src/library/dao/directorydao.h2
-rw-r--r--src/library/dao/trackdao.cpp93
-rw-r--r--src/library/dao/trackdao.h10
-rw-r--r--src/library/dlghidden.cpp2
-rw-r--r--src/library/dlgmissing.cpp2
-rw-r--r--src/library/externaltrackcollection.cpp16
-rw-r--r--src/library/externaltrackcollection.h103
-rw-r--r--src/library/hiddentablemodel.cpp8
-rw-r--r--src/library/hiddentablemodel.h7
-rw-r--r--src/library/library.cpp285
-rw-r--r--src/library/library.h13
-rw-r--r--src/library/locationdelegate.cpp23
-rw-r--r--src/library/locationdelegate.h23
-rw-r--r--src/library/missingtablemodel.cpp15
-rw-r--r--src/library/missingtablemodel.h7
-rw-r--r--src/library/scanner/libraryscanner.cpp43
-rw-r--r--src/library/scanner/libraryscanner.h2
-rw-r--r--src/library/stareditor.cpp5
-rw-r--r--src/library/tableitemdelegate.cpp36
-rw-r--r--src/library/tableitemdelegate.h23
-rw-r--r--src/library/trackcollection.cpp37
-rw-r--r--src/library/trackcollection.h12
-rw-r--r--src/mixxxapplication.cpp18
-rw-r--r--src/preferences/upgrade.cpp2
-rw-r--r--src/sources/soundsourceproxy.cpp67
-rw-r--r--src/test/cuecontrol_test.cpp2
-rw-r--r--src/test/directorydaotest.cpp4
-rw-r--r--src/test/trackdao_test.cpp16
-rw-r--r--src/test/trackmetadata_test.cpp63
-rw-r--r--src/track/albuminfo.cpp9
-rw-r--r--src/track/albuminfo.h5
-rw-r--r--src/track/trackinfo.cpp70
-rw-r--r--src/track/trackinfo.h14
-rw-r--r--src/track/trackmetadatataglib.cpp668
-rw-r--r--src/track/trackrecord.h4
-rw-r--r--src/util/painterscope.h2
-rw-r--r--src/waveform/renderers/qtvsynctestrenderer.cpp5
-rw-r--r--src/waveform/renderers/qtwaveformrendererfilteredsignal.cpp5
-rw-r--r--src/waveform/renderers/qtwaveformrenderersimplesignal.cpp5
-rw-r--r--src/waveform/renderers/waveformrenderbeat.cpp6
-rw-r--r--src/waveform/renderers/waveformrendererendoftrack.cpp5
-rw-r--r--src/waveform/renderers/waveformrendererfilteredsignal.cpp6
-rw-r--r--src/waveform/renderers/waveformrendererhsv.cpp6
-rw-r--r--src/waveform/renderers/waveformrendererpreroll.cpp6
-rw-r--r--src/waveform/renderers/waveformrendererrgb.cpp6
-rw-r--r--src/waveform/renderers/waveformrendermark.cpp5
-rw-r--r--src/waveform/renderers/waveformrendermarkrange.cpp5
-rw-r--r--src/widget/paintable.cpp7
-rw-r--r--src/widget/wanalysislibrarytableview.cpp2
-rw-r--r--src/widget/wcoverart.cpp18
-rw-r--r--src/widget/wcoverart.h3
-rw-r--r--src/widget/wtracktableview.cpp103
-rw-r--r--src/widget/wtracktableview.h20
63 files changed, 1720 insertions, 382 deletions
diff --git a/build/depends.py b/build/depends.py
index a127271a46..3cb0980d8b 100644
--- a/build/depends.py
+++ b/build/depends.py
@@ -975,6 +975,7 @@ class MixxxCore(Feature):
"src/database/schemamanager.cpp",
"src/library/trackcollection.cpp",
+ "src/library/externaltrackcollection.cpp",
"src/library/basesqltablemodel.cpp",
"src/library/basetrackcache.cpp",
"src/library/columncache.cpp",
diff --git a/default.nix b/default.nix
index 1b674e0041..165206dc65 100644
--- a/default.nix
+++ b/default.nix
@@ -1,4 +1,7 @@
-{ nixroot ? (import <nixpkgs> {}) }:
+{ nixroot ? (import <nixpkgs> {})
+, defaultLv2Plugins ? false
+, lv2Plugins ? []
+}:
let inherit (nixroot) stdenv pkgs lib
chromaprint fftw flac libid3tag libmad libopus libshout libsndfile lilv
libusb1 libvorbis libebur128 pkgconfig portaudio portmidi protobuf qt5 glib
@@ -42,7 +45,7 @@ let inherit (nixroot) stdenv pkgs lib
shell-run = nixroot.writeShellScriptBin "run" ''
BUILDDIR=$(ls -1 -d -t lin64_build lin_build | head -1)
- $BUILDDIR/mixxx --settingsPath ./devsettings/ --resourcePath ./res "$@"
+ /usr/bin/env LV2_PATH=${lib.makeSearchPathOutput "lib" "lib/lv2" allLv2Plugins}:$LV2_PATH $BUILDDIR/mixxx --settingsPath ./devsettings/ --resourcePath ./res "$@"
'';
shell-debug = nixroot.writeShellScriptBin "debug" ''
@@ -50,6 +53,11 @@ let inherit (nixroot) stdenv pkgs lib
gdb --args $BUILDDIR/mixxx --settingsPath ./devsettings/ --resourcePath ./res "$@"
'';
+ allLv2Plugins = lv2Plugins ++ (if defaultLv2Plugins then [
+ nixroot.x42-plugins nixroot.zam-plugins nixroot.rkrlv2 nixroot.mod-distortion
+ nixroot.infamousPlugins nixroot.artyFX
+ ] else []);
+
in stdenv.mkDerivation rec {
name = "mixxx-${version}";
# reading the version from git output is very hard to do without wasting lots of diskspace and runtime
@@ -83,7 +91,7 @@ in stdenv.mkDerivation rec {
libusb1 libvorbis libebur128 pkgconfig portaudio portmidi protobuf qt5.full
rubberband scons sqlite taglib soundtouch vamp.vampSDK opusfile upower hidapi
ccache git glib x11 libGLU lilv lame lv2 makeWrapper qt5.qtbase
- ];
+ ] ++ allLv2Plugins;
sconsFlags = [
"build=debug"
@@ -102,7 +110,7 @@ in stdenv.mkDerivation rec {
installPhase = ''
runHook preInstall
scons $sconsFlags "prefix=$out" install
- wrapProgram $out/bin/mixxx --suffix QT_PLUGIN_PATH : ${qt5.qtbase}/${qt5.qtbase.qtPluginPrefix} --set QTDIR ${qt5.full}
+ wrapProgram $out/bin/mixxx --suffix QT_PLUGIN_PATH : ${qt5.qtbase}/${qt5.qtbase.qtPluginPrefix} --set QTDIR ${qt5.full} --prefix LV2_PATH : ${lib.makeSearchPath "lib/lv2" allLv2Plugins}
runHook postInstall
'';
diff --git a/res/controllers/midi-components-0.0.js b/res/controllers/midi-components-0.0.js
index 4dc43be1e9..7bb5c00957 100644
--- a/res/controllers/midi-components-0.0.js
+++ b/res/controllers/midi-components-0.0.js
@@ -533,6 +533,34 @@
}
}
},
+ forEachComponentContainer: function (operation, recursive) {
+ if (typeof operation !== 'function') {
+ print('ERROR: ComponentContainer.forEachComponentContainer requires a function argument');
+ return;
+ }
+ if (recursive === undefined) { recursive = true; }
+
+ var that = this;
+ var applyOperationTo = function (obj) {
+ if (obj instanceof ComponentContainer) {
+ operation.call(that, obj);
+
+ if (recursive) {
+ obj.forEachComponentContainer(operation);
+ }
+ } else if (Array.isArray(obj)) {
+ obj.forEach(function (element) {
+ applyOperationTo(element);
+ });
+ }
+ };
+
+ for (var memberName in this) {
+ if (this.hasOwnProperty(memberName)) {
+ applyOperationTo(this[memberName]);
+ }
+ }
+ },
reconnectComponents: function (operation, recursive) {
this.forEachComponent(function (component) {
component.disconnect();
@@ -545,6 +573,7 @@
},
isShifted: false,
shift: function () {
+ // Shift direct child Components
this.forEachComponent(function (component) {
// Controls for push type Buttons depend on getting reset to 0 when the
// Button is released for correct behavior. If there is a skin button
@@ -568,11 +597,18 @@
}
component.shift();
}
- // Set isShifted for child ComponentContainers forEachComponent is iterating through recursively
- this.isShifted = true;
- });
+ }, false);
+
+ // Shift child ComponentContainers
+ this.forEachComponentContainer(function (container) {
+ container.shift();
+ }, false);
+
+ // Set isShifted for each ComponentContainer recursively
+ this.isShifted = true;
},
unshift: function () {
+ // Unshift direct child Components
this.forEachComponent(function (component) {
// Refer to comment in ComponentContainer.shift() above for explanation
if (typeof component.unshift === 'function') {
@@ -588,9 +624,15 @@
}
component.unshift();
}
- // Set isShifted for child ComponentContainers forEachComponent is iterating through recursively
- this.isShifted = false;
- });
+ }, false);
+
+ // Unshift child ComponentContainers
+ this.forEachComponentContainer(function (container) {
+ container.unshift();
+ }, false);
+
+ // Unset isShifted for each ComponentContainer recursively
+ this.isShifted = false;
},
applyLayer: function (newLayer, reconnectComponents) {
if (reconnectComponents !== false) {
diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp
index 02f9e10fb4..245201df76 100644
--- a/src/engine/controls/loopingcontrol.cpp
+++ b/src/engine/controls/loopingcontrol.cpp
@@ -53,7 +53,7 @@ LoopingControl::LoopingControl(QString group,
m_loopSamples.setValue(m_oldLoopSamples);
m_currentSample.setValue(0.0);
m_pActiveBeatLoop = NULL;
-
+ m_pRateControl = NULL;
//Create loop-in, loop-out, loop-exit, and reloop/exit ControlObjects
m_pLoopInButton = new ControlPushButton(ConfigKey(group, "loop_in"));
connect(m_pLoopInButton, &ControlObject::valueChanged,
@@ -682,6 +682,10 @@ void LoopingControl::setLoopOutToCurrentPosition() {
m_loopSamples.setValue(loopSamples);
}
+void LoopingControl::setRateControl(RateControl* rateControl) {
+ m_pRateControl = rateControl;
+}
+
void LoopingControl::slotLoopOut(double pressed) {
if (m_pTrack == nullptr) {
return;
@@ -1060,16 +1064,19 @@ void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable
newloopSamples.start = currentSample;
}
} else {
- // loop_in is set to the previous beat if quantize is on. The
- // closest beat might be ahead of play position which would cause a seek.
- // TODO: If in reverse, should probably choose nextBeat.
+ // 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);
if (m_pQuantizeEnabled->toBool() && prevBeat != -1) {
+ double beatLength = nextBeat - prevBeat;
+ double loopLength = beatLength * beats;
+
+ double closestBeat = pBeats->findClosestBeat(currentSample);
if (beats >= 1.0) {
- newloopSamples.start = prevBeat;
+ newloopSamples.start = closestBeat;
} else {
// In case of beat length less then 1 beat:
// (| - beats, ^ - current track's position):
@@ -1078,15 +1085,29 @@ void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable
//
// If we press 1/2 beatloop we want loop from 50% to 100%,
// If I press 1/4 beatloop, we want loop from 50% to 75% etc
- double beat_len = nextBeat - prevBeat;
- double loops_per_beat = 1.0 / beats;
- double beat_pos = currentSample - prevBeat;
- int beat_frac =
- static_cast<int>(floor((beat_pos / beat_len) *
- loops_per_beat));
- newloopSamples.start = prevBeat + beat_len / loops_per_beat * beat_frac;
+ double samplesSinceLastBeat = currentSample - prevBeat;
+
+ // find the previous beat fraction and check if the current position is closer to this or the next one
+ // place the new loop start to the closer one
+ double previousFractionBeat = prevBeat + floor(samplesSinceLastBeat / loopLength) * loopLength;
+ double samplesSinceLastFractionBeat = currentSample - previousFractionBeat;
+
+ if (samplesSinceLastFractionBeat <= (loopLength / 2.0)) {
+ newloopSamples.start = previousFractionBeat;
+ } else {
+ newloopSamples.start = previousFractionBeat + loopLength;
+ }
}
+ // If running reverse, move the loop one loop size to the left.
+ // Thus, the loops end will be closest to the current position
+ bool reverse = false;
+ if (m_pRateControl != NULL) {
+ reverse = m_pRateControl->isReverseButtonPressed();
+ }
+ if (reverse) {
+ newloopSamples.start -= loopLength;
+ }
} else {
newloopSamples.start = currentSample;
}
diff --git a/src/engine/controls/loopingcontrol.h b/src/engine/controls/loopingcontrol.h
index 55d4f0c15f..6be5fdb78b 100644
--- a/src/engine/controls/loopingcontrol.h
+++ b/src/engine/controls/loopingcontrol.h
@@ -8,11 +8,12 @@
#include <QObject>
#include <QStack>
-#include "preferences/usersettings.h"
+#include "control/controlvalue.h"
#include "engine/controls/enginecontrol.h"
-#include "track/track.h"
+#include "engine/controls/ratecontrol.h"
+#include "preferences/usersettings.h"
#include "track/beats.h"
-#include "control/controlvalue.h"
+#include "track/track.h"
#define MINIMUM_AUDIBLE_LOOP_SIZE 300 // In samples
@@ -50,7 +51,7 @@ class LoopingControl : public EngineControl {
double getSyncPositionInsideLoop(double dRequestedPlaypos, double dSyncedPlayPos);
void notifySeek(double dNewPlaypos) override;
-
+ void setRateControl(RateControl* rateControl);
bool isLoopingEnabled();
public slots:
@@ -129,6 +130,7 @@ class LoopingControl : public EngineControl {
ControlPushButton* m_pLoopHalveButton;
ControlPushButton* m_pLoopDoubleButton;
ControlObject* m_pSlipEnabled;
+ RateControl* m_pRateControl;
ControlObject* m_pPlayButton;
bool m_bLoopingEnabled;
diff --git a/src/engine/controls/ratecontrol.cpp b/src/engine/controls/ratecontrol.cpp
index 75c7327b10..5ee5af58ff 100644
--- a/src/engine/controls/ratecontrol.cpp
+++ b/src/engine/controls/ratecontrol.cpp
@@ -556,3 +556,10 @@ void RateControl::resetRateTemp(void)
void RateControl::notifySeek(double playPos) {
m_pScratchController->notifySeek(playPos);
}
+
+bool RateControl::isReverseButtonPressed() {
+ if (m_pReverseButton) {
+ return m_pReverseButton->toBool();
+ }
+ return false;
+}
diff --git a/src/engine/controls/ratecontrol.h b/src/engine/controls/ratecontrol.h
index 635ae15b2e..a53dfd383f 100644
--- a/src/engine/controls/ratecontrol.h
+++ b/src/engine/controls/ratecontrol.h
@@ -78,6 +78,7 @@ public:
static void setRateRampSensitivity(int);
static int getRateRampSensitivity();
void notifySeek(double dNewPlaypos) override;
+ bool isReverseButtonPressed();
public slots:
void slotReverseRollActivate(double);
diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp
index 2c10c3bfe8..5ba47c24a5 100644
--- a/src/engine/enginebuffer.cpp
+++ b/src/engine/enginebuffer.cpp
@@ -180,14 +180,13 @@ EngineBuffer::EngineBuffer(const QString& group, UserSettingsPointer pConfig,
// quantization (alignment) of loop in/out positions and (hot)cues with
// beats.
QuantizeControl* quantize_control = new QuantizeControl(group, pConfig);
+ addControl(quantize_control);
+ m_pQuantize = ControlObject::getControl(ConfigKey(group, "quantize"));
// Create the Loop Controller
m_pLoopingControl = new LoopingControl(group, pConfig);
addControl(m_pLoopingControl);
- addControl(quantize_control);
- m_pQuantize = ControlObject::getControl(ConfigKey(group, "quantize"));
-
m_pEngineSync = pMixingEngine->getEngineSync();
m_pSyncControl = new SyncControl(group, pConfig, pChannel, m_pEngineSync);
@@ -198,9 +197,12 @@ EngineBuffer::EngineBuffer(const QString& group, UserSettingsPointer pConfig,
addControl(m_pVinylControlControl);
#endif
+ // Create the Rate Controller
m_pRateControl = new RateControl(group, pConfig);
// Add the Rate Controller
addControl(m_pRateControl);
+ // Looping Control needs Rate Control for Reverse Button
+ m_pLoopingControl->setRateControl(m_pRateControl);
// Create the BPM Controller
m_pBpmControl = new BpmControl(group, pConfig);
@@ -532,6 +534,10 @@ TrackPointer EngineBuffer::getLoadedTrack() const {
return m_pCurrentTrack;
}
+bool EngineBuffer::isReverse() {
+ return m_reverse_old;
+}
+
void EngineBuffer::ejectTrack() {
// clear track values in any case, this may fix Bug #1450424
//qDebug() << "EngineBuffer::ejectTrack()";
diff --git a/src/engine/enginebuffer.h b/src/engine/enginebuffer.h
index 46735d16fa..394794225f 100644
--- a/src/engine/enginebuffer.h
+++ b/src/engine/enginebuffer.h
@@ -146,6 +146,8 @@ class EngineBuffer : public EngineObject {
bool getQueuedSeekPosition(double* pSeekPosition);
TrackPointer getLoadedTrack() const;
+ bool isReverse();
+
double getExactPlayPos();
double getVisualPlayPos();
double getTrackSamples();
diff --git a/src/library/dao/directorydao.cpp b/src/library/dao/directorydao.cpp
index c490ef959d..15338680c7 100644
--- a/src/library/dao/directorydao.cpp
+++ b/src/library/dao/directorydao.cpp
@@ -14,7 +14,6 @@
int DirectoryDAO::addDirectory(const QString& newDir) {
// Do nothing if the dir to add is a child of a directory that is already in
// the db.
- ScopedTransaction transaction(m_database);
QStringList dirs = getDirs();
QString childDir;
QString parentDir;
@@ -46,7 +45,6 @@ int DirectoryDAO::addDirectory(const QString& newDir) {
LOG_FAILED_QUERY(query) << "Adding new dir (" % newDir % ") failed.";
return SQL_ERROR;
}
- transaction.commit();
return ALL_FINE;
}
@@ -80,13 +78,12 @@ int DirectoryDAO::removeDirectory(const QString& dir) {
}
-QSet<TrackId> DirectoryDAO::relocateDirectory(const QString& oldFolder,
+QList<TrackRef> DirectoryDAO::relocateDirectory(const QString& oldFolder,
const QString& newFolder) {
// TODO(rryan): This method could use error reporting. It can fail in
// mysterious ways for example if a track in the oldFolder also has a zombie
// track location in newFolder then the replace query will fail because the
// location column becomes non-unique.
- ScopedTransaction transaction(m_database);
QSqlQuery query(m_database);
query.prepare("UPDATE " % DIRECTORYDAO_TABLE % " SET " % DIRECTORYDAO_DIR %
"=:newFolder WHERE " % DIRECTORYDAO_DIR % " = :oldFolder");
@@ -95,7 +92,7 @@ QSet<TrackId> DirectoryDAO::relocateDirectory(const QString& oldFolder,
if (!query.exec()) {
LOG_FAILED_QUERY(query) << "could not relocate directory"
<< oldFolder << "to" << newFolder;
- return QSet<TrackId>();
+ return {};
}
// on Windows the absolute path starts with the drive name
@@ -113,35 +110,32 @@ QSet<TrackId> DirectoryDAO::relocateDirectory(const QString& oldFolder,
.arg(startsWithOldFolder, kSqlLikeMatchAll));
if (!query.exec()) {
LOG_FAILED_QUERY(query) << "could not relocate path of tracks";
- return QSet<TrackId>();
+ return {};
}
- QSet<TrackId> trackIds;
- QList<int> loc_ids;
- QStringList old_locs;
+ QList<DbId> loc_ids;
+ QList<TrackRef> trackRefs;
while (query.next()) {
- trackIds.insert(TrackId(query.value(0)));
- loc_ids.append(query.value(1).toInt());
- old_locs.append(query.value(2).toString());
+ loc_ids.append(DbId(query.value(1).toInt()));
+ trackRefs.append(TrackRef::fromFileInfo(query.value(2).toString(), TrackId(query.value(0))));
}
QString replacement = "UPDATE track_locations SET location = :newloc "
"WHERE id = :id";
query.prepare(replacement);
for (int i = 0; i < loc_ids.size(); ++i) {
- QString newloc = old_locs.at(i);
+ QString newloc = trackRefs.at(i).getLocation();
newloc.replace(0, oldFolder.size(), newFolder);
query.bindValue("newloc", newloc);
- query.bindValue("id", loc_ids.at(i));
+ query.bindValue("id", loc_ids.at(i).toVariant());
if (!query.exec()) {
LOG_FAILED_QUERY(query) << "could not relocate path of tracks";
- return QSet<TrackId>();
+ return {};
}
}
- qDebug() << "Relocated tracks:" << trackIds.size();
- transaction.commit();
- return trackIds;
+ qDebug() << "Relocated tracks:" << trackRefs.size();
+ return trackRefs;
}
QStringList DirectoryDAO::getDirs() {
diff --git a/src/library/dao/directorydao.h b/src/library/dao/directorydao.h
index 827bd4a703..6892021a96 100644
--- a/src/library/dao/directorydao.h
+++ b/src/library/dao/directorydao.h
@@ -21,7 +21,7 @@ class DirectoryDAO : public DAO {