int ReverbAccumulationBuffer::accumulate(const float* source,
                                         size_t numberOfFrames, int* readIndex,
                                         size_t delayFrames) {
  size_t bufferLength = m_buffer.Length();

  size_t writeIndex = (*readIndex + delayFrames) % bufferLength;

  // Update caller's readIndex
  *readIndex = (*readIndex + numberOfFrames) % bufferLength;

  size_t framesAvailable = bufferLength - writeIndex;
  size_t numberOfFrames1 = std::min(numberOfFrames, framesAvailable);
  size_t numberOfFrames2 = numberOfFrames - numberOfFrames1;

  float* destination = m_buffer.Elements();

  bool isSafe = writeIndex <= bufferLength &&
                numberOfFrames1 + writeIndex <= bufferLength &&
                numberOfFrames2 <= bufferLength;
  MOZ_ASSERT(isSafe);
  if (!isSafe) return 0;

  AudioBufferAddWithScale(source, 1.0f, destination + writeIndex,
                          numberOfFrames1);
  if (numberOfFrames2 > 0) {
    AudioBufferAddWithScale(source + numberOfFrames1, 1.0f, destination,
                            numberOfFrames2);
  }

  return writeIndex;
}
void
AudioBlockAddChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE],
                              float aScale,
                              float aOutput[WEBAUDIO_BLOCK_SIZE])
{
  AudioBufferAddWithScale(aInput, aScale, aOutput, WEBAUDIO_BLOCK_SIZE);
}
Exemple #3
0
const float* FFTConvolver::process(FFTBlock* fftKernel, const float* sourceP)
{
    size_t halfSize = fftSize() / 2;

    // WEBAUDIO_BLOCK_SIZE must be an exact multiple of halfSize,
    // halfSize must be a multiple of WEBAUDIO_BLOCK_SIZE
    // and > WEBAUDIO_BLOCK_SIZE.
    MOZ_ASSERT(halfSize % WEBAUDIO_BLOCK_SIZE == 0 &&
               WEBAUDIO_BLOCK_SIZE <= halfSize);

    // Copy samples to input buffer (note contraint above!)
    float* inputP = m_inputBuffer.Elements();

    MOZ_ASSERT(sourceP && inputP && m_readWriteIndex + WEBAUDIO_BLOCK_SIZE <= m_inputBuffer.Length());

    memcpy(inputP + m_readWriteIndex, sourceP, sizeof(float) * WEBAUDIO_BLOCK_SIZE);

    float* outputP = m_outputBuffer.Elements();
    m_readWriteIndex += WEBAUDIO_BLOCK_SIZE;

    // Check if it's time to perform the next FFT
    if (m_readWriteIndex == halfSize) {
        // The input buffer is now filled (get frequency-domain version)
        m_frame.PerformFFT(m_inputBuffer.Elements());
        m_frame.Multiply(*fftKernel);
        m_frame.GetInverseWithoutScaling(m_outputBuffer.Elements());

        // Overlap-add 1st half from previous time
        AudioBufferAddWithScale(m_lastOverlapBuffer.Elements(), 1.0f,
                                m_outputBuffer.Elements(), halfSize);

        // Finally, save 2nd half of result
        MOZ_ASSERT(m_outputBuffer.Length() == 2 * halfSize && m_lastOverlapBuffer.Length() == halfSize);

        memcpy(m_lastOverlapBuffer.Elements(), m_outputBuffer.Elements() + halfSize, sizeof(float) * halfSize);

        // Reset index back to start for next time
        m_readWriteIndex = 0;
    }

    return outputP + m_readWriteIndex;
}
Exemple #4
0
void Reverb::process(const AudioBlock* sourceBus, AudioBlock* destinationBus)
{
    // 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->ChannelCount() > 0 && destinationBus->mChannelData.Length() > 0
        && WEBAUDIO_BLOCK_SIZE <= MaxFrameSize && WEBAUDIO_BLOCK_SIZE <= size_t(sourceBus->GetDuration()) && WEBAUDIO_BLOCK_SIZE <= size_t(destinationBus->GetDuration());

    MOZ_ASSERT(isSafeToProcess);
    if (!isSafeToProcess)
        return;

    // For now only handle mono or stereo output
    MOZ_ASSERT(destinationBus->ChannelCount() <= 2);

    float* destinationChannelL = static_cast<float*>(const_cast<void*>(destinationBus->mChannelData[0]));
    const float* sourceBusL = static_cast<const float*>(sourceBus->mChannelData[0]);

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

    if (numInputChannels == 2 && numReverbChannels == 2 && numOutputChannels == 2) {
        // 2 -> 2 -> 2
        const float* sourceBusR = static_cast<const float*>(sourceBus->mChannelData[1]);
        float* destinationChannelR = static_cast<float*>(const_cast<void*>(destinationBus->mChannelData[1]));
        m_convolvers[0]->process(sourceBusL, destinationChannelL);
        m_convolvers[1]->process(sourceBusR, destinationChannelR);
    } else  if (numInputChannels == 1 && numOutputChannels == 2 && numReverbChannels == 2) {
        // 1 -> 2 -> 2
        for (int i = 0; i < 2; ++i) {
            float* destinationChannel = static_cast<float*>(const_cast<void*>(destinationBus->mChannelData[i]));
            m_convolvers[i]->process(sourceBusL, destinationChannel);
        }
    } else if (numInputChannels == 1 && numReverbChannels == 1 && numOutputChannels == 2) {
        // 1 -> 1 -> 2
        m_convolvers[0]->process(sourceBusL, destinationChannelL);

        // simply copy L -> R
        float* destinationChannelR = static_cast<float*>(const_cast<void*>(destinationBus->mChannelData[1]));
        bool isCopySafe = destinationChannelL && destinationChannelR && size_t(destinationBus->GetDuration()) >= WEBAUDIO_BLOCK_SIZE;
        MOZ_ASSERT(isCopySafe);
        if (!isCopySafe)
            return;
        PodCopy(destinationChannelR, destinationChannelL, WEBAUDIO_BLOCK_SIZE);
    } else if (numInputChannels == 1 && numReverbChannels == 1 && numOutputChannels == 1) {
        // 1 -> 1 -> 1
        m_convolvers[0]->process(sourceBusL, destinationChannelL);
    } else if (numInputChannels == 2 && numReverbChannels == 4 && numOutputChannels == 2) {
        // 2 -> 4 -> 2 ("True" stereo)
        const float* sourceBusR = static_cast<const float*>(sourceBus->mChannelData[1]);
        float* destinationChannelR = static_cast<float*>(const_cast<void*>(destinationBus->mChannelData[1]));

        float* tempChannelL = static_cast<float*>(const_cast<void*>(m_tempBuffer.mChannelData[0]));
        float* tempChannelR = static_cast<float*>(const_cast<void*>(m_tempBuffer.mChannelData[1]));

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

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

        AudioBufferAddWithScale(tempChannelL, 1.0f, destinationChannelL, sourceBus->GetDuration());
        AudioBufferAddWithScale(tempChannelR, 1.0f, destinationChannelR, sourceBus->GetDuration());
    } 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.
        float* destinationChannelR = static_cast<float*>(const_cast<void*>(destinationBus->mChannelData[1]));

        float* tempChannelL = static_cast<float*>(const_cast<void*>(m_tempBuffer.mChannelData[0]));
        float* tempChannelR = static_cast<float*>(const_cast<void*>(m_tempBuffer.mChannelData[1]));

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

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

        AudioBufferAddWithScale(tempChannelL, 1.0f, destinationChannelL, sourceBus->GetDuration());
        AudioBufferAddWithScale(tempChannelR, 1.0f, destinationChannelR, sourceBus->GetDuration());
    } else {
        // Handle gracefully any unexpected / unsupported matrixing
        // FIXME: add code for 5.1 support...
        destinationBus->SetNull(destinationBus->GetDuration());
    }
}
Exemple #5
0
void FFTConvolver::process(FFTBlock* fftKernel, const float* sourceP, float* destP, size_t framesToProcess)
{
    size_t halfSize = fftSize() / 2;

    // framesToProcess must be an exact multiple of halfSize,
    // or halfSize is a multiple of framesToProcess when halfSize > framesToProcess.
    bool isGood = !(halfSize % framesToProcess && framesToProcess % halfSize);
    MOZ_ASSERT(isGood);
    if (!isGood)
        return;

    size_t numberOfDivisions = halfSize <= framesToProcess ? (framesToProcess / halfSize) : 1;
    size_t divisionSize = numberOfDivisions == 1 ? framesToProcess : halfSize;

    for (size_t i = 0; i < numberOfDivisions; ++i, sourceP += divisionSize, destP += divisionSize) {
        // Copy samples to input buffer (note contraint above!)
        float* inputP = m_inputBuffer.Elements();

        // Sanity check
        bool isCopyGood1 = sourceP && inputP && m_readWriteIndex + divisionSize <= m_inputBuffer.Length();
        MOZ_ASSERT(isCopyGood1);
        if (!isCopyGood1)
            return;

        memcpy(inputP + m_readWriteIndex, sourceP, sizeof(float) * divisionSize);

        // Copy samples from output buffer
        float* outputP = m_outputBuffer.Elements();

        // Sanity check
        bool isCopyGood2 = destP && outputP && m_readWriteIndex + divisionSize <= m_outputBuffer.Length();
        MOZ_ASSERT(isCopyGood2);
        if (!isCopyGood2)
            return;

        memcpy(destP, outputP + m_readWriteIndex, sizeof(float) * divisionSize);
        m_readWriteIndex += divisionSize;

        // Check if it's time to perform the next FFT
        if (m_readWriteIndex == halfSize) {
            // The input buffer is now filled (get frequency-domain version)
            m_frame.PerformFFT(m_inputBuffer.Elements());
            m_frame.Multiply(*fftKernel);
            m_frame.GetInverseWithoutScaling(m_outputBuffer.Elements());

            // Overlap-add 1st half from previous time
            AudioBufferAddWithScale(m_lastOverlapBuffer.Elements(), 1.0f,
                                    m_outputBuffer.Elements(), halfSize);

            // Finally, save 2nd half of result
            bool isCopyGood3 = m_outputBuffer.Length() == 2 * halfSize && m_lastOverlapBuffer.Length() == halfSize;
            MOZ_ASSERT(isCopyGood3);
            if (!isCopyGood3)
                return;

            memcpy(m_lastOverlapBuffer.Elements(), m_outputBuffer.Elements() + halfSize, sizeof(float) * halfSize);

            // Reset index back to start for next time
            m_readWriteIndex = 0;
        }
    }
}