1 #pragma once
2 
3 #include <taglib/tag.h>
4 #include <taglib/tstringlist.h>
5 
6 #include <QByteArray>
7 #include <QFlags>
8 #include <QImage>
9 #include <QString>
10 
11 #if defined(__EXTRA_METADATA__)
12 // UUID -> QString
13 #include "util/compatibility.h"
14 #endif // __EXTRA_METADATA__
15 
16 // TagLib has support for the Ogg Opus file format since version 1.9
17 #define TAGLIB_HAS_OPUSFILE \
18     ((TAGLIB_MAJOR_VERSION > 1) || ((TAGLIB_MAJOR_VERSION == 1) && (TAGLIB_MINOR_VERSION >= 9)))
19 
20 // TagLib has support for hasID3v2Tag()/ID3v2Tag() for WAV files since version 1.9
21 #define TAGLIB_HAS_WAV_ID3V2TAG \
22     (TAGLIB_MAJOR_VERSION > 1) || ((TAGLIB_MAJOR_VERSION == 1) && (TAGLIB_MINOR_VERSION >= 9))
23 
24 #include "track/trackmetadata.h"
25 
26 namespace mixxx {
27 
28 namespace taglib {
29 
30 QString toQString(
31         const TagLib::String& tString);
32 
33 TagLib::String toTString(
34         const QString& qString);
35 
36 /// Returns the first element of TagLib string list that is not empty.
37 TagLib::String firstNonEmptyStringListItem(
38         const TagLib::StringList& strList);
39 
40 /// Returns a QByteArray that owns the data.
toQByteArray(const TagLib::ByteVector & tByteVector)41 inline QByteArray toQByteArray(
42         const TagLib::ByteVector& tByteVector) {
43         return QByteArray(
44                 tByteVector.data(),
45                 tByteVector.size());
46 }
47 
48 /// Returns a QByteArray that directly accesses the underlying byte vector!
toQByteArrayRaw(const TagLib::ByteVector & tByteVector)49 inline QByteArray toQByteArrayRaw(
50         const TagLib::ByteVector& tByteVector) {
51         return QByteArray::fromRawData(
52                 tByteVector.data(),
53                 tByteVector.size());
54 }
55 
toTByteVector(const QByteArray & byteArray)56 inline TagLib::ByteVector toTByteVector(
57         const QByteArray& byteArray) {
58     if (byteArray.isNull()) {
59         return TagLib::ByteVector();
60     } else {
61         return TagLib::ByteVector(byteArray.constData(), byteArray.size());
62     }
63 }
64 
65 #if defined(__EXTRA_METADATA__)
uuidToTString(const QUuid & uuid)66 inline TagLib::String uuidToTString(
67         const QUuid& uuid) {
68     return toTString(uuidToNullableStringWithoutBraces(uuid));
69 }
70 #endif // __EXTRA_METADATA__
71 
formatBpm(const TrackMetadata & trackMetadata)72 inline QString formatBpm(
73         const TrackMetadata& trackMetadata) {
74     return Bpm::valueToString(
75             trackMetadata.getTrackInfo().getBpm().getValue());
76 }
77 
78 bool parseBpm(
79         TrackMetadata* pTrackMetadata,
80         const QString& sBpm);
81 
formatReplayGainGain(const ReplayGain & replayGain)82 inline QString formatReplayGainGain(
83         const ReplayGain& replayGain) {
84     return ReplayGain::ratioToString(replayGain.getRatio());
85 }
86 
formatReplayGainPeak(const ReplayGain & replayGain)87 inline QString formatReplayGainPeak(
88         const ReplayGain& replayGain) {
89     return ReplayGain::peakToString(replayGain.getPeak());
90 }
91 
formatTrackGain(const TrackMetadata & trackMetadata)92 inline QString formatTrackGain(
93         const TrackMetadata& trackMetadata) {
94     return formatReplayGainGain(
95             trackMetadata.getTrackInfo().getReplayGain());
96 }
97 
98 bool parseTrackGain(
99         TrackMetadata* pTrackMetadata,
100         const QString& dbGain);
101 
formatTrackPeak(const TrackMetadata & trackMetadata)102 inline QString formatTrackPeak(
103         const TrackMetadata& trackMetadata) {
104     return formatReplayGainPeak(
105             trackMetadata.getTrackInfo().getReplayGain());
106 }
107 
108 bool parseTrackPeak(
109         TrackMetadata* pTrackMetadata,
110         const QString& strPeak);
111 
112 #if defined(__EXTRA_METADATA__)
formatAlbumGain(const TrackMetadata & trackMetadata)113 inline QString formatAlbumGain(
114         const TrackMetadata& trackMetadata) {
115     return formatReplayGainGain(trackMetadata.getAlbumInfo().getReplayGain());
116 }
117 
118 bool parseAlbumGain(
119         TrackMetadata* pTrackMetadata,
120         const QString& dbGain);
121 
formatAlbumPeak(const TrackMetadata & trackMetadata)122 inline QString formatAlbumPeak(
123         const TrackMetadata& trackMetadata) {
124     return formatReplayGainPeak(trackMetadata.getAlbumInfo().getReplayGain());
125 }
126 
127 bool parseAlbumPeak(
128         TrackMetadata* pTrackMetadata,
129         const QString& strPeak);
130 #endif // __EXTRA_METADATA__
131 
132 bool parseSeratoBeatGrid(
133         TrackMetadata* pTrackMetadata,
134         const QByteArray& data,
135         FileType fileType);
136 
137 bool parseSeratoBeatGrid(
138         TrackMetadata* pTrackMetadata,
139         const TagLib::String& data,
140         FileType fileType);
141 
142 bool parseSeratoMarkers(
143         TrackMetadata* pTrackMetadata,
144         const QByteArray& data,
145         FileType fileType);
146 
147 bool parseSeratoMarkers(
148         TrackMetadata* pTrackMetadata,
149         const TagLib::String& data,
150         FileType fileType);
151 
152 bool parseSeratoMarkers2(
153         TrackMetadata* pTrackMetadata,
154         const QByteArray& data,
155         FileType fileType);
156 
157 bool parseSeratoMarkers2(
158         TrackMetadata* pTrackMetadata,
159         const TagLib::String& data,
160         FileType fileType);
161 
162 TagLib::String dumpSeratoBeatGrid(
163         const TrackMetadata& trackMetadata,
164         FileType fileType);
165 
166 TagLib::String dumpSeratoMarkers(
167         const TrackMetadata& trackMetadata,
168         FileType fileType);
169 
170 TagLib::String dumpSeratoMarkers2(
171         const TrackMetadata& trackMetadata,
172         FileType fileType);
173 
174 inline QImage loadImageFromByteVector(
175         const TagLib::ByteVector& imageData,
176         const char* format = nullptr) {
177     return QImage::fromData(
178             // char -> uchar
179             reinterpret_cast<const uchar*>(imageData.data()),
180             imageData.size(),
181             format);
182 }
183 
184 /// Bitmask of optional tag fields that should NOT be read from the
185 /// common part of the tag through TagLib::Tag.
186 /// Usage: The write functions for ID3v2, MP4, APE and XiphComment tags
187 /// have specialized code for some or all of the corresponding tag fields
188 /// and the common implementation sometime doesn't work as expected.
189 enum class ReadTagFlag {
190     OmitNone = 0,
191     OmitComment = 1 << 0,
192 };
193 
194 Q_DECLARE_FLAGS(ReadTagMask, ReadTagFlag)
195 
196 Q_DECLARE_OPERATORS_FOR_FLAGS(ReadTagMask)
197 
198 void importTrackMetadataFromTag(
199         TrackMetadata* pTrackMetadata,
200         const TagLib::Tag& tag,
201         ReadTagMask readMask = ReadTagFlag::OmitNone);
202 
203 /// Bitmask of optional tag fields that should NOT be written into the
204 /// common part of the tag through TagLib::Tag. For future extension
205 /// it is safer to explicitly specify these exceptions!
206 /// Usage: The write functions for ID3v2, MP4, APE and XiphComment tags
207 /// have specialized code for some or all of the corresponding tag fields
208 /// and it is not needed or even dangerous to use the common setters of
209 /// TagLib::Tag.
210 enum class WriteTagFlag {
211     OmitNone = 0,
212     OmitComment = 1 << 0,
213     OmitTrackNumber = 1 << 1,
214     OmitYear = 1 << 2,
215 };
216 
217 Q_DECLARE_FLAGS(WriteTagMask, WriteTagFlag)
218 
219 Q_DECLARE_OPERATORS_FOR_FLAGS(WriteTagMask)
220 
221 void exportTrackMetadataIntoTag(
222         TagLib::Tag* pTag,
223         const TrackMetadata& trackMetadata,
224         WriteTagMask writeMask);
225 
226 } // namespace taglib
227 
228 } // namespace mixxx
229