diff --git a/src/track/track.cpp b/src/track/track.cpp index 79499c034fab..4a1dc85104c8 100644 --- a/src/track/track.cpp +++ b/src/track/track.cpp @@ -48,7 +48,6 @@ Track::Track( m_qMutex(QMutex::Recursive), m_id(trackId), m_bDirty(false), - m_iRating(0), m_cuePoint(0.0), m_dateAdded(QDateTime::currentDateTime()), m_bHeaderParsed(false), @@ -819,12 +818,13 @@ bool Track::isDirty() { int Track::getRating() const { QMutexLocker lock(&m_qMutex); - return m_iRating; + return m_metadata.getRating(); } void Track::setRating (int rating) { QMutexLocker lock(&m_qMutex); - if (compareAndSet(&m_iRating, rating)) { + if (m_metadata.getRating() != rating) { + m_metadata.setRating(rating); markDirtyAndUnlock(&lock); } } diff --git a/src/track/track.h b/src/track/track.h index c76cb649eb18..eafed9a26b1f 100644 --- a/src/track/track.h +++ b/src/track/track.h @@ -58,6 +58,7 @@ class Track : public QObject { Q_PROPERTY(int times_played READ getTimesPlayed) Q_PROPERTY(QString comment READ getComment WRITE setComment) Q_PROPERTY(double bpm READ getBpm WRITE setBpm) + Q_PROPERTY(int rating READ getRating WRITE setRating) Q_PROPERTY(QString bpmFormatted READ getBpmText STORED false) Q_PROPERTY(QString key READ getKeyText WRITE setKeyText) Q_PROPERTY(double duration READ getDuration WRITE setDuration) @@ -224,7 +225,7 @@ class Track : public QObject { // Returns rating int getRating() const; // Sets rating - void setRating(int); + void setRating(int rating); // Get URL for track QString getURL() const; @@ -379,9 +380,6 @@ class Track : public QObject { // URL (used in promo track) QString m_sURL; - // Track rating - int m_iRating; - // Cue point in samples double m_cuePoint; diff --git a/src/track/trackmetadata.cpp b/src/track/trackmetadata.cpp index 37402699340f..5f251f376bef 100644 --- a/src/track/trackmetadata.cpp +++ b/src/track/trackmetadata.cpp @@ -70,6 +70,7 @@ TrackMetadata::TrackMetadata() : m_duration(0.0), m_bitrate(0), m_channels(0), + m_rating(0), m_sampleRate(0) { } @@ -92,6 +93,7 @@ bool operator==(const TrackMetadata& lhs, const TrackMetadata& rhs) { (lhs.getGrouping() == rhs.getGrouping()) && (lhs.getKey() == rhs.getKey()) && (lhs.getBpm() == rhs.getBpm()) && + (lhs.getRating() == rhs.getRating()) && (lhs.getReplayGain() == rhs.getReplayGain()); } diff --git a/src/track/trackmetadata.h b/src/track/trackmetadata.h index d00bbf3a1444..0ed5a1411d1c 100644 --- a/src/track/trackmetadata.h +++ b/src/track/trackmetadata.h @@ -140,6 +140,13 @@ class TrackMetadata final { m_bpm.resetValue(); } + int getRating() const { + return m_rating; + } + void setRating(int rating) { + m_rating = rating; + } + const ReplayGain& getReplayGain() const { return m_replayGain; } @@ -195,6 +202,7 @@ class TrackMetadata final { // Integer fields (in alphabetical order) int m_bitrate; // kbit/s int m_channels; + int m_rating; int m_sampleRate; // Hz }; diff --git a/src/track/trackmetadatataglib.cpp b/src/track/trackmetadatataglib.cpp index 05a3eb525441..0bada54f34f2 100644 --- a/src/track/trackmetadatataglib.cpp +++ b/src/track/trackmetadatataglib.cpp @@ -49,6 +49,7 @@ #include #include +#include #include #include #include @@ -227,7 +228,6 @@ inline QString formatBpmInteger(const TrackMetadata& trackMetadata) { bool parseBpm(TrackMetadata* pTrackMetadata, QString sBpm) { DEBUG_ASSERT(pTrackMetadata); - bool isBpmValid = false; const double bpmValue = Bpm::valueFromString(sBpm, &isBpmValid); if (isBpmValid) { @@ -236,6 +236,73 @@ bool parseBpm(TrackMetadata* pTrackMetadata, QString sBpm) { return isBpmValid; } +int parseFlacRating(int rating) { + + int starRatingValue; + + if (rating <= 0) { + starRatingValue = 0; + } else if (rating <= 20) { + starRatingValue = 1; + } else if (rating <= 40) { + starRatingValue = 2; + } else if (rating <= 60) { + starRatingValue = 3; + } else if (rating <= 80) { + starRatingValue = 4; + } else if (rating <= 100) { + starRatingValue = 5; + } else { + starRatingValue = 0; + } + + return starRatingValue; +} + +int parseMp4Rating(int rating) { + int starRatingValue; + + if (rating <= 0) { + starRatingValue = 0; + } else if (rating <= 20) { + starRatingValue = 1; + } else if (rating <= 40) { + starRatingValue = 2; + } else if (rating <= 60) { + starRatingValue = 3; + } else if (rating <= 80) { + starRatingValue = 4; + } else if (rating <= 100) { + starRatingValue = 5; + } else { + starRatingValue = 0; + } + + return starRatingValue; +} + +int parseMp3Rating(int rating) { + int starRatingValue; + + if (rating <= 0) { + starRatingValue = 0; + } else if (rating <= 31) { //WMP writes 1 + starRatingValue = 1; + } else if (rating <= 95) { //WMP writes 64 + starRatingValue = 2; + } else if (rating <= 159) { //WMP writes 128 + starRatingValue = 3; + } else if (rating <= 221) { //WMP writes 196 + starRatingValue = 4; + } else if (rating <= 255) { //WMP writes 255 + starRatingValue = 5; + } else { + starRatingValue = 0; + } + + return starRatingValue; +} + inline QString formatTrackGain(const TrackMetadata& trackMetadata) { const double trackGainRatio(trackMetadata.getReplayGain().getRatio()); return ReplayGain::ratioToString(trackGainRatio); @@ -1059,6 +1126,19 @@ void readTrackMetadataFromID3v2Tag(TrackMetadata* pTrackMetadata, pTrackMetadata->setAlbumArtist(toQStringFirstNotEmpty(albumArtistFrame)); } + int rating = -1; + const TagLib::ID3v2::FrameList popmRatingFrameList(tag.frameListMap()["POPM"]); + if (!popmRatingFrameList.isEmpty()) { + //All elements of frameListMap() are normal Framelist classes. + //You have to convert to a PopularimeterFrame to access the rating() + //and email() functions. + auto popmRatingFrame = dynamic_cast(popmRatingFrameList.front()); + if (popmRatingFrame != nullptr){ + rating = popmRatingFrame->rating(); + pTrackMetadata->setRating(parseMp3Rating(rating)); + } + } + if (pTrackMetadata->getAlbum().isEmpty()) { const TagLib::ID3v2::FrameList originalAlbumFrame( tag.frameListMap()["TOAL"]); @@ -1279,6 +1359,12 @@ void readTrackMetadataFromVorbisCommentTag(TrackMetadata* pTrackMetadata, parseBpm(pTrackMetadata, bpm); } + QString rating; + if (readXiphCommentField(tag, "RATING", &rating)) { + int intRating = rating.toInt(); //readXiphCommentField reads all fields as strings + pTrackMetadata->setRating(parseFlacRating(intRating)); + } + // Only read track gain (not album gain) QString trackGain; if (readXiphCommentField(tag, "REPLAYGAIN_TRACK_GAIN", &trackGain)) { @@ -1360,6 +1446,12 @@ void readTrackMetadataFromMP4Tag(TrackMetadata* pTrackMetadata, const TagLib::MP #endif } + QString rating; + if (readMP4Atom(tag, "rate", &rating)) { + int intRating = rating.toInt(); //readMP4Atom reads all atoms as strings + pTrackMetadata->setRating(parseMp4Rating(intRating)); + } + // Only read track gain (not album gain) QString trackGain; if (readMP4Atom(tag, "----:com.apple.iTunes:replaygain_track_gain", &trackGain)) {