summaryrefslogtreecommitdiffstats
path: root/src/track
diff options
context:
space:
mode:
Diffstat (limited to 'src/track')
-rw-r--r--src/track/albuminfo.cpp2
-rw-r--r--src/track/albuminfo.h2
-rw-r--r--src/track/cue.cpp12
-rw-r--r--src/track/cue.h4
-rw-r--r--src/track/track.cpp100
-rw-r--r--src/track/track.h25
-rw-r--r--src/track/trackinfo.cpp2
-rw-r--r--src/track/trackinfo.h2
-rw-r--r--src/track/trackmetadata.cpp88
-rw-r--r--src/track/trackmetadata.h30
-rw-r--r--src/track/trackmetadatataglib.cpp11
11 files changed, 220 insertions, 58 deletions
diff --git a/src/track/albuminfo.cpp b/src/track/albuminfo.cpp
index 232de95ea4..fdd72f1fc2 100644
--- a/src/track/albuminfo.cpp
+++ b/src/track/albuminfo.cpp
@@ -18,7 +18,7 @@ bool operator==(const AlbumInfo& lhs, const AlbumInfo& rhs) {
}
QDebug operator<<(QDebug dbg, const AlbumInfo& arg) {
- dbg << '{';
+ dbg << "AlbumInfo{";
arg.dbgArtist(dbg);
#if defined(__EXTRA_METADATA__)
arg.dbgCopyright(dbg);
diff --git a/src/track/albuminfo.h b/src/track/albuminfo.h
index f4b45125aa..4c9da32339 100644
--- a/src/track/albuminfo.h
+++ b/src/track/albuminfo.h
@@ -11,7 +11,7 @@
namespace mixxx {
class AlbumInfo final {
- // Album and release properties (in alphabetical order)
+ // Properties in alphabetical order
PROPERTY_SET_BYVAL_GET_BYREF(QString, artist, Artist)
#if defined(__EXTRA_METADATA__)
PROPERTY_SET_BYVAL_GET_BYREF(QString, copyright, Copyright)
diff --git a/src/track/cue.cpp b/src/track/cue.cpp
index 7ba0ad9925..5cdb1fee6c 100644
--- a/src/track/cue.cpp
+++ b/src/track/cue.cpp
@@ -15,8 +15,8 @@ namespace {
inline std::optional<double> positionSamplesToMillis(
double positionSamples,
- mixxx::AudioSignal::SampleRate sampleRate) {
- VERIFY_OR_DEBUG_ASSERT(sampleRate.valid()) {
+ mixxx::audio::SampleRate sampleRate) {
+ VERIFY_OR_DEBUG_ASSERT(sampleRate.isValid()) {
return Cue::kNoPosition;
}
if (positionSamples == Cue::kNoPosition) {
@@ -28,8 +28,8 @@ inline std::optional<double> positionSamplesToMillis(
inline double positionMillisToSamples(
std::optional<double> positionMillis,
- mixxx::AudioSignal::SampleRate sampleRate) {
- VERIFY_OR_DEBUG_ASSERT(sampleRate.valid()) {
+ mixxx::audio::SampleRate sampleRate) {
+ VERIFY_OR_DEBUG_ASSERT(sampleRate.isValid()) {
return Cue::kNoPosition;
}
if (!positionMillis) {
@@ -87,7 +87,7 @@ Cue::Cue(
Cue::Cue(
const mixxx::CueInfo& cueInfo,
- mixxx::AudioSignal::SampleRate sampleRate)
+ mixxx::audio::SampleRate sampleRate)
: m_bDirty(false),
m_iId(-1),
m_type(cueInfo.getType()),
@@ -105,7 +105,7 @@ Cue::Cue(
}
mixxx::CueInfo Cue::getCueInfo(
- mixxx::AudioSignal::SampleRate sampleRate) const {
+ mixxx::audio::SampleRate sampleRate) const {
QMutexLocker lock(&m_mutex);
return mixxx::CueInfo(
m_type,
diff --git a/src/track/cue.h b/src/track/cue.h
index 14f605c28f..fdda9fc063 100644
--- a/src/track/cue.h
+++ b/src/track/cue.h
@@ -24,7 +24,7 @@ class Cue : public QObject {
Cue();
Cue(
const mixxx::CueInfo& cueInfo,
- mixxx::AudioSignal::SampleRate sampleRate);
+ mixxx::audio::SampleRate sampleRate);
~Cue() override = default;
bool isDirty() const;
@@ -56,7 +56,7 @@ class Cue : public QObject {
double getEndPosition() const;
mixxx::CueInfo getCueInfo(
- mixxx::AudioSignal::SampleRate sampleRate) const;
+ mixxx::audio::SampleRate sampleRate) const;
signals:
void updated();
diff --git a/src/track/track.cpp b/src/track/track.cpp
index 27e04c8282..00c907f0bb 100644
--- a/src/track/track.cpp
+++ b/src/track/track.cpp
@@ -357,7 +357,19 @@ void Track::setDateAdded(const QDateTime& dateAdded) {
void Track::setDuration(mixxx::Duration duration) {
QMutexLocker lock(&m_qMutex);
- if (compareAndSet(&m_record.refMetadata().refDuration(), duration)) {
+ VERIFY_OR_DEBUG_ASSERT(!m_streamInfo ||
+ m_streamInfo->getDuration() <= mixxx::Duration::empty() ||
+ m_streamInfo->getDuration() == duration) {
+ kLogger.warning()
+ << "Cannot override stream duration:"
+ << m_streamInfo->getDuration()
+ << "->"
+ << duration;
+ return;
+ }
+ if (compareAndSet(
+ &m_record.refMetadata().refDuration(),
+ duration)) {
markDirtyAndUnlock(&lock);
}
}
@@ -576,28 +588,14 @@ void Track::setType(const QString& sType) {
}
}
-void Track::setSampleRate(int iSampleRate) {
- QMutexLocker lock(&m_qMutex);
- if (compareAndSet(&m_record.refMetadata().refSampleRate(), mixxx::AudioSignal::SampleRate(iSampleRate))) {
- markDirtyAndUnlock(&lock);
- }
-}
-
int Track::getSampleRate() const {
QMutexLocker lock(&m_qMutex);
return m_record.getMetadata().getSampleRate();
}
-void Track::setChannels(int iChannels) {
- QMutexLocker lock(&m_qMutex);
- if (compareAndSet(&m_record.refMetadata().refChannels(), mixxx::AudioSignal::ChannelCount(iChannels))) {
- markDirtyAndUnlock(&lock);
- }
-}
-
int Track::getChannels() const {
QMutexLocker lock(&m_qMutex);
- return m_record.getMetadata().getChannels();
+ return m_record.getMetadata().getChannelCount();
}
int Track::getBitrate() const {
@@ -611,7 +609,20 @@ QString Track::getBitrateText() const {
void Track::setBitrate(int iBitrate) {
QMutexLocker lock(&m_qMutex);
- if (compareAndSet(&m_record.refMetadata().refBitrate(), mixxx::AudioSource::Bitrate(iBitrate))) {
+ const mixxx::audio::Bitrate bitrate(iBitrate);
+ VERIFY_OR_DEBUG_ASSERT(!m_streamInfo ||
+ !m_streamInfo->getBitrate().isValid() ||
+ m_streamInfo->getBitrate() == bitrate) {
+ kLogger.warning()
+ << "Cannot override stream bitrate:"
+ << m_streamInfo->getBitrate()
+ << "->"
+ << bitrate;
+ return;
+ }
+ if (compareAndSet(
+ &m_record.refMetadata().refBitrate(),
+ bitrate)) {
markDirtyAndUnlock(&lock);
}
}
@@ -804,7 +815,7 @@ void Track::setCuePoints(const QList<CuePointer>& cuePoints) {
void Track::importCuePoints(const QList<mixxx::CueInfo>& cueInfos) {
TrackId trackId;
- mixxx::AudioSignal::SampleRate sampleRate;
+ mixxx::audio::SampleRate sampleRate;
{
QMutexLocker lock(&m_qMutex);
trackId = m_record.getId();
@@ -1122,3 +1133,56 @@ ExportTrackMetadataResult Track::exportMetadata(
return ExportTrackMetadataResult::Failed;
}
}
+
+void Track::setAudioProperties(
+ mixxx::audio::ChannelCount channelCount,
+ mixxx::audio::SampleRate sampleRate,
+ mixxx::audio::Bitrate bitrate,
+ mixxx::Duration duration) {
+ QMutexLocker lock(&m_qMutex);
+ DEBUG_ASSERT(!m_streamInfo);
+ bool dirty = false;
+ if (compareAndSet(
+ &m_record.refMetadata().refChannelCount(),
+ channelCount)) {
+ dirty = true;
+ }
+ if (compareAndSet(
+ &m_record.refMetadata().refSampleRate(),
+ sampleRate)) {
+ dirty = true;
+ }
+ if (compareAndSet(
+ &m_record.refMetadata().refBitrate(),
+ bitrate)) {
+ dirty = true;
+ }
+ if (compareAndSet(
+ &m_record.refMetadata().refDuration(),
+ duration)) {
+ dirty = true;
+ }
+ if (dirty) {
+ markDirtyAndUnlock(&lock);
+ }
+}
+
+void Track::updateAudioPropertiesFromStream(
+ mixxx::audio::StreamInfo&& streamInfo) {
+ QMutexLocker lock(&m_qMutex);
+ VERIFY_OR_DEBUG_ASSERT(!m_streamInfo ||
+ *m_streamInfo == streamInfo) {
+ kLogger.warning()
+ << "Varying stream properties:"
+ << *m_streamInfo
+ << "->"
+ << streamInfo;
+ }
+ bool updated = m_record.refMetadata().updateAudioPropertiesFromStream(
+ streamInfo);
+ m_streamInfo = std::make_optional(std::move(streamInfo));
+ // TODO: Continue deferred import of pending CueInfo objects
+ if (updated) {
+ markDirtyAndUnlock(&lock);
+ }
+}
diff --git a/src/track/track.h b/src/track/track.h
index 78965cf65d..530a1d3e2a 100644
--- a/src/track/track.h
+++ b/src/track/track.h
@@ -5,6 +5,7 @@
#include <QObject>
#include <QUrl>
+#include "audio/streaminfo.h"
#include "track/beats.h"
#include "track/cue.h"
#include "track/trackfile.h"
@@ -68,7 +69,7 @@ class Track : public QObject {
Q_PROPERTY(double bpm READ getBpm WRITE setBpm)
Q_PROPERTY(QString bpmFormatted READ getBpmText STORED false)
Q_PROPERTY(QString key READ getKeyText WRITE setKeyText)
- Q_PROPERTY(double duration READ getDuration WRITE setDuration)
+ Q_PROPERTY(double duration READ getDuration)
Q_PROPERTY(QString durationFormatted READ getDurationTextSeconds STORED false)
Q_PROPERTY(QString durationFormattedCentiseconds READ getDurationTextCentiseconds STORED false)
Q_PROPERTY(QString durationFormattedMilliseconds READ getDurationTextMilliseconds STORED false)
@@ -99,13 +100,9 @@ class Track : public QObject {
void setType(const QString&);
QString getType() const;
- // Set number of channels
- void setChannels(int iChannels);
// Get number of channels
int getChannels() const;
- // Set sample rate
- void setSampleRate(int iSampleRate);
// Get sample rate
int getSampleRate() const;
@@ -315,6 +312,12 @@ class Track : public QObject {
void markForMetadataExport();
bool isMarkedForMetadataExport() const;
+ void setAudioProperties(
+ mixxx::audio::ChannelCount channelCount,
+ mixxx::audio::SampleRate sampleRate,
+ mixxx::audio::Bitrate bitrate,
+ mixxx::Duration duration);
+
signals:
void waveformUpdated();
void waveformSummaryUpdated();
@@ -366,6 +369,13 @@ class Track : public QObject {
ExportTrackMetadataResult exportMetadata(
mixxx::MetadataSourcePointer pMetadataSource);
+ // Information about the actual properties of the
+ // audio stream is only available after opening it.
+ // On this occasion the audio properties of the track
+ // need to be updated to reflect these values.
+ void updateAudioPropertiesFromStream(
+ mixxx::audio::StreamInfo&& streamInfo);
+
// Mutex protecting access to object
mutable QMutex m_qMutex;
@@ -384,6 +394,11 @@ class Track : public QObject {
// the metadata.
bool m_bMarkedForMetadataExport;
+ // Reliable information about the PCM audio stream
+ // that only becomes available when opening the
+ // corresponding file.
+ std::optional<mixxx::audio::StreamInfo> m_streamInfo;
+
// The list of cue points for the track
QList<CuePointer> m_cuePoints;
diff --git a/src/track/trackinfo.cpp b/src/track/trackinfo.cpp
index 4adcdee652..203bb1ce28 100644
--- a/src/track/trackinfo.cpp
+++ b/src/track/trackinfo.cpp
@@ -88,7 +88,7 @@ bool TrackInfo::compareEq(
}
QDebug operator<<(QDebug dbg, const TrackInfo& arg) {
- dbg << '{';
+ dbg << "TrackInfo{";
arg.dbgArtist(dbg);
arg.dbgBpm(dbg);
arg.dbgComment(dbg);
diff --git a/src/track/trackinfo.h b/src/track/trackinfo.h
index 367a4eb53d..9f784a181b 100644
--- a/src/track/trackinfo.h
+++ b/src/track/trackinfo.h
@@ -13,7 +13,7 @@
namespace mixxx {
class TrackInfo final {
- // Track properties (in alphabetical order)
+ // Properties in alphabetical order
PROPERTY_SET_BYVAL_GET_BYREF(QString, artist, Artist)
PROPERTY_SET_BYVAL_GET_BYREF(Bpm, bpm, Bpm)
PROPERTY_SET_BYVAL_GET_BYREF(QString, comment, Comment)
diff --git a/src/track/trackmetadata.cpp b/src/track/trackmetadata.cpp
index b372430a18..8085e260b5 100644
--- a/src/track/trackmetadata.cpp
+++ b/src/track/trackmetadata.cpp
@@ -1,9 +1,81 @@
#include "track/trackmetadata.h"
+#include "audio/streaminfo.h"
+#include "util/logger.h"
+
namespace mixxx {
+namespace {
+
+const Logger kLogger("TrackMetadata");
+
+} // anonymous namespace
+
/*static*/ constexpr int TrackMetadata::kCalendarYearInvalid;
+bool TrackMetadata::updateAudioPropertiesFromStream(
+ const audio::StreamInfo& streamInfo) {
+ bool changed = false;
+ const auto streamChannelCount =
+ streamInfo.getSignalInfo().getChannelCount();
+ if (streamChannelCount.isValid() &&
+ streamChannelCount != getChannelCount()) {
+ if (getChannelCount().isValid()) {
+ kLogger.debug()
+ << "Modifying channel count:"
+ << getChannelCount()
+ << "->"
+ << streamChannelCount;
+ }
+ setChannelCount(streamChannelCount);
+ changed = true;
+ }
+ const auto streamSampleRate =
+ streamInfo.getSignalInfo().getSampleRate();
+ if (streamSampleRate.isValid() &&
+ streamSampleRate != getSampleRate()) {
+ if (getSampleRate().isValid()) {
+ kLogger.debug()
+ << "Modifying sample rate:"
+ << getSampleRate()
+ << "->"
+ << streamSampleRate;
+ }
+ setSampleRate(streamSampleRate);
+ changed = true;
+ }
+ const auto streamBitrate =
+ streamInfo.getBitrate();
+ if (streamBitrate.isValid() &&
+ streamBitrate != getBitrate()) {
+ if (getBitrate().isValid()) {
+ kLogger.debug()
+ << "Modifying bitrate:"
+ << getBitrate()
+ << "->"
+ << streamBitrate;
+ }
+ setBitrate(streamBitrate);
+ changed = true;
+ }
+ const auto streamDuration =
+ streamInfo.getDuration();
+ if (streamDuration > Duration::empty() &&
+ streamDuration != getDuration()) {
+ if (getDuration() > Duration::empty()) {
+ kLogger.debug()
+ << "Modifying duration:"
+ << getDuration()
+ << "->"
+ << streamDuration;
+ }
+ setDuration(streamDuration);
+ changed = true;
+ }
+ return changed;
+}
+
+
int TrackMetadata::parseCalendarYear(QString year, bool* pValid) {
const QDateTime dateTime(parseDateTime(year));
if (0 < dateTime.date().year()) {
@@ -83,20 +155,20 @@ bool TrackMetadata::anyFileTagsModified(
}
bool operator==(const TrackMetadata& lhs, const TrackMetadata& rhs) {
- return (lhs.getAlbumInfo() == rhs.getAlbumInfo()) &&
- (lhs.getTrackInfo() == rhs.getTrackInfo()) &&
- (lhs.getBitrate() == rhs.getBitrate()) &&
- (lhs.getChannels() == rhs.getChannels()) &&
- (lhs.getDuration() == rhs.getDuration()) &&
- (lhs.getSampleRate() == rhs.getSampleRate());
+ return lhs.getAlbumInfo() == rhs.getAlbumInfo() &&
+ lhs.getTrackInfo() == rhs.getTrackInfo() &&
+ lhs.getChannelCount() == rhs.getChannelCount() &&
+ lhs.getSampleRate() == rhs.getSampleRate() &&
+ lhs.getBitrate() == rhs.getBitrate() &&
+ lhs.getDuration() == rhs.getDuration();
}
QDebug operator<<(QDebug dbg, const TrackMetadata& arg) {
- dbg << '{';
+ dbg << "TrackMetadata{";
arg.dbgTrackInfo(dbg);
arg.dbgAlbumInfo(dbg);
arg.dbgBitrate(dbg);
- arg.dbgChannels(dbg);
+ arg.dbgChannelCount(dbg);
arg.dbgDuration(dbg);
arg.dbgSampleRate(dbg);
dbg << '}';
diff --git a/src/track/trackmetadata.h b/src/track/trackmetadata.h
index 9ca165c4be..07bdc30b22 100644
--- a/src/track/trackmetadata.h
+++ b/src/track/trackmetadata.h
@@ -2,21 +2,27 @@
#include <QDateTime>
+#include "audio/types.h"
#include "track/albuminfo.h"
#include "track/trackinfo.h"
-
namespace mixxx {
+namespace audio {
+
+class StreamInfo;
+
+} // namespace audio
+
class TrackMetadata final {
// Audio properties
- // - read-only
- // - stored file tags
- // - adjusted by audio decoder AFTER import from file tags
- PROPERTY_SET_BYVAL_GET_BYREF(AudioSource::Bitrate, bitrate, Bitrate)
- PROPERTY_SET_BYVAL_GET_BYREF(AudioSignal::ChannelCount, channels, Channels)
- PROPERTY_SET_BYVAL_GET_BYREF(Duration, duration, Duration)
- PROPERTY_SET_BYVAL_GET_BYREF(AudioSignal::SampleRate, sampleRate, SampleRate)
+ // - read-only
+ // - stored in file tags
+ // - adjusted when opening the audio stream (if available)
+ PROPERTY_SET_BYVAL_GET_BYREF(audio::ChannelCount, channels, ChannelCount)
+ PROPERTY_SET_BYVAL_GET_BYREF(audio::SampleRate, sampleRate, SampleRate)
+ PROPERTY_SET_BYVAL_GET_BYREF(audio::Bitrate, bitrate, Bitrate)
+ PROPERTY_SET_BYVAL_GET_BYREF(Duration, duration, Duration)
// Track properties
// - read-write
@@ -24,7 +30,7 @@ class TrackMetadata final {
PROPERTY_SET_BYVAL_GET_BYREF(AlbumInfo, albumInfo, AlbumInfo)
PROPERTY_SET_BYVAL_GET_BYREF(TrackInfo, trackInfo, TrackInfo)
-public:
+ public:
TrackMetadata() = default;
TrackMetadata(TrackMetadata&&) = default;
TrackMetadata(const TrackMetadata&) = default;
@@ -33,6 +39,9 @@ public:
TrackMetadata& operator=(TrackMetadata&&) = default;
TrackMetadata& operator=(const TrackMetadata&) = default;
+ bool updateAudioPropertiesFromStream(
+ const audio::StreamInfo& streamInfo);
+
// Adjusts floating-point values to match their string representation
// in file tags to account for rounding errors.
void normalizeBeforeExport();
@@ -72,8 +81,7 @@ public:
bool operator==(const TrackMetadata& lhs, const TrackMetadata& rhs);
-inline
-bool operator!=(const TrackMetadata& lhs, const TrackMetadata& rhs) {
+inline bool operator!=(const TrackMetadata& lhs, const TrackMetadata& rhs) {
return !(lhs == rhs);
}
diff --git a/src/track/trackmetadatataglib.cpp b/src/track/trackmetadatataglib.cpp
index d70673fee2..d0c217cf47 100644
--- a/src/track/trackmetadatataglib.cpp
+++ b/src/track/trackmetadatataglib.cpp
@@ -2,8 +2,8 @@
#include <taglib/tpropertymap.h>
+#include "audio/streaminfo.h"
#include "track/tracknumbers.h"
-
#include "util/assert.h"
#include "util/compatibility.h"
#include "util/duration.h"
@@ -484,9 +484,12 @@ void readAudioProperties(
// the audio data for this track. Often those properties
// stored in tags don't match with the corresponding
// audio data in the file.
- pTrackMetadata->setChannels(AudioSignal::ChannelCount(audioProperties.channels()));
- pTrackMetadata->setSampleRate(AudioSignal::SampleRate(audioProperties.sampleRate()));
- pTrackMetadata->setBitrate(AudioSource::Bitrate(audioProperties.bitrate()));
+ pTrackMetadata->setChannelCount(
+ audio::ChannelCount(audioProperties.channels()));
+ pTrackMetadata->setSampleRate(
+ audio::SampleRate(audioProperties.sampleRate()));
+ pTrackMetadata->setBitrate(
+ audio::Bitrate(audioProperties.bitrate()));
#if (TAGLIB_HAS_LENGTH_IN_MILLISECONDS)
const auto duration = Duration::fromMillis(audioProperties.lengthInMilliseconds());
#else