mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
194 lines
6.5 KiB
Objective-C
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
|