void EqualPowerPanner::pan(double azimuth, double /*elevation*/, AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess)
{
    // FIXME: implement stereo sources
    bool isInputSafe = inputBus && inputBus->numberOfChannels() == 1 && framesToProcess <= inputBus->length();
    ASSERT(isInputSafe);
    if (!isInputSafe)
        return;

    bool isOutputSafe = outputBus && outputBus->numberOfChannels() == 2 && framesToProcess <= outputBus->length();
    ASSERT(isOutputSafe);
    if (!isOutputSafe)
        return;

    AudioChannel* channel = inputBus->channel(0);
    float* sourceP = channel->data();                               
    float* destinationL = outputBus->channelByType(AudioBus::ChannelLeft)->data();
    float* destinationR = outputBus->channelByType(AudioBus::ChannelRight)->data();

    if (!sourceP || !destinationL || !destinationR)
        return;

    // Pan smoothly from left to right with azimuth going from -30 -> +30 degrees.
    double desiredPanPosition;
    if (azimuth > 30.0)
        desiredPanPosition = 1.0;
    else if (azimuth < -30.0)
        desiredPanPosition = 0.0;
    else
        desiredPanPosition = (azimuth + 30.0) / 60.0;

    double desiredGainL = 0.5 * cos(piDouble * desiredPanPosition) + 0.5;
    double desiredGainR = sqrt(1.0 - desiredGainL*desiredGainL);

    // Don't de-zipper on first render call.
    if (m_isFirstRender) {
        m_isFirstRender = false;
        m_gainL = desiredGainL;
        m_gainR = desiredGainR;
    }

    // Cache in local variables.
    double gainL = m_gainL;
    double gainR = m_gainR;

    // Get local copy of smoothing constant.
    const double SmoothingConstant = m_smoothingConstant;

    int n = framesToProcess;

    while (n--) {
        float input = *sourceP++;
        gainL += (desiredGainL - gainL) * SmoothingConstant;
        gainR += (desiredGainR - gainR) * SmoothingConstant;
        *destinationL++ = static_cast<float>(input * gainL);
        *destinationR++ = static_cast<float>(input * gainR);
    }

    m_gainL = gainL;
    m_gainR = gainR;
}
// Pulls on our provider to get rendered audio stream.
OSStatus AudioDestinationMac::render(UInt32 numberOfFrames, AudioBufferList* ioData)
{
    AudioBuffer* buffers = ioData->mBuffers;
    m_renderBus.setChannelMemory(0, (float*)buffers[0].mData, numberOfFrames);
    m_renderBus.setChannelMemory(1, (float*)buffers[1].mData, numberOfFrames);

    //@tofix - add support for local/live audio input.
    m_callback.render(m_input->m_audioBus, &m_renderBus, numberOfFrames);

    // Clamp values at 0db (i.e., [-1.0, 1.0])
    for (unsigned i = 0; i < m_renderBus.numberOfChannels(); ++i) {
        AudioChannel* channel = m_renderBus.channel(i);
        VectorMath::vclip(channel->data(), 1, &kLowThreshold, &kHighThreshold, channel->mutableData(), 1, numberOfFrames);
    }

    return noErr;
}
Example #3
0
void Reverb::process(const AudioBus* sourceBus, AudioBus* destinationBus, size_t framesToProcess)
{
    // Do a fairly comprehensive sanity check.
    // If these conditions are satisfied, all of the source and destination pointers will be valid for the various matrixing cases.
    bool isSafeToProcess = sourceBus && destinationBus && sourceBus->numberOfChannels() > 0 && destinationBus->numberOfChannels() > 0
        && framesToProcess <= MaxFrameSize && framesToProcess <= sourceBus->length() && framesToProcess <= destinationBus->length();

    ASSERT(isSafeToProcess);
    if (!isSafeToProcess)
        return;

    // For now only handle mono or stereo output
    if (destinationBus->numberOfChannels() > 2) {
        destinationBus->zero();
        return;
    }

    AudioChannel* destinationChannelL = destinationBus->channel(0);
    const AudioChannel* sourceChannelL = sourceBus->channel(0);

    // Handle input -> output matrixing...
    size_t numInputChannels = sourceBus->numberOfChannels();
    size_t numOutputChannels = destinationBus->numberOfChannels();
    size_t numReverbChannels = m_convolvers.size();

    if (numInputChannels == 2 && numReverbChannels == 2 && numOutputChannels == 2) {
        // 2 -> 2 -> 2
        const AudioChannel* sourceChannelR = sourceBus->channel(1);
        AudioChannel* destinationChannelR = destinationBus->channel(1);
        m_convolvers[0]->process(sourceChannelL, destinationChannelL, framesToProcess);
        m_convolvers[1]->process(sourceChannelR, destinationChannelR, framesToProcess);
    } else  if (numInputChannels == 1 && numOutputChannels == 2 && numReverbChannels == 2) {
        // 1 -> 2 -> 2
        for (int i = 0; i < 2; ++i) {
            AudioChannel* destinationChannel = destinationBus->channel(i);
            m_convolvers[i]->process(sourceChannelL, destinationChannel, framesToProcess);
        }
    } else if (numInputChannels == 1 && numReverbChannels == 1 && numOutputChannels == 2) {
        // 1 -> 1 -> 2
        m_convolvers[0]->process(sourceChannelL, destinationChannelL, framesToProcess);

        // simply copy L -> R
        AudioChannel* destinationChannelR = destinationBus->channel(1);
        bool isCopySafe = destinationChannelL->data() && destinationChannelR->data() && destinationChannelL->length() >= framesToProcess && destinationChannelR->length() >= framesToProcess;
        ASSERT(isCopySafe);
        if (!isCopySafe)
            return;
        memcpy(destinationChannelR->mutableData(), destinationChannelL->data(), sizeof(float) * framesToProcess);
    } else if (numInputChannels == 1 && numReverbChannels == 1 && numOutputChannels == 1) {
        // 1 -> 1 -> 1
        m_convolvers[0]->process(sourceChannelL, destinationChannelL, framesToProcess);
    } else if (numInputChannels == 2 && numReverbChannels == 4 && numOutputChannels == 2) {
        // 2 -> 4 -> 2 ("True" stereo)
        const AudioChannel* sourceChannelR = sourceBus->channel(1);
        AudioChannel* destinationChannelR = destinationBus->channel(1);

        AudioChannel* tempChannelL = m_tempBuffer->channel(0);
        AudioChannel* tempChannelR = m_tempBuffer->channel(1);

        // Process left virtual source
        m_convolvers[0]->process(sourceChannelL, destinationChannelL, framesToProcess);
        m_convolvers[1]->process(sourceChannelL, destinationChannelR, framesToProcess);

        // Process right virtual source
        m_convolvers[2]->process(sourceChannelR, tempChannelL, framesToProcess);
        m_convolvers[3]->process(sourceChannelR, tempChannelR, framesToProcess);

        destinationBus->sumFrom(*m_tempBuffer);
    } else if (numInputChannels == 1 && numReverbChannels == 4 && numOutputChannels == 2) {
        // 1 -> 4 -> 2 (Processing mono with "True" stereo impulse response)
        // This is an inefficient use of a four-channel impulse response, but we should handle the case.
        AudioChannel* destinationChannelR = destinationBus->channel(1);

        AudioChannel* tempChannelL = m_tempBuffer->channel(0);
        AudioChannel* tempChannelR = m_tempBuffer->channel(1);

        // Process left virtual source
        m_convolvers[0]->process(sourceChannelL, destinationChannelL, framesToProcess);
        m_convolvers[1]->process(sourceChannelL, destinationChannelR, framesToProcess);

        // Process right virtual source
        m_convolvers[2]->process(sourceChannelL, tempChannelL, framesToProcess);
        m_convolvers[3]->process(sourceChannelL, tempChannelR, framesToProcess);

        destinationBus->sumFrom(*m_tempBuffer);
    } else {
        // Handle gracefully any unexpected / unsupported matrixing
        // FIXME: add code for 5.1 support...
        destinationBus->zero();
    }
}