![]() |
Mixxx
|
00001 // enginepassthrough.cpp 00002 // created 4/8/2011 by Bill Good (bkgood@gmail.com) 00003 // shameless stolen from enginemicrophone.cpp (from RJ) 00004 00005 #include <QtDebug> 00006 00007 #include "engine/enginepassthrough.h" 00008 00009 #include "configobject.h" 00010 #include "sampleutil.h" 00011 00012 EnginePassthrough::EnginePassthrough(const char* pGroup) 00013 : EngineChannel(pGroup, EngineChannel::CENTER), 00014 m_clipping(pGroup), 00015 m_vuMeter(pGroup), 00016 m_pEnabled(new ControlObject(ConfigKey(pGroup, "passthrough_enabled"))), 00017 m_pPassing(new ControlPushButton(ConfigKey(pGroup, "passthrough_passing"))), 00018 m_pConversionBuffer(SampleUtil::alloc(MAX_BUFFER_LEN)), 00019 // Need a +1 here because the CircularBuffer only allows its size-1 00020 // items to be held at once (it keeps a blank spot open persistently) 00021 m_sampleBuffer(MAX_BUFFER_LEN+1) { 00022 m_pPassing->setToggleButton(true); 00023 } 00024 00025 EnginePassthrough::~EnginePassthrough() { 00026 qDebug() << "~EnginePassthrough()"; 00027 SampleUtil::free(m_pConversionBuffer); 00028 delete m_pEnabled; 00029 delete m_pPassing; 00030 } 00031 00032 bool EnginePassthrough::isActive() { 00033 bool enabled = m_pEnabled->get() > 0.0; 00034 return enabled && !m_sampleBuffer.isEmpty(); 00035 } 00036 00037 bool EnginePassthrough::isPFL() { 00038 return true; 00039 } 00040 00041 bool EnginePassthrough::isMaster() { 00042 return true; 00043 } 00044 00045 void EnginePassthrough::onInputConnected(AudioInput input) { 00046 if (input.getType() != AudioPath::EXTPASSTHROUGH) { 00047 // This is an error! 00048 qDebug() << "WARNING: EnginePassthrough connected to AudioInput for a non-passthrough type!"; 00049 return; 00050 } 00051 m_sampleBuffer.clear(); 00052 m_pEnabled->set(1.0f); 00053 } 00054 00055 void EnginePassthrough::onInputDisconnected(AudioInput input) { 00056 if (input.getType() != AudioPath::EXTPASSTHROUGH) { 00057 // This is an error! 00058 qDebug() << "WARNING: EnginePassthrough connected to AudioInput for a non-passthrough type!"; 00059 return; 00060 } 00061 m_sampleBuffer.clear(); 00062 m_pEnabled->set(0.0f); 00063 } 00064 00065 void EnginePassthrough::receiveBuffer(AudioInput input, const short* pBuffer, unsigned int nFrames) { 00066 00067 if (input.getType() != AudioPath::EXTPASSTHROUGH) { 00068 // This is an error! 00069 qDebug() << "WARNING: EnginePassthrough receieved an AudioInput for a non-passthrough type!"; 00070 return; 00071 } 00072 00073 // Use the conversion buffer to both convert from short and double into 00074 // stereo. 00075 00076 // Check that the number of mono samples doesn't exceed MAX_BUFFER_LEN/2 00077 // because thats our conversion buffer size. 00078 if (nFrames > MAX_BUFFER_LEN / 2) { 00079 qDebug() << "WARNING: Dropping passthrough samples because the input buffer is too large."; 00080 nFrames = MAX_BUFFER_LEN / 2; 00081 } 00082 00083 // There isn't a suitable SampleUtil method that can do mono->stereo and 00084 // short->float in one pass. 00085 // SampleUtil::convert(m_pConversionBuffer, pBuffer, iNumSamples); 00086 SampleUtil::convert(m_pConversionBuffer, pBuffer, nFrames*2); 00087 00088 // TODO(rryan) (or bkgood?) do we need to verify the input is the one we asked for? Oh well. 00089 unsigned int samplesWritten = m_sampleBuffer.write(m_pConversionBuffer, nFrames*2); 00090 if (samplesWritten < nFrames*2) { 00091 // Buffer overflow. We aren't processing samples fast enough. This 00092 // shouldn't happen since the deck spits out samples just as fast as they 00093 // come in, right? 00094 Q_ASSERT(false); 00095 } 00096 } 00097 00098 void EnginePassthrough::process(const CSAMPLE* pInput, const CSAMPLE* pOutput, const int iBufferSize) { 00099 CSAMPLE* pOut = const_cast<CSAMPLE*>(pOutput); 00100 Q_UNUSED(pInput); 00101 00102 // If passthrough is enabled, then read into the output buffer. Otherwise, 00103 // skip the appropriate number of samples to throw them away. 00104 if (m_pPassing->get() > 0.0f) { 00105 int samplesRead = m_sampleBuffer.read(pOut, iBufferSize); 00106 if (samplesRead < iBufferSize) { 00107 // Buffer underflow. There aren't getting samples fast enough. This 00108 // shouldn't happen since PortAudio should feed us samples just as fast 00109 // as we consume them, right? 00110 Q_ASSERT(false); 00111 } 00112 } else { 00113 SampleUtil::applyGain(pOut, 0.0, iBufferSize); 00114 m_sampleBuffer.skip(iBufferSize); 00115 } 00116 00117 // Apply clipping 00118 m_clipping.process(pOut, pOut, iBufferSize); 00119 // Update VU meter 00120 m_vuMeter.process(pOut, pOut, iBufferSize); 00121 }