-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
AUEffectBase.h
194 lines (150 loc) · 6.53 KB
/
AUEffectBase.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/*!
@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