diff options
author | Uwe Klotz <uklotz@mixxx.org> | 2020-05-01 19:01:00 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-01 19:01:00 +0200 |
commit | 48c7fe12dd52ccc5c036a7f3f1fa5b59d57345c8 (patch) | |
tree | ebe02a2164b057aa7ae20f46633dec3938c94689 /src/track | |
parent | c894af633e87aa3d1caae4fb09d09b965bbac12a (diff) | |
parent | 43c8a63149be98c7f8b35b215dd14b1f823a6559 (diff) |
Merge pull request #2709 from uklotzde/seratomarkers2_metadata
Import/export Serato marker file tags (MP4/FLAC)
Diffstat (limited to 'src/track')
-rw-r--r-- | src/track/serato/markers.cpp | 357 | ||||
-rw-r--r-- | src/track/serato/markers.h | 27 | ||||
-rw-r--r-- | src/track/serato/markers2.cpp | 327 | ||||
-rw-r--r-- | src/track/serato/markers2.h | 39 | ||||
-rw-r--r-- | src/track/serato/tags.h | 26 | ||||
-rw-r--r-- | src/track/taglib/trackmetadata_common.cpp | 48 | ||||
-rw-r--r-- | src/track/taglib/trackmetadata_common.h | 24 | ||||
-rw-r--r-- | src/track/taglib/trackmetadata_file.cpp | 1 | ||||
-rw-r--r-- | src/track/taglib/trackmetadata_file.h | 7 | ||||
-rw-r--r-- | src/track/taglib/trackmetadata_id3v2.cpp | 14 | ||||
-rw-r--r-- | src/track/taglib/trackmetadata_mp4.cpp | 40 | ||||
-rw-r--r-- | src/track/taglib/trackmetadata_xiph.cpp | 42 | ||||
-rw-r--r-- | src/track/taglib/trackmetadata_xiph.h | 6 |
13 files changed, 781 insertions, 177 deletions
diff --git a/src/track/serato/markers.cpp b/src/track/serato/markers.cpp index bdb540001c..bce826e538 100644 --- a/src/track/serato/markers.cpp +++ b/src/track/serato/markers.cpp @@ -3,14 +3,22 @@ #include <QtEndian> #include "track/serato/tags.h" +#include "util/logger.h" namespace { +mixxx::Logger kLogger("SeratoMarkers"); + const int kNumEntries = 14; const int kLoopEntryStartIndex = 5; -const int kEntrySize = 22; +const int kEntrySizeID3 = 22; +const int kEntrySizeMP4 = 19; const quint16 kVersion = 0x0205; +const QByteArray kSeratoMarkersBase64EncodedPrefix = QByteArray( + "application/octet-stream\x00\x00Serato Markers_\x00", + 24 + 2 + 15 + 1); + // These functions convert between a custom 4-byte format (that we'll call // "serato32" for brevity) and 3-byte plaintext (both quint32). // Serato's custom format inserts a single null bit after every 7 payload @@ -66,12 +74,11 @@ quint32 serato32fromUint24(quint32 value) { namespace mixxx { -QByteArray SeratoMarkersEntry::dump() const { +QByteArray SeratoMarkersEntry::dumpID3() const { QByteArray data; - data.resize(kEntrySize); + data.resize(kEntrySizeID3); QDataStream stream(&data, QIODevice::WriteOnly); - stream.setVersion(QDataStream::Qt_5_0); stream.setByteOrder(QDataStream::BigEndian); stream << static_cast<quint8>((m_hasStartPosition ? 0x00 : 0x7F)) << static_cast<quint32>( @@ -87,10 +94,27 @@ QByteArray SeratoMarkersEntry::dump() const { return data; } -SeratoMarkersEntryPointer SeratoMarkersEntry::parse(const QByteArray& data) { - if (data.length() != kEntrySize) { - qWarning() << "Parsing SeratoMarkersEntry failed:" - << "Length" << data.length() << "!=" << kEntrySize; +QByteArray SeratoMarkersEntry::dumpMP4() const { + QByteArray data; + data.resize(kEntrySizeMP4); + + QDataStream stream(&data, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::BigEndian); + stream << static_cast<quint32>(m_startPosition) + << static_cast<quint32>(m_endPosition); + stream.writeRawData("\x00\xFF\xFF\xFF\xFF\x00", 6); + stream << static_cast<quint8>(qRed(m_color)) + << static_cast<quint8>(qGreen(m_color)) + << static_cast<quint8>(qBlue(m_color)) + << static_cast<quint8>(m_type) + << static_cast<quint8>(m_isLocked); + return data; +} + +SeratoMarkersEntryPointer SeratoMarkersEntry::parseID3(const QByteArray& data) { + if (data.length() != kEntrySizeID3) { + kLogger.warning() << "Parsing SeratoMarkersEntry failed:" + << "Length" << data.length() << "!=" << kEntrySizeID3; return nullptr; } @@ -104,14 +128,13 @@ SeratoMarkersEntryPointer SeratoMarkersEntry::parse(const QByteArray& data) { char buffer[6]; QDataStream stream(data); - stream.setVersion(QDataStream::Qt_5_0); stream.setByteOrder(QDataStream::BigEndian); stream >> startPositionStatus >> startPositionSerato32 >> endPositionStatus >> endPositionSerato32; if (stream.readRawData(buffer, sizeof(buffer)) != sizeof(buffer)) { - qWarning() << "Parsing SeratoMarkersEntry failed:" - << "unable to read bytes 10..16"; + kLogger.warning() << "Parsing SeratoMarkersEntry failed:" + << "unable to read bytes 10..16"; return nullptr; } @@ -125,8 +148,8 @@ SeratoMarkersEntryPointer SeratoMarkersEntry::parse(const QByteArray& data) { if (!hasStartPosition) { // Start position not set if (startPositionSerato32 != 0x7F7F7F7F) { - qWarning() << "Parsing SeratoMarkersEntry failed:" - << "startPosition != 0x7F7F7F7F"; + kLogger.warning() << "Parsing SeratoMarkersEntry failed:" + << "startPosition != 0x7F7F7F7F"; return nullptr; } @@ -140,8 +163,8 @@ SeratoMarkersEntryPointer SeratoMarkersEntry::parse(const QByteArray& data) { if (!hasEndPosition) { // End position not set if (endPositionSerato32 != 0x7F7F7F7F) { - qWarning() << "Parsing SeratoMarkersEntry failed:" - << "endPosition != 0x7F7F7F7F"; + kLogger.warning() << "Parsing SeratoMarkersEntry failed:" + << "endPosition != 0x7F7F7F7F"; return nullptr; } @@ -151,20 +174,20 @@ SeratoMarkersEntryPointer SeratoMarkersEntry::parse(const QByteArray& data) { // Make sure that the unknown (and probably unused) bytes have the expected value if (strncmp(buffer, "\x00\x7F\x7F\x7F\x7F\x7F", sizeof(buffer)) != 0) { - qWarning() << "Parsing SeratoMarkersEntry failed:" - << "Unexpected value at offset 10"; + kLogger.warning() << "Parsing SeratoMarkersEntry failed:" + << "Unexpected value at offset 10"; return nullptr; } if (stream.status() != QDataStream::Status::Ok) { - qWarning() << "Parsing SeratoMarkersEntry failed:" - << "Stream read failed with status" << stream.status(); + kLogger.warning() << "Parsing SeratoMarkersEntry failed:" + << "Stream read failed with status" << stream.status(); return nullptr; } if (!stream.atEnd()) { - qWarning() << "Parsing SeratoMarkersEntry failed:" - << "Unexpected trailing data"; + kLogger.warning() << "Parsing SeratoMarkersEntry failed:" + << "Unexpected trailing data"; return nullptr; } @@ -176,21 +199,100 @@ SeratoMarkersEntryPointer SeratoMarkersEntry::parse(const QByteArray& data) { color, type, isLocked)); - qDebug() << "SeratoMarkersEntry" << *pEntry; + kLogger.trace() << "SeratoMarkersEntry" << *pEntry; + return pEntry; +} + +SeratoMarkersEntryPointer SeratoMarkersEntry::parseMP4(const QByteArray& data) { + if (data.length() != kEntrySizeMP4) { + kLogger.warning() << "Parsing SeratoMarkersEntry (MP4) failed:" + << "Length" << data.length() << "!=" << kEntrySizeMP4; + return nullptr; + } + + quint32 startPosition; + quint32 endPosition; + char buffer[6]; + quint8 colorRed; + quint8 colorGreen; + quint8 colorBlue; + quint8 type; + bool isLocked; + + QDataStream stream(data); + stream.setByteOrder(QDataStream::BigEndian); + stream >> startPosition >> endPosition; + + if (stream.readRawData(buffer, sizeof(buffer)) != sizeof(buffer)) { + kLogger.warning() << "Parsing SeratoMarkersEntry (MP4) failed:" + << "unable to read bytes 8..14"; + return nullptr; + } + + stream >> colorRed >> colorGreen >> colorBlue >> type >> isLocked; + const RgbColor color = RgbColor(qRgb(colorRed, colorGreen, colorBlue)); + + // Make sure that the unknown (and probably unused) bytes have the expected value + if (strncmp(buffer, "\x00\xFF\xFF\xFF\xFF\x00", sizeof(buffer)) != 0) { + kLogger.warning() << "Parsing SeratoMarkersEntry (MP4) failed:" + << "Unexpected value at offset 8"; + return nullptr; + } + + if (stream.status() != QDataStream::Status::Ok) { + kLogger.warning() << "Parsing SeratoMarkersEntry failed:" + << "Stream read failed with status" << stream.status(); + return nullptr; + } + + if (!stream.atEnd()) { + kLogger.warning() << "Parsing SeratoMarkersEntry failed:" + << "Unexpected trailing data"; + return nullptr; + } + + SeratoMarkersEntryPointer pEntry = + SeratoMarkersEntryPointer(new SeratoMarkersEntry( + true, + startPosition, + type == static_cast<quint8>(TypeId::Loop), + endPosition, + color, + type, + isLocked)); + kLogger.trace() << "SeratoMarkersEntry" << *pEntry; return pEntry; } +// static bool SeratoMarkers::parse( + SeratoMarkers* seratoMarkers, const QByteArray& data, taglib::FileType fileType) { + VERIFY_OR_DEBUG_ASSERT(seratoMarkers) { + return false; + } + + switch (fileType) { + case taglib::FileType::MP3: + case taglib::FileType::AIFF: + return parseID3(seratoMarkers, data); + case taglib::FileType::MP4: + return parseMP4(seratoMarkers, data); + default: + return false; + } +} + +// static +bool SeratoMarkers::parseID3( SeratoMarkers* seratoMarkers, const QByteArray& data) { QDataStream stream(data); - stream.setVersion(QDataStream::Qt_5_0); stream.setByteOrder(QDataStream::BigEndian); quint16 version; stream >> version; if (version != kVersion) { - qWarning() << "Parsing SeratoMarkers_ failed:" - << "Unknown Serato Markers_ tag version"; + kLogger.warning() << "Parsing SeratoMarkers_ failed:" + << "Unknown Serato Markers_ tag version"; return false; } @@ -198,42 +300,42 @@ bool SeratoMarkers::parse( stream >> numEntries; if (numEntries != kNumEntries) { - qWarning() << "Parsing SeratoMarkers_ failed:" - << "Expected" << kNumEntries << "entries but found" - << numEntries; + kLogger.warning() << "Parsing SeratoMarkers_ failed:" + << "Expected" << kNumEntries << "entries but found" + << numEntries; return false; } - char buffer[kEntrySize]; + char buffer[kEntrySizeID3]; QList<SeratoMarkersEntryPointer> entries; for (quint32 i = 0; i < numEntries; i++) { if (stream.readRawData(buffer, sizeof(buffer)) != sizeof(buffer)) { - qWarning() << "Parsing SeratoMarkersEntry failed:" - << "unable to read entry data"; + kLogger.warning() << "Parsing SeratoMarkersEntry failed:" + << "unable to read entry data"; return false; } - QByteArray entryData = QByteArray(buffer, kEntrySize); + QByteArray entryData = QByteArray(buffer, kEntrySizeID3); SeratoMarkersEntryPointer pEntry = - SeratoMarkersEntryPointer(SeratoMarkersEntry::parse(entryData)); + SeratoMarkersEntryPointer(SeratoMarkersEntry::parseID3(entryData)); if (!pEntry) { - qWarning() << "Parsing SeratoMarkers_ failed:" - << "Unable to parse entry!"; + kLogger.warning() << "Parsing SeratoMarkers_ failed:" + << "Unable to parse entry!"; return false; } if (i < kLoopEntryStartIndex && pEntry->typeId() != SeratoMarkersEntry::TypeId::Cue) { - qWarning() << "Parsing SeratoMarkers_ failed:" - << "Expected cue entry but found type" << pEntry->type(); + kLogger.warning() << "Parsing SeratoMarkers_ failed:" + << "Expected cue entry but found type" << pEntry->type(); return false; } if (i >= kLoopEntryStartIndex && pEntry->typeId() != SeratoMarkersEntry::TypeId::Loop) { - qWarning() << "Parsing SeratoMarkers_ failed:" - << "Expected loop entry but found type" - << pEntry->type(); + kLogger.warning() << "Parsing SeratoMarkers_ failed:" + << "Expected loop entry but found type" + << pEntry->type(); return false; } @@ -245,14 +347,14 @@ bool SeratoMarkers::parse( RgbColor trackColor = RgbColor(serato32toUint24(trackColorSerato32)); if (stream.status() != QDataStream::Status::Ok) { - qWarning() << "Parsing SeratoMarkers_ failed:" - << "Stream read failed with status" << stream.status(); + kLogger.warning() << "Parsing SeratoMarkers_ failed:" + << "Stream read failed with status" << stream.status(); return false; } if (!stream.atEnd()) { - qWarning() << "Parsing SeratoMarkers_ failed:" - << "Unexpected trailing data"; + kLogger.warning() << "Parsing SeratoMarkers_ failed:" + << "Unexpected trailing data"; return false; } seratoMarkers->setEntries(std::move(entries)); @@ -261,7 +363,119 @@ bool SeratoMarkers::parse( return true; } -QByteArray SeratoMarkers::dump() const { +// static +bool SeratoMarkers::parseMP4( + SeratoMarkers* seratoMarkers, + const QByteArray& base64EncodedData) { + const auto decodedData = QByteArray::fromBase64(base64EncodedData); + if (!decodedData.startsWith(kSeratoMarkersBase64EncodedPrefix)) { + kLogger.warning() << "Decoding SeratoMarkers_ from base64 failed:" + << "Unexpected prefix"; + return false; + } + + QDataStream stream(decodedData.mid(kSeratoMarkersBase64EncodedPrefix.length())); + stream.setByteOrder(QDataStream::BigEndian); + + quint16 version; + stream >> version; + if (version != kVersion) { + kLogger.warning() << "Parsing SeratoMarkers_ (MP4) failed:" + << "Unknown Serato Markers_ tag version" << QString::number(version, 16); + return false; + } + + quint32 numEntries; + stream >> numEntries; + + if (numEntries != kNumEntries) { + kLogger.warning() << "Parsing SeratoMarkers_ (MP4) failed:" + << "Expected" << kNumEntries << "entries but found" + << numEntries; + return false; + } + + char buffer[kEntrySizeMP4]; + QList<SeratoMarkersEntryPointer> entries; + for (quint32 i = 0; i < numEntries; i++) { + if (stream.readRawData(buffer, sizeof(buffer)) != sizeof(buffer)) { + kLogger.warning() << "Parsing SeratoMarkersEntry (MP4) failed:" + << "unable to read entry data"; + return false; + } + + QByteArray entryData = QByteArray(buffer, kEntrySizeMP4); + SeratoMarkersEntryPointer pEntry = + SeratoMarkersEntryPointer(SeratoMarkersEntry::parseMP4(entryData)); + if (!pEntry) { + kLogger.warning() << "Parsing SeratoMarkers_ (MP4) failed:" + << "Unable to parse entry!"; + return false; + } + + if (i < kLoopEntryStartIndex && + pEntry->typeId() != SeratoMarkersEntry::TypeId::Cue) { + kLogger.warning() << "Parsing SeratoMarkers_ (MP4) failed:" + << "Expected cue entry but found type" << pEntry->type(); + return false; + } + + if (i >= kLoopEntryStartIndex && + pEntry->typeId() != SeratoMarkersEntry::TypeId::Loop) { + kLogger.warning() << "Parsing SeratoMarkers_ (MP4) failed:" + << "Expected loop entry but found type" + << pEntry->type(); + return false; + } + + entries.append(pEntry); + } + + quint8 field1; + quint8 colorRed; + quint8 colorGreen; + quint8 colorBlue; + stream >> field1 >> colorRed >> colorGreen >> colorBlue; + RgbColor trackColor = RgbColor(qRgb(colorRed, colorGreen, colorBlue)); + + if (field1 != 0x00) { + kLogger.warning() << "Parsing SeratoMarkers_ (MP4) failed:" + << "Unexpected value before track color" + << field1; + return false; + } + + if (stream.status() != QDataStream::Status::Ok) { + kLogger.warning() << "Parsing SeratoMarkers_ failed:" + << "Stream read failed with status" << stream.status(); + return false; + } + + if (!stream.atEnd()) { + kLogger.warning() << "Parsing SeratoMarkers_ failed:" + << "Unexpected trailing data"; + return false; + } + seratoMarkers->setEntries(std::move(entries)); + seratoMarkers->setTrackColor(trackColor); + + return true; +} + +QByteArray SeratoMarkers::dump(taglib::FileType fileType) const { + switch (fileType) { + case taglib::FileType::MP3: + case taglib::FileType::AIFF: + return dumpID3(); + case taglib::FileType::MP4: + return dumpMP4(); + default: + DEBUG_ASSERT(false); + return {}; + } +} + +QByteArray SeratoMarkers::dumpID3() const { QByteArray data; if (isEmpty()) { // Return empty QByteArray @@ -269,21 +483,68 @@ QByteArray SeratoMarkers::dump() const { } data.resize(sizeof(quint16) + 2 * sizeof(quint32) + - kEntrySize * m_entries.size()); + kEntrySizeID3 * m_entries.size()); QDataStream stream(&data, QIODevice::WriteOnly); - stream.setVersion(QDataStream::Qt_5_0); stream.setByteOrder(QDataStream::BigEndian); stream << kVersion << m_entries.size(); for (int i = 0; i < m_entries.size(); i++) { SeratoMarkersEntryPointer pEntry = m_entries.at(i); - stream.writeRawData(pEntry->dump(), kEntrySize); + stream.writeRawData(pEntry->dumpID3(), kEntrySizeID3); } stream << serato32fromUint24(static_cast<quint32>( m_trackColor.value_or(SeratoTags::kDefaultTrackColor))); return data; } +QByteArray SeratoMarkers::dumpMP4() const { + if (isEmpty()) { + // Return empty QByteArray + return {}; + } + + QByteArray data; + data.resize(kSeratoMarkersBase64EncodedPrefix.length() + + sizeof(quint16) + 2 * sizeof(quint32) + + kEntrySizeMP4 * m_entries.size()); + QDataStream stream(&data, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::BigEndian); + stream.writeRawData(kSeratoMarkersBase64EncodedPrefix.constData(), + kSeratoMarkersBase64EncodedPrefix.length()); + stream << kVersion << m_entries.size(); + for (int i = 0; i < m_entries.size(); i++) { + SeratoMarkersEntryPointer pEntry = m_entries.at(i); + stream.writeRawData(pEntry->dumpMP4(), kEntrySizeMP4); + } + + RgbColor trackColor = m_trackColor.value_or(SeratoTags::kDefaultTrackColor); + stream << static_cast<quint8>(0x00) + << static_cast<quint8>(qRed(trackColor)) + << static_cast<quint8>(qGreen(trackColor)) + << static_cast<quint8>(qBlue(trackColor)); + + // A newline char is inserted at every 72 bytes of base64-encoded content. + // Hence, we can split the data into blocks of 72 bytes * 3/4 = 54 bytes + // and base64-encode them one at a time: + const int base64Size = (data.size() * 4 + 2) / 3; + QByteArray base64Data; + base64Data.reserve(base64Size + base64Size / 72); + int offset = 0; + while (offset < data.size()) { + if (offset > 0) { + base64Data.append('\n'); + } + QByteArray block = data.mid(offset, 54); + base64Data.append(block.toBase64(QByteArray::Base64Encoding | QByteArray::OmitTrailingEquals)); + offset += block.size(); + } + + // FIXME: Why do we need to append another "A" here? + base64Data.append('A'); + + return base64Data; +} + QList<CueInfo> SeratoMarkers::getCues() const { qDebug() << "Reading cues from 'Serato Markers_' tag data..."; diff --git a/src/track/serato/markers.h b/src/track/serato/markers.h index ec05c57915..c593d4bfaa 100644 --- a/src/track/serato/markers.h +++ b/src/track/serato/markers.h @@ -7,6 +7,7 @@ #include <memory> #include "track/cueinfo.h" +#include "track/taglib/trackmetadata_file.h" #include "util/types.h" namespace mixxx { @@ -40,8 +41,11 @@ class SeratoMarkersEntry { } ~SeratoMarkersEntry() = default; - QByteArray dump() const; - static SeratoMarkersEntryPointer parse(const QByteArray& data); + QByteArray dumpID3() const; + QByteArray dumpMP4() const; + + static SeratoMarkersEntryPointer parseID3(const QByteArray& data); + static SeratoMarkersEntryPointer parseMP4(const QByteArray& data); int type() const { return m_type; @@ -97,7 +101,7 @@ class SeratoMarkersEntry { }; inline bool operator==(const SeratoMarkersEntry& lhs, const SeratoMarkersEntry& rhs) { - return (lhs.dump() == rhs.dump()); + return (lhs.dumpID3() == rhs.dumpID3()); } inline bool operator!=(const SeratoMarkersEntry& lhs, const SeratoMarkersEntry& rhs) { @@ -132,9 +136,20 @@ class SeratoMarkers final { : m_entries(std::move(entries)) { } - static bool parse(SeratoMarkers* seratoMarkers, const QByteArray& data); - - QByteArray dump() const; + static bool parse( + SeratoMarkers* seratoMarkers, + const QByteArray& data, + taglib::FileType fileType); + static bool parseID3( + SeratoMarkers* seratoMarkers, + const QByteArray& data); + static bool parseMP4( + SeratoMarkers* seratoMarkers, + const QByteArray& base64EncodedData); + + QByteArray dump(taglib::FileType fileType) const; + QByteArray dumpID3() const; + QByteArray dumpMP4() const; bool isEmpty() const { return m_entries.isEmpty() && !m_trackColor; diff --git a/src/track/serato/markers2.cpp b/src/track/serato/markers2.cpp index 6f37d59714..f03e77457a 100644 --- a/src/track/serato/markers2.cpp +++ b/src/track/serato/markers2.cpp @@ -2,7 +2,20 @@ #include <QtEndian> +#include "util/logger.h" + namespace { + +mixxx::Logger kLogger("SeratoMarkers2"); + +constexpr quint32 kLoopUnknownField2ExpectedValue = 0xFFFFFFFF; +constexpr quint8 kLoopUnknownField3ExpectedValue = 0x00; +constexpr quint8 kLoopUnknownField4ExpectedValue = 0x00; + +const QByteArray kSeratoMarkers2Base64EncodedPrefix = QByteArray( + "application/octet-stream\x00\x00Serato Markers2\x00", + 24 + 2 + 15 + 1); + QString zeroTerminatedUtf8StringtoQString(QDataStream* stream) { DEBUG_ASSERT(stream); @@ -17,20 +30,49 @@ QString zeroTerminatedUtf8StringtoQString(QDataStream* stream) { } return QString::fromUtf8(data); } + +QByteArray base64encode(const QByteArray& data, bool chopPadding) { + QByteArray dataBase64; + + // A newline char is inserted at every 72 bytes of base64-encoded content. + // Hence, we can split the data into blocks of 72 bytes * 3/4 = 54 bytes + // and base64-encode them one at a time: + int offset = 0; + while (offset < data.size()) { + if (offset > 0) { + dataBase64.append('\n'); + } + QByteArray block = data.mid(offset, 54); + dataBase64.append(block.toBase64( + QByteArray::Base64Encoding | QByteArray::OmitTrailingEquals)); + offset += block.size(); + + if (chopPadding) { + // In case that the last block would require padding, Serato seems to + // chop off the last byte of the base64-encoded data + if (block.size() % 3) { + dataBase64.chop(1); + } + } + } + + return dataBase64; +} + } // namespace namespace mixxx { SeratoMarkers2EntryPointer SeratoMarkers2BpmlockEntry::parse(const QByteArray& data) { if (data.length() != 1) { - qWarning() << "Parsing SeratoMarkers2BpmlockEntry failed:" - << "Length" << data.length() << "!= 1"; + kLogger.warning() << "Parsing SeratoMarkers2BpmlockEntry failed:" + << "Length" << data.length() << "!= 1"; return nullptr; } const bool locked = data.at(0); SeratoMarkers2BpmlockEntry* pEntry = new SeratoMarkers2BpmlockEntry(locked); - qDebug() << "SeratoMarkers2BpmlockEntry" << *pEntry; + kLogger.trace() << "SeratoMarkers2BpmlockEntry" << *pEntry; return SeratoMarkers2EntryPointer(pEntry); } @@ -39,7 +81,6 @@ QByteArray SeratoMarkers2BpmlockEntry::dump() const { data.resize(length()); QDataStream stream(&data, QIODevice::WriteOnly); - stream.setVersion(QDataStream::Qt_5_0); stream.setByteOrder(QDataStream::BigEndian); stream << static_cast<quint8>(m_locked); @@ -52,16 +93,16 @@ quint32 SeratoMarkers2BpmlockEntry::length() const { SeratoMarkers2EntryPointer SeratoMarkers2ColorEntry::parse(const QByteArray& data) { if (data.length() != 4) { - qWarning() << "Parsing SeratoMarkers2ColorEntry failed:" - << "Length" << data.length() << "!= 4"; + kLogger.warning() << "Parsing SeratoMarkers2ColorEntry failed:" + << "Length" << data.length() << "!= 4"; return nullptr; } // Unknown field, make sure it's 0 in case it's a // null-terminated string if (data.at(0) != '\x00') { - qWarning() << "Parsing SeratoMarkers2ColorEntry failed:" - << "Byte 0: " << data.at(0) << "!= '\\0'"; + kLogger.warning() << "Parsing SeratoMarkers2ColorEntry failed:" + << "Byte 0: " << data.at(0) << "!= '\\0'"; return nullptr; } @@ -71,7 +112,7 @@ SeratoMarkers2EntryPointer SeratoMarkers2ColorEntry::parse(const QByteArray& dat static_cast<quint8>(data.at(3)))); SeratoMarkers2ColorEntry* pEntry = new SeratoMarkers2ColorEntry(color); - qDebug() << "SeratoMarkers2ColorEntry" << *pEntry; + kLogger.trace() << "SeratoMarkers2ColorEntry" << *pEntry; return SeratoMarkers2EntryPointer(pEntry); } @@ -80,7 +121,6 @@ QByteArray SeratoMarkers2ColorEntry::dump() const { data.resize(length()); QDataStream stream(&data, QIODevice::WriteOnly); - stream.setVersion(QDataStream::Qt_5_0); stream.setByteOrder(QDataStream::BigEndian); stream << static_cast<quint8>('\x00') << static_cast<quint8>(qRed(m_color)) @@ -96,8 +136,8 @@ quint32 SeratoMarkers2ColorEntry::length() const { SeratoMarkers2EntryPointer SeratoMarkers2CueEntry::parse(const QByteArray& data) { if (data.length() < 13) { - qWarning() << "Parsing SeratoMarkers2CueEntry failed:" - << "Length" << data.length() << "< 13"; + kLogger.warning() << "Parsing SeratoMarkers2CueEntry failed:" + << "Length" << data.length() << "< 13"; return nullptr; } @@ -112,7 +152,6 @@ SeratoMarkers2EntryPointer SeratoMarkers2CueEntry::parse(const QByteArray& data) quint16 unknownField3; QDataStream stream(data); - stream.setVersion(QDataStream::Qt_5_0); stream.setByteOrder(QDataStream::BigEndian); stream >> unknownField1; @@ -120,8 +159,8 @@ SeratoMarkers2EntryPointer SeratoMarkers2CueEntry::parse(const QByteArray& data) // Unknown field, make sure it's 0 in case it's a // null-terminated string if (unknownField1 != '\x00') { - qWarning() << "Parsing SeratoMarkers2CueEntry failed:" - << "Byte 0: " << data.at(0) << "!= '\\0'"; + kLogger.warning() << "Parsing SeratoMarkers2CueEntry failed:" + << "Byte 0: " << data.at(0) << "!= '\\0'"; return nullptr; } @@ -130,8 +169,8 @@ SeratoMarkers2EntryPointer SeratoMarkers2CueEntry::parse(const QByteArray& data) // Unknown field, make sure it's 0 in case it's a // null-terminated string if (unknownField2 != '\x00') { - qWarning() << "Parsing SeratoMarkers2CueEntry failed:" - << "Byte 6: " << data.at(6) << "!= '\\0'"; + kLogger.warning() << "Parsing SeratoMarkers2CueEntry failed:" + << "Byte 6: " << data.at(6) << "!= '\\0'"; return nullptr; } @@ -141,27 +180,27 @@ SeratoMarkers2EntryPointer SeratoMarkers2CueEntry::parse(const QByteArray& data) // Unknown field(s), make sure it's 0 in case it's a // null-terminated string if (unknownField3 != 0x0000) { - qWarning() << "Parsing SeratoMarkers2CueEntry failed:" - << "Bytes 10-11:" << unknownField3 << "!= \"\\0\\0\""; + kLogger.warning() << "Parsing SeratoMarkers2CueEntry failed:" + << "Bytes 10-11:" << unknownField3 << "!= \"\\0\\0\""; return nullptr; } QString label = zeroTerminatedUtf8StringtoQString(&stream); if (stream.status() != QDataStream::Status::Ok) { - qWarning() << "Parsing SeratoMarkersEntry failed:" - << "Stream read failed with status" << stream.status(); + kLogger.warning() << "Parsing SeratoMarkersEntry failed:" + << "Stream read failed with status" << stream.status(); return nullptr; } if (!stream.atEnd()) { - qWarning() << "Parsing SeratoMarkersEntry failed:" - << "Unexpected trailing data"; + kLogger.warning() << "Parsing SeratoMarkersEntry failed:" + << "Unexpected trailing data"; return nullptr; } SeratoMarkers2CueEntry* pEntry = new SeratoMarkers2CueEntry(index, position, color, label); - qDebug() << "SeratoMarkers2CueEntry" << *pEntry; + kLogger.trace() << "SeratoMarkers2CueEntry" << *pEntry; return SeratoMarkers2EntryPointer(pEntry); } @@ -170,7 +209,6 @@ QByteArray SeratoMarkers2CueEntry::dump() const { data.resize(length()); QDataStream stream(&data, QIODevice::WriteOnly); - stream.setVersion(QDataStream::Qt_5_0); stream.setByteOrder(QDataStream::BigEndian); stream << static_cast<quint8>('\x00') << m_index @@ -195,8 +233,8 @@ quint32 SeratoMarkers2CueEntry::length() const { SeratoMarkers2EntryPointer SeratoMarkers2LoopEntry::parse(const QByteArray& data) { if (data.length() < 21) { - qWarning() << "Parsing SeratoMarkers2LoopEntry failed:" - << "Length" << data.length() << "< 21"; + kLogger.warning() << "Parsing SeratoMarkers2LoopEntry failed:" + << "Length" << data.length() << "< 21"; return nullptr; } @@ -206,45 +244,52 @@ SeratoMarkers2EntryPointer SeratoMarkers2LoopEntry::parse(const QByteArray& data quint32 startPosition; quint32 endPosition; quint32 unknownField2; - quint32 unknownField3; + quint8 unknownField3; + quint8 colorRed; + quint8 colorGreen; + quint8 colorBlue; quint8 unknownField4; bool locked; QDataStream stream(data); - stream.setVersion(QDataStream::Qt_5_0); stream.setByteOrder(QDataStream::BigEndian); stream >> unknownField1; // Unknown field, make sure it's 0 in case it's a // null-terminated string if (unknownField1 != '\x00') { - qWarning() << "Parsing SeratoMarkers2LoopEntry failed:" - << "Byte 0: " << unknownField1 << "!= '\\0'"; + kLogger.warning() << "Parsing SeratoMarkers2LoopEntry failed:" + << "Byte 0: " << unknownField1 << "!= '\\0'"; return nullptr; } stream >> index >> startPosition >> endPosition >> unknownField2; // Unknown field, make sure it contains the expected "default" value - if (unknownField2 != 0xffffffff) { - qWarning() << "Parsing SeratoMarkers2LoopEntry failed:" - << "Invalid magic value" << unknownField2 << "at offset 10"; + if (unknownField2 != kLoopUnknownField2ExpectedValue) { + kLogger.warning() << "Parsing SeratoMarkers2LoopEntry failed:" + << "Invalid magic value" << unknownField2 + << "!=" << kLoopUnknownField2ExpectedValue << "at offset 10"; return nullptr; } stream >> unknownField3; // Unknown field, make sure it contains the expected "default" value - if (unknownField3 != 0x002 |