From 2ec07ccca44eddb7d96b13c52e3dd9391577299b Mon Sep 17 00:00:00 2001 From: needspeed Date: Tue, 12 Dec 2017 20:40:39 +0100 Subject: [PATCH 1/4] Added Traktor Cue Support --- res/schema.xml | 17 ++++ src/database/mixxxdb.cpp | 2 +- src/library/dao/cue.h | 4 +- src/library/trackcollection.h | 3 + src/library/traktor/traktorfeature.cpp | 133 ++++++++++++++++++++++++- src/library/traktor/traktorfeature.h | 4 +- 6 files changed, 156 insertions(+), 7 deletions(-) diff --git a/res/schema.xml b/res/schema.xml index e58c8033f68..0afe4f4d66a 100644 --- a/res/schema.xml +++ b/res/schema.xml @@ -426,4 +426,21 @@ METADATA ALTER TABLE cues ADD COLUMN color INTEGER DEFAULT 4294901760 NOT NULL; + + + Add traktor color support. + See library/traktor/traktorfeature.cpp + + + CREATE TABLE IF NOT EXISTS traktor_cues ( + id integer PRIMARY KEY AUTOINCREMENT, + track_id integer NOT NULL REFERENCES traktor_library(id), + type integer DEFAULT 0 NOT NULL, + position integer DEFAULT -1 NOT NULL, + length integer DEFAULT 0 NOT NULL, + hotcue integer DEFAULT -1 NOT NULL, + label text DEFAULT '' NOT NULL, + color INTEGER DEFAULT 4294901760 NOT NULL); + + diff --git a/src/database/mixxxdb.cpp b/src/database/mixxxdb.cpp index 2046129b445..a831d35b94c 100644 --- a/src/database/mixxxdb.cpp +++ b/src/database/mixxxdb.cpp @@ -11,7 +11,7 @@ const QString MixxxDb::kDefaultSchemaFile(":/schema.xml"); //static -const int MixxxDb::kRequiredSchemaVersion = 27; +const int MixxxDb::kRequiredSchemaVersion = 28; namespace { diff --git a/src/library/dao/cue.h b/src/library/dao/cue.h index 796dba0493a..d41035d2f3f 100644 --- a/src/library/dao/cue.h +++ b/src/library/dao/cue.h @@ -23,6 +23,8 @@ class Cue : public QObject { JUMP = 5, }; + Cue(int id, TrackId trackId, CueType type, double position, double length, + int hotCue, QString label, QColor color); ~Cue() override; bool isDirty() const; @@ -52,8 +54,6 @@ class Cue : public QObject { private: explicit Cue(TrackId trackId); - Cue(int id, TrackId trackId, CueType type, double position, double length, - int hotCue, QString label, QColor color); void setDirty(bool dirty); void setId(int id); void setTrackId(TrackId trackId); diff --git a/src/library/trackcollection.h b/src/library/trackcollection.h index f98f98c6907..9268a8f4b1c 100644 --- a/src/library/trackcollection.h +++ b/src/library/trackcollection.h @@ -56,6 +56,9 @@ class TrackCollection : public QObject, AnalysisDao& getAnalysisDAO() { return m_analysisDao; } + CueDAO& getCueDAO() { + return m_cueDao; + } QSharedPointer getTrackSource() const { return m_pTrackSource; diff --git a/src/library/traktor/traktorfeature.cpp b/src/library/traktor/traktorfeature.cpp index 8583be90f51..8ecf13ae1b4 100644 --- a/src/library/traktor/traktorfeature.cpp +++ b/src/library/traktor/traktorfeature.cpp @@ -50,6 +50,82 @@ bool TraktorPlaylistModel::isColumnHiddenByDefault(int column) { return BaseSqlTableModel::isColumnHiddenByDefault(column); } +void addCuesToTrack(CueDAO &cueDao, TrackPointer pTrack, QString traktorTrackId, const QSqlDatabase &m_database) { + QList cues; + // A hash from hotcue index to cue id and cue*, used to detect if more + // than one cue has been assigned to a single hotcue id. + QMap > dupe_hotcues; + + const double posMultiplier = double(pTrack->getSampleRate())/48000.0; //Assumed 48k in xml parse + + QSqlQuery query(m_database); + query.prepare("SELECT * FROM traktor_cues WHERE track_id = :track_id"); + query.bindValue(":track_id", traktorTrackId); + if (query.exec()) { + QSqlRecord record = query.record(); + const int idColumn = record.indexOf("id"); + const int trackIdColumn = record.indexOf("track_id"); + const int typeColumn = record.indexOf("type"); + const int positionColumn = record.indexOf("position"); + const int lengthColumn = record.indexOf("length"); + const int hotcueColumn = record.indexOf("hotcue"); + const int labelColumn = record.indexOf("label"); + const int colorColumn = record.indexOf("color"); + + while (query.next()) { + int id = query.value(idColumn).toInt(); + TrackId trackId(query.value(trackIdColumn)); + int type = query.value(typeColumn).toInt(); + int position = int(double(query.value(positionColumn).toInt()) * posMultiplier); + int length = query.value(lengthColumn).toInt(); + int hotcue = query.value(hotcueColumn).toInt(); + QString label = query.value(labelColumn).toString(); + QColor color = QColor::fromRgba(query.value(colorColumn).toInt()); + + CuePointer pCue(new Cue(-1, trackId, (Cue::CueType)type, + position, length, hotcue, label, color)); + if (hotcue != -1) { + if (dupe_hotcues.contains(hotcue)) { + cues.removeOne(dupe_hotcues[hotcue].second); + } + dupe_hotcues[hotcue] = qMakePair(id, pCue); + } + cues.push_back(pCue); + } + qDebug() << "Found " << cues.count() << " cues"; + cueDao.saveTrackCues(pTrack->getId(), cues); + pTrack->setCuePoints(cues); //needed? + } else { + LOG_FAILED_QUERY(query); + } +} + +TrackPointer TraktorTrackModel::getTrack(const QModelIndex& index) const { + QString id = index.sibling(index.row(), fieldIndex("id")).data().toString(); + QString location = index.sibling(index.row(), fieldIndex("location")).data().toString(); + bool track_already_in_library = m_pTrackCollection->getTrackDAO().trackExistsInDatabase(location); + TrackPointer pTrack = BaseExternalTrackModel::getTrack(index); + + if (pTrack && !track_already_in_library) { + addCuesToTrack(m_pTrackCollection->getCueDAO(), pTrack, id, m_database); + } + + return pTrack; +} + +TrackPointer TraktorPlaylistModel::getTrack(const QModelIndex& index) const { + QString id = index.sibling(index.row(), fieldIndex("track_id")).data().toString(); + QString location = index.sibling(index.row(), fieldIndex("location")).data().toString(); + bool track_already_in_library = m_pTrackCollection->getTrackDAO().trackExistsInDatabase(location); + TrackPointer pTrack = BaseExternalPlaylistModel::getTrack(index); + + if (pTrack && !track_already_in_library) { + addCuesToTrack(m_pTrackCollection->getCueDAO(), pTrack, id, m_database); + } + + return pTrack; +} + TraktorFeature::TraktorFeature(QObject* parent, TrackCollection* pTrackCollection) : BaseExternalLibraryFeature(parent, pTrackCollection), m_pTrackCollection(pTrackCollection), @@ -187,6 +263,7 @@ TreeItem* TraktorFeature::importLibrary(QString file) { clearTable("traktor_playlist_tracks"); clearTable("traktor_library"); clearTable("traktor_playlists"); + clearTable("traktor_cues"); transaction.commit(); transaction.transaction(); @@ -196,6 +273,10 @@ TreeItem* TraktorFeature::importLibrary(QString file) { "rating,key) VALUES (:artist, :title, :album, :year,:genre," ":comment, :tracknumber,:bpm, :bitrate,:duration, :location," ":rating,:key)"); + QSqlQuery cue_query(m_database); + cue_query.prepare("INSERT INTO traktor_cues (track_id, type, position," + "length, hotcue, label) VALUES (:track_id," + ":type, :position, :length, :hotcue, :label)"); //Parse Trakor XML file using SAX (for performance) QFile traktor_file(file); @@ -218,7 +299,7 @@ TreeItem* TraktorFeature::importLibrary(QString file) { // Each "ENTRY" tag in represents a track if (inCollectionTag && xml.name() == "ENTRY") { //parse track - parseTrack(xml, query); + parseTrack(xml, query, cue_query); ++nAudioFiles; //increment number of files in the music collection } if (xml.name() == "PLAYLISTS") { @@ -259,7 +340,7 @@ TreeItem* TraktorFeature::importLibrary(QString file) { return root; } -void TraktorFeature::parseTrack(QXmlStreamReader &xml, QSqlQuery &query) { +void TraktorFeature::parseTrack(QXmlStreamReader &xml, QSqlQuery &query, QSqlQuery &cue_query) { QString title; QString artist; QString album; @@ -278,6 +359,7 @@ void TraktorFeature::parseTrack(QXmlStreamReader &xml, QSqlQuery &query) { int rating = 0; QString comment; QString tracknumber; + QList cues; //get XML attributes of starting ENTRY tag QXmlStreamAttributes attr = xml.attributes (); @@ -337,6 +419,28 @@ void TraktorFeature::parseTrack(QXmlStreamReader &xml, QSqlQuery &query) { bpm = attr.value("BPM").toString().toFloat(); continue; } + if (xml.name() == "CUE_V2") { + QXmlStreamAttributes attr = xml.attributes (); + int hotcue = attr.value("HOTCUE").toString().toInt(); + //int position = int(attr.value("START").toString().toFloat()/1000.0 * float(samplerate) * 2.0); + int position = int(attr.value("START").toString().toDouble()/1000.0 * 48000.0 * 2.0); + int length = attr.value("LEN").toString().toInt(); + int type = attr.value("TYPE").toString().toInt(); + QString label = attr.value("NAME").toString(); + switch (type) { //TODO + case 0: + type = 1; + break; + case 4: + type = 2; + break; + default: + continue; + } + Cue *cue = new Cue(0, TrackId(), (Cue::CueType)type, position, length, hotcue, label, QColor("#FF0000")); + cues.push_back(CuePointer(cue)); + continue; + } } //We leave the infinte loop, if twe have the closing tag "ENTRY" if (xml.name() == "ENTRY" && xml.isEndElement()) { @@ -360,12 +464,35 @@ void TraktorFeature::parseTrack(QXmlStreamReader &xml, QSqlQuery &query) { query.bindValue(":bpm", bpm); query.bindValue(":bitrate", bitrate); + bool success = query.exec(); if (!success) { - qDebug() << "SQL Error in TraktorTableModel.cpp: line" + qDebug() << "SQL Error in TraktorFeature.cpp: line" << __LINE__ << " " << query.lastError(); return; } + QVariant id = query.lastInsertId(); + if (id.isValid()) { + int id_ = id.toInt(); + for (CuePointer c : cues) { + cue_query.bindValue(":track_id", id_); + cue_query.bindValue(":type", c->getType()); + cue_query.bindValue(":position", c->getPosition()); + cue_query.bindValue(":length", c->getLength()); + cue_query.bindValue(":hotcue", c->getHotCue()); + cue_query.bindValue(":label", c->getLabel()); + //cue_query.bindValue(":color", c->getColor()); + bool success = cue_query.exec(); + if (!success) { + qDebug() << "SQL Error in TraktorFeature.cpp: line" + << __LINE__ << cue_query.executedQuery() << " " << cue_query.lastError(); + return; + } + } + } + else { + qDebug() << "Could not get track id of last inserted track to add cues"; + } } // Purpose: Parsing all the folder and playlists of Traktor diff --git a/src/library/traktor/traktorfeature.h b/src/library/traktor/traktorfeature.h index edf04e42664..1ba428abc54 100644 --- a/src/library/traktor/traktorfeature.h +++ b/src/library/traktor/traktorfeature.h @@ -25,6 +25,7 @@ class TraktorTrackModel : public BaseExternalTrackModel { TrackCollection* pTrackCollection, QSharedPointer trackSource); virtual bool isColumnHiddenByDefault(int column); + TrackPointer getTrack(const QModelIndex& index) const override; }; class TraktorPlaylistModel : public BaseExternalPlaylistModel { @@ -33,6 +34,7 @@ class TraktorPlaylistModel : public BaseExternalPlaylistModel { TrackCollection* pTrackCollection, QSharedPointer trackSource); virtual bool isColumnHiddenByDefault(int column); + TrackPointer getTrack(const QModelIndex& index) const override; }; class TraktorFeature : public BaseExternalLibraryFeature { @@ -57,7 +59,7 @@ class TraktorFeature : public BaseExternalLibraryFeature { virtual BaseSqlTableModel* getPlaylistModelForPlaylist(QString playlist); TreeItem* importLibrary(QString file); // parses a track in the music collection - void parseTrack(QXmlStreamReader &xml, QSqlQuery &query); + void parseTrack(QXmlStreamReader &xml, QSqlQuery &query, QSqlQuery &cue_query); // Iterates over all playliost and folders and constructs the childmodel TreeItem* parsePlaylists(QXmlStreamReader &xml); // processes a particular playlist From 6f22022ab5e108018460b866b7e0f6f0c3b5c1dd Mon Sep 17 00:00:00 2001 From: needspeed Date: Tue, 12 Dec 2017 23:11:31 +0100 Subject: [PATCH 2/4] Added (incomplete) TraktorCueType enum --- src/library/traktor/traktorfeature.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/library/traktor/traktorfeature.cpp b/src/library/traktor/traktorfeature.cpp index 8ecf13ae1b4..65c3a36d2bd 100644 --- a/src/library/traktor/traktorfeature.cpp +++ b/src/library/traktor/traktorfeature.cpp @@ -425,19 +425,21 @@ void TraktorFeature::parseTrack(QXmlStreamReader &xml, QSqlQuery &query, QSqlQue //int position = int(attr.value("START").toString().toFloat()/1000.0 * float(samplerate) * 2.0); int position = int(attr.value("START").toString().toDouble()/1000.0 * 48000.0 * 2.0); int length = attr.value("LEN").toString().toInt(); - int type = attr.value("TYPE").toString().toInt(); + TraktorCueType type = (TraktorCueType)attr.value("TYPE").toString().toInt(); QString label = attr.value("NAME").toString(); - switch (type) { //TODO - case 0: - type = 1; + Cue::CueType cue_type; + switch (type) { + case HOTCUE: + cue_type = Cue::CueType::CUE; break; - case 4: - type = 2; + case AUTOGRID: + cue_type = Cue::CueType::LOAD; break; default: + qDebug() << "Unsupported traktor cue type: " << type; continue; } - Cue *cue = new Cue(0, TrackId(), (Cue::CueType)type, position, length, hotcue, label, QColor("#FF0000")); + Cue *cue = new Cue(0, TrackId(), cue_type, position, length, hotcue, label, QColor("#FF0000")); cues.push_back(CuePointer(cue)); continue; } From 8f03e8fecb2928379cbb483bc950863c38a47c19 Mon Sep 17 00:00:00 2001 From: needspeed Date: Thu, 14 Dec 2017 00:29:57 +0100 Subject: [PATCH 3/4] Now Traktor cues are saved in their native format into traktor_cues. Moved the cue code to a seperate file. --- build/depends.py | 1 + res/schema.xml | 20 ++++--- src/library/traktor/traktor_cue.cpp | 69 ++++++++++++++++++++++ src/library/traktor/traktor_cue.h | 42 ++++++++++++++ src/library/traktor/traktorfeature.cpp | 80 ++++---------------------- 5 files changed, 136 insertions(+), 76 deletions(-) create mode 100644 src/library/traktor/traktor_cue.cpp create mode 100644 src/library/traktor/traktor_cue.h diff --git a/build/depends.py b/build/depends.py index 8824db46c98..7c7205fb0b2 100644 --- a/build/depends.py +++ b/build/depends.py @@ -970,6 +970,7 @@ def sources(self, build): "library/itunes/itunesfeature.cpp", "library/traktor/traktorfeature.cpp", + "library/traktor/traktor_cue.cpp", "library/sidebarmodel.cpp", "library/library.cpp", diff --git a/res/schema.xml b/res/schema.xml index 0afe4f4d66a..80a3ed84c9e 100644 --- a/res/schema.xml +++ b/res/schema.xml @@ -428,19 +428,25 @@ METADATA - Add traktor color support. - See library/traktor/traktorfeature.cpp + Add traktor cue support. + Table represents traktor cues in their native format. + Traktor cues are pushed into it when the traktor library is parsed. + The traktor cues are read from this table, when a track is added to + the library. + See library/traktor/traktorfeature.cpp and library/traktor/traktor_cue.cpp CREATE TABLE IF NOT EXISTS traktor_cues ( id integer PRIMARY KEY AUTOINCREMENT, track_id integer NOT NULL REFERENCES traktor_library(id), - type integer DEFAULT 0 NOT NULL, - position integer DEFAULT -1 NOT NULL, - length integer DEFAULT 0 NOT NULL, + displ_order integer DEFAULT 0 NOT NULL, hotcue integer DEFAULT -1 NOT NULL, - label text DEFAULT '' NOT NULL, - color INTEGER DEFAULT 4294901760 NOT NULL); + len integer DEFAULT 0 NOT NULL, + name text DEFAULT '' NOT NULL, + repeats integer DEFAULT -1 NOT NULL, + start double DEFAULT -1 NOT NULL, + type integer DEFAULT 0 NOT NULL + ); diff --git a/src/library/traktor/traktor_cue.cpp b/src/library/traktor/traktor_cue.cpp new file mode 100644 index 00000000000..62ad0edff1b --- /dev/null +++ b/src/library/traktor/traktor_cue.cpp @@ -0,0 +1,69 @@ +#include "library/traktor/traktor_cue.h" +#include + +TraktorCue::TraktorCue(int displ_order, int hotcue, double len, QString name, + int repeats, double start, TraktorCueType type) : + displ_order(displ_order), hotcue(hotcue), len(len), name(name), repeats(repeats), + start(start), type(type) { +} + +TraktorCue::TraktorCue(const QXmlStreamAttributes &cue_attributes) : + TraktorCue( + cue_attributes.value("DISPL_ORDER").toString().toInt(), + cue_attributes.value("HOTCUE").toString().toInt(), + cue_attributes.value("LEN").toString().toDouble(), + cue_attributes.value("NAME").toString(), + cue_attributes.value("REPEATS").toString().toInt(), + cue_attributes.value("START").toString().toDouble(), + (TraktorCueType)cue_attributes.value("TYPE").toString().toInt() + ) { +} + +TraktorCue::TraktorCue(const QSqlRecord &record, const QSqlQuery &query) : + TraktorCue( + query.value(record.indexOf("displ_order")).toInt(), + query.value(record.indexOf("hotcue")).toInt(), + query.value(record.indexOf("len")).toDouble(), + query.value(record.indexOf("name")).toString(), + query.value(record.indexOf("repeats")).toInt(), + query.value(record.indexOf("start")).toDouble(), + (TraktorCueType)query.value(record.indexOf("type")).toInt() + ) { + track_id = query.value(record.indexOf("track_id")).toInt(); +} + +void TraktorCue::fillQuery(int track_id, QSqlQuery &query) { + query.bindValue(":track_id", track_id); + query.bindValue(":displ_order", displ_order); + query.bindValue(":hotcue", hotcue); + query.bindValue(":len", len); + query.bindValue(":name", name); + query.bindValue(":repeats", repeats); + query.bindValue(":start", start); + query.bindValue(":type", type); +} + +CuePointer TraktorCue::toCue(int samplerate) { + //Incomplete + Cue::CueType type; + switch (this->type) { + case HOTCUE: + type = Cue::CueType::CUE; + break; + case AUTOGRID: + type = Cue::CueType::LOAD; + break; + default: + qDebug() << "Unsupported traktor cue type: " << this->type; + return CuePointer(NULL); + } + TrackId track_id(this->track_id); + QColor color("#FF0000"); + //start is a a float denoting milliseconds + //convert to stereoSamplePointer + int position = int(start/1000.0 * double(samplerate) * 2.0); + + return CuePointer(new Cue(-1, track_id, type, position, len, hotcue, name, + color)); +} + diff --git a/src/library/traktor/traktor_cue.h b/src/library/traktor/traktor_cue.h new file mode 100644 index 00000000000..64f225e6164 --- /dev/null +++ b/src/library/traktor/traktor_cue.h @@ -0,0 +1,42 @@ +#ifndef TRAKTOR_CUE_H +#define TRAKTOR_CUE_H + +#include +#include +#include +#include "library/dao/cue.h" + +#define TRAKTOR_CUE_QUERY "INSERT INTO traktor_cues (track_id, displ_order," \ + "hotcue, len, name, repeats, start, type)" \ + " VALUES (:track_id, :displ_order, :hotcue, :len," \ + ":name, :repeats, :start, :type)" +enum TraktorCueType { + HOTCUE, + TBD1, + TBD2, + TBD3, + AUTOGRID, + TBD5 +}; + +class TraktorCue { + public: + TraktorCue(const QXmlStreamAttributes &cue_attributes); + TraktorCue(const QSqlRecord &record, const QSqlQuery &query); + CuePointer toCue(int samplerate); + void fillQuery(int track_id, QSqlQuery &query); + void setTrackId(int track_id); + + private: + TraktorCue(int displ_order, int hotcue, double len, QString name, int repeats, double start, TraktorCueType type); + int track_id; + int displ_order; + int hotcue; + double len; + QString name; + int repeats; + double start; + TraktorCueType type; +}; + +#endif // TRAKTOR_CUE_H diff --git a/src/library/traktor/traktorfeature.cpp b/src/library/traktor/traktorfeature.cpp index 65c3a36d2bd..bd56ace2dfc 100644 --- a/src/library/traktor/traktorfeature.cpp +++ b/src/library/traktor/traktorfeature.cpp @@ -9,6 +9,7 @@ #include #include "library/traktor/traktorfeature.h" +#include "library/traktor/traktor_cue.h" #include "library/librarytablemodel.h" #include "library/missingtablemodel.h" @@ -52,45 +53,16 @@ bool TraktorPlaylistModel::isColumnHiddenByDefault(int column) { void addCuesToTrack(CueDAO &cueDao, TrackPointer pTrack, QString traktorTrackId, const QSqlDatabase &m_database) { QList cues; - // A hash from hotcue index to cue id and cue*, used to detect if more - // than one cue has been assigned to a single hotcue id. - QMap > dupe_hotcues; - - const double posMultiplier = double(pTrack->getSampleRate())/48000.0; //Assumed 48k in xml parse - QSqlQuery query(m_database); query.prepare("SELECT * FROM traktor_cues WHERE track_id = :track_id"); query.bindValue(":track_id", traktorTrackId); if (query.exec()) { - QSqlRecord record = query.record(); - const int idColumn = record.indexOf("id"); - const int trackIdColumn = record.indexOf("track_id"); - const int typeColumn = record.indexOf("type"); - const int positionColumn = record.indexOf("position"); - const int lengthColumn = record.indexOf("length"); - const int hotcueColumn = record.indexOf("hotcue"); - const int labelColumn = record.indexOf("label"); - const int colorColumn = record.indexOf("color"); - while (query.next()) { - int id = query.value(idColumn).toInt(); - TrackId trackId(query.value(trackIdColumn)); - int type = query.value(typeColumn).toInt(); - int position = int(double(query.value(positionColumn).toInt()) * posMultiplier); - int length = query.value(lengthColumn).toInt(); - int hotcue = query.value(hotcueColumn).toInt(); - QString label = query.value(labelColumn).toString(); - QColor color = QColor::fromRgba(query.value(colorColumn).toInt()); - - CuePointer pCue(new Cue(-1, trackId, (Cue::CueType)type, - position, length, hotcue, label, color)); - if (hotcue != -1) { - if (dupe_hotcues.contains(hotcue)) { - cues.removeOne(dupe_hotcues[hotcue].second); - } - dupe_hotcues[hotcue] = qMakePair(id, pCue); + TraktorCue cue(query.record(), query); + CuePointer pCue = cue.toCue(pTrack->getSampleRate()); + if (pCue) { + cues.push_back(pCue); } - cues.push_back(pCue); } qDebug() << "Found " << cues.count() << " cues"; cueDao.saveTrackCues(pTrack->getId(), cues); @@ -274,9 +246,7 @@ TreeItem* TraktorFeature::importLibrary(QString file) { ":comment, :tracknumber,:bpm, :bitrate,:duration, :location," ":rating,:key)"); QSqlQuery cue_query(m_database); - cue_query.prepare("INSERT INTO traktor_cues (track_id, type, position," - "length, hotcue, label) VALUES (:track_id," - ":type, :position, :length, :hotcue, :label)"); + cue_query.prepare(TRAKTOR_CUE_QUERY); //Parse Trakor XML file using SAX (for performance) QFile traktor_file(file); @@ -359,7 +329,7 @@ void TraktorFeature::parseTrack(QXmlStreamReader &xml, QSqlQuery &query, QSqlQue int rating = 0; QString comment; QString tracknumber; - QList cues; + QList cues; //get XML attributes of starting ENTRY tag QXmlStreamAttributes attr = xml.attributes (); @@ -420,27 +390,7 @@ void TraktorFeature::parseTrack(QXmlStreamReader &xml, QSqlQuery &query, QSqlQue continue; } if (xml.name() == "CUE_V2") { - QXmlStreamAttributes attr = xml.attributes (); - int hotcue = attr.value("HOTCUE").toString().toInt(); - //int position = int(attr.value("START").toString().toFloat()/1000.0 * float(samplerate) * 2.0); - int position = int(attr.value("START").toString().toDouble()/1000.0 * 48000.0 * 2.0); - int length = attr.value("LEN").toString().toInt(); - TraktorCueType type = (TraktorCueType)attr.value("TYPE").toString().toInt(); - QString label = attr.value("NAME").toString(); - Cue::CueType cue_type; - switch (type) { - case HOTCUE: - cue_type = Cue::CueType::CUE; - break; - case AUTOGRID: - cue_type = Cue::CueType::LOAD; - break; - default: - qDebug() << "Unsupported traktor cue type: " << type; - continue; - } - Cue *cue = new Cue(0, TrackId(), cue_type, position, length, hotcue, label, QColor("#FF0000")); - cues.push_back(CuePointer(cue)); + cues.push_back(TraktorCue(xml.attributes())); continue; } } @@ -473,17 +423,12 @@ void TraktorFeature::parseTrack(QXmlStreamReader &xml, QSqlQuery &query, QSqlQue << __LINE__ << " " << query.lastError(); return; } + //Insert Cues to traktor_cue table QVariant id = query.lastInsertId(); if (id.isValid()) { int id_ = id.toInt(); - for (CuePointer c : cues) { - cue_query.bindValue(":track_id", id_); - cue_query.bindValue(":type", c->getType()); - cue_query.bindValue(":position", c->getPosition()); - cue_query.bindValue(":length", c->getLength()); - cue_query.bindValue(":hotcue", c->getHotCue()); - cue_query.bindValue(":label", c->getLabel()); - //cue_query.bindValue(":color", c->getColor()); + for (TraktorCue &cue : cues) { + cue.fillQuery(id_, cue_query); bool success = cue_query.exec(); if (!success) { qDebug() << "SQL Error in TraktorFeature.cpp: line" @@ -492,9 +437,6 @@ void TraktorFeature::parseTrack(QXmlStreamReader &xml, QSqlQuery &query, QSqlQue } } } - else { - qDebug() << "Could not get track id of last inserted track to add cues"; - } } // Purpose: Parsing all the folder and playlists of Traktor From f55b111f2ef780c35efc940c2436c811b25b7acd Mon Sep 17 00:00:00 2001 From: needspeed Date: Thu, 14 Dec 2017 19:49:20 +0100 Subject: [PATCH 4/4] Added supported for all Traktor cue types Removed unecessary call to cueDAO --- src/library/traktor/traktor_cue.cpp | 20 ++++++++++++++++---- src/library/traktor/traktor_cue.h | 12 ++++++------ src/library/traktor/traktorfeature.cpp | 9 ++++----- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/library/traktor/traktor_cue.cpp b/src/library/traktor/traktor_cue.cpp index 62ad0edff1b..19c2691633f 100644 --- a/src/library/traktor/traktor_cue.cpp +++ b/src/library/traktor/traktor_cue.cpp @@ -45,16 +45,27 @@ void TraktorCue::fillQuery(int track_id, QSqlQuery &query) { CuePointer TraktorCue::toCue(int samplerate) { //Incomplete + int hotcue = this->hotcue; Cue::CueType type; switch (this->type) { case HOTCUE: type = Cue::CueType::CUE; break; - case AUTOGRID: + case LOAD: type = Cue::CueType::LOAD; break; + case LOOP: + type = Cue::CueType::LOOP; + break; + case AUTOGRID: + type = Cue::CueType::BEAT; + break; + case FADEIN: + case FADEOUT: + qDebug() << "Fade cue points are not yet supported in mixxx"; + return CuePointer(NULL); default: - qDebug() << "Unsupported traktor cue type: " << this->type; + qDebug() << "Unknown traktor cue type: " << this->type; return CuePointer(NULL); } TrackId track_id(this->track_id); @@ -62,8 +73,9 @@ CuePointer TraktorCue::toCue(int samplerate) { //start is a a float denoting milliseconds //convert to stereoSamplePointer int position = int(start/1000.0 * double(samplerate) * 2.0); + int length = int(len/1000.0 * double(samplerate) * 2.0); - return CuePointer(new Cue(-1, track_id, type, position, len, hotcue, name, - color)); + return CuePointer(new Cue(-1, track_id, type, position, length, hotcue, + name, color)); } diff --git a/src/library/traktor/traktor_cue.h b/src/library/traktor/traktor_cue.h index 64f225e6164..4c372fcbea2 100644 --- a/src/library/traktor/traktor_cue.h +++ b/src/library/traktor/traktor_cue.h @@ -11,12 +11,12 @@ " VALUES (:track_id, :displ_order, :hotcue, :len," \ ":name, :repeats, :start, :type)" enum TraktorCueType { - HOTCUE, - TBD1, - TBD2, - TBD3, - AUTOGRID, - TBD5 + HOTCUE, //Normal Cue + FADEIN, //Triggered by fadeout in playing deck + FADEOUT, //Triggers fadein cue in other deck + LOAD, //Position to jump to when track is loaded into deck + AUTOGRID, //First beat of track + LOOP //Loop Cue }; class TraktorCue { diff --git a/src/library/traktor/traktorfeature.cpp b/src/library/traktor/traktorfeature.cpp index bd56ace2dfc..0962dfb4036 100644 --- a/src/library/traktor/traktorfeature.cpp +++ b/src/library/traktor/traktorfeature.cpp @@ -51,7 +51,7 @@ bool TraktorPlaylistModel::isColumnHiddenByDefault(int column) { return BaseSqlTableModel::isColumnHiddenByDefault(column); } -void addCuesToTrack(CueDAO &cueDao, TrackPointer pTrack, QString traktorTrackId, const QSqlDatabase &m_database) { +void addCuesToTrack(TrackPointer pTrack, QString traktorTrackId, const QSqlDatabase &m_database) { QList cues; QSqlQuery query(m_database); query.prepare("SELECT * FROM traktor_cues WHERE track_id = :track_id"); @@ -65,8 +65,7 @@ void addCuesToTrack(CueDAO &cueDao, TrackPointer pTrack, QString traktorTrackId, } } qDebug() << "Found " << cues.count() << " cues"; - cueDao.saveTrackCues(pTrack->getId(), cues); - pTrack->setCuePoints(cues); //needed? + pTrack->setCuePoints(cues); } else { LOG_FAILED_QUERY(query); } @@ -79,7 +78,7 @@ TrackPointer TraktorTrackModel::getTrack(const QModelIndex& index) const { TrackPointer pTrack = BaseExternalTrackModel::getTrack(index); if (pTrack && !track_already_in_library) { - addCuesToTrack(m_pTrackCollection->getCueDAO(), pTrack, id, m_database); + addCuesToTrack(pTrack, id, m_database); } return pTrack; @@ -92,7 +91,7 @@ TrackPointer TraktorPlaylistModel::getTrack(const QModelIndex& index) const { TrackPointer pTrack = BaseExternalPlaylistModel::getTrack(index); if (pTrack && !track_already_in_library) { - addCuesToTrack(m_pTrackCollection->getCueDAO(), pTrack, id, m_database); + addCuesToTrack(pTrack, id, m_database); } return pTrack;