diff --git a/.eslintrc.json b/.eslintrc.json
index 7d2927c69ba..5b871fcb9b9 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -84,6 +84,7 @@
"object-curly-spacing": "warn",
"prefer-const": "warn",
"prefer-regex-literals": "warn",
+ "prefer-template": "warn",
"quotes": [ "warn", "double" ],
"require-atomic-updates": "error",
"semi": "warn",
diff --git a/cmake/modules/FindTagLib.cmake b/cmake/modules/FindTagLib.cmake
index 63aa6d8c25e..7e907f6794b 100644
--- a/cmake/modules/FindTagLib.cmake
+++ b/cmake/modules/FindTagLib.cmake
@@ -48,8 +48,8 @@ include(IsStaticLibrary)
find_package(PkgConfig QUIET)
if(PkgConfig_FOUND)
if(UNIX AND NOT APPLE)
- # priorize the taglib1 package introduced in https://aur.archlinux.org/packages/taglib1
- set(ENV{PKG_CONFIG_PATH} "/usr/lib/taglib1/lib/pkgconfig/:$ENV{PKG_CONFIG_PATH}")
+ # priorize the taglib1 package introduced in https://www.archlinux.de/packages/extra/x86_64/taglib1
+ set(ENV{PKG_CONFIG_PATH} "/usr/lib/taglib1/pkgconfig/:$ENV{PKG_CONFIG_PATH}")
endif()
pkg_check_modules(PC_TagLib QUIET taglib)
endif()
diff --git a/res/controllers/Pioneer-DDJ-FLX4-script.js b/res/controllers/Pioneer-DDJ-FLX4-script.js
index 3514f52421e..3c1db2b4c97 100644
--- a/res/controllers/Pioneer-DDJ-FLX4-script.js
+++ b/res/controllers/Pioneer-DDJ-FLX4-script.js
@@ -276,6 +276,18 @@ PioneerDDJFLX4.init = function() {
PioneerDDJFLX4.sendKeepAlive(); // the query seems to double as a keep alive message
};
+//
+// Waveform zoom
+//
+
+PioneerDDJFLX4.waveformZoom = function(midichan, control, value, status, group) {
+ if (value === 0x7f) {
+ script.triggerControl(group, "waveform_zoom_up", 100);
+ } else {
+ script.triggerControl(group, "waveform_zoom_down", 100);
+ }
+};
+
//
// Channel level lights
//
diff --git a/res/controllers/Pioneer-DDJ-FLX4.midi.xml b/res/controllers/Pioneer-DDJ-FLX4.midi.xml
index 1e99c3d0cbd..12875bbd5a4 100644
--- a/res/controllers/Pioneer-DDJ-FLX4.midi.xml
+++ b/res/controllers/Pioneer-DDJ-FLX4.midi.xml
@@ -25,6 +25,16 @@
+
+ BROWSE +SHIFT - Zoom waveform
+ [Channel1]
+ PioneerDDJFLX4.waveformZoom
+ 0xB6
+ 0x64
+
+
+
+
BROWSE - press - Move cursor between track list and tree view
[Library]
diff --git a/res/controllers/Traktor-Kontrol-F1-scripts.js b/res/controllers/Traktor-Kontrol-F1-scripts.js
index c02d2ca2172..7c004cf3b4d 100644
--- a/res/controllers/Traktor-Kontrol-F1-scripts.js
+++ b/res/controllers/Traktor-Kontrol-F1-scripts.js
@@ -75,94 +75,94 @@ function KontrolF1Controller() {
this.registerOutputPackets = function() {
var packet = new HIDPacket("lights", 0x80);
// Right 7-segment element - 0x0 off, 0x40 on
- packet.addControl("hid", "right_segment_dp", 0,"B");
- packet.addControl("hid", "right_segment_1", 1,"B");
- packet.addControl("hid", "right_segment_2", 2,"B");
- packet.addControl("hid", "right_segment_3", 3,"B");
- packet.addControl("hid", "right_segment_4", 4,"B");
- packet.addControl("hid", "right_segment_5", 5,"B");
- packet.addControl("hid", "right_segment_6", 6,"B");
- packet.addControl("hid", "right_segment_7", 7,"B");
+ packet.addOutput("hid", "right_segment_dp", 1, "B");
+ packet.addOutput("hid", "right_segment_1", 2, "B");
+ packet.addOutput("hid", "right_segment_2", 3, "B");
+ packet.addOutput("hid", "right_segment_3", 4, "B");
+ packet.addOutput("hid", "right_segment_4", 5, "B");
+ packet.addOutput("hid", "right_segment_5", 6, "B");
+ packet.addOutput("hid", "right_segment_6", 7, "B");
+ packet.addOutput("hid", "right_segment_7", 8, "B");
// Left 7-segment element - 0x0 off, 0x40 on
- packet.addControl("hid", "left_segment_dp", 8,"B");
- packet.addControl("hid", "left_segment_1", 9,"B");
- packet.addControl("hid", "left_segment_2", 10,"B");
- packet.addControl("hid", "left_segment_3", 11,"B");
- packet.addControl("hid", "left_segment_4", 12,"B");
- packet.addControl("hid", "left_segment_5", 13,"B");
- packet.addControl("hid", "left_segment_6", 14,"B");
- packet.addControl("hid", "left_segment_7", 15,"B");
+ packet.addOutput("hid", "left_segment_dp", 9, "B");
+ packet.addOutput("hid", "left_segment_1", 10, "B");
+ packet.addOutput("hid", "left_segment_2", 11, "B");
+ packet.addOutput("hid", "left_segment_3", 12, "B");
+ packet.addOutput("hid", "left_segment_4", 13, "B");
+ packet.addOutput("hid", "left_segment_5", 14, "B");
+ packet.addOutput("hid", "left_segment_6", 15, "B");
+ packet.addOutput("hid", "left_segment_7", 16, "B");
// Button led brightness, 0-0xff
- packet.addControl("hid", "browse_brightness", 16,"B");
- packet.addControl("hid", "size_brightness", 17,"B");
- packet.addControl("hid", "type_brightness", 18,"B");
- packet.addControl("hid", "reverse_brightness", 19,"B");
- packet.addControl("hid", "shift_brightness", 20,"B");
- packet.addControl("hid", "capture_brightness", 21,"B");
- packet.addControl("hid", "quant_brightness", 22,"B");
- packet.addControl("hid", "sync_brightness", 23,"B");
+ packet.addOutput("hid", "browse_brightness", 17, "B");
+ packet.addOutput("hid", "size_brightness", 18, "B");
+ packet.addOutput("hid", "type_brightness", 19, "B");
+ packet.addOutput("hid", "reverse_brightness", 20, "B");
+ packet.addOutput("hid", "shift_brightness", 21, "B");
+ packet.addOutput("hid", "capture_brightness", 22, "B");
+ packet.addOutput("hid", "quant_brightness", 23, "B");
+ packet.addOutput("hid", "sync_brightness", 24, "B");
// Pad RGB color button controls, 3 bytes per pad
- packet.addControl("hid", "grid_1_blue", 24,"B")
- packet.addControl("hid", "grid_1_red", 25,"B")
- packet.addControl("hid", "grid_1_green", 26,"B")
- packet.addControl("hid", "grid_2_blue", 27,"B")
- packet.addControl("hid", "grid_2_red", 28,"B")
- packet.addControl("hid", "grid_2_green", 29,"B")
- packet.addControl("hid", "grid_3_blue", 30,"B")
- packet.addControl("hid", "grid_3_red", 31,"B")
- packet.addControl("hid", "grid_3_green", 32,"B")
- packet.addControl("hid", "grid_4_blue", 33,"B")
- packet.addControl("hid", "grid_4_red", 34,"B")
- packet.addControl("hid", "grid_4_green", 35,"B")
- packet.addControl("hid", "grid_5_blue", 36,"B")
- packet.addControl("hid", "grid_5_red", 37,"B")
- packet.addControl("hid", "grid_5_green", 38,"B")
- packet.addControl("hid", "grid_6_blue", 39,"B")
- packet.addControl("hid", "grid_6_red", 40,"B")
- packet.addControl("hid", "grid_6_green", 41,"B")
- packet.addControl("hid", "grid_7_blue", 42,"B")
- packet.addControl("hid", "grid_7_red", 43,"B")
- packet.addControl("hid", "grid_7_green", 44,"B")
- packet.addControl("hid", "grid_8_blue", 45,"B")
- packet.addControl("hid", "grid_8_red", 46,"B")
- packet.addControl("hid", "grid_8_green", 47,"B")
- packet.addControl("hid", "grid_9_blue", 48,"B")
- packet.addControl("hid", "grid_9_red", 49,"B")
- packet.addControl("hid", "grid_9_green", 50,"B")
- packet.addControl("hid", "grid_10_blue", 51,"B")
- packet.addControl("hid", "grid_10_red", 52,"B")
- packet.addControl("hid", "grid_10_green", 53,"B")
- packet.addControl("hid", "grid_11_blue", 54,"B")
- packet.addControl("hid", "grid_11_red", 55,"B")
- packet.addControl("hid", "grid_11_green", 56,"B")
- packet.addControl("hid", "grid_12_blue", 57,"B")
- packet.addControl("hid", "grid_12_red", 58,"B")
- packet.addControl("hid", "grid_12_green", 59,"B")
- packet.addControl("hid", "grid_13_blue", 60,"B")
- packet.addControl("hid", "grid_13_red", 61,"B")
- packet.addControl("hid", "grid_13_green", 62,"B")
- packet.addControl("hid", "grid_14_blue", 63,"B")
- packet.addControl("hid", "grid_14_red", 64,"B")
- packet.addControl("hid", "grid_14_green", 65,"B")
- packet.addControl("hid", "grid_15_blue", 66,"B")
- packet.addControl("hid", "grid_15_red", 67,"B")
- packet.addControl("hid", "grid_15_green", 68,"B")
- packet.addControl("hid", "grid_16_blue", 69,"B")
- packet.addControl("hid", "grid_16_red", 70,"B")
- packet.addControl("hid", "grid_16_green", 71,"B")
+ packet.addOutput("hid", "grid_1_blue", 25, "B");
+ packet.addOutput("hid", "grid_1_red", 26, "B");
+ packet.addOutput("hid", "grid_1_green", 27, "B");
+ packet.addOutput("hid", "grid_2_blue", 28, "B");
+ packet.addOutput("hid", "grid_2_red", 29, "B");
+ packet.addOutput("hid", "grid_2_green", 30, "B");
+ packet.addOutput("hid", "grid_3_blue", 31, "B");
+ packet.addOutput("hid", "grid_3_red", 32, "B");
+ packet.addOutput("hid", "grid_3_green", 33, "B");
+ packet.addOutput("hid", "grid_4_blue", 34, "B");
+ packet.addOutput("hid", "grid_4_red", 35, "B");
+ packet.addOutput("hid", "grid_4_green", 36, "B");
+ packet.addOutput("hid", "grid_5_blue", 37, "B");
+ packet.addOutput("hid", "grid_5_red", 38, "B");
+ packet.addOutput("hid", "grid_5_green", 39, "B");
+ packet.addOutput("hid", "grid_6_blue", 40, "B");
+ packet.addOutput("hid", "grid_6_red", 41, "B");
+ packet.addOutput("hid", "grid_6_green", 42, "B");
+ packet.addOutput("hid", "grid_7_blue", 43, "B");
+ packet.addOutput("hid", "grid_7_red", 44, "B");
+ packet.addOutput("hid", "grid_7_green", 45, "B");
+ packet.addOutput("hid", "grid_8_blue", 46, "B");
+ packet.addOutput("hid", "grid_8_red", 47, "B");
+ packet.addOutput("hid", "grid_8_green", 48, "B");
+ packet.addOutput("hid", "grid_9_blue", 49, "B");
+ packet.addOutput("hid", "grid_9_red", 50, "B");
+ packet.addOutput("hid", "grid_9_green", 51, "B");
+ packet.addOutput("hid", "grid_10_blue", 52, "B");
+ packet.addOutput("hid", "grid_10_red", 53, "B");
+ packet.addOutput("hid", "grid_10_green", 54, "B");
+ packet.addOutput("hid", "grid_11_blue", 55, "B");
+ packet.addOutput("hid", "grid_11_red", 56, "B");
+ packet.addOutput("hid", "grid_11_green", 57, "B");
+ packet.addOutput("hid", "grid_12_blue", 58, "B");
+ packet.addOutput("hid", "grid_12_red", 59, "B");
+ packet.addOutput("hid", "grid_12_green", 60, "B");
+ packet.addOutput("hid", "grid_13_blue", 61, "B");
+ packet.addOutput("hid", "grid_13_red", 62, "B");
+ packet.addOutput("hid", "grid_13_green", 63, "B");
+ packet.addOutput("hid", "grid_14_blue", 64, "B");
+ packet.addOutput("hid", "grid_14_red", 65, "B");
+ packet.addOutput("hid", "grid_14_green", 66, "B");
+ packet.addOutput("hid", "grid_15_blue", 67, "B");
+ packet.addOutput("hid", "grid_15_red", 68, "B");
+ packet.addOutput("hid", "grid_15_green", 69, "B");
+ packet.addOutput("hid", "grid_16_blue", 70, "B");
+ packet.addOutput("hid", "grid_16_red", 71, "B");
+ packet.addOutput("hid", "grid_16_green", 72, "B");
// Play key brightness control, 0-0xff
- packet.addControl("hid", "play_4_1_brightness", 72,"B");
- packet.addControl("hid", "play_4_2_brightness", 73,"B");
- packet.addControl("hid", "play_3_1_brightness", 74,"B");
- packet.addControl("hid", "play_3_2_brightness", 75,"B");
- packet.addControl("hid", "play_2_1_brightness", 76,"B");
- packet.addControl("hid", "play_2_2_brightness", 77,"B");
- packet.addControl("hid", "play_1_1_brightness", 78,"B");
- packet.addControl("hid", "play_1_2_brightness", 79,"B");
+ packet.addOutput("hid", "play_4_1_brightness", 73, "B");
+ packet.addOutput("hid", "play_4_2_brightness", 74, "B");
+ packet.addOutput("hid", "play_3_1_brightness", 75, "B");
+ packet.addOutput("hid", "play_3_2_brightness", 76, "B");
+ packet.addOutput("hid", "play_2_1_brightness", 77, "B");
+ packet.addOutput("hid", "play_2_2_brightness", 78, "B");
+ packet.addOutput("hid", "play_1_1_brightness", 79, "B");
+ packet.addOutput("hid", "play_1_2_brightness", 80, "B");
this.controller.registerOutputPacket(packet);
diff --git a/res/controllers/common-hid-packet-parser.js b/res/controllers/common-hid-packet-parser.js
index 2b66d00fade..5547af90050 100644
--- a/res/controllers/common-hid-packet-parser.js
+++ b/res/controllers/common-hid-packet-parser.js
@@ -696,14 +696,14 @@ class HIDPacket {
field.auto_repeat = undefined;
field.auto_repeat_interval = undefined;
- const packet_max_value = Math.pow(2, this.packSizes[field.pack] * 8);
+ const packet_max_value = Math.pow(2, this.packSizes[field.pack] * 8) - 1;
const signed = this.signedPackFormats.includes(field.pack);
if (signed) {
- field.min = 0 - (packet_max_value / 2) + 1;
- field.max = (packet_max_value / 2) - 1;
+ field.min = 0 - ((packet_max_value + 1) / 2) + 1;
+ field.max = ((packet_max_value + 1) / 2) - 1;
} else {
field.min = 0;
- field.max = packet_max_value - 1;
+ field.max = packet_max_value;
}
if (bitmask === undefined || bitmask === packet_max_value) {
@@ -1679,7 +1679,7 @@ class HIDController {
*/
processIncomingPacket(packet, delta) {
- HIDController.fastForIn(delta, (field_name) => {
+ HIDController.fastForIn(delta, (function(field_name) {
// @ts-ignore ignoredControlChanges should be defined in the users mapping
// see EKS-Otus.js for an example
if (this.ignoredControlChanges !== undefined &&
@@ -1697,8 +1697,7 @@ class HIDController {
} else {
console.warn(`HIDController.processIncomingPacket - Unknown field ${field.name} type ${field.type}`);
}
- }
- );
+ }).bind(this)); // Qt < 6.2.4 : .bind(this) needed because of QTBUG-95677
}
/**
* Get active group for this field
diff --git a/src/dialog/dlgdevelopertools.cpp b/src/dialog/dlgdevelopertools.cpp
index 4e9af0206cd..6d9c34a3b2f 100644
--- a/src/dialog/dlgdevelopertools.cpp
+++ b/src/dialog/dlgdevelopertools.cpp
@@ -18,6 +18,7 @@ DlgDeveloperTools::DlgDeveloperTools(QWidget* pParent,
controlsTable->hideColumn(ControlModel::CONTROL_COLUMN_TITLE);
controlsTable->hideColumn(ControlModel::CONTROL_COLUMN_DESCRIPTION);
controlsTable->hideColumn(ControlModel::CONTROL_COLUMN_FILTER);
+ m_controlProxyModel.sort(0, Qt::AscendingOrder);
StatsManager* pManager = StatsManager::instance();
if (pManager) {
diff --git a/src/library/trackset/baseplaylistfeature.cpp b/src/library/trackset/baseplaylistfeature.cpp
index ac81372e687..0b18a37b1ae 100644
--- a/src/library/trackset/baseplaylistfeature.cpp
+++ b/src/library/trackset/baseplaylistfeature.cpp
@@ -804,6 +804,16 @@ void BasePlaylistFeature::markTreeItem(TreeItem* pTreeItem) {
}
}
+QString BasePlaylistFeature::createPlaylistLabel(const QString& name,
+ int count,
+ int duration) const {
+ return QStringLiteral("%1 (%2) %3")
+ .arg(name,
+ QString::number(count),
+ mixxx::Duration::formatTime(
+ duration, mixxx::Duration::Precision::SECONDS));
+}
+
void BasePlaylistFeature::slotResetSelectedTrack() {
slotTrackSelected(TrackId{});
}
diff --git a/src/library/trackset/baseplaylistfeature.h b/src/library/trackset/baseplaylistfeature.h
index 761f94305be..fbcbf16586a 100644
--- a/src/library/trackset/baseplaylistfeature.h
+++ b/src/library/trackset/baseplaylistfeature.h
@@ -92,6 +92,8 @@ class BasePlaylistFeature : public BaseTrackSetFeature {
QModelIndex indexFromPlaylistId(int playlistId);
bool isChildIndexSelectedInSidebar(const QModelIndex& index);
+ QString createPlaylistLabel(const QString& name, int count, int duration) const;
+
PlaylistDAO& m_playlistDao;
QModelIndex m_lastClickedIndex;
QModelIndex m_lastRightClickedIndex;
diff --git a/src/library/trackset/playlistfeature.cpp b/src/library/trackset/playlistfeature.cpp
index d76e0923a83..4f00f80f07b 100644
--- a/src/library/trackset/playlistfeature.cpp
+++ b/src/library/trackset/playlistfeature.cpp
@@ -18,21 +18,6 @@
#include "widget/wlibrarysidebar.h"
#include "widget/wtracktableview.h"
-namespace {
-
-QString createPlaylistLabel(
- const QString& name,
- int count,
- int duration) {
- return QStringLiteral("%1 (%2) %3")
- .arg(name,
- QString::number(count),
- mixxx::Duration::formatTime(
- duration, mixxx::Duration::Precision::SECONDS));
-}
-
-} // anonymous namespace
-
PlaylistFeature::PlaylistFeature(Library* pLibrary, UserSettingsPointer pConfig)
: BasePlaylistFeature(pLibrary,
pConfig,
@@ -152,7 +137,7 @@ QList PlaylistFeature::createPlaylistLabels() {
" ON PlaylistTracks.playlist_id = Playlists.id "
"LEFT JOIN library "
" ON PlaylistTracks.track_id = library.id "
- " WHERE Playlists.hidden = 0 "
+ " WHERE Playlists.hidden = 0 " // PlaylistDAO::HiddenType::PLHT_NOT_HIDDEN
" GROUP BY Playlists.id");
queryString.append(
mixxx::DbConnection::collateLexicographically(
diff --git a/src/library/trackset/setlogfeature.cpp b/src/library/trackset/setlogfeature.cpp
index 74ca557f2b6..e27527e5923 100644
--- a/src/library/trackset/setlogfeature.cpp
+++ b/src/library/trackset/setlogfeature.cpp
@@ -226,14 +226,42 @@ void SetlogFeature::onRightClickChild(const QPoint& globalPos, const QModelIndex
/// Use a custom model in the history for grouping by year
/// @param selectedId row which should be selected
QModelIndex SetlogFeature::constructChildModel(int selectedId) {
- // qDebug() << "SetlogFeature::constructChildModel() id:" << selectedId;
+ // qDebug() << "SetlogFeature::constructChildModel() selected:" << selectedId;
// Setup the sidebar playlist model
- QSqlTableModel playlistTableModel(this,
- m_pLibrary->trackCollectionManager()->internalCollection()->database());
- playlistTableModel.setTable("Playlists");
- playlistTableModel.setFilter("hidden=" + QString::number(PlaylistDAO::PLHT_SET_LOG));
- playlistTableModel.setSort(
- playlistTableModel.fieldIndex("id"), Qt::DescendingOrder);
+ QSqlDatabase database =
+ m_pLibrary->trackCollectionManager()->internalCollection()->database();
+
+ QString queryString = QStringLiteral(
+ "CREATE TEMPORARY VIEW IF NOT EXISTS SetlogCountsDurations "
+ "AS SELECT "
+ " Playlists.id AS id, "
+ " Playlists.name AS name, "
+ " Playlists.date_created AS date_created, "
+ " LOWER(Playlists.name) AS sort_name, "
+ " COUNT(case library.mixxx_deleted when 0 then 1 else null end) "
+ " AS count, "
+ " SUM(case library.mixxx_deleted "
+ " when 0 then library.duration else 0 end) AS durationSeconds "
+ "FROM Playlists "
+ "LEFT JOIN PlaylistTracks "
+ " ON PlaylistTracks.playlist_id = Playlists.id "
+ "LEFT JOIN library "
+ " ON PlaylistTracks.track_id = library.id "
+ " WHERE Playlists.hidden = %1 "
+ " GROUP BY Playlists.id")
+ .arg(QString::number(PlaylistDAO::HiddenType::PLHT_SET_LOG));
+ queryString.append(
+ mixxx::DbConnection::collateLexicographically(
+ " ORDER BY sort_name"));
+ QSqlQuery query(database);
+ if (!query.exec(queryString)) {
+ LOG_FAILED_QUERY(query);
+ }
+
+ // Setup the sidebar playlist model
+ QSqlTableModel playlistTableModel(this, database);
+ playlistTableModel.setTable("SetlogCountsDurations");
+ playlistTableModel.setSort(playlistTableModel.fieldIndex("id"), Qt::DescendingOrder);
playlistTableModel.select();
while (playlistTableModel.canFetchMore()) {
playlistTableModel.fetchMore();
@@ -242,6 +270,8 @@ QModelIndex SetlogFeature::constructChildModel(int selectedId) {
int nameColumn = record.indexOf("name");
int idColumn = record.indexOf("id");
int createdColumn = record.indexOf("date_created");
+ int countColumn = record.indexOf("count");
+ int durationColumn = record.indexOf("durationSeconds");
// Nice to have: restore previous expanded/collapsed state of YEAR items
clearChildModel();
@@ -263,8 +293,16 @@ QModelIndex SetlogFeature::constructChildModel(int selectedId) {
playlistTableModel
.data(playlistTableModel.index(row, createdColumn))
.toDateTime();
+ int count = playlistTableModel
+ .data(playlistTableModel.index(row, countColumn))
+ .toInt();
+ int duration =
+ playlistTableModel
+ .data(playlistTableModel.index(row, durationColumn))
+ .toInt();
+ QString label = createPlaylistLabel(name, count, duration);
- // Create the TreeItem whose parent is the invisible root item
+ // Create the TreeItem whose parent is the invisible root item.
// Show only [kNumToplevelHistoryEntries] recent playlists at the top level
// before grouping them by year.
if (row >= kNumToplevelHistoryEntries) {
@@ -286,12 +324,12 @@ QModelIndex SetlogFeature::constructChildModel(int selectedId) {
itemList.push_back(std::move(pNewGroupItem));
}
- TreeItem* pItem = pGroupItem->appendChild(name, id);
+ TreeItem* pItem = pGroupItem->appendChild(label, id);
pItem->setBold(m_playlistIdsOfSelectedTrack.contains(id));
decorateChild(pItem, id);
} else {
// add most recent top-level playlist
- auto pItem = std::make_unique(name, id);
+ auto pItem = std::make_unique(label, id);
pItem->setBold(m_playlistIdsOfSelectedTrack.contains(id));
decorateChild(pItem.get(), id);