diff options
author | Adam Szmigin <smidge@xsco.net> | 2023-06-23 23:16:52 +0100 |
---|---|---|
committer | Adam Szmigin <smidge@xsco.net> | 2023-06-23 23:16:52 +0100 |
commit | ab66ed6670e62d651ded088015a2cf0a00af1b0c (patch) | |
tree | b5cee833f48d21a29df13481baa22f6f94c4b65b | |
parent | d763be606148a1047522b21a8840d50d882cf1c2 (diff) |
Update to libdjinterop 0.19.0enh/djinterop-0.19.0
-rw-r--r-- | CMakeLists.txt | 5 | ||||
-rw-r--r-- | src/library/export/dlglibraryexport.cpp | 50 | ||||
-rw-r--r-- | src/library/export/engineprimeexportjob.cpp | 71 | ||||
-rw-r--r-- | src/library/export/engineprimeexportrequest.h | 2 |
4 files changed, 57 insertions, 71 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 807f63f919..58ff53fd12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2038,7 +2038,7 @@ endif() # Denon Engine Prime library export support (using libdjinterop) option(ENGINEPRIME "Support for library export to Denon Engine Prime" ON) if(ENGINEPRIME) - set(LIBDJINTEROP_VERSION 0.16.1) + set(LIBDJINTEROP_VERSION 0.19.0) # Look for an existing installation of libdjinterop and use that if available. # Otherwise, download and build from GitHub. # Note: Version 0.17.0 is not yet compatible @@ -2075,7 +2075,7 @@ if(ENGINEPRIME) # the configuration. ExternalProject_Add(libdjinterop URL "https://github.com/xsco/libdjinterop/archive/refs/tags/${LIBDJINTEROP_VERSION}.tar.gz" - URL_HASH SHA256=25461f5cc3ea80850d8400872f4fef08ad3730d9f2051719cccf2460f5ac15ad + URL_HASH SHA256=0fb8374f0074d4399d29cd3356f5f68969194711f2e36f5db5b34b56e2607c64 DOWNLOAD_DIR "${CMAKE_CURRENT_BINARY_DIR}/downloads" DOWNLOAD_NAME "libdjinterop-${LIBDJINTEROP_VERSION}.tar.gz" INSTALL_DIR ${DJINTEROP_INSTALL_DIR} @@ -2089,6 +2089,7 @@ if(ENGINEPRIME) -DCMAKE_INSTALL_LIBDIR:PATH=lib -DCMAKE_MODULE_PATH:PATH=${CMAKE_MODULE_PATH} -DSYSTEM_SQLITE=${DJINTEROP_SYSTEM_SQLITE} + BUILD_COMMAND ${CMAKE_COMMAND} --build . --target DjInterop BUILD_BYPRODUCTS <INSTALL_DIR>/${DJINTEROP_LIBRARY} EXCLUDE_FROM_ALL TRUE ) diff --git a/src/library/export/dlglibraryexport.cpp b/src/library/export/dlglibraryexport.cpp index 26fbdf73ae..22bc707c47 100644 --- a/src/library/export/dlglibraryexport.cpp +++ b/src/library/export/dlglibraryexport.cpp @@ -17,7 +17,7 @@ #include "library/trackset/crate/crateid.h" #include "library/trackset/crate/cratestorage.h" -namespace el = djinterop::enginelibrary; +namespace el = djinterop::engine; namespace mixxx { @@ -198,8 +198,8 @@ void DlgLibraryExport::exportRequested() { // Work out what version was requested. // If there is an existing database, the version does not matter. int versionIndex = m_pVersionCombo->currentData().toInt(); - djinterop::semantic_version exportVersion = - versionIndex == -1 ? el::version_latest_firmware : el::all_versions[versionIndex]; + el::engine_version exportVersion = + versionIndex == -1 ? el::latest_os : el::all_versions[versionIndex]; // Construct a request to export the library/crates. auto pRequest = QSharedPointer<EnginePrimeExportRequest>::create(); @@ -231,46 +231,30 @@ void DlgLibraryExport::checkExistingDatabase() { m_pExistingDatabaseLabel->setText(""); m_pVersionCombo->clear(); m_pVersionCombo->setEnabled(true); - int versionIndex = 0; - for (const djinterop::semantic_version& version : el::all_versions) { + for (int versionIndex = 0; versionIndex < (int)el::all_versions.size(); ++versionIndex) { + el::engine_version version = el::all_versions[versionIndex]; m_pVersionCombo->insertItem(0, - QString::fromStdString(el::version_name(version)), + QString::fromStdString(version.name), QVariant{versionIndex}); - if (version == el::version_latest_firmware) { + if (version == el::latest_os) { // Latest firmware version is the default selection. m_pVersionCombo->setCurrentIndex(0); } - - ++versionIndex; } return; } - // Find out version of the existing database, and set the displayed - // version widget accordingly. Changing the schema version of existing - // databases is not currently supported. + // Load the existing database, and set the displayed version widget + // accordingly. Changing the schema version of existing databases is + // not currently supported. djinterop::database db = el::load_database(databaseDirectory.toStdString()); - const auto version = db.version(); - - const auto result = std::find(el::all_versions.begin(), el::all_versions.end(), version); - if (result == el::all_versions.end()) { - // Unknown database version. - m_pExistingDatabaseLabel->setText( - tr("A database already exists in the chosen directory, " - "but it is of an unsupported version. Export is not " - "guaranteed to succeed in this situation.")); - m_pVersionCombo->clear(); - m_pVersionCombo->setEnabled(false); - } else { - int versionIndex = std::distance(el::all_versions.begin(), result); - m_pExistingDatabaseLabel->setText( - tr("A database already exists in the chosen directory. " - "Exported tracks will be added into this database.")); - m_pVersionCombo->clear(); - m_pVersionCombo->insertItem( - 0, QString::fromStdString(el::version_name(version)), QVariant{versionIndex}); - m_pVersionCombo->setEnabled(false); - } + m_pExistingDatabaseLabel->setText( + tr("A database already exists in the chosen directory. " + "Exported tracks will be added into this database.")); + m_pVersionCombo->clear(); + m_pVersionCombo->insertItem( + 0, QString::fromStdString(db.version_name()), QVariant{-1}); + m_pVersionCombo->setEnabled(false); } catch (std::exception& e) { Q_UNUSED(e); diff --git a/src/library/export/engineprimeexportjob.cpp b/src/library/export/engineprimeexportjob.cpp index d5db7057d6..840f4fa32c 100644 --- a/src/library/export/engineprimeexportjob.cpp +++ b/src/library/export/engineprimeexportjob.cpp @@ -18,7 +18,7 @@ #include "util/thread_affinity.h" #include "waveform/waveformfactory.h" -namespace el = djinterop::enginelibrary; +namespace el = djinterop::engine; namespace mixxx { @@ -168,7 +168,9 @@ bool tryGetBeatgrid(BeatsPointer pBeats, return true; } -void exportMetadata(djinterop::database* pDatabase, +void exportMetadata( + djinterop::database* pDatabase, + const el::engine_version& dbVersion, QHash<TrackId, int64_t>* pMixxxToEnginePrimeTrackIdMap, TrackPointer pTrack, const Waveform* pWaveform, @@ -182,12 +184,11 @@ void exportMetadata(djinterop::database* pDatabase, : djinterop::track_snapshot{}; snapshot.relative_path = relativePath.toStdString(); - // Note that the Engine Prime format has the scope for recording meta-data - // about whether track was imported from an external database. However, - // that meta-data only extends as far as other Engine Prime databases, - // which Mixxx is not. So we do not set any import information on the - // exported track. snapshot.track_number = pTrack->getTrackNumber().toInt(); + if (snapshot.track_number == 0) { + snapshot.track_number = djinterop::stdx::nullopt; + } + snapshot.duration = std::chrono::milliseconds{ static_cast<int64_t>(1000 * pTrack->getDuration())}; snapshot.bpm = pTrack->getBpm(); @@ -199,24 +200,14 @@ void exportMetadata(djinterop::database* pDatabase, snapshot.comment = pTrack->getComment().toStdString(); snapshot.composer = pTrack->getComposer().toStdString(); snapshot.key = toDjinteropKey(pTrack->getKey()); - int64_t lastModifiedMillisSinceEpoch = 0; - const QDateTime fileLastModified = pTrack->getFileInfo().lastModified(); - if (fileLastModified.isValid()) { - // Only defined if valid - lastModifiedMillisSinceEpoch = fileLastModified.toMSecsSinceEpoch(); - } - std::chrono::system_clock::time_point lastModifiedAt{ - std::chrono::milliseconds{lastModifiedMillisSinceEpoch}}; - snapshot.last_modified_at = lastModifiedAt; - snapshot.last_accessed_at = lastModifiedAt; snapshot.bitrate = pTrack->getBitrate(); snapshot.rating = pTrack->getRating() * 20; // note rating is in range 0-100 snapshot.file_bytes = pTrack->getFileInfo().sizeInBytes(); // Frames used interchangeably with "samples" here. const auto frameCount = static_cast<int64_t>(pTrack->getDuration() * pTrack->getSampleRate()); - snapshot.sampling = djinterop::sampling_info{ - static_cast<double>(pTrack->getSampleRate()), frameCount}; + snapshot.sample_count = frameCount; + snapshot.sample_rate = pTrack->getSampleRate(); // Set track loudness. // Note that the djinterop API method for setting loudness may be revised @@ -229,16 +220,14 @@ void exportMetadata(djinterop::database* pDatabase, // Set main cue-point. mixxx::audio::FramePos cuePlayPos = pTrack->getMainCuePosition(); const auto cuePlayPosValue = cuePlayPos.isValid() ? cuePlayPos.value() : 0; - snapshot.default_main_cue = cuePlayPosValue; - snapshot.adjusted_main_cue = cuePlayPosValue; + snapshot.main_cue = cuePlayPosValue; // Fill in beat grid. BeatsPointer beats = pTrack->getBeats(); if (beats != nullptr) { std::vector<djinterop::beatgrid_marker> beatgrid; if (tryGetBeatgrid(beats, cuePlayPos, frameCount, &beatgrid)) { - snapshot.default_beatgrid = beatgrid; - snapshot.adjusted_beatgrid = beatgrid; + snapshot.beatgrid = beatgrid; } else { qWarning() << "Beats data exists but is invalid for track" << pTrack->getId() << "(" @@ -252,7 +241,7 @@ void exportMetadata(djinterop::database* pDatabase, // Note that any existing hot cues on the track are kept in place, if Mixxx // does not have a hot cue at that location. const auto cues = pTrack->getCuePoints(); - snapshot.hot_cues.fill(djinterop::stdx::nullopt); + snapshot.hot_cues.resize(kMaxHotCues); for (const CuePointer& pCue : cues) { // We are only interested in hot cues. if (pCue->getType() != CueType::HotCue) { @@ -303,16 +292,15 @@ void exportMetadata(djinterop::database* pDatabase, // Note also that the loops on any existing track are not modified here. // Write waveform. - // Note that writing a single waveform will automatically calculate an - // overview waveform too. if (pWaveform) { - int64_t samplesPerEntry = - el::required_waveform_samples_per_entry(pTrack->getSampleRate()); - int64_t externalWaveformSize = (frameCount + samplesPerEntry - 1) / samplesPerEntry; + djinterop::waveform_extents extents = dbVersion.is_v2_schema() + ? el::calculate_overview_waveform_extents( + frameCount, pTrack->getSampleRate()) + : el::calculate_high_resolution_waveform_extents(frameCount, pTrack->getSampleRate()); std::vector<djinterop::waveform_entry> externalWaveform; - externalWaveform.reserve(externalWaveformSize); - for (int64_t i = 0; i < externalWaveformSize; ++i) { - int64_t j = pWaveform->getDataSize() * i / externalWaveformSize; + externalWaveform.reserve(extents.size); + for (uint64_t i = 0; i < extents.size; ++i) { + uint64_t j = pWaveform->getDataSize() * i / extents.size; externalWaveform.push_back({{pWaveform->getLow(j), kDefaultWaveformOpacity}, {pWaveform->getMid(j), kDefaultWaveformOpacity}, {pWaveform->getHigh(j), kDefaultWaveformOpacity}}); @@ -339,6 +327,7 @@ void exportMetadata(djinterop::database* pDatabase, void exportTrack( const QSharedPointer<EnginePrimeExportRequest> pRequest, djinterop::database* pDatabase, + const el::engine_version& dbVersion, QHash<TrackId, int64_t>* pMixxxToEnginePrimeTrackIdMap, const TrackPointer pTrack, const Waveform* pWaveform) { @@ -355,6 +344,7 @@ void exportTrack( // Export meta-data. exportMetadata(pDatabase, + dbVersion, pMixxxToEnginePrimeTrackIdMap, pTrack, pWaveform, @@ -366,8 +356,12 @@ void exportCrate( const QHash<TrackId, int64_t>& mixxxToEnginePrimeTrackIdMap, const Crate& crate, const QList<TrackId>& trackIds) { - // Create a new crate as a sub-crate of the top-level Mixxx crate. - auto extCrate = pExtRootCrate->create_sub_crate(crate.getName().toStdString()); + // Create a new crate as a sub-crate of the top-level Mixxx crate, if one does not already exist. + auto crateName = crate.getName().toStdString(); + const auto optionalExtCrate = pExtRootCrate->sub_crate_by_name(crateName); + auto extCrate = optionalExtCrate + ? *optionalExtCrate + : pExtRootCrate->create_sub_crate(crateName); // Loop through all track ids in this crate and add. for (const auto& trackId : trackIds) { @@ -520,12 +514,18 @@ void EnginePrimeExportJob::run() { // Ensure that the database exists, creating an empty one if not. std::unique_ptr<djinterop::database> pDb; + el::engine_version dbVersion; try { bool created; pDb = std::make_unique<djinterop::database>(el::create_or_load_database( m_pRequest->engineLibraryDbDir.path().toStdString(), m_pRequest->exportVersion, - created)); + created, + dbVersion)); + + if (!created) { + dbVersion = m_pRequest->exportVersion; + } } catch (std::exception& e) { qWarning() << "Failed to create/load database:" << e.what(); m_lastErrorMessage = e.what(); @@ -561,6 +561,7 @@ void EnginePrimeExportJob::run() { try { exportTrack(m_pRequest, pDb.get(), + dbVersion, &mixxxToEnginePrimeTrackIdMap, m_pLastLoadedTrack, m_pLastLoadedWaveform.get()); diff --git a/src/library/export/engineprimeexportrequest.h b/src/library/export/engineprimeexportrequest.h index efd840be83..1f31b2beea 100644 --- a/src/library/export/engineprimeexportrequest.h +++ b/src/library/export/engineprimeexportrequest.h @@ -18,7 +18,7 @@ struct EnginePrimeExportRequest { QDir musicFilesDir; /// Version of Engine Prime database to use when exporting. - djinterop::semantic_version exportVersion; + djinterop::engine::engine_version exportVersion; /// Set of crates to export, if `exportSelectedCrates` is set to true. /// |