[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/reillypascal/RSAlgorithmicVerb/main/Source/EarlyReflections.cpp [Back]  [Original]

// FIR-based early reflections with 6 taps and HRTF for binaural stereo. Based on Dattorro

#include "EarlyReflections.h"

EarlyReflections::EarlyReflections() = default;

EarlyReflections::~EarlyReflections() = default;

void EarlyReflections::prepare(const juce::dsp::ProcessSpec& spec)
{
    juce::dsp::ProcessSpec monoSpec;
    monoSpec.sampleRate = spec.sampleRate;
    monoSpec.maximumBlockSize = spec.maximumBlockSize;
    monoSpec.numChannels = 1;

    earlyReflectionsDelayLine.prepare(monoSpec);

    // leftHRTFDelay.prepare(monoSpec);
    // rightHRTFDelay.prepare(monoSpec);

    // leftHRTFFilter.prepare(monoSpec);
    // rightHRTFFilter.prepare(monoSpec);

    hrtfDelays.resize(spec.numChannels);
    hrtfFilters.resize(spec.numChannels);
    channelOutputs.resize(spec.numChannels, 0.0);

    for (auto& delay : hrtfDelays)
    {
        delay.prepare(monoSpec);
        delay.setMaximumDelayInSamples(441);
    }

    for (auto& filter : hrtfFilters)
        filter.prepare(monoSpec);
}

void EarlyReflections::processBlock(juce::AudioBuffer& buffer, juce::MidiBuffer& midiMessages)
{
    juce::ScopedNoDenormals noDenormals;
    int numSamples = buffer.getNumSamples();
    int numChannels = buffer.getNumChannels();

    juce::AudioBuffer monoBuffer(1, numSamples);
    monoBuffer.clear();

    monoBuffer.copyFrom(0, 0, buffer, 0, 0, numSamples);
    if (numChannels > 1)
    {
        monoBuffer.addFrom(0, 0, buffer, 1, 0, numSamples);
        monoBuffer.applyGain(0.5f);
    }

    // leftHRTFDelay.setDelay(35);
    // rightHRTFDelay.setDelay(35);

    for (auto& delay : hrtfDelays)
        delay.setDelay(35);

    auto* channelData = monoBuffer.getWritePointer(0);
    for (int sample = 0; sample < numSamples; ++sample)
    {
        earlyReflectionsDelayLine.pushSample(0, channelData[sample]);

        for (int channel = 0; channel < numChannels; ++channel)
        {
            for (int delTime = 0; delTime < hrtfDelayTimes.size(); ++delTime)
            {
                // sum 3 left/ 3 right taps (interleaved w/ each other)
                // channel % 2 because could be many channels, but only 2 lists of delay times
                channelOutputs[channel] = earlyReflectionsDelayLine.getSampleAtDelay(
                                              0, hrtfDelayTimes[channel % 2][delTime] * parameters.roomSize) *
                                          initialLevel * pow(parameters.decayTime, delTime);
            }
        }

        for (int channel = 0; channel < numChannels; ++channel)
        {
            if (!monoFlag)
            {
                // right into left HRTF and vice versa
                hrtfDelays[channel].pushSample(0, channelOutputs[(channel + 1) % numChannels]);

                // filter HRTFs and add to outputs
                channelOutputs[channel] += hrtfFilters[channel].processSample(0, hrtfDelays[channel].popSample(0));
            }

            // outputs into original stereo buffer
            buffer.setSample(0, sample, channelOutputs[channel]);
        }
    }

    // for (int sample = 0; sample < numSamples; ++sample)
    // {
    //     earlyReflectionsDelayLine.pushSample(0, channelData[sample]);

    //     // sum left 3 taps
    //     channel0Output = earlyReflectionsDelayLine.getSampleAtDelay(0, 441 * parameters.roomSize) * initialLevel;
    //     channel0Output += earlyReflectionsDelayLine.getSampleAtDelay(0, 2929 * parameters.roomSize) * initialLevel *
    //     parameters.decayTime; channel0Output += earlyReflectionsDelayLine.getSampleAtDelay(0, 6319 *
    //     parameters.roomSize) * initialLevel * pow(parameters.decayTime, 2);

    //     // sum right 3 taps (interleaved w/ left)
    //     channel1Output = earlyReflectionsDelayLine.getSampleAtDelay(0, 1191 * parameters.roomSize) * initialLevel;
    //     channel1Output += earlyReflectionsDelayLine.getSampleAtDelay(0, 3948 * parameters.roomSize) * initialLevel *
    //     parameters.decayTime; channel1Output += earlyReflectionsDelayLine.getSampleAtDelay(0, 9462 *
    //     parameters.roomSize) * initialLevel * pow(parameters.decayTime, 2);

    //     if (!monoFlag)
    //     {
    //         // right into left HRTF and vice versa
    //         leftHRTFDelay.pushSample(0, channel1Output);
    //         rightHRTFDelay.pushSample(0, channel0Output);

    //         // filter HRTFs and add to outputs
    //         channel0Output += leftHRTFFilter.processSample(0, leftHRTFDelay.popSample(0));
    //         channel1Output += rightHRTFFilter.processSample(0, rightHRTFDelay.popSample(0));
    //     }

    //     // outputs into original stereo buffer
    //     for (int destChannel = 0; destChannel < numChannels; ++destChannel)
    //     {
    //         if (destChannel == 0)
    //             buffer.setSample(0, sample, channel0Output);
    //         else if (destChannel == 1)
    //             buffer.setSample(1, sample, channel1Output);
    //     }
    // }
}

void EarlyReflections::reset()
{
    earlyReflectionsDelayLine.reset();

    for (auto& delay : hrtfDelays)
        delay.reset();

    for (auto& filter : hrtfFilters)
        filter.reset();
    // leftHRTFDelay.reset();
    // rightHRTFDelay.reset();
    // leftHRTFFilter.reset();
    // rightHRTFFilter.reset();
}

ReverbProcessorParameters& EarlyReflections::getParameters()
{
    return parameters;
}

void EarlyReflections::setParameters(const ReverbProcessorParameters& params)
{
    if (!(params == parameters))
    {
        parameters = params;
        parameters.roomSize = scale(parameters.roomSize, 0.0f, 1.0f, 0.25f, 1.75f);
    }
}

void EarlyReflections::setMonoFlag(const bool newMonoFlag)
{
    monoFlag = newMonoFlag;
}

Web Proxy Viewer  |  New URL  |  Original Page