The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
5.2KB

  1. /*
  2. ==============================================================================
  3. This file was auto-generated!
  4. It contains the basic framework code for an ARA playback renderer implementation.
  5. ==============================================================================
  6. */
  7. %%araplaybackrenderer_headers%%
  8. //==============================================================================
  9. void %%araplaybackrenderer_class_name%%::prepareToPlay (double sampleRateIn, int maximumSamplesPerBlockIn, int numChannelsIn, juce::AudioProcessor::ProcessingPrecision, AlwaysNonRealtime alwaysNonRealtime)
  10. {
  11. numChannels = numChannelsIn;
  12. sampleRate = sampleRateIn;
  13. maximumSamplesPerBlock = maximumSamplesPerBlockIn;
  14. useBufferedAudioSourceReader = alwaysNonRealtime == AlwaysNonRealtime::no;
  15. }
  16. void %%araplaybackrenderer_class_name%%::releaseResources()
  17. {
  18. }
  19. //==============================================================================
  20. bool %%araplaybackrenderer_class_name%%::processBlock (juce::AudioBuffer<float>& buffer,
  21. juce::AudioProcessor::Realtime realtime,
  22. const juce::AudioPlayHead::PositionInfo& positionInfo) noexcept
  23. {
  24. const auto numSamples = buffer.getNumSamples();
  25. jassert (numSamples <= maximumSamplesPerBlock);
  26. jassert (numChannels == buffer.getNumChannels());
  27. jassert (realtime == juce::AudioProcessor::Realtime::no || useBufferedAudioSourceReader);
  28. const auto timeInSamples = positionInfo.getTimeInSamples().orFallback (0);
  29. const auto isPlaying = positionInfo.getIsPlaying();
  30. bool success = true;
  31. bool didRenderAnyRegion = false;
  32. if (isPlaying)
  33. {
  34. const auto blockRange = juce::Range<juce::int64>::withStartAndLength (timeInSamples, numSamples);
  35. for (const auto& playbackRegion : getPlaybackRegions())
  36. {
  37. // Evaluate region borders in song time, calculate sample range to render in song time.
  38. // Note that this example does not use head- or tailtime, so the includeHeadAndTail
  39. // parameter is set to false here - this might need to be adjusted in actual plug-ins.
  40. const auto playbackSampleRange = playbackRegion->getSampleRange (sampleRate,
  41. juce::ARAPlaybackRegion::IncludeHeadAndTail::no);
  42. auto renderRange = blockRange.getIntersectionWith (playbackSampleRange);
  43. if (renderRange.isEmpty())
  44. continue;
  45. // Evaluate region borders in modification/source time and calculate offset between
  46. // song and source samples, then clip song samples accordingly
  47. // (if an actual plug-in supports time stretching, this must be taken into account here).
  48. juce::Range<juce::int64> modificationSampleRange { playbackRegion->getStartInAudioModificationSamples(),
  49. playbackRegion->getEndInAudioModificationSamples() };
  50. const auto modificationSampleOffset = modificationSampleRange.getStart() - playbackSampleRange.getStart();
  51. renderRange = renderRange.getIntersectionWith (modificationSampleRange.movedToStartAt (playbackSampleRange.getStart()));
  52. if (renderRange.isEmpty())
  53. continue;
  54. // Now calculate the samples in renderRange for this PlaybackRegion based on the ARA model
  55. // graph. If didRenderAnyRegion is true, add the region's output samples in renderRange to
  56. // the buffer. Otherwise the buffer needs to be initialised so the sample value must be
  57. // overwritten.
  58. const int numSamplesToRead = (int) renderRange.getLength();
  59. const int startInBuffer = (int) (renderRange.getStart() - blockRange.getStart());
  60. const auto startInSource = renderRange.getStart() + modificationSampleOffset;
  61. for (int c = 0; c < numChannels; ++c)
  62. {
  63. auto* channelData = buffer.getWritePointer (c);
  64. for (int i = 0; i < numSamplesToRead; ++i)
  65. {
  66. // Calculate region output sample at index startInSource + i ...
  67. float sample = 0.0f;
  68. if (didRenderAnyRegion)
  69. channelData[startInBuffer + i] += sample;
  70. else
  71. channelData[startInBuffer + i] = sample;
  72. }
  73. }
  74. // If rendering first region, clear any excess at start or end of the region.
  75. if (! didRenderAnyRegion)
  76. {
  77. if (startInBuffer != 0)
  78. buffer.clear (0, startInBuffer);
  79. const int endInBuffer = startInBuffer + numSamples;
  80. const int remainingSamples = numSamples - endInBuffer;
  81. if (remainingSamples != 0)
  82. buffer.clear (endInBuffer, remainingSamples);
  83. didRenderAnyRegion = true;
  84. }
  85. }
  86. }
  87. if (! didRenderAnyRegion)
  88. buffer.clear();
  89. return success;
  90. }