summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUwe Klotz <uklotz@mixxx.org>2020-03-22 11:13:25 +0100
committerUwe Klotz <uklotz@mixxx.org>2020-03-30 11:32:18 +0200
commitdadc2cada290d8ac2d63fc1723217c8f45e585fa (patch)
treebf0478559a32af58c92f60bc134d5fe16f6e83d0
parentb384921bfa4400685d729d10db46c2a59ce3752a (diff)
Get rid of the Janus-headed AudioSignal base class
-rw-r--r--CMakeLists.txt1
-rw-r--r--build/depends.py1
-rw-r--r--src/analyzer/analyzerthread.cpp6
-rw-r--r--src/analyzer/constants.h1
-rw-r--r--src/engine/cachingreader/cachingreaderchunk.cpp4
-rw-r--r--src/engine/cachingreader/cachingreaderworker.cpp8
-rw-r--r--src/musicbrainz/chromaprinter.cpp19
-rw-r--r--src/sources/audiosource.cpp145
-rw-r--r--src/sources/audiosource.h103
-rw-r--r--src/sources/audiosourceproxy.h51
-rw-r--r--src/sources/audiosourcestereoproxy.cpp57
-rw-r--r--src/sources/audiosourcestereoproxy.h24
-rw-r--r--src/sources/audiosourcetrackproxy.h66
-rw-r--r--src/sources/soundsourcecoreaudio.cpp19
-rw-r--r--src/sources/soundsourceffmpeg.cpp50
-rw-r--r--src/sources/soundsourceflac.cpp34
-rw-r--r--src/sources/soundsourcem4a.cpp30
-rw-r--r--src/sources/soundsourcemediafoundation.cpp32
-rw-r--r--src/sources/soundsourcemediafoundation.h4
-rw-r--r--src/sources/soundsourcemodplug.cpp10
-rw-r--r--src/sources/soundsourcemp3.cpp38
-rw-r--r--src/sources/soundsourceoggvorbis.cpp12
-rw-r--r--src/sources/soundsourceopus.cpp22
-rw-r--r--src/sources/soundsourcesndfile.cpp6
-rw-r--r--src/sources/soundsourcewv.cpp12
-rw-r--r--src/sources/v1/legacyaudiosourceadapter.cpp6
-rw-r--r--src/test/soundproxy_test.cpp47
-rw-r--r--src/track/cue.h2
-rw-r--r--src/util/audiosignal.cpp71
-rw-r--r--src/util/audiosignal.h90
30 files changed, 503 insertions, 468 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ed9f31a04b..6151943031 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -562,7 +562,6 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL
src/track/tracknumbers.cpp
src/track/trackrecord.cpp
src/track/trackref.cpp
- src/util/audiosignal.cpp
src/util/autohidpi.cpp
src/util/battery/battery.cpp
src/util/cache.cpp
diff --git a/build/depends.py b/build/depends.py
index 0f11432197..21c74600e8 100644
--- a/build/depends.py
+++ b/build/depends.py
@@ -1313,7 +1313,6 @@ class MixxxCore(Feature):
"src/util/logger.cpp",
"src/util/logging.cpp",
"src/util/cmdlineargs.cpp",
- "src/util/audiosignal.cpp",
"src/util/widgethider.cpp",
"src/util/autohidpi.cpp",
"src/util/screensaver.cpp",
diff --git a/src/analyzer/analyzerthread.cpp b/src/analyzer/analyzerthread.cpp
index a6f7f0802e..88b714ddc2 100644
--- a/src/analyzer/analyzerthread.cpp
+++ b/src/analyzer/analyzerthread.cpp
@@ -145,7 +145,7 @@ void AnalyzerThread::doRun() {
// Make sure not to short-circuit initialize(...)
if (analyzer.initialize(
m_currentTrack,
- audioSource->sampleRate(),
+ audioSource->getSignalInfo().getSampleRate(),
audioSource->frameLength() * mixxx::kAnalysisChannels)) {
processTrack = true;
}
@@ -226,7 +226,9 @@ AnalyzerThread::AnalysisResult AnalyzerThread::analyzeAudioSource(
mixxx::AudioSourceStereoProxy audioSourceProxy(
audioSource,
mixxx::kAnalysisFramesPerChunk);
- DEBUG_ASSERT(audioSourceProxy.channelCount() == mixxx::kAnalysisChannels);
+ DEBUG_ASSERT(
+ audioSourceProxy.getSignalInfo().getChannelCount() ==
+ mixxx::kAnalysisChannels);
// Analysis starts now
emitBusyProgress(kAnalyzerProgressNone);
diff --git a/src/analyzer/constants.h b/src/analyzer/constants.h
index c936de1515..d014aae440 100644
--- a/src/analyzer/constants.h
+++ b/src/analyzer/constants.h
@@ -1,7 +1,6 @@
#pragma once
#include "engine/engine.h"
-#include "util/audiosignal.h"
namespace mixxx {
diff --git a/src/engine/cachingreader/cachingreaderchunk.cpp b/src/engine/cachingreader/cachingreaderchunk.cpp
index 9409ad97a1..a24c9605d9 100644
--- a/src/engine/cachingreader/cachingreaderchunk.cpp
+++ b/src/engine/cachingreader/cachingreaderchunk.cpp
@@ -66,7 +66,9 @@ mixxx::IndexRange CachingReaderChunk::bufferSampleFrames(
mixxx::AudioSourceStereoProxy audioSourceProxy(
pAudioSource,
tempOutputBuffer);
- DEBUG_ASSERT(audioSourceProxy.channelCount() == kChannels);
+ DEBUG_ASSERT(
+ audioSourceProxy.getSignalInfo().getChannelCount() ==
+ kChannels);
m_bufferedSampleFrames =
audioSourceProxy.readSampleFrames(
mixxx::WritableSampleFrames(
diff --git a/src/engine/cachingreader/cachingreaderworker.cpp b/src/engine/cachingreader/cachingreaderworker.cpp
index 5f2182acc4..2364536388 100644
--- a/src/engine/cachingreader/cachingreaderworker.cpp
+++ b/src/engine/cachingreader/cachingreaderworker.cpp
@@ -180,7 +180,8 @@ void CachingReaderWorker::loadTrack(const TrackPointer& pTrack) {
// Adjust the internal buffer
const SINT tempReadBufferSize =
- m_pAudioSource->frames2samples(CachingReaderChunk::kFrames);
+ m_pAudioSource->getSignalInfo().frames2samples(
+ CachingReaderChunk::kFrames);
if (m_tempReadBuffer.size() != tempReadBufferSize) {
mixxx::SampleBuffer(tempReadBufferSize).swap(m_tempReadBuffer);
}
@@ -194,7 +195,10 @@ void CachingReaderWorker::loadTrack(const TrackPointer& pTrack) {
const SINT sampleCount =
CachingReaderChunk::frames2samples(
m_pAudioSource->frameLength());
- emit trackLoaded(pTrack, m_pAudioSource->sampleRate(), sampleCount);
+ emit trackLoaded(
+ pTrack,
+ m_pAudioSource->getSignalInfo().getSampleRate(),
+ sampleCount);
}
void CachingReaderWorker::quitWait() {
diff --git a/src/musicbrainz/chromaprinter.cpp b/src/musicbrainz/chromaprinter.cpp
index c25acad437..7775926b4b 100644
--- a/src/musicbrainz/chromaprinter.cpp
+++ b/src/musicbrainz/chromaprinter.cpp
@@ -37,7 +37,7 @@ QString calcFingerprint(
mixxx::SampleBuffer sampleBuffer(math_max(
fingerprintRange.length(),
- audioSourceProxy.frames2samples(fingerprintRange.length())));
+ audioSourceProxy.getSignalInfo().frames2samples(fingerprintRange.length())));
const auto readableSampleFrames =
audioSourceProxy.readSampleFrames(
mixxx::WritableSampleFrames(
@@ -49,7 +49,7 @@ QString calcFingerprint(
}
std::vector<SAMPLE> fingerprintSamples(
- audioSourceProxy.frames2samples(
+ audioSourceProxy.getSignalInfo().frames2samples(
readableSampleFrames.frameLength()));
// Convert floating-point to integer
SampleUtil::convertFloat32ToS16(
@@ -60,11 +60,17 @@ QString calcFingerprint(
qDebug() << "reading file took" << timerReadingFile.elapsed().debugMillisWithUnit();
ChromaprintContext* ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_DEFAULT);
- chromaprint_start(ctx, audioSourceProxy.sampleRate(), audioSourceProxy.channelCount());
+ chromaprint_start(
+ ctx,
+ audioSourceProxy.getSignalInfo().getSampleRate(),
+ audioSourceProxy.getSignalInfo().getChannelCount());
PerformanceTimer timerGeneratingFingerprint;
timerGeneratingFingerprint.start();
- int success = chromaprint_feed(ctx, &fingerprintSamples[0], static_cast<int>(fingerprintSamples.size()));
+ const int success = chromaprint_feed(
+ ctx,
+ &fingerprintSamples[0],
+ static_cast<int>(fingerprintSamples.size()));
chromaprint_finish(ctx);
if (!success) {
qWarning() << "Failed to generate fingerprint from sample data";
@@ -105,7 +111,8 @@ ChromaPrinter::ChromaPrinter(QObject* parent)
QString ChromaPrinter::getFingerprint(TrackPointer pTrack) {
mixxx::AudioSource::OpenParams config;
- config.setChannelCount(2); // always stereo / 2 channels (see below)
+ // always stereo / 2 channels (see below)
+ config.setChannelCount(mixxx::audio::ChannelCount(2));
auto pAudioSource = SoundSourceProxy(pTrack).openAudioSource(config);
if (!pAudioSource) {
qDebug()
@@ -118,7 +125,7 @@ QString ChromaPrinter::getFingerprint(TrackPointer pTrack) {
pAudioSource->frameIndexRange(),
mixxx::IndexRange::forward(
pAudioSource->frameIndexMin(),
- kFingerprintDuration * pAudioSource->sampleRate()));
+ kFingerprintDuration * pAudioSource->getSignalInfo().getSampleRate()));
mixxx::AudioSourceStereoProxy audioSourceProxy(
pAudioSource,
fingerprintRange.length());
diff --git a/src/sources/audiosource.cpp b/src/sources/audiosource.cpp
index 26142824ea..2dca3e0aa8 100644
--- a/src/sources/audiosource.cpp
+++ b/src/sources/audiosource.cpp
@@ -12,7 +12,16 @@ const Logger kLogger("AudioSource");
AudioSource::AudioSource(QUrl url)
: UrlResource(url),
- AudioSignal(kSampleLayout) {
+ m_signalInfo(kSampleLayout) {
+}
+
+AudioSource::AudioSource(
+ const AudioSource& inner,
+ const audio::SignalInfo& signalInfo)
+ : UrlResource(inner),
+ m_signalInfo(signalInfo),
+ m_bitrate(inner.m_bitrate),
+ m_frameIndexRange(inner.m_frameIndexRange) {
}
AudioSource::OpenResult AudioSource::open(
@@ -56,14 +65,61 @@ bool AudioSource::initFrameIndexRangeOnce(
return true;
}
+bool AudioSource::initChannelCountOnce(
+ audio::ChannelCount channelCount) {
+ if (!channelCount.isValid()) {
+ kLogger.warning()
+ << "Invalid channel count"
+ << channelCount;
+ return false; // abort
+ }
+ VERIFY_OR_DEBUG_ASSERT(
+ !m_signalInfo.getChannelCount().isValid() ||
+ m_signalInfo.getChannelCount() == channelCount) {
+ kLogger.warning()
+ << "Channel count has already been initialized to"
+ << m_signalInfo.getChannelCount()
+ << "which differs from"
+ << channelCount;
+ return false; // abort
+ }
+ m_signalInfo.setChannelCount(channelCount);
+ return true;
+}
+
+bool AudioSource::initSampleRateOnce(
+ audio::SampleRate sampleRate) {
+ if (!sampleRate.isValid()) {
+ kLogger.warning()
+ << "Invalid sample rate"
+ << sampleRate;
+ return false; // abort
+ }
+ VERIFY_OR_DEBUG_ASSERT(
+ !m_signalInfo.getSampleRate().isValid() ||
+ m_signalInfo.getSampleRate() == sampleRate) {
+ kLogger.warning()
+ << "Sample rate has already been initialized to"
+ << m_signalInfo.getSampleRate()
+ << "which differs from"
+ << sampleRate;
+ return false; // abort
+ }
+ m_signalInfo.setSampleRate(sampleRate);
+ return true;
+}
+
bool AudioSource::initBitrateOnce(audio::Bitrate bitrate) {
+ // Bitrate is optional and might be invalid (= audio::Bitrate())
if (bitrate < audio::Bitrate()) {
kLogger.warning()
<< "Invalid bitrate"
<< bitrate;
return false; // abort
}
- VERIFY_OR_DEBUG_ASSERT(!m_bitrate.isValid() || (m_bitrate == bitrate)) {
+ VERIFY_OR_DEBUG_ASSERT(
+ !m_bitrate.isValid() ||
+ m_bitrate == bitrate) {
kLogger.warning()
<< "Bitrate has already been initialized to"
<< m_bitrate
@@ -76,14 +132,34 @@ bool AudioSource::initBitrateOnce(audio::Bitrate bitrate) {
}
bool AudioSource::verifyReadable() const {
- bool result = AudioSignal::verifyReadable();
- if (frameIndexRange().empty()) {
+ bool result = true;
+ DEBUG_ASSERT(m_signalInfo.getSampleLayout());
+ if (!m_signalInfo.getChannelCount().isValid()) {
kLogger.warning()
- << "No audio data available";
- // Don't set the result to false, even if reading from an empty source
- // is pointless!
+ << "Invalid number of channels:"
+ << getSignalInfo().getChannelCount()
+ << "is out of range ["
+ << audio::ChannelCount::min()
+ << ","
+ << audio::ChannelCount::max()
+ << "]";
+ result = false;
+ }
+ if (!m_signalInfo.getSampleRate().isValid()) {
+ kLogger.warning()
+ << "Invalid sample rate:"
+ << getSignalInfo().getSampleRate()
+ << "is out of range ["
+ << audio::SampleRate::min()
+ << ","
+ << audio::SampleRate::max()
+ << "]";
+ result = false;
}
+ DEBUG_ASSERT(result == m_signalInfo.isValid());
+ // Bitrate is optional and might be invalid (= audio::Bitrate())
if (m_bitrate != audio::Bitrate()) {
+ // Non-default bitrate must be valid
VERIFY_OR_DEBUG_ASSERT(m_bitrate.isValid()) {
kLogger.warning()
<< "Invalid bitrate"
@@ -93,6 +169,12 @@ bool AudioSource::verifyReadable() const {
// to decode audio data!
}
}
+ if (frameIndexRange().empty()) {
+ kLogger.warning()
+ << "No audio data available";
+ // Don't set the result to false, even if reading from an
+ // empty source is pointless!
+ }
return result;
}
@@ -101,12 +183,19 @@ WritableSampleFrames AudioSource::clampWritableSampleFrames(
const auto readableFrameIndexRange =
clampFrameIndexRange(sampleFrames.frameIndexRange());
// adjust offset and length of the sample buffer
- DEBUG_ASSERT(sampleFrames.frameIndexRange().start() <= readableFrameIndexRange.end());
+ DEBUG_ASSERT(
+ sampleFrames.frameIndexRange().start() <=
+ readableFrameIndexRange.end());
auto writableFrameIndexRange =
- IndexRange::between(sampleFrames.frameIndexRange().start(), readableFrameIndexRange.end());
+ IndexRange::between(
+ sampleFrames.frameIndexRange().start(),
+ readableFrameIndexRange.end());
const SINT minSampleBufferCapacity =
- frames2samples(writableFrameIndexRange.length());
- VERIFY_OR_DEBUG_ASSERT(sampleFrames.writableLength() >= minSampleBufferCapacity) {
+ m_signalInfo.frames2samples(
+ writableFrameIndexRange.length());
+ VERIFY_OR_DEBUG_ASSERT(
+ sampleFrames.writableLength() >=
+ minSampleBufferCapacity) {
kLogger.critical()
<< "Capacity of output buffer is too small"
<< sampleFrames.writableLength()
@@ -118,20 +207,27 @@ WritableSampleFrames AudioSource::clampWritableSampleFrames(
<< writableFrameIndexRange;
writableFrameIndexRange =
writableFrameIndexRange.splitAndShrinkFront(
- samples2frames(sampleFrames.writableLength()));
+ m_signalInfo.samples2frames(
+ sampleFrames.writableLength()));
kLogger.warning()
<< "Reduced writable sample frames"
<< writableFrameIndexRange;
}
- DEBUG_ASSERT(readableFrameIndexRange.start() >= writableFrameIndexRange.start());
+ DEBUG_ASSERT(
+ readableFrameIndexRange.start() >=
+ writableFrameIndexRange.start());
const SINT writableFrameOffset =
- readableFrameIndexRange.start() - writableFrameIndexRange.start();
- writableFrameIndexRange.shrinkFront(writableFrameOffset);
+ readableFrameIndexRange.start() -
+ writableFrameIndexRange.start();
+ writableFrameIndexRange.shrinkFront(
+ writableFrameOffset);
return WritableSampleFrames(
writableFrameIndexRange,
SampleBuffer::WritableSlice(
- sampleFrames.writableData(frames2samples(writableFrameOffset)),
- frames2samples(writableFrameIndexRange.length())));
+ sampleFrames.writableData(
+ m_signalInfo.frames2samples(writableFrameOffset)),
+ m_signalInfo.frames2samples(
+ writableFrameIndexRange.length())));
}
ReadableSampleFrames AudioSource::readSampleFrames(
@@ -156,17 +252,22 @@ ReadableSampleFrames AudioSource::readSampleFrames(
// Adjust upper bound: Consider all audio data following
// the read position until the end as unreadable
shrinkedFrameIndexRange.shrinkBack(
- shrinkedFrameIndexRange.end() - writable.frameIndexRange().start());
+ shrinkedFrameIndexRange.end() -
+ writable.frameIndexRange().start());
} else {
// Adjust lower bound of readable audio data
- if (writable.frameIndexRange().start() < readable.frameIndexRange().start()) {
+ if (writable.frameIndexRange().start() <
+ readable.frameIndexRange().start()) {
shrinkedFrameIndexRange.shrinkFront(
- readable.frameIndexRange().start() - shrinkedFrameIndexRange.start());
+ readable.frameIndexRange().start() -
+ shrinkedFrameIndexRange.start());
}
// Adjust upper bound of readable audio data
- if (writable.frameIndexRange().end() > readable.frameIndexRange().end()) {
+ if (writable.frameIndexRange().end() >
+ readable.frameIndexRange().end()) {
shrinkedFrameIndexRange.shrinkBack(
- shrinkedFrameIndexRange.end() - readable.frameIndexRange().end());
+ shrinkedFrameIndexRange.end() -
+ readable.frameIndexRange().end());
}
}
DEBUG_ASSERT(shrinkedFrameIndexRange < m_frameIndexRange);
diff --git a/src/sources/audiosource.h b/src/sources/audiosource.h
index 461b9ea2b0..a5cb7379cd 100644
--- a/src/sources/audiosource.h
+++ b/src/sources/audiosource.h
@@ -3,7 +3,6 @@
#include "audio/streaminfo.h"
#include "engine/engine.h"
#include "sources/urlresource.h"
-#include "util/audiosignal.h"
#include "util/indexrange.h"
#include "util/memory.h"
#include "util/samplebuffer.h"
@@ -139,7 +138,7 @@ class IAudioSourceReader {
//
// Audio sources are implicitly opened upon creation and
// closed upon destruction.
-class AudioSource : public UrlResource, public AudioSignal, public virtual /*implements*/ IAudioSourceReader {
+class AudioSource : public UrlResource, public virtual /*implements*/ IAudioSourceReader {
public:
virtual ~AudioSource() = default;
@@ -182,31 +181,37 @@ class AudioSource : public UrlResource, public AudioSignal, public virtual /*imp
};
// Parameters for opening audio sources
- class OpenParams : public AudioSignal {
+ class OpenParams {
public:
OpenParams()
- : AudioSignal(kSampleLayout) {
+ : m_signalInfo(kSampleLayout) {
}
OpenParams(
audio::ChannelCount channelCount,
audio::SampleRate sampleRate)
- : AudioSignal(
- audio::SignalInfo(
- channelCount,
- sampleRate,
- kSampleLayout)) {
+ : m_signalInfo(
+ channelCount,
+ sampleRate,
+ kSampleLayout) {
}
- using AudioSignal::setChannelCount;
- using AudioSignal::setSampleRate;
- };
+ const audio::SignalInfo& getSignalInfo() const {
+ return m_signalInfo;
+ }
- audio::StreamInfo getStreamInfo() const {
- return audio::StreamInfo(
- getSignalInfo(),
- m_bitrate,
- Duration::fromSeconds(getDuration()));
- }
+ void setChannelCount(
+ audio::ChannelCount channelCount) {
+ m_signalInfo.setChannelCount(channelCount);
+ }
+
+ void setSampleRate(
+ audio::SampleRate sampleRate) {
+ m_signalInfo.setSampleRate(sampleRate);
+ }
+
+ private:
+ audio::SignalInfo m_signalInfo;
+ };
// Opens the AudioSource for reading audio data.
//
@@ -227,6 +232,22 @@ class AudioSource : public UrlResource, public AudioSignal, public virtual /*imp
// opened, has already been closed, or if opening has failed.
virtual void close() = 0;
+ const audio::SignalInfo& getSignalInfo() const {
+ DEBUG_ASSERT(m_signalInfo.isValid());
+ return m_signalInfo;
+ }
+
+ const audio::Bitrate getBitrate() const {
+ return m_bitrate;
+ }
+
+ audio::StreamInfo getStreamInfo() const {
+ return audio::StreamInfo(
+ getSignalInfo(),
+ getBitrate(),
+ Duration::fromSeconds(getDuration()));
+ }
+
// The total length of audio data is bounded and measured in frames.
IndexRange frameIndexRange() const {
return m_frameIndexRange;
@@ -259,25 +280,38 @@ class AudioSource : public UrlResource, public AudioSignal, public virtual /*imp
// The actual duration in seconds.
// Well defined only for valid files!
inline bool hasDuration() const {
- return sampleRate().isValid();
+ return getSignalInfo().getSampleRate().isValid();
}
inline double getDuration() const {
DEBUG_ASSERT(hasDuration()); // prevents division by zero
- return double(frameLength()) / double(sampleRate());
- }
-
- audio::Bitrate bitrate() const {
- return m_bitrate;
+ return double(frameLength()) / double(getSignalInfo().getSampleRate());
}
- bool verifyReadable() const override;
+ // Verifies various properties to ensure that the audio data is
+ // actually readable. Warning messages are logged for properties
+ // with invalid values for diagnostic purposes.
+ bool verifyReadable() const;
ReadableSampleFrames readSampleFrames(
WritableSampleFrames sampleFrames);
protected:
explicit AudioSource(QUrl url);
- AudioSource(const AudioSource&) = default;
+
+ bool initChannelCountOnce(audio::ChannelCount channelCount);
+ bool initChannelCountOnce(SINT channelCount) {
+ return initChannelCountOnce(audio::ChannelCount(channelCount));
+ }
+
+ bool initSampleRateOnce(audio::SampleRate sampleRate);
+ bool initSampleRateOnce(SINT sampleRate) {
+ return initSampleRateOnce(audio::SampleRate(sampleRate));
+ }
+
+ bool initBitrateOnce(audio::Bitrate bitrate);
+ bool initBitrateOnce(SINT bitrate) {
+ return initBitrateOnce(audio::Bitrate(bitrate));
+ }
bool initFrameIndexRangeOnce(
IndexRange frameIndexRange);
@@ -294,11 +328,6 @@ class AudioSource : public UrlResource, public AudioSignal, public virtual /*imp
that.adjustFrameIndexRange(frameIndexRange);
}
- bool initBitrateOnce(audio::Bitrate bitrate);
- bool initBitrateOnce(SINT bitrate) {
- return initBitrateOnce(audio::Bitrate(bitrate));
- }
-
// Tries to open the AudioSource for reading audio data according
// to the "Template Method" design pattern.
//
@@ -325,10 +354,18 @@ class AudioSource : public UrlResource, public AudioSignal, public virtual /*imp
}
private:
+ AudioSource(const AudioSource&) = delete;
AudioSource(AudioSource&&) = delete;
AudioSource& operator=(const AudioSource&) = delete;
AudioSource& operator=(AudioSource&&) = delete;
+ // Ugly workaround for AudioSourceProxy to wrap
+ // an existing AudioSource.
+ friend class AudioSourceProxy;
+ AudioSource(
+ const AudioSource& inner,
+ const audio::SignalInfo& signalInfo);
+
WritableSampleFrames clampWritableSampleFrames(
WritableSampleFrames sampleFrames) const;
IndexRange clampFrameIndexRange(
@@ -336,9 +373,11 @@ class AudioSource : public UrlResource, public AudioSignal, public virtual /*imp
return intersect(frameIndexRange, this->frameIndexRange());
}
- IndexRange m_frameIndexRange;
+ audio::SignalInfo m_signalInfo;
audio::Bitrate m_bitrate;
+
+ IndexRange m_frameIndexRange;
};
typedef std::shared_ptr<AudioSource> AudioSourcePointer;
diff --git a/src/sources/audiosourceproxy.h b/src/sources/audiosourceproxy.h
new file mode 100644
index 0000000000..33fa6978e7
--- /dev/null
+++ b/src/sources/audiosourceproxy.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include "sources/audiosource.h"
+
+namespace mixxx {
+
+class AudioSourceProxy : public AudioSource {
+ public:
+ explicit AudioSourceProxy(
+ AudioSourcePointer&& pAudioSource)
+ : AudioSourceProxy(
+ std::move(pAudioSource),
+ pAudioSource->getSignalInfo()) {
+ }
+ AudioSourceProxy(
+ AudioSourcePointer&& pAudioSource,
+ const audio::SignalInfo& signalInfo)
+ : AudioSource(*pAudioSource, signalInfo),
+ m_pAudioSource(std::move(pAudioSource)) {
+ }
+
+ void close() override {
+ m_pAudioSource->close();
+ }
+
+ protected:
+ OpenResult tryOpen(
+ OpenMode mode,
+ const OpenParams& params) override {
+ return tryOpenOn(*m_pAudioSource, mode, params);
+ }
+
+ ReadableSampleFrames readSampleFramesClamped(
+ WritableSampleFrames sampleFrames) override {
+ DEBUG_ASSERT(getSignalInfo() == m_pAudioSource->getSignalInfo());
+ DEBUG_ASSERT(getBitrate() == m_pAudioSource->getBitrate());
+ DEBUG_ASSERT(frameIndexRange() == m_pAudioSource->frameIndexRange());
+ return readSampleFramesClampedOn(*m_pAudioSource, sampleFrames);
+ }
+
+ void adjustFrameIndexRange(
+ IndexRange frameIndexRange) final {
+ // Ugly hack to keep both sources (inherited base + inner delegate) in sync!
+ AudioSource::adjustFrameIndexRange(frameIndexRange);
+ adjustFrameIndexRangeOn(*m_pAudioSource, frameIndexRange);
+ }
+
+ const AudioSourcePointer m_pAudioSource;
+};
+
+} // namespace mixxx
diff --git a/src/sources/audiosourcestereoproxy.cpp b/src/sources/audiosourcestereoproxy.cpp
index 8571e20364..95bdd0d1cb 100644
--- a/src/sources/audiosourcestereoproxy.cpp
+++ b/src/sources/audiosourcestereoproxy.cpp
@@ -9,26 +9,39 @@ namespace {
const Logger kLogger("AudioSourceStereoProxy");
+constexpr audio::ChannelCount kChannelCount = audio::ChannelCount(2);
+
+audio::SignalInfo proxySignalInfo(
+ const audio::SignalInfo& signalInfo) {
+ DEBUG_ASSERT(signalInfo.isValid());
+ return audio::SignalInfo(
+ kChannelCount,
+ signalInfo.getSampleRate(),
+ signalInfo.getSampleLayout());
+}
+
} // anonymous namespace
AudioSourceStereoProxy::AudioSourceStereoProxy(
AudioSourcePointer pAudioSource,
SINT maxReadableFrames)
- : AudioSource(*pAudioSource),
- m_pAudioSource(std::move(pAudioSource)),
+ : AudioSourceProxy(
+ std::move(pAudioSource),
+ proxySignalInfo(pAudioSource->getSignalInfo())),
m_tempSampleBuffer(
- (m_pAudioSource->channelCount() != 2) ? m_pAudioSource->frames2samples(maxReadableFrames) : 0),
+ (m_pAudioSource->getSignalInfo().getChannelCount() != kChannelCount) ?
+ m_pAudioSource->getSignalInfo().frames2samples(maxReadableFrames) :
+ 0),
m_tempWritableSlice(m_tempSampleBuffer) {
- setChannelCount(2);
}
AudioSourceStereoProxy::AudioSourceStereoProxy(
AudioSourcePointer pAudioSource,
SampleBuffer::WritableSlice tempWritableSlice)
- : AudioSource(*pAudioSource),
- m_pAudioSource(std::move(pAudioSource)),
+ : AudioSourceProxy(
+ std::move(pAudioSource),
+ proxySignalInfo(pAudioSource->getSignalInfo())),
m_tempWritableSlice(std::move(tempWritableSlice)) {
- setChannelCount(2);
}
namespace {
@@ -53,7 +66,7 @@ inline bool isDisjunct(
ReadableSampleFrames AudioSourceStereoProxy::readSampleFramesClamped(
WritableSampleFrames sampleFrames) {
- if (m_pAudioSource->channelCount() == 2) {
+ if (m_pAudioSource->getSignalInfo().getChannelCount() == kChannelCount) {
return readSampleFramesClampedOn(*m_pAudioSource, sampleFrames);
}
@@ -67,7 +80,7 @@ ReadableSampleFrames AudioSourceStereoProxy::readSampleFramesClamped(
}
{
const SINT numberOfSamplesToRead =
- m_pAudioSource->frames2samples(
+ m_pAudioSource->getSignalInfo().frames2samples(
sampleFrames.frameLength());
VERIFY_OR_DEBUG_ASSERT(m_tempWritableSlice.length() >= numberOfSamplesToRead) {
kLogger.warning()
@@ -90,14 +103,19 @@ ReadableSampleFrames AudioSourceStereoProxy::readSampleFramesClamped(
if (readableSampleFrames.frameIndexRange().empty()) {
return readableSampleFrames;
}
- DEBUG_ASSERT(readableSampleFrames.frameIndexRange() <= sampleFrames.frameIndexRange());
- DEBUG_ASSERT(readableSampleFrames.frameIndexRange().start() >= sampleFrames.frameIndexRange().start());
+ DEBUG_ASSERT(
+ readableSampleFrames.frameIndexRange() <=
+ sampleFrames.frameIndexRange());
+ DEBUG_ASSERT(
+ readableSampleFrames.frameIndexRange().start() >=
+ sampleFrames.frameIndexRange().start());
const SINT frameOffset =
- readableSampleFrames.frameIndexRange().start() - sampleFrames.frameIndexRange().start();
+ readableSampleFrames.frameIndexRange().start() -
+ sampleFrames.frameIndexRange().start();
SampleBuffer::WritableSlice writableSlice(
- sampleFrames.writableData(frames2samples(frameOffset)),
- frames2samples(readableSampleFrames.frameLength()));