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.

195 lines
6.5KB

  1. /*!
  2. @file AudioUnitSDK/AUEffectBase.h
  3. @copyright © 2000-2021 Apple Inc. All rights reserved.
  4. */
  5. #ifndef AudioUnitSDK_AUEffectBase_h
  6. #define AudioUnitSDK_AUEffectBase_h
  7. #include <AudioUnitSDK/AUBase.h>
  8. #include <AudioUnitSDK/AUSilentTimeout.h>
  9. #include <memory>
  10. namespace ausdk {
  11. class AUKernelBase;
  12. /*!
  13. @class AUEffectBase
  14. @brief Base class for an effect with one input stream, one output stream, and any number of
  15. channels.
  16. */
  17. class AUEffectBase : public AUBase {
  18. public:
  19. explicit AUEffectBase(AudioComponentInstance audioUnit, bool inProcessesInPlace = true);
  20. AUEffectBase(const AUEffectBase&) = delete;
  21. AUEffectBase(AUEffectBase&&) = delete;
  22. AUEffectBase& operator=(const AUEffectBase&) = delete;
  23. AUEffectBase& operator=(AUEffectBase&&) = delete;
  24. ~AUEffectBase() override = default;
  25. OSStatus Initialize() override;
  26. void Cleanup() override;
  27. OSStatus Reset(AudioUnitScope inScope, AudioUnitElement inElement) override;
  28. OSStatus GetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope,
  29. AudioUnitElement inElement, UInt32& outDataSize, bool& outWritable) override;
  30. OSStatus GetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,
  31. AudioUnitElement inElement, void* outData) override;
  32. OSStatus SetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,
  33. AudioUnitElement inElement, const void* inData, UInt32 inDataSize) override;
  34. bool StreamFormatWritable(AudioUnitScope scope, AudioUnitElement element) override;
  35. OSStatus ChangeStreamFormat(AudioUnitScope inScope, AudioUnitElement inElement,
  36. const AudioStreamBasicDescription& inPrevFormat,
  37. const AudioStreamBasicDescription& inNewFormat) override;
  38. OSStatus Render(AudioUnitRenderActionFlags& ioActionFlags, const AudioTimeStamp& inTimeStamp,
  39. UInt32 nFrames) override;
  40. // our virtual methods
  41. // If your unit processes N to N channels, and there are no interactions between channels,
  42. // it can override NewKernel to create a mono processing object per channel. Otherwise,
  43. // don't override NewKernel, and instead, override ProcessBufferLists.
  44. virtual std::unique_ptr<AUKernelBase> NewKernel() { return {}; }
  45. OSStatus ProcessBufferLists(AudioUnitRenderActionFlags& ioActionFlags,
  46. const AudioBufferList& inBuffer, AudioBufferList& outBuffer,
  47. UInt32 inFramesToProcess) override;
  48. // convenience format accessors (use output 0's format)
  49. Float64 GetSampleRate();
  50. UInt32 GetNumberOfChannels();
  51. // convenience wrappers for accessing parameters in the global scope
  52. using AUBase::SetParameter;
  53. void SetParameter(AudioUnitParameterID paramID, AudioUnitParameterValue value)
  54. {
  55. Globals()->SetParameter(paramID, value);
  56. }
  57. using AUBase::GetParameter;
  58. AudioUnitParameterValue GetParameter(AudioUnitParameterID paramID)
  59. {
  60. return Globals()->GetParameter(paramID);
  61. }
  62. [[nodiscard]] bool CanScheduleParameters() const override { return true; }
  63. // This is used for the property value - to reflect to the UI if an effect is bypassed
  64. [[nodiscard]] bool IsBypassEffect() const noexcept { return mBypassEffect; }
  65. virtual void SetBypassEffect(bool inFlag) { mBypassEffect = inFlag; }
  66. void SetParamHasSampleRateDependency(bool inFlag) noexcept { mParamSRDep = inFlag; }
  67. [[nodiscard]] bool GetParamHasSampleRateDependency() const noexcept { return mParamSRDep; }
  68. /// Context, passed as `void* userData`, for `ProcessScheduledSlice()`.
  69. struct ScheduledProcessParams {
  70. AudioUnitRenderActionFlags* actionFlags = nullptr;
  71. AudioBufferList* inputBufferList = nullptr;
  72. AudioBufferList* outputBufferList = nullptr;
  73. };
  74. OSStatus ProcessScheduledSlice(void* inUserData, UInt32 inStartFrameInBuffer,
  75. UInt32 inSliceFramesToProcess, UInt32 inTotalBufferFrames) override;
  76. [[nodiscard]] bool ProcessesInPlace() const noexcept { return mProcessesInPlace; }
  77. void SetProcessesInPlace(bool inProcessesInPlace) noexcept
  78. {
  79. mProcessesInPlace = inProcessesInPlace;
  80. }
  81. using KernelList = std::vector<std::unique_ptr<AUKernelBase>>;
  82. protected:
  83. void MaintainKernels();
  84. // This is used in the render call to see if an effect is bypassed
  85. // It can return a different status than IsBypassEffect (though it MUST take that into account)
  86. virtual bool ShouldBypassEffect() { return IsBypassEffect(); }
  87. [[nodiscard]] AUKernelBase* GetKernel(UInt32 index) const
  88. {
  89. return (index < mKernelList.size()) ? mKernelList[index].get() : nullptr;
  90. }
  91. [[nodiscard]] const KernelList& GetKernelList() const noexcept { return mKernelList; }
  92. bool IsInputSilent(AudioUnitRenderActionFlags inActionFlags, UInt32 inFramesToProcess)
  93. {
  94. bool inputSilent = (inActionFlags & kAudioUnitRenderAction_OutputIsSilence) != 0;
  95. // take latency and tail time into account when propagating the silent bit
  96. const auto silentTimeoutFrames =
  97. static_cast<UInt32>(GetSampleRate() * (GetLatency() + GetTailTime()));
  98. mSilentTimeout.Process(inFramesToProcess, silentTimeoutFrames, inputSilent);
  99. return inputSilent;
  100. }
  101. #if TARGET_OS_IPHONE
  102. void SetOnlyOneKernel(bool inUseOnlyOneKernel) noexcept
  103. {
  104. mOnlyOneKernel = inUseOnlyOneKernel;
  105. } // set in ctor of subclass that wants it.
  106. #endif
  107. private:
  108. KernelList mKernelList;
  109. bool mBypassEffect{ false };
  110. bool mParamSRDep{ false };
  111. bool mProcessesInPlace;
  112. AUSilentTimeout mSilentTimeout;
  113. AUOutputElement* mMainOutput{ nullptr };
  114. AUInputElement* mMainInput{ nullptr };
  115. #if TARGET_OS_IPHONE
  116. bool mOnlyOneKernel;
  117. #endif
  118. UInt32 mBytesPerFrame = 0;
  119. };
  120. /*!
  121. @class AUKernelBase
  122. @brief Base class for a signal-processing "kernel", an object that performs DSP on one channel
  123. of an audio stream.
  124. */
  125. class AUKernelBase {
  126. public:
  127. explicit AUKernelBase(AUEffectBase& inAudioUnit) : mAudioUnit(inAudioUnit) {}
  128. AUSDK_DEPRECATED("Construct with a reference")
  129. explicit AUKernelBase(AUEffectBase* inAudioUnit) : mAudioUnit(*inAudioUnit) {}
  130. AUKernelBase(const AUKernelBase&) = delete;
  131. AUKernelBase(AUKernelBase&&) = delete;
  132. AUKernelBase& operator=(const AUKernelBase&) = delete;
  133. AUKernelBase& operator=(AUKernelBase&&) = delete;
  134. virtual ~AUKernelBase() = default;
  135. virtual void Reset() {}
  136. virtual void Process(const Float32* /*inSourceP*/, Float32* /*inDestP*/,
  137. UInt32 /*inFramesToProcess*/, bool& /*ioSilence*/) = 0;
  138. Float64 GetSampleRate() { return mAudioUnit.GetSampleRate(); }
  139. AudioUnitParameterValue GetParameter(AudioUnitParameterID paramID)
  140. {
  141. return mAudioUnit.GetParameter(paramID);
  142. }
  143. void SetChannelNum(UInt32 inChan) noexcept { mChannelNum = inChan; }
  144. [[nodiscard]] UInt32 GetChannelNum() const noexcept { return mChannelNum; }
  145. protected:
  146. AUEffectBase& mAudioUnit; // NOLINT protected
  147. UInt32 mChannelNum = 0; // NOLINT protected
  148. };
  149. } // namespace ausdk
  150. #endif // AudioUnitSDK_AUEffectBase_h