From bb58f66a6cb06b1c8568dabc9d1ca50523061255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 2 May 2020 01:57:17 +0200 Subject: Fill sidechainMix from external sidechain input. This fixes lp1876222 --- src/engine/enginemaster.cpp | 15 +++++++++------ src/engine/sidechain/enginesidechain.cpp | 12 ++++++++---- src/engine/sidechain/enginesidechain.h | 3 ++- 3 files changed, 19 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/engine/enginemaster.cpp b/src/engine/enginemaster.cpp index 5454723c90..c89649e968 100644 --- a/src/engine/enginemaster.cpp +++ b/src/engine/enginemaster.cpp @@ -153,7 +153,9 @@ EngineMaster::EngineMaster(UserSettingsPointer pConfig, } // Starts a thread for recording and broadcast - m_pEngineSideChain = bEnableSidechain ? new EngineSideChain(pConfig) : NULL; + m_pEngineSideChain = + bEnableSidechain ? + new EngineSideChain(pConfig, m_pSidechainMix) : nullptr; // X-Fader Setup m_pXFaderMode = new ControlPushButton( @@ -632,7 +634,8 @@ void EngineMaster::process(const int iBufferSize) { SampleUtil::applyRampingGain(m_pMaster, m_masterGainOld, master_gain, m_iBufferSize); m_masterGainOld = master_gain; - if (!m_bExternalRecordBroadcastInputConnected) { + if (m_pEngineSideChain && + !m_bExternalRecordBroadcastInputConnected) { SampleUtil::copy(m_pSidechainMix, m_pMaster, m_iBufferSize); } @@ -651,8 +654,9 @@ void EngineMaster::process(const int iBufferSize) { // mixing the talkover signal for the record/broadcast mix. // If not using microphone inputs or recording/broadcasting from // a sound card input, skip unnecessary processing here. - if (m_pNumMicsConfigured->get() > 0 - && !m_bExternalRecordBroadcastInputConnected) { + if (m_pEngineSideChain && + !m_bExternalRecordBroadcastInputConnected && + m_pNumMicsConfigured->get() > 0) { // Copy the master mix to a separate buffer before delaying it // to avoid delaying the master output. m_pLatencyCompensationDelay->process(m_pSidechainMix, m_iBufferSize); @@ -665,8 +669,7 @@ void EngineMaster::process(const int iBufferSize) { // If recording/broadcasting from a sound card input, // SoundManager will send the input buffer from the sound card to m_pSidechain // so skip sending a buffer to m_pSidechain here. - if (!m_bExternalRecordBroadcastInputConnected - && m_pEngineSideChain != nullptr) { + if (m_pEngineSideChain) { m_pEngineSideChain->writeSamples(m_pSidechainMix, iFrames); } diff --git a/src/engine/sidechain/enginesidechain.cpp b/src/engine/sidechain/enginesidechain.cpp index 3dbd3f4590..02be62e1d4 100644 --- a/src/engine/sidechain/enginesidechain.cpp +++ b/src/engine/sidechain/enginesidechain.cpp @@ -28,6 +28,7 @@ #include #include "engine/sidechain/sidechainworker.h" +#include "engine/engine.h" #include "util/counter.h" #include "util/event.h" #include "util/sample.h" @@ -36,11 +37,14 @@ #define SIDECHAIN_BUFFER_SIZE 65536 -EngineSideChain::EngineSideChain(UserSettingsPointer pConfig) +EngineSideChain::EngineSideChain( + UserSettingsPointer pConfig, + CSAMPLE* sidechainMix) : m_pConfig(pConfig), m_bStopThread(false), m_sampleFifo(SIDECHAIN_BUFFER_SIZE), - m_pWorkBuffer(SampleUtil::alloc(SIDECHAIN_BUFFER_SIZE)) { + m_pWorkBuffer(SampleUtil::alloc(SIDECHAIN_BUFFER_SIZE)), + m_pSidechainMix(sidechainMix) { // We use HighPriority to prevent starvation by lower-priority processes (Qt // main thread, analysis, etc.). This used to be LowPriority but that is not // a suitable choice since we do semi-realtime tasks @@ -78,11 +82,11 @@ void EngineSideChain::addSideChainWorker(SideChainWorker* pWorker) { void EngineSideChain::receiveBuffer(AudioInput input, const CSAMPLE* pBuffer, unsigned int iFrames) { - if (input.getType() != AudioInput::RECORD_BROADCAST) { + VERIFY_OR_DEBUG_ASSERT(input.getType() == AudioInput::RECORD_BROADCAST) { qDebug() << "WARNING: AudioInput type is not RECORD_BROADCAST. Ignoring incoming buffer."; return; } - writeSamples(pBuffer, iFrames); + SampleUtil::copy(m_pSidechainMix, pBuffer, iFrames * mixxx::kEngineChannelCount); } void EngineSideChain::writeSamples(const CSAMPLE* pBuffer, int iFrames) { diff --git a/src/engine/sidechain/enginesidechain.h b/src/engine/sidechain/enginesidechain.h index 8497c07d91..23c4ae1ad3 100644 --- a/src/engine/sidechain/enginesidechain.h +++ b/src/engine/sidechain/enginesidechain.h @@ -32,7 +32,7 @@ class EngineSideChain : public QThread, public AudioDestination { Q_OBJECT public: - EngineSideChain(UserSettingsPointer pConfig); + EngineSideChain(UserSettingsPointer pConfig, CSAMPLE* sidechainMix); virtual ~EngineSideChain(); // Not thread-safe, wait-free. Submit buffer of samples to the sidechain for @@ -58,6 +58,7 @@ class EngineSideChain : public QThread, public AudioDestination { FIFO m_sampleFifo; CSAMPLE* m_pWorkBuffer; + CSAMPLE* m_pSidechainMix; // Provides thread safety around the wait condition below. QMutex m_waitLock; -- cgit v1.2.3 From 64abeda46ddd6eea39078b1b036f2cbdff97d601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 2 May 2020 14:23:14 +0200 Subject: Improve comments --- src/engine/enginemaster.cpp | 12 +++++++----- src/engine/sidechain/enginesidechain.cpp | 2 ++ 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/engine/enginemaster.cpp b/src/engine/enginemaster.cpp index c89649e968..e86de44c58 100644 --- a/src/engine/enginemaster.cpp +++ b/src/engine/enginemaster.cpp @@ -664,11 +664,13 @@ void EngineMaster::process(const int iBufferSize) { } } - // Submit buffer to the side chain to do broadcasting, recording, - // etc. (CPU intensive non-realtime tasks) - // If recording/broadcasting from a sound card input, - // SoundManager will send the input buffer from the sound card to m_pSidechain - // so skip sending a buffer to m_pSidechain here. + // Submit buffer to the side chain to do CPU intensive non-realtime + // tasks like recording. The SoundDeviceNetwork, responsible for + // passing samples to the network reads directly from m_pSidechainMix, + // registering it with SoundDevice::addOutput(). + // Note: In case the broadcast/recording input is configured, + // EngineSideChain::receiveBuffer has copied the input buffer to m_pSidechainMix + // via before (called by SoundManager::pushInputBuffers()) if (m_pEngineSideChain) { m_pEngineSideChain->writeSamples(m_pSidechainMix, iFrames); } diff --git a/src/engine/sidechain/enginesidechain.cpp b/src/engine/sidechain/enginesidechain.cpp index 02be62e1d4..5580862124 100644 --- a/src/engine/sidechain/enginesidechain.cpp +++ b/src/engine/sidechain/enginesidechain.cpp @@ -86,6 +86,8 @@ void EngineSideChain::receiveBuffer(AudioInput input, qDebug() << "WARNING: AudioInput type is not RECORD_BROADCAST. Ignoring incoming buffer."; return; } + // Just copy the received samples form the sound card input to the + // engine. After processing we get it back via writeSamples() SampleUtil::copy(m_pSidechainMix, pBuffer, iFrames * mixxx::kEngineChannelCount); } -- cgit v1.2.3 From 4d60739ff3ba90148d9cbd74fa4da449aa7e1419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 2 May 2020 18:00:47 +0200 Subject: guard more copy calls with if (m_pEngineSideChain) --- src/engine/enginemaster.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/engine/enginemaster.cpp b/src/engine/enginemaster.cpp index e86de44c58..6d33a80b18 100644 --- a/src/engine/enginemaster.cpp +++ b/src/engine/enginemaster.cpp @@ -564,7 +564,8 @@ void EngineMaster::process(const int iBufferSize) { m_masterGainOld = master_gain; // Record/broadcast signal is the same as the master output - if (!m_bExternalRecordBroadcastInputConnected) { + if (m_pEngineSideChain && + !m_bExternalRecordBroadcastInputConnected) { SampleUtil::copy(m_pSidechainMix, m_pMaster, m_iBufferSize); } } else if (configuredMicMonitorMode == MicMonitorMode::MASTER_AND_BOOTH) { @@ -601,7 +602,8 @@ void EngineMaster::process(const int iBufferSize) { m_masterGainOld = master_gain; // Record/broadcast signal is the same as the master output - if (!m_bExternalRecordBroadcastInputConnected) { + if (m_pEngineSideChain && + !m_bExternalRecordBroadcastInputConnected) { SampleUtil::copy(m_pSidechainMix, m_pMaster, m_iBufferSize); } } else if (configuredMicMonitorMode == MicMonitorMode::DIRECT_MONITOR) { -- cgit v1.2.3 From d00f2ca943758e39a20fe8964617b3abaca7d4c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 3 May 2020 15:01:00 +0200 Subject: Added EngineMaster::sidechainMixRequired() function for a repeated condition --- src/engine/enginemaster.cpp | 58 ++++++++++++++++++++++----------------------- src/engine/enginemaster.h | 1 + 2 files changed, 30 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/engine/enginemaster.cpp b/src/engine/enginemaster.cpp index 6d33a80b18..a1d8a4d643 100644 --- a/src/engine/enginemaster.cpp +++ b/src/engine/enginemaster.cpp @@ -564,8 +564,7 @@ void EngineMaster::process(const int iBufferSize) { m_masterGainOld = master_gain; // Record/broadcast signal is the same as the master output - if (m_pEngineSideChain && - !m_bExternalRecordBroadcastInputConnected) { + if (sidechainMixRequired()) { SampleUtil::copy(m_pSidechainMix, m_pMaster, m_iBufferSize); } } else if (configuredMicMonitorMode == MicMonitorMode::MASTER_AND_BOOTH) { @@ -602,8 +601,7 @@ void EngineMaster::process(const int iBufferSize) { m_masterGainOld = master_gain; // Record/broadcast signal is the same as the master output - if (m_pEngineSideChain && - !m_bExternalRecordBroadcastInputConnected) { + if (sidechainMixRequired()) { SampleUtil::copy(m_pSidechainMix, m_pMaster, m_iBufferSize); } } else if (configuredMicMonitorMode == MicMonitorMode::DIRECT_MONITOR) { @@ -636,33 +634,31 @@ void EngineMaster::process(const int iBufferSize) { SampleUtil::applyRampingGain(m_pMaster, m_masterGainOld, master_gain, m_iBufferSize); m_masterGainOld = master_gain; - if (m_pEngineSideChain && - !m_bExternalRecordBroadcastInputConnected) { + if (sidechainMixRequired()) { SampleUtil::copy(m_pSidechainMix, m_pMaster, m_iBufferSize); - } - // The talkover signal Mixxx receives is delayed by the round trip latency. - // There is an output latency between the time Mixxx processes the audio - // and the user hears it. So if the microphone user plays on beat with - // what they hear, they will be playing out of sync with the engine's - // processing by the output latency. Additionally, Mixxx gets input signals - // delayed by the input latency. By the time Mixxx receives the input signal, - // a full round trip through the signal chain has elapsed since Mixxx - // processed the output signal. - // Although Mixxx receives the input signal delayed, the user hears it mixed - // in hardware with the master & booth outputs without that - // latency, so to record/broadcast the same signal that is heard - // on the master & booth outputs, the master mix must be delayed before - // mixing the talkover signal for the record/broadcast mix. - // If not using microphone inputs or recording/broadcasting from - // a sound card input, skip unnecessary processing here. - if (m_pEngineSideChain && - !m_bExternalRecordBroadcastInputConnected && - m_pNumMicsConfigured->get() > 0) { - // Copy the master mix to a separate buffer before delaying it - // to avoid delaying the master output. - m_pLatencyCompensationDelay->process(m_pSidechainMix, m_iBufferSize); - SampleUtil::add(m_pSidechainMix, m_pTalkover, m_iBufferSize); + if (m_pNumMicsConfigured->get() > 0) { + // The talkover signal Mixxx receives is delayed by the round trip latency. + // There is an output latency between the time Mixxx processes the audio + // and the user hears it. So if the microphone user plays on beat with + // what they hear, they will be playing out of sync with the engine's + // processing by the output latency. Additionally, Mixxx gets input signals + // delayed by the input latency. By the time Mixxx receives the input signal, + // a full round trip through the signal chain has elapsed since Mixxx + // processed the output signal. + // Although Mixxx receives the input signal delayed, the user hears it mixed + // in hardware with the master & booth outputs without that + // latency, so to record/broadcast the same signal that is heard + // on the master & booth outputs, the master mix must be delayed before + // mixing the talkover signal for the record/broadcast mix. + // If not using microphone inputs or recording/broadcasting from + // a sound card input, skip unnecessary processing here. + + // Copy the master mix to a separate buffer before delaying it + // to avoid delaying the master output. + m_pLatencyCompensationDelay->process(m_pSidechainMix, m_iBufferSize); + SampleUtil::add(m_pSidechainMix, m_pTalkover, m_iBufferSize); + } } } @@ -970,3 +966,7 @@ void EngineMaster::registerNonEngineChannelSoundIO(SoundManager* pSoundManager) } pSoundManager->registerOutput(AudioOutput(AudioOutput::RECORD_BROADCAST, 0, 2), this); } + +bool EngineMaster::sidechainMixRequired() { + return m_pEngineSideChain && !m_bExternalRecordBroadcastInputConnected; +} diff --git a/src/engine/enginemaster.h b/src/engine/enginemaster.h index ea891b5f7f..f8c4ef0e3f 100644 --- a/src/engine/enginemaster.h +++ b/src/engine/enginemaster.h @@ -273,6 +273,7 @@ class EngineMaster : public QObject, public AudioSource { ChannelHandleFactory* m_pChannelHandleFactory; void applyMasterEffects(); void processHeadphones(const double masterMixGainInHeadphones); + bool sidechainMixRequired(); EngineEffectsManager* m_pEngineEffectsManager; -- cgit v1.2.3 From 89e99fb5133b3c126190b34d77d7066e2a687452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 3 May 2020 20:47:55 +0200 Subject: make sidechainMixRequired const --- src/engine/enginemaster.cpp | 2 +- src/engine/enginemaster.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/engine/enginemaster.cpp b/src/engine/enginemaster.cpp index a1d8a4d643..8312f84979 100644 --- a/src/engine/enginemaster.cpp +++ b/src/engine/enginemaster.cpp @@ -967,6 +967,6 @@ void EngineMaster::registerNonEngineChannelSoundIO(SoundManager* pSoundManager) pSoundManager->registerOutput(AudioOutput(AudioOutput::RECORD_BROADCAST, 0, 2), this); } -bool EngineMaster::sidechainMixRequired() { +bool EngineMaster::sidechainMixRequired() const { return m_pEngineSideChain && !m_bExternalRecordBroadcastInputConnected; } diff --git a/src/engine/enginemaster.h b/src/engine/enginemaster.h index f8c4ef0e3f..3dc2e21518 100644 --- a/src/engine/enginemaster.h +++ b/src/engine/enginemaster.h @@ -273,7 +273,7 @@ class EngineMaster : public QObject, public AudioSource { ChannelHandleFactory* m_pChannelHandleFactory; void applyMasterEffects(); void processHeadphones(const double masterMixGainInHeadphones); - bool sidechainMixRequired(); + bool sidechainMixRequired() const; EngineEffectsManager* m_pEngineEffectsManager; -- cgit v1.2.3