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