void EngineMicrophone::process(CSAMPLE* pOut, const int iBufferSize) {

    // If talkover is enabled, then read into the output buffer. Otherwise, skip
    // the appropriate number of samples to throw them away.
    const CSAMPLE* sampleBuffer = m_sampleBuffer; // save pointer on stack
    double pregain =  m_pPregain->get();
    if (isTalkover() && sampleBuffer) {
        SampleUtil::copyWithGain(pOut, sampleBuffer, pregain, iBufferSize);
        m_sampleBuffer = NULL;
    } else {
        SampleUtil::clear(pOut, iBufferSize);
    }


    if (m_pEngineEffectsManager != NULL) {
        // Process effects enabled for this channel
        GroupFeatureState features;
        // This is out of date by a callback but some effects will want the RMS
        // volume.
        m_vuMeter.collectFeatures(&features);
        m_pEngineEffectsManager->process(getGroup(), pOut, iBufferSize,
                                         m_pSampleRate->get(), features);
    }
    // Update VU meter
    m_vuMeter.process(pOut, iBufferSize);
}
void EngineMicrophone::process(const CSAMPLE* pInput, CSAMPLE* pOut, const int iBufferSize) {
    Q_UNUSED(pInput);

    // If talkover is enabled, then read into the output buffer. Otherwise, skip
    // the appropriate number of samples to throw them away.
    if (isTalkover()) {
        int samplesRead = m_sampleBuffer.read(pOut, iBufferSize);
        if (samplesRead < iBufferSize) {
            // Buffer underflow. There aren't getting samples fast enough. This
            // shouldn't happen since PortAudio should feed us samples just as fast
            // as we consume them, right?
            qWarning() << "ERROR: Buffer underflow in EngineMicrophone. Playing silence.";
            SampleUtil::clear(pOut + samplesRead, iBufferSize - samplesRead);
        }
    } else {
        SampleUtil::clear(pOut, iBufferSize);
        m_sampleBuffer.skip(iBufferSize);
    }

    if (m_pEngineEffectsManager != NULL) {
        // Process effects enabled for this channel
        GroupFeatureState features;
        // This is out of date by a callback but some effects will want the RMS
        // volume.
        m_vuMeter.collectFeatures(&features);
        m_pEngineEffectsManager->process(getGroup(), pOut, pOut, iBufferSize,
                                         features);
    }
    // Apply clipping
    m_clipping.process(pOut, pOut, iBufferSize);
    // Update VU meter
    m_vuMeter.process(pOut, pOut, iBufferSize);
}
void EngineMicrophone::receiveBuffer(AudioInput input, const CSAMPLE* pBuffer,
                                     unsigned int nFrames) {
    Q_UNUSED(input);
    Q_UNUSED(nFrames);
    if (!isTalkover()) {
        m_sampleBuffer = NULL;
        return;
    } else {
        m_sampleBuffer = pBuffer;
    }
}
void EngineMicrophone::receiveBuffer(AudioInput input, const CSAMPLE* pBuffer,
                                     unsigned int nFrames) {
    if (!isTalkover()) {
        return;
    }

    if (input.getType() != AudioPath::MICROPHONE) {
        // This is an error!
        qWarning() << "EngineMicrophone receieved an AudioInput for a non-Microphone type!";
        return;
    }

    const unsigned int iChannels = input.getChannelGroup().getChannelCount();

    // Check that the number of mono frames doesn't exceed MAX_BUFFER_LEN/2
    // because thats our conversion buffer size.
    if (nFrames > MAX_BUFFER_LEN / iChannels) {
        qWarning() << "Dropping microphone samples because the input buffer is too large.";
        nFrames = MAX_BUFFER_LEN / iChannels;
    }

    const CSAMPLE* pWriteBuffer = NULL;
    unsigned int samplesToWrite = 0;

    if (iChannels == 1) {
        // Do mono -> stereo conversion.
        for (unsigned int i = 0; i < nFrames; ++i) {
            m_pConversionBuffer[i*2 + 0] = pBuffer[i];
            m_pConversionBuffer[i*2 + 1] = pBuffer[i];
        }
        pWriteBuffer = m_pConversionBuffer;
        samplesToWrite = nFrames * 2;
    } else if (iChannels == 2) {
        // Already in stereo. Use pBuffer as-is.
        pWriteBuffer = pBuffer;
        samplesToWrite = nFrames * iChannels;
    } else {
        qWarning() << "EngineMicrophone got greater than stereo input. Not currently handled.";
    }

    if (pWriteBuffer != NULL) {
        // TODO(rryan) do we need to verify the input is the one we asked for?
        // Oh well.
        unsigned int samplesWritten = m_sampleBuffer.write(pWriteBuffer,
                                                           samplesToWrite);
        if (samplesWritten < samplesToWrite) {
            // Buffer overflow. We aren't processing samples fast enough. This
            // shouldn't happen since the mic spits out samples just as fast as they
            // come in, right?
            qWarning() << "ERROR: Buffer overflow in EngineMicrophone. Dropping samples on the floor.";
        }
    }
}