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.

113 lines
5.1KB

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