File: jucer_AudioPluginARAPlaybackRendererTemplate.cpp

package info (click to toggle)
juce 7.0.5%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, sid
  • size: 63,880 kB
  • sloc: cpp: 458,845; ansic: 24,200; java: 2,877; xml: 265; python: 216; sh: 135; makefile: 76
file content (114 lines) | stat: -rw-r--r-- 5,322 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/*
  ==============================================================================

    This file was auto-generated!

    It contains the basic framework code for an ARA playback renderer implementation.

  ==============================================================================
*/

%%araplaybackrenderer_headers%%

//==============================================================================
void %%araplaybackrenderer_class_name%%::prepareToPlay (double sampleRateIn, int maximumSamplesPerBlockIn, int numChannelsIn, juce::AudioProcessor::ProcessingPrecision, AlwaysNonRealtime alwaysNonRealtime)
{
    numChannels = numChannelsIn;
    sampleRate = sampleRateIn;
    maximumSamplesPerBlock = maximumSamplesPerBlockIn;
    useBufferedAudioSourceReader = alwaysNonRealtime == AlwaysNonRealtime::no;
}

void %%araplaybackrenderer_class_name%%::releaseResources()
{
}

//==============================================================================
bool %%araplaybackrenderer_class_name%%::processBlock (juce::AudioBuffer<float>& buffer,
                                                       juce::AudioProcessor::Realtime realtime,
                                                       const juce::AudioPlayHead::PositionInfo& positionInfo) noexcept
{
    const auto numSamples = buffer.getNumSamples();
    jassert (numSamples <= maximumSamplesPerBlock);
    jassert (numChannels == buffer.getNumChannels());
    jassert (realtime == juce::AudioProcessor::Realtime::no || useBufferedAudioSourceReader);
    const auto timeInSamples = positionInfo.getTimeInSamples().orFallback (0);
    const auto isPlaying = positionInfo.getIsPlaying();

    bool success = true;
    bool didRenderAnyRegion = false;

    if (isPlaying)
    {
        const auto blockRange = juce::Range<juce::int64>::withStartAndLength (timeInSamples, numSamples);

        for (const auto& playbackRegion : getPlaybackRegions())
        {
            // Evaluate region borders in song time, calculate sample range to render in song time.
            // Note that this example does not use head- or tailtime, so the includeHeadAndTail
            // parameter is set to false here - this might need to be adjusted in actual plug-ins.
            const auto playbackSampleRange = playbackRegion->getSampleRange (sampleRate,
                                                                             juce::ARAPlaybackRegion::IncludeHeadAndTail::no);
            auto renderRange = blockRange.getIntersectionWith (playbackSampleRange);

            if (renderRange.isEmpty())
                continue;

            // Evaluate region borders in modification/source time and calculate offset between
            // song and source samples, then clip song samples accordingly
            // (if an actual plug-in supports time stretching, this must be taken into account here).
            juce::Range<juce::int64> modificationSampleRange { playbackRegion->getStartInAudioModificationSamples(),
                                                               playbackRegion->getEndInAudioModificationSamples() };
            const auto modificationSampleOffset = modificationSampleRange.getStart() - playbackSampleRange.getStart();

            renderRange = renderRange.getIntersectionWith (modificationSampleRange.movedToStartAt (playbackSampleRange.getStart()));

            if (renderRange.isEmpty())
                continue;

            // Now calculate the samples in renderRange for this PlaybackRegion based on the ARA model
            // graph. If didRenderAnyRegion is true, add the region's output samples in renderRange to
            // the buffer. Otherwise the buffer needs to be initialised so the sample value must be
            // overwritten.
            const int numSamplesToRead = (int) renderRange.getLength();
            const int startInBuffer = (int) (renderRange.getStart() - blockRange.getStart());
            const auto startInSource = renderRange.getStart() + modificationSampleOffset;

            for (int c = 0; c < numChannels; ++c)
            {
                auto* channelData = buffer.getWritePointer (c);

                for (int i = 0; i < numSamplesToRead; ++i)
                {
                    // Calculate region output sample at index startInSource + i ...
                    float sample = 0.0f;

                    if (didRenderAnyRegion)
                        channelData[startInBuffer + i] += sample;
                    else
                        channelData[startInBuffer + i] = sample;
                }
            }

            // If rendering first region, clear any excess at start or end of the region.
            if (! didRenderAnyRegion)
            {
                if (startInBuffer != 0)
                    buffer.clear (0, startInBuffer);

                const int endInBuffer = startInBuffer + numSamples;
                const int remainingSamples = numSamples - endInBuffer;

                if (remainingSamples != 0)
                    buffer.clear (endInBuffer, remainingSamples);

                didRenderAnyRegion = true;
            }
        }
    }

    if (! didRenderAnyRegion)
        buffer.clear();

    return success;
}