1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00
JUCE/modules/juce_audio_plugin_client/AU/AudioUnitSDK/AUEffectBase.h

194 lines
6.5 KiB
Objective-C

/*!
@file AudioUnitSDK/AUEffectBase.h
@copyright © 2000-2021 Apple Inc. All rights reserved.
*/
#ifndef AudioUnitSDK_AUEffectBase_h
#define AudioUnitSDK_AUEffectBase_h
#include <AudioUnitSDK/AUBase.h>
#include <AudioUnitSDK/AUSilentTimeout.h>
#include <memory>
namespace ausdk {
class AUKernelBase;
/*!
@class AUEffectBase
@brief Base class for an effect with one input stream, one output stream, and any number of
channels.
*/
class AUEffectBase : public AUBase {
public:
explicit AUEffectBase(AudioComponentInstance audioUnit, bool inProcessesInPlace = true);
AUEffectBase(const AUEffectBase&) = delete;
AUEffectBase(AUEffectBase&&) = delete;
AUEffectBase& operator=(const AUEffectBase&) = delete;
AUEffectBase& operator=(AUEffectBase&&) = delete;
~AUEffectBase() override = default;
OSStatus Initialize() override;
void Cleanup() override;
OSStatus Reset(AudioUnitScope inScope, AudioUnitElement inElement) override;
OSStatus GetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope,
AudioUnitElement inElement, UInt32& outDataSize, bool& outWritable) override;
OSStatus GetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,
AudioUnitElement inElement, void* outData) override;
OSStatus SetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,
AudioUnitElement inElement, const void* inData, UInt32 inDataSize) override;
bool StreamFormatWritable(AudioUnitScope scope, AudioUnitElement element) override;
OSStatus ChangeStreamFormat(AudioUnitScope inScope, AudioUnitElement inElement,
const AudioStreamBasicDescription& inPrevFormat,
const AudioStreamBasicDescription& inNewFormat) override;
OSStatus Render(AudioUnitRenderActionFlags& ioActionFlags, const AudioTimeStamp& inTimeStamp,
UInt32 nFrames) override;
// our virtual methods
// If your unit processes N to N channels, and there are no interactions between channels,
// it can override NewKernel to create a mono processing object per channel. Otherwise,
// don't override NewKernel, and instead, override ProcessBufferLists.
virtual std::unique_ptr<AUKernelBase> NewKernel() { return {}; }
OSStatus ProcessBufferLists(AudioUnitRenderActionFlags& ioActionFlags,
const AudioBufferList& inBuffer, AudioBufferList& outBuffer,
UInt32 inFramesToProcess) override;
// convenience format accessors (use output 0's format)
Float64 GetSampleRate();
UInt32 GetNumberOfChannels();
// convenience wrappers for accessing parameters in the global scope
using AUBase::SetParameter;
void SetParameter(AudioUnitParameterID paramID, AudioUnitParameterValue value)
{
Globals()->SetParameter(paramID, value);
}
using AUBase::GetParameter;
AudioUnitParameterValue GetParameter(AudioUnitParameterID paramID)
{
return Globals()->GetParameter(paramID);
}
[[nodiscard]] bool CanScheduleParameters() const override { return true; }
// This is used for the property value - to reflect to the UI if an effect is bypassed
[[nodiscard]] bool IsBypassEffect() const noexcept { return mBypassEffect; }
virtual void SetBypassEffect(bool inFlag) { mBypassEffect = inFlag; }
void SetParamHasSampleRateDependency(bool inFlag) noexcept { mParamSRDep = inFlag; }
[[nodiscard]] bool GetParamHasSampleRateDependency() const noexcept { return mParamSRDep; }
/// Context, passed as `void* userData`, for `ProcessScheduledSlice()`.
struct ScheduledProcessParams {
AudioUnitRenderActionFlags* actionFlags = nullptr;
AudioBufferList* inputBufferList = nullptr;
AudioBufferList* outputBufferList = nullptr;
};
OSStatus ProcessScheduledSlice(void* inUserData, UInt32 inStartFrameInBuffer,
UInt32 inSliceFramesToProcess, UInt32 inTotalBufferFrames) override;
[[nodiscard]] bool ProcessesInPlace() const noexcept { return mProcessesInPlace; }
void SetProcessesInPlace(bool inProcessesInPlace) noexcept
{
mProcessesInPlace = inProcessesInPlace;
}
using KernelList = std::vector<std::unique_ptr<AUKernelBase>>;
protected:
void MaintainKernels();
// This is used in the render call to see if an effect is bypassed
// It can return a different status than IsBypassEffect (though it MUST take that into account)
virtual bool ShouldBypassEffect() { return IsBypassEffect(); }
[[nodiscard]] AUKernelBase* GetKernel(UInt32 index) const
{
return (index < mKernelList.size()) ? mKernelList[index].get() : nullptr;
}
[[nodiscard]] const KernelList& GetKernelList() const noexcept { return mKernelList; }
bool IsInputSilent(AudioUnitRenderActionFlags inActionFlags, UInt32 inFramesToProcess)
{
bool inputSilent = (inActionFlags & kAudioUnitRenderAction_OutputIsSilence) != 0;
// take latency and tail time into account when propagating the silent bit
const auto silentTimeoutFrames =
static_cast<UInt32>(GetSampleRate() * (GetLatency() + GetTailTime()));
mSilentTimeout.Process(inFramesToProcess, silentTimeoutFrames, inputSilent);
return inputSilent;
}
#if TARGET_OS_IPHONE
void SetOnlyOneKernel(bool inUseOnlyOneKernel) noexcept
{
mOnlyOneKernel = inUseOnlyOneKernel;
} // set in ctor of subclass that wants it.
#endif
private:
KernelList mKernelList;
bool mBypassEffect{ false };
bool mParamSRDep{ false };
bool mProcessesInPlace;
AUSilentTimeout mSilentTimeout;
AUOutputElement* mMainOutput{ nullptr };
AUInputElement* mMainInput{ nullptr };
#if TARGET_OS_IPHONE
bool mOnlyOneKernel;
#endif
UInt32 mBytesPerFrame = 0;
};
/*!
@class AUKernelBase
@brief Base class for a signal-processing "kernel", an object that performs DSP on one channel
of an audio stream.
*/
class AUKernelBase {
public:
explicit AUKernelBase(AUEffectBase& inAudioUnit) : mAudioUnit(inAudioUnit) {}
AUSDK_DEPRECATED("Construct with a reference")
explicit AUKernelBase(AUEffectBase* inAudioUnit) : mAudioUnit(*inAudioUnit) {}
AUKernelBase(const AUKernelBase&) = delete;
AUKernelBase(AUKernelBase&&) = delete;
AUKernelBase& operator=(const AUKernelBase&) = delete;
AUKernelBase& operator=(AUKernelBase&&) = delete;
virtual ~AUKernelBase() = default;
virtual void Reset() {}
virtual void Process(const Float32* /*inSourceP*/, Float32* /*inDestP*/,
UInt32 /*inFramesToProcess*/, bool& /*ioSilence*/) = 0;
Float64 GetSampleRate() { return mAudioUnit.GetSampleRate(); }
AudioUnitParameterValue GetParameter(AudioUnitParameterID paramID)
{
return mAudioUnit.GetParameter(paramID);
}
void SetChannelNum(UInt32 inChan) noexcept { mChannelNum = inChan; }
[[nodiscard]] UInt32 GetChannelNum() const noexcept { return mChannelNum; }
protected:
AUEffectBase& mAudioUnit; // NOLINT protected
UInt32 mChannelNum = 0; // NOLINT protected
};
} // namespace ausdk
#endif // AudioUnitSDK_AUEffectBase_h