diff options
author | Uwe Klotz <uklotz@mixxx.org> | 2020-03-21 12:02:52 +0100 |
---|---|---|
committer | Uwe Klotz <uklotz@mixxx.org> | 2020-03-30 11:32:18 +0200 |
commit | b384921bfa4400685d729d10db46c2a59ce3752a (patch) | |
tree | 46c2def649f5a6f33072e5d2b24066f937dbb3f0 | |
parent | 829ec47831e22bb0afae953faaafd59e24aca608 (diff) |
Use new PCM audio property types
55 files changed, 582 insertions, 545 deletions
diff --git a/src/analyzer/constants.h b/src/analyzer/constants.h index 468ed741ed..c936de1515 100644 --- a/src/analyzer/constants.h +++ b/src/analyzer/constants.h @@ -9,7 +9,7 @@ namespace mixxx { // depending on the track length. A block size of 4096 frames per block // seems to do fine. Signal processing during analysis uses the same, // fixed number of channels like the engine does, usually 2 = stereo. -constexpr mixxx::AudioSignal::ChannelCount kAnalysisChannels = mixxx::kEngineChannelCount; +constexpr audio::ChannelCount kAnalysisChannels = mixxx::kEngineChannelCount; constexpr SINT kAnalysisFramesPerChunk = 4096; constexpr SINT kAnalysisSamplesPerChunk = kAnalysisFramesPerChunk * kAnalysisChannels; diff --git a/src/effects/effectchain.cpp b/src/effects/effectchain.cpp index 3dd1ac7310..c24442a90f 100644 --- a/src/effects/effectchain.cpp +++ b/src/effects/effectchain.cpp @@ -183,7 +183,7 @@ void EffectChain::enableForInputChannel(const ChannelHandleAndGroup& handle_grou //TODO: get actual configuration of engine const mixxx::EngineParameters bufferParameters( - mixxx::AudioSignal::SampleRate(96000), + mixxx::audio::SampleRate(96000), MAX_BUFFER_LEN / mixxx::kEngineChannelCount); for (int i = 0; i < m_effects.size(); ++i) { diff --git a/src/engine/bufferscalers/enginebufferscale.cpp b/src/engine/bufferscalers/enginebufferscale.cpp index 8e3f977ad0..b250c48f37 100644 --- a/src/engine/bufferscalers/enginebufferscale.cpp +++ b/src/engine/bufferscalers/enginebufferscale.cpp @@ -2,27 +2,26 @@ #include "engine/engine.h" #include "util/defs.h" -#include "util/sample.h" EngineBufferScale::EngineBufferScale() : m_audioSignal( - mixxx::AudioSignal::SampleLayout::Interleaved, - mixxx::AudioSignal::ChannelCount(mixxx::kEngineChannelCount), - mixxx::AudioSignal::SampleRate(44100)), + mixxx::audio::SignalInfo( + mixxx::kEngineChannelCount, + mixxx::audio::SampleRate(), + mixxx::kEngineSampleLayout)), m_dBaseRate(1.0), m_bSpeedAffectsPitch(false), m_dTempoRatio(1.0), m_dPitchRatio(1.0) { - DEBUG_ASSERT(m_audioSignal.verifyReadable()); + DEBUG_ASSERT(!m_audioSignal.isValid()); } -EngineBufferScale::~EngineBufferScale() { -} - -void EngineBufferScale::setSampleRate(SINT iSampleRate) { - m_audioSignal = mixxx::AudioSignal( - m_audioSignal.sampleLayout(), - m_audioSignal.channelCount(), - mixxx::AudioSignal::SampleRate(iSampleRate)); - DEBUG_ASSERT(m_audioSignal.verifyReadable()); +void EngineBufferScale::setSampleRate( + mixxx::audio::SampleRate sampleRate) { + DEBUG_ASSERT(sampleRate.isValid()); + if (sampleRate != m_audioSignal.getSampleRate()) { + m_audioSignal.setSampleRate(sampleRate); + onSampleRateChanged(); + } + DEBUG_ASSERT(m_audioSignal.isValid()); } diff --git a/src/engine/bufferscalers/enginebufferscale.h b/src/engine/bufferscalers/enginebufferscale.h index 609cf54fb5..f8ba5d827e 100644 --- a/src/engine/bufferscalers/enginebufferscale.h +++ b/src/engine/bufferscalers/enginebufferscale.h @@ -3,7 +3,7 @@ #include <QObject> -#include "util/audiosignal.h" +#include "audio/signalinfo.h" // MAX_SEEK_SPEED needs to be good and high to allow room for the very high // instantaneous velocities of advanced scratching (Uzi) and spin-backs. @@ -24,7 +24,7 @@ class EngineBufferScale : public QObject { Q_OBJECT public: EngineBufferScale(); - virtual ~EngineBufferScale(); + ~EngineBufferScale() override = default; // Sets the scaling parameters. // * The base rate (ratio of track sample rate to output sample rate). @@ -48,9 +48,10 @@ class EngineBufferScale : public QObject { } // Set the desired output sample rate. - virtual void setSampleRate(SINT iSampleRate); + void setSampleRate( + mixxx::audio::SampleRate sampleRate); - const mixxx::AudioSignal& getAudioSignal() const { + const mixxx::audio::SignalInfo& getAudioSignal() const { return m_audioSignal; } @@ -68,7 +69,9 @@ class EngineBufferScale : public QObject { SINT iOutputBufferSize) = 0; private: - mixxx::AudioSignal m_audioSignal; + mixxx::audio::SignalInfo m_audioSignal; + + virtual void onSampleRateChanged() = 0; protected: double m_dBaseRate; diff --git a/src/engine/bufferscalers/enginebufferscalelinear.cpp b/src/engine/bufferscalers/enginebufferscalelinear.cpp index c632158b20..e268cfee04 100644 --- a/src/engine/bufferscalers/enginebufferscalelinear.cpp +++ b/src/engine/bufferscalers/enginebufferscalelinear.cpp @@ -92,12 +92,12 @@ double EngineBufferScaleLinear::scaleBuffer( // if the buffer has extra samples, do a read so RAMAN ends up back where // it should be SINT iCurSample = getAudioSignal().frames2samples(static_cast<SINT>(ceil(m_dCurrentFrame))); - SINT extra_samples = m_bufferIntSize - iCurSample - getAudioSignal().channelCount(); + SINT extra_samples = m_bufferIntSize - iCurSample - getAudioSignal().getChannelCount(); if (extra_samples > 0) { - if (extra_samples % getAudioSignal().channelCount() != 0) { + if (extra_samples % getAudioSignal().getChannelCount() != 0) { // extra samples should include the whole frame - extra_samples -= extra_samples % getAudioSignal().channelCount(); - extra_samples += getAudioSignal().channelCount(); + extra_samples -= extra_samples % getAudioSignal().getChannelCount(); + extra_samples += getAudioSignal().getChannelCount(); } //qDebug() << "extra samples" << extra_samples; @@ -339,7 +339,7 @@ SINT EngineBufferScaleLinear::do_scale(CSAMPLE* buf, SINT buf_size) { // samples. This prevents the change from being discontinuous and helps // improve sound quality. rate_add += rate_delta_abs; - i += getAudioSignal().channelCount(); + i += getAudioSignal().getChannelCount(); } SampleUtil::clear(&buf[i], buf_size - i); diff --git a/src/engine/bufferscalers/enginebufferscalelinear.h b/src/engine/bufferscalers/enginebufferscalelinear.h index f30a951db8..d46f342ba6 100644 --- a/src/engine/bufferscalers/enginebufferscalelinear.h +++ b/src/engine/bufferscalers/enginebufferscalelinear.h @@ -24,6 +24,8 @@ class EngineBufferScaleLinear : public EngineBufferScale { double* pPitchRatio) override; private: + void onSampleRateChanged() override {} + SINT do_scale(CSAMPLE* buf, SINT buf_size); SINT do_copy(CSAMPLE* buf, SINT buf_size); diff --git a/src/engine/bufferscalers/enginebufferscalerubberband.cpp b/src/engine/bufferscalers/enginebufferscalerubberband.cpp index c17973804d..c403d16bf6 100644 --- a/src/engine/bufferscalers/enginebufferscalerubberband.cpp +++ b/src/engine/bufferscalers/enginebufferscalerubberband.cpp @@ -28,7 +28,6 @@ EngineBufferScaleRubberBand::EngineBufferScaleRubberBand( m_bBackwards(false) { m_retrieve_buffer[0] = SampleUtil::alloc(MAX_BUFFER_LEN); m_retrieve_buffer[1] = SampleUtil::alloc(MAX_BUFFER_LEN); - initRubberBand(); } EngineBufferScaleRubberBand::~EngineBufferScaleRubberBand() { @@ -37,19 +36,6 @@ EngineBufferScaleRubberBand::~EngineBufferScaleRubberBand() { SampleUtil::free(m_retrieve_buffer[1]); } -void EngineBufferScaleRubberBand::initRubberBand() { - m_pRubberBand = std::make_unique<RubberBandStretcher>( - getAudioSignal().sampleRate(), - getAudioSignal().channelCount(), - RubberBandStretcher::OptionProcessRealTime); - m_pRubberBand->setMaxProcessSize(kRubberBandBlockSize); - // Setting the time ratio to a very high value will cause RubberBand - // to preallocate buffers large enough to (almost certainly) - // avoid memory reallocations during playback. - m_pRubberBand->setTimeRatio(2.0); - m_pRubberBand->setTimeRatio(1.0); -} - void EngineBufferScaleRubberBand::setScaleParameters(double base_rate, double* pTempoRatio, double* pPitchRatio) { @@ -111,12 +97,27 @@ void EngineBufferScaleRubberBand::setScaleParameters(double base_rate, m_dPitchRatio = *pPitchRatio; } -void EngineBufferScaleRubberBand::setSampleRate(SINT iSampleRate) { - EngineBufferScale::setSampleRate(iSampleRate); - initRubberBand(); +void EngineBufferScaleRubberBand::onSampleRateChanged() { + if (!getAudioSignal().isValid()) { + m_pRubberBand.reset(); + return; + } + m_pRubberBand = std::make_unique<RubberBandStretcher>( + getAudioSignal().getSampleRate(), + getAudioSignal().getChannelCount(), + RubberBandStretcher::OptionProcessRealTime); + m_pRubberBand->setMaxProcessSize(kRubberBandBlockSize); + // Setting the time ratio to a very high value will cause RubberBand + // to preallocate buffers large enough to (almost certainly) + // avoid memory reallocations during playback. + m_pRubberBand->setTimeRatio(2.0); + m_pRubberBand->setTimeRatio(1.0); } void EngineBufferScaleRubberBand::clear() { + VERIFY_OR_DEBUG_ASSERT(m_pRubberBand) { + return; + } m_pRubberBand->reset(); } diff --git a/src/engine/bufferscalers/enginebufferscalerubberband.h b/src/engine/bufferscalers/enginebufferscalerubberband.h index 53d07370a7..7ee14e084c 100644 --- a/src/engine/bufferscalers/enginebufferscalerubberband.h +++ b/src/engine/bufferscalers/enginebufferscalerubberband.h @@ -22,8 +22,6 @@ class EngineBufferScaleRubberBand : public EngineBufferScale { double* pTempoRatio, double* pPitchRatio) override; - void setSampleRate(SINT iSampleRate) override; - double scaleBuffer( CSAMPLE* pOutputBuffer, SINT iOutputBufferSize) override; @@ -33,7 +31,7 @@ class EngineBufferScaleRubberBand : public EngineBufferScale { private: // Reset RubberBand library with new audio signal - void initRubberBand(); + void onSampleRateChanged() override; void deinterleaveAndProcess(const CSAMPLE* pBuffer, SINT frames, bool flush); SINT retrieveAndDeinterleave(CSAMPLE* pBuffer, SINT frames); diff --git a/src/engine/bufferscalers/enginebufferscalest.cpp b/src/engine/bufferscalers/enginebufferscalest.cpp index 59a19a8af8..4e62432e59 100644 --- a/src/engine/bufferscalers/enginebufferscalest.cpp +++ b/src/engine/bufferscalers/enginebufferscalest.cpp @@ -29,27 +29,14 @@ const SINT kSeekOffsetFrames = 519; EngineBufferScaleST::EngineBufferScaleST(ReadAheadManager *pReadAheadManager) : m_pReadAheadManager(pReadAheadManager), m_pSoundTouch(std::make_unique<soundtouch::SoundTouch>()), - buffer_back_size(getAudioSignal().frames2samples(kSeekOffsetFrames)), - buffer_back(SampleUtil::alloc(buffer_back_size)), m_bBackwards(false) { - DEBUG_ASSERT(getAudioSignal().verifyReadable()); - m_pSoundTouch->setChannels(getAudioSignal().channelCount()); - m_pSoundTouch->setSampleRate(getAudioSignal().sampleRate()); + m_pSoundTouch->setChannels(getAudioSignal().getChannelCount()); m_pSoundTouch->setRate(m_dBaseRate); m_pSoundTouch->setPitch(1.0); m_pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, 1); - - // Setting the tempo to a very low value will force SoundTouch - // to preallocate buffers large enough to (almost certainly) - // avoid memory reallocations during playback. - m_pSoundTouch->setTempo(0.1); - m_pSoundTouch->putSamples(buffer_back, kSeekOffsetFrames); - m_pSoundTouch->clear(); - m_pSoundTouch->setTempo(m_dTempoRatio); } EngineBufferScaleST::~EngineBufferScaleST() { - SampleUtil::free(buffer_back); } void EngineBufferScaleST::setScaleParameters(double base_rate, @@ -98,17 +85,32 @@ void EngineBufferScaleST::setScaleParameters(double base_rate, // changed direction. I removed it because this is handled by EngineBuffer. } -void EngineBufferScaleST::setSampleRate(SINT iSampleRate) { - EngineBufferScale::setSampleRate(iSampleRate); - m_pSoundTouch->setSampleRate(iSampleRate); +void EngineBufferScaleST::onSampleRateChanged() { + buffer_back.clear(); + if (!getAudioSignal().isValid()) { + return; + } + m_pSoundTouch->setSampleRate(getAudioSignal().getSampleRate()); + const auto bufferSize = getAudioSignal().frames2samples(kSeekOffsetFrames); + if (bufferSize > buffer_back.size()) { + // grow buffer + buffer_back = mixxx::SampleBuffer(bufferSize); + } + // Setting the tempo to a very low value will force SoundTouch + // to preallocate buffers large enough to (almost certainly) + // avoid memory reallocations during playback. + m_pSoundTouch->setTempo(0.1); + m_pSoundTouch->putSamples(buffer_back.data(), kSeekOffsetFrames); + m_pSoundTouch->clear(); + m_pSoundTouch->setTempo(m_dTempoRatio); } void EngineBufferScaleST::clear() { m_pSoundTouch->clear(); // compensate seek offset for a rate of 1.0 - SampleUtil::clear(buffer_back, getAudioSignal().frames2samples(kSeekOffsetFrames)); - m_pSoundTouch->putSamples(buffer_back, kSeekOffsetFrames); + SampleUtil::clear(buffer_back.data(), buffer_back.size()); + m_pSoundTouch->putSamples(buffer_back.data(), kSeekOffsetFrames); } double EngineBufferScaleST::scaleBuffer( @@ -140,14 +142,14 @@ double EngineBufferScaleST::scaleBuffer( // The value doesn't matter here. All that matters is we // are going forward or backward. (m_bBackwards ? -1.0 : 1.0) * m_dBaseRate * m_dTempoRatio, - buffer_back, - buffer_back_size); + buffer_back.data(), + buffer_back.size()); SINT iAvailFrames = getAudioSignal().samples2frames(iAvailSamples); if (iAvailFrames > 0) { last_read_failed = false; total_read_frames += iAvailFrames; - m_pSoundTouch->putSamples(buffer_back, iAvailFrames); + m_pSoundTouch->putSamples(buffer_back.data(), iAvailFrames); } else { if (last_read_failed) { m_pSoundTouch->flush(); diff --git a/src/engine/bufferscalers/enginebufferscalest.h b/src/engine/bufferscalers/enginebufferscalest.h index 7ac8d61100..8212ecb75d 100644 --- a/src/engine/bufferscalers/enginebufferscalest.h +++ b/src/engine/bufferscalers/enginebufferscalest.h @@ -1,8 +1,8 @@ -#ifndef ENGINEBUFFERSCALEST_H -#define ENGINEBUFFERSCALEST_H +#pragma once #include "engine/bufferscalers/enginebufferscale.h" #include "util/memory.h" +#include "util/samplebuffer.h" class ReadAheadManager; @@ -22,8 +22,6 @@ class EngineBufferScaleST : public EngineBufferScale { double* pTempoRatio, double* pPitchRatio) override; - void setSampleRate(SINT iSampleRate) override; - // Scale buffer. double scaleBuffer( CSAMPLE* pOutputBuffer, @@ -33,6 +31,8 @@ class EngineBufferScaleST : public EngineBufferScale { void clear() override; private: + void onSampleRateChanged() override; + // The read-ahead manager that we use to fetch samples ReadAheadManager* m_pReadAheadManager; @@ -40,11 +40,8 @@ class EngineBufferScaleST : public EngineBufferScale { std::unique_ptr<soundtouch::SoundTouch> m_pSoundTouch; // Temporary buffer for reading from the RAMAN. - SINT buffer_back_size; - CSAMPLE* buffer_back; + mixxx::SampleBuffer buffer_back; // Holds the playback direction. bool m_bBackwards; }; - -#endif diff --git a/src/engine/cachingreader/cachingreaderchunk.cpp b/src/engine/cachingreader/cachingreaderchunk.cpp index 732cebc00d..9409ad97a1 100644 --- a/src/engine/cachingreader/cachingreaderchunk.cpp +++ b/src/engine/cachingreader/cachingreaderchunk.cpp @@ -25,7 +25,7 @@ const SINT kInvalidChunkIndex = -1; // easier memory alignment. // TODO(XXX): The optimum value of the "constant" kFrames depends // on the properties of the AudioSource as the remarks above suggest! -const mixxx::AudioSignal::ChannelCount CachingReaderChunk::kChannels = mixxx::kEngineChannelCount; +const mixxx::audio::ChannelCount CachingReaderChunk::kChannels = mixxx::kEngineChannelCount; const SINT CachingReaderChunk::kFrames = 8192; // ~ 170 ms at 48 kHz const SINT CachingReaderChunk::kSamples = CachingReaderChunk::frames2samples(CachingReaderChunk::kFrames); diff --git a/src/engine/cachingreader/cachingreaderchunk.h b/src/engine/cachingreader/cachingreaderchunk.h index 9f44ec3d7b..7e9409a9b2 100644 --- a/src/engine/cachingreader/cachingreaderchunk.h +++ b/src/engine/cachingreader/cachingreaderchunk.h @@ -16,7 +16,7 @@ // and the worker. class CachingReaderChunk { public: - static const mixxx::AudioSignal::ChannelCount kChannels; + static const mixxx::audio::ChannelCount kChannels; static const SINT kFrames; static const SINT kSamples; diff --git a/src/engine/effects/engineeffect.cpp b/src/engine/effects/engineeffect.cpp index 24fef32817..8ef4593028 100644 --- a/src/engine/effects/engineeffect.cpp +++ b/src/engine/effects/engineeffect.cpp @@ -34,7 +34,7 @@ EngineEffect::EngineEffect(EffectManifestPointer pManifest, m_pProcessor = pInstantiator->instantiate(this, pManifest); //TODO: get actual configuration of engine const mixxx::EngineParameters bufferParameters( - mixxx::AudioSignal::SampleRate(96000), + mixxx::audio::SampleRate(96000), MAX_BUFFER_LEN / mixxx::kEngineChannelCount); m_pProcessor->initialize(activeInputChannels, pEffectsManager, bufferParameters); m_effectRampsFromDry = pManifest->effectRampsFromDry(); @@ -191,7 +191,7 @@ bool EngineEffect::process(const ChannelHandle& inputHandle, if (effectiveEffectEnableState != EffectEnableState::Disabled) { //TODO: refactor rest of audio engine to use mixxx::AudioParameters const mixxx::EngineParameters bufferParameters( - mixxx::AudioSignal::SampleRate(sampleRate), + mixxx::audio::SampleRate(sampleRate), numSamples / mixxx::kEngineChannelCount); m_pProcessor->process(inputHandle, outputHandle, pInput, pOutput, diff --git a/src/engine/engine.h b/src/engine/engine.h index 014b369b37..b7f3d780e6 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -1,11 +1,14 @@ #pragma once -#include "util/audiosignal.h" +#include "audio/signalinfo.h" namespace mixxx { // TODO(XXX): When we move from stereo to multi-channel this needs updating. - static constexpr mixxx::AudioSignal::ChannelCount kEngineChannelCount(2); + static constexpr audio::ChannelCount kEngineChannelCount = + audio::ChannelCount(2); + static constexpr audio::SampleLayout kEngineSampleLayout = + audio::SampleLayout::Interleaved; // Contains the information needed to process a buffer of audio class EngineParameters { @@ -17,25 +20,27 @@ namespace mixxx { return m_audioSignal.frames2samples(framesPerBuffer()); } - mixxx::AudioSignal::ChannelCount channelCount() const { - return m_audioSignal.channelCount(); + audio::ChannelCount channelCount() const { + return m_audioSignal.getChannelCount(); } - mixxx::AudioSignal::SampleRate sampleRate() const { - return m_audioSignal.sampleRate(); + audio::SampleRate sampleRate() const { + return m_audioSignal.getSampleRate(); } explicit EngineParameters( - AudioSignal::SampleRate sampleRate, + audio::SampleRate sampleRate, SINT framesPerBuffer) - : m_audioSignal(mixxx::AudioSignal::SampleLayout::Interleaved, - kEngineChannelCount, sampleRate), - m_framesPerBuffer(framesPerBuffer) { + : m_audioSignal( + kEngineChannelCount, + sampleRate, + kEngineSampleLayout), + m_framesPerBuffer(framesPerBuffer) { DEBUG_ASSERT(framesPerBuffer > 0); } private: - const mixxx::AudioSignal m_audioSignal; + const audio::SignalInfo m_audioSignal; const SINT m_framesPerBuffer; }; } diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index ca73661aa6..2f535ae4f9 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -1025,21 +1025,19 @@ void EngineBuffer::process(CSAMPLE* pOutput, const int iBufferSize) { // - Set last sample value (m_fLastSampleValue) so that rampOut works? Other // miscellaneous upkeep issues. - int sample_rate = static_cast<int>(m_pSampleRate->get()); + m_iSampleRate = static_cast<int>(m_pSampleRate->get()); // If the sample rate has changed, force Rubberband to reset so that // it doesn't reallocate when the user engages keylock during playback. // We do this even if rubberband is not active. - if (sample_rate != m_iSampleRate) { - m_pScaleLinear->setSampleRate(sample_rate); - m_pScaleST->setSampleRate(sample_rate); - m_pScaleRB->setSampleRate(sample_rate); - m_iSampleRate = sample_rate; - } + const auto sampleRate = mixxx::audio::SampleRate(m_iSampleRate); + m_pScaleLinear->setSampleRate(sampleRate); + m_pScaleST->setSampleRate(sampleRate); + m_pScaleRB->setSampleRate(sampleRate); bool bTrackLoading = atomicLoadRelaxed(m_iTrackLoading) != 0; if (!bTrackLoading && m_pause.tryLock()) { - processTrackLocked(pOutput, iBufferSize, sample_rate); |