diff options
author | be_ <be.0@gmx.com> | 2017-06-20 14:32:35 -0500 |
---|---|---|
committer | be_ <be.0@gmx.com> | 2017-06-21 14:24:48 -0500 |
commit | da3702c603f04b4c8de4c55d1dfbf6eaabe3d7d5 (patch) | |
tree | 79ae940ec704c1fe037e225b628d468e3da87835 | |
parent | f61908e240b4c75621cfb030757eae0e7a3b8e71 (diff) |
add a record/broadcast input
so users do not have to use external programs like Audacity and BUTT
when using external mixers
-rw-r--r-- | src/engine/enginemaster.cpp | 21 | ||||
-rw-r--r-- | src/engine/enginemaster.h | 1 | ||||
-rw-r--r-- | src/engine/sidechain/enginesidechain.cpp | 19 | ||||
-rw-r--r-- | src/engine/sidechain/enginesidechain.h | 13 | ||||
-rw-r--r-- | src/soundio/soundmanager.cpp | 4 | ||||
-rw-r--r-- | src/soundio/soundmanagerutil.cpp | 5 | ||||
-rw-r--r-- | src/soundio/soundmanagerutil.h | 1 |
7 files changed, 54 insertions, 10 deletions
diff --git a/src/engine/enginemaster.cpp b/src/engine/enginemaster.cpp index 0c3375188d..0719939081 100644 --- a/src/engine/enginemaster.cpp +++ b/src/engine/enginemaster.cpp @@ -48,6 +48,7 @@ EngineMaster::EngineMaster(UserSettingsPointer pConfig, m_bBusOutputConnected[EngineChannel::LEFT] = false; m_bBusOutputConnected[EngineChannel::CENTER] = false; m_bBusOutputConnected[EngineChannel::RIGHT] = false; + m_bExternalRecordBroadcastInputConnected = false; m_pWorkerScheduler = new EngineWorkerScheduler(this); m_pWorkerScheduler->start(QThread::HighPriority); @@ -379,6 +380,9 @@ void EngineMaster::process(const int iBufferSize) { bool boothEnabled = m_pBoothEnabled->get(); bool headphoneEnabled = m_pHeadphoneEnabled->get(); + // TODO: remove assumption of stereo buffer + const unsigned int kChannels = 2; + const unsigned int iFrames = iBufferSize / kChannels; unsigned int iSampleRate = static_cast<int>(m_pMasterSampleRate->get()); if (m_pEngineEffectsManager) { m_pEngineEffectsManager->onCallbackStart(); @@ -424,7 +428,7 @@ void EngineMaster::process(const int iBufferSize) { double measuredRoundTripLatency = m_pRoundTripLatency->get(); // iBufferSize / iSampleRate gives double Mixxx's processing latency because // there are 2 channels per buffer. FIXME when removing the assumption of stereo channels. - double processingLatency = (double)iBufferSize / iSampleRate / 2.0 * 1000.0; + double processingLatency = (double)iBufferSize / iSampleRate / kChannels * 1000.0; if (measuredRoundTripLatency == 0.0) { inputLatencyCompensation = processingLatency; } else { @@ -657,7 +661,10 @@ void EngineMaster::process(const int iBufferSize) { // Submit master samples to the side chain to do broadcasting, recording, // etc. (cpu intensive non-realtime tasks) - if (m_pEngineSideChain != NULL) { + // 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 signal to m_pSidechain here. + if (m_pEngineSideChain != NULL && !m_bExternalRecordBroadcastInputConnected) { if (configuredTalkoverMixMode == TalkoverMixMode::DIRECT_MONITOR && m_pNumMicsConfigured->get() > 0) { // When using direct monitoring, the user hears the microphone inputs @@ -674,9 +681,9 @@ void EngineMaster::process(const int iBufferSize) { m_pSidechain, 1.0, m_pTalkover, 1.0, iBufferSize); - m_pEngineSideChain->writeSamples(m_pSidechain, iBufferSize); + m_pEngineSideChain->writeSamples(m_pSidechain, iFrames); } else { - m_pEngineSideChain->writeSamples(m_pMaster, iBufferSize); + m_pEngineSideChain->writeSamples(m_pMaster, iFrames); } } @@ -907,6 +914,9 @@ void EngineMaster::onInputConnected(AudioInput input) { case AudioInput::VINYLCONTROL: // We don't track enabled vinyl control inputs. break; + case AudioInput::RECORD_BROADCAST: + m_bExternalRecordBroadcastInputConnected = true; + break; default: break; } @@ -923,6 +933,9 @@ void EngineMaster::onInputDisconnected(AudioInput input) { case AudioInput::VINYLCONTROL: // We don't track enabled vinyl control inputs. break; + case AudioInput::RECORD_BROADCAST: + m_bExternalRecordBroadcastInputConnected = false; + break; default: break; } diff --git a/src/engine/enginemaster.h b/src/engine/enginemaster.h index 3ed0b50345..7e0c654571 100644 --- a/src/engine/enginemaster.h +++ b/src/engine/enginemaster.h @@ -364,6 +364,7 @@ class EngineMaster : public QObject, public AudioSource { ControlObject* m_pHeadphoneEnabled; volatile bool m_bBusOutputConnected[3]; + bool m_bExternalRecordBroadcastInputConnected; }; #endif diff --git a/src/engine/sidechain/enginesidechain.cpp b/src/engine/sidechain/enginesidechain.cpp index 6081fd966b..f7f2fec5a4 100644 --- a/src/engine/sidechain/enginesidechain.cpp +++ b/src/engine/sidechain/enginesidechain.cpp @@ -75,11 +75,24 @@ void EngineSideChain::addSideChainWorker(SideChainWorker* pWorker) { m_workers.append(pWorker); } -void EngineSideChain::writeSamples(const CSAMPLE* newBuffer, int buffer_size) { +void EngineSideChain::receiveBuffer(AudioInput input, + const CSAMPLE* pBuffer, + unsigned int iFrames) { + if (input.getType() != AudioInput::RECORD_BROADCAST) { + qDebug() << "WARNING: AudioInput type is not RECORD_BROADCAST. Ignoring incoming buffer."; + return; + } + writeSamples(pBuffer, iFrames); +} + +void EngineSideChain::writeSamples(const CSAMPLE* pBuffer, int iFrames) { Trace sidechain("EngineSideChain::writeSamples"); - int samples_written = m_sampleFifo.write(newBuffer, buffer_size); + // TODO: remove assumption of stereo buffer + const int kChannels = 2; + const int iSamples = iFrames * kChannels; + int samples_written = m_sampleFifo.write(pBuffer, iSamples); - if (samples_written != buffer_size) { + if (samples_written != iFrames) { Counter("EngineSideChain::writeSamples buffer overrun").increment(); } diff --git a/src/engine/sidechain/enginesidechain.h b/src/engine/sidechain/enginesidechain.h index 72904b3a94..8497c07d91 100644 --- a/src/engine/sidechain/enginesidechain.h +++ b/src/engine/sidechain/enginesidechain.h @@ -24,11 +24,12 @@ #include "preferences/usersettings.h" #include "engine/sidechain/sidechainworker.h" +#include "soundio/soundmanagerutil.h" #include "util/fifo.h" #include "util/mutex.h" #include "util/types.h" -class EngineSideChain : public QThread { +class EngineSideChain : public QThread, public AudioDestination { Q_OBJECT public: EngineSideChain(UserSettingsPointer pConfig); @@ -37,13 +38,19 @@ class EngineSideChain : public QThread { // Not thread-safe, wait-free. Submit buffer of samples to the sidechain for // processing. Should only be called from a single writer thread (typically // the engine callback). - void writeSamples(const CSAMPLE* buffer, int buffer_size); + void writeSamples(const CSAMPLE* pBuffer, int iFrames); + + // Thin wrapper around writeSamples that is used by SoundManager when receiving + // from a sound card input instead of the engine + void receiveBuffer(AudioInput input, + const CSAMPLE* pBuffer, + unsigned int iFrames) override; // Thread-safe, blocking. void addSideChainWorker(SideChainWorker* pWorker); private: - void run(); + void run() override; UserSettingsPointer m_pConfig; // Indicates that the thread should exit. diff --git a/src/soundio/soundmanager.cpp b/src/soundio/soundmanager.cpp index ee000846de..51da1cd814 100644 --- a/src/soundio/soundmanager.cpp +++ b/src/soundio/soundmanager.cpp @@ -28,6 +28,7 @@ #include "engine/enginebuffer.h" #include "engine/enginemaster.h" #include "engine/sidechain/enginenetworkstream.h" +#include "engine/sidechain/enginesidechain.h" #include "soundio/sounddevice.h" #include "soundio/sounddevicenetwork.h" #include "soundio/sounddevicenotfound.h" @@ -80,6 +81,9 @@ SoundManager::SoundManager(UserSettingsPointer pConfig, m_pNetworkStream = QSharedPointer<EngineNetworkStream>( new EngineNetworkStream(2, 0)); + AudioInput recordInput = AudioInput(AudioPath::RECORD_BROADCAST, 0, 2); + registerInput(recordInput, pMaster->getSideChain()); + queryDevices(); if (!m_config.readFromDisk()) { diff --git a/src/soundio/soundmanagerutil.cpp b/src/soundio/soundmanagerutil.cpp index 8abfe01fbe..e890aa6237 100644 --- a/src/soundio/soundmanagerutil.cpp +++ b/src/soundio/soundmanagerutil.cpp @@ -163,6 +163,8 @@ QString AudioPath::getStringFromType(AudioPathType type) { return QString::fromAscii("Bus"); case DECK: return QString::fromAscii("Deck"); + case RECORD_BROADCAST: + return QString::fromAscii("Record/Broadcast"); case VINYLCONTROL: return QString::fromAscii("Vinyl Control"); case MICROPHONE: @@ -205,6 +207,8 @@ QString AudioPath::getTrStringFromType(AudioPathType type, unsigned char index) case DECK: return QString("%1 %2").arg(QObject::tr("Deck"), QString::number(index + 1)); + case RECORD_BROADCAST: + return QObject::tr("Record/Broadcast"); case VINYLCONTROL: return QString("%1 %2").arg(QObject::tr("Vinyl Control"), QString::number(index + 1)); @@ -446,6 +450,7 @@ QList<AudioPathType> AudioInput::getSupportedTypes() { #endif types.append(AUXILIARY); types.append(MICROPHONE); + types.append(RECORD_BROADCAST); return types; } diff --git a/src/soundio/soundmanagerutil.h b/src/soundio/soundmanagerutil.h index 5088d3e10c..c8676b0c84 100644 --- a/src/soundio/soundmanagerutil.h +++ b/src/soundio/soundmanagerutil.h @@ -60,6 +60,7 @@ public: HEADPHONES, BUS, DECK, + RECORD_BROADCAST, VINYLCONTROL, MICROPHONE, AUXILIARY, |