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; }
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(); } }