1 /*
2 Copyright (C) 2016 Apple Inc. All Rights Reserved.
3 See LICENSE.txt for this sample’s licensing information
4
5 Abstract:
6 Part of Core Audio AUBase Classes
7 */
8
9 #ifndef __AUEffectBase_h__
10 #define __AUEffectBase_h__
11
12 #include "AUBase.h"
13 #include "AUSilentTimeout.h"
14 #include "CAException.h"
15
16 class AUKernelBase;
17
18 // Base class for an effect with one input stream, one output stream,
19 // any number of channels.
20 /*! @class AUEffectBase */
21 class AUEffectBase : public AUBase {
22 public:
23 /*! @ctor AUEffectBase */
24 AUEffectBase( AudioComponentInstance audioUnit,
25 bool inProcessesInPlace = true );
26 /*! @dtor ~AUEffectBase */
27 ~AUEffectBase();
28
29 /*! @method Initialize */
30 virtual OSStatus Initialize();
31
32 /*! @method Cleanup */
33 virtual void Cleanup();
34
35
36 /*! @method Reset */
37 virtual OSStatus Reset( AudioUnitScope inScope,
38 AudioUnitElement inElement);
39
40 /*! @method GetPropertyInfo */
41 virtual OSStatus GetPropertyInfo (AudioUnitPropertyID inID,
42 AudioUnitScope inScope,
43 AudioUnitElement inElement,
44 UInt32 & outDataSize,
45 Boolean & outWritable);
46
47 /*! @method GetProperty */
48 virtual OSStatus GetProperty (AudioUnitPropertyID inID,
49 AudioUnitScope inScope,
50 AudioUnitElement inElement,
51 void * outData);
52
53 /*! @method SetProperty */
54 virtual OSStatus SetProperty(AudioUnitPropertyID inID,
55 AudioUnitScope inScope,
56 AudioUnitElement inElement,
57 const void * inData,
58 UInt32 inDataSize);
59
60 /*! @method StreamFormatWritable */
61 virtual bool StreamFormatWritable (AudioUnitScope scope,
62 AudioUnitElement element);
63
64 /*! @method ChangeStreamFormat */
65 virtual OSStatus ChangeStreamFormat (
66 AudioUnitScope inScope,
67 AudioUnitElement inElement,
68 const CAStreamBasicDescription & inPrevFormat,
69 const CAStreamBasicDescription & inNewFormat);
70
71 /*! @method Render */
72 virtual OSStatus Render(AudioUnitRenderActionFlags & ioActionFlags,
73 const AudioTimeStamp & inTimeStamp,
74 UInt32 inNumberFrames);
75
76 // our virtual methods
77
78 // If your unit processes N to N channels, and there are no interactions between channels,
79 // it can override NewKernel to create a mono processing object per channel. Otherwise,
80 // don't override NewKernel, and instead, override ProcessBufferLists.
81 /*! @method NewKernel */
NewKernel()82 virtual AUKernelBase * NewKernel() { return NULL; }
83
84 /*! @method ProcessBufferLists */
85 virtual OSStatus ProcessBufferLists(
86 AudioUnitRenderActionFlags & ioActionFlags,
87 const AudioBufferList & inBuffer,
88 AudioBufferList & outBuffer,
89 UInt32 inFramesToProcess );
90
91 // convenience format accessors (use output 0's format)
92 /*! @method GetSampleRate */
93 Float64 GetSampleRate();
94
95 /*! @method GetNumberOfChannels */
96 UInt32 GetNumberOfChannels();
97
98 // convenience wrappers for accessing parameters in the global scope
99 /*! @method SetParameter */
100 using AUBase::SetParameter;
SetParameter(AudioUnitParameterID paramID,AudioUnitParameterValue value)101 void SetParameter( AudioUnitParameterID paramID,
102 AudioUnitParameterValue value)
103 {
104 Globals()->SetParameter(paramID, value);
105 }
106
107 /*! @method GetParameter */
108 using AUBase::GetParameter;
GetParameter(AudioUnitParameterID paramID)109 AudioUnitParameterValue GetParameter( AudioUnitParameterID paramID )
110 {
111 return Globals()->GetParameter(paramID );
112 }
113
114 /*! @method CanScheduleParameters */
CanScheduleParameters()115 virtual bool CanScheduleParameters() const { return true; }
116
117 /*! @method IsBypassEffect */
118 // This is used for the property value - to reflect to the UI if an effect is bypassed
IsBypassEffect()119 bool IsBypassEffect () { return mBypassEffect; }
120
121 protected:
122
123 /*! @method MaintainKernels */
124 void MaintainKernels();
125
126 /*! @method ShouldBypassEffect */
127 // This is used in the render call to see if an effect is bypassed
128 // It can return a different status than IsBypassEffect (though it MUST take that into account)
ShouldBypassEffect()129 virtual bool ShouldBypassEffect () { return IsBypassEffect(); }
130
131 public:
132 /*! @method SetBypassEffect */
SetBypassEffect(bool inFlag)133 virtual void SetBypassEffect (bool inFlag) { mBypassEffect = inFlag; }
134
135 /*! @method SetParamHasSampleRateDependency */
SetParamHasSampleRateDependency(bool inFlag)136 void SetParamHasSampleRateDependency (bool inFlag)
137 {
138 mParamSRDep = inFlag;
139 }
140
141 /*! @method GetParamHasSampleRateDependency */
GetParamHasSampleRateDependency()142 bool GetParamHasSampleRateDependency () const { return mParamSRDep; }
143
144 struct ScheduledProcessParams // pointer passed in as void* userData param for ProcessScheduledSlice()
145 {
146 AudioUnitRenderActionFlags *actionFlags;
147 AudioBufferList *inputBufferList;
148 AudioBufferList *outputBufferList;
149 };
150
151 virtual OSStatus ProcessScheduledSlice( void *inUserData,
152 UInt32 inStartFrameInBuffer,
153 UInt32 inSliceFramesToProcess,
154 UInt32 inTotalBufferFrames );
155
156
ProcessesInPlace()157 bool ProcessesInPlace() const {return mProcessesInPlace;};
SetProcessesInPlace(bool inProcessesInPlace)158 void SetProcessesInPlace(bool inProcessesInPlace) {mProcessesInPlace = inProcessesInPlace;};
159
160 typedef std::vector<AUKernelBase *> KernelList;
161
162
163
164 protected:
165 /*! @var mKernelList */
166 KernelList mKernelList;
167
GetKernel(UInt32 index)168 AUKernelBase* GetKernel(UInt32 index) { return mKernelList[index]; }
169
170 /*! @method IsInputSilent */
IsInputSilent(AudioUnitRenderActionFlags inActionFlags,UInt32 inFramesToProcess)171 bool IsInputSilent (AudioUnitRenderActionFlags inActionFlags, UInt32 inFramesToProcess)
172 {
173 bool inputSilent = (inActionFlags & kAudioUnitRenderAction_OutputIsSilence) != 0;
174
175 // take latency and tail time into account when propagating the silent bit
176 UInt32 silentTimeoutFrames = UInt32(GetSampleRate() * (GetLatency() + GetTailTime()));
177 mSilentTimeout.Process (inFramesToProcess, silentTimeoutFrames, inputSilent);
178 return inputSilent;
179 }
180
181 #if TARGET_OS_IPHONE
SetOnlyOneKernel(bool inUseOnlyOneKernel)182 void SetOnlyOneKernel(bool inUseOnlyOneKernel) { mOnlyOneKernel = inUseOnlyOneKernel; } // set in ctor of subclass that wants it.
183 #endif
184
185 template <typename T>
186 void ProcessBufferListsT(
187 AudioUnitRenderActionFlags & ioActionFlags,
188 const AudioBufferList & inBuffer,
189 AudioBufferList & outBuffer,
190 UInt32 inFramesToProcess );
191
GetCommonPCMFormat()192 CAStreamBasicDescription::CommonPCMFormat GetCommonPCMFormat() const { return mCommonPCMFormat; }
193
194
195 private:
196 /*! @var mBypassEffect */
197 bool mBypassEffect;
198 /*! @var mParamSRDep */
199 bool mParamSRDep;
200
201 /*! @var mProcessesInplace */
202 bool mProcessesInPlace;
203
204 /*! @var mSilentTimeout */
205 AUSilentTimeout mSilentTimeout;
206
207 /*! @var mMainOutput */
208 AUOutputElement * mMainOutput;
209
210 /*! @var mMainInput */
211 AUInputElement * mMainInput;
212
213 #if TARGET_OS_IPHONE
214 /*! @var mOnlyOneKernel */
215 bool mOnlyOneKernel;
216 #endif
217
218 /*! @var mCommonPCMFormat */
219 CAStreamBasicDescription::CommonPCMFormat mCommonPCMFormat;
220 UInt32 mBytesPerFrame;
221 };
222
223
224 // Base class for a "kernel", an object that performs DSP on one channel of an interleaved stream.
225 /*! @class AUKernelBase */
226 class AUKernelBase {
227 public:
228 /*! @ctor AUKernelBase */
AUKernelBase(AUEffectBase * inAudioUnit)229 AUKernelBase(AUEffectBase *inAudioUnit ) :
230 mAudioUnit(inAudioUnit) { }
231
232 /*! @dtor ~AUKernelBase */
~AUKernelBase()233 virtual ~AUKernelBase() { }
234
235 /*! @method Reset */
Reset()236 virtual void Reset() { }
237
238 /*! @method Process */
Process(const Float32 * inSourceP,Float32 * inDestP,UInt32 inFramesToProcess,UInt32 inNumChannels,bool & ioSilence)239 virtual void Process( const Float32 * inSourceP,
240 Float32 * inDestP,
241 UInt32 inFramesToProcess,
242 UInt32 inNumChannels,
243 bool & ioSilence) { throw CAException(kAudio_UnimplementedError ); }
244
245 /*! @method Process */
Process(const SInt32 * inSourceP,SInt32 * inDestP,UInt32 inFramesToProcess,UInt32 inNumChannels,bool & ioSilence)246 virtual void Process( const SInt32 * inSourceP,
247 SInt32 * inDestP,
248 UInt32 inFramesToProcess,
249 UInt32 inNumChannels,
250 bool & ioSilence) { throw CAException(kAudio_UnimplementedError ); }
251
252 /*! @method Process */
Process(const SInt16 * inSourceP,SInt16 * inDestP,UInt32 inFramesToProcess,UInt32 inNumChannels,bool & ioSilence)253 virtual void Process( const SInt16 * inSourceP,
254 SInt16 * inDestP,
255 UInt32 inFramesToProcess,
256 UInt32 inNumChannels,
257 bool & ioSilence) { throw CAException(kAudio_UnimplementedError ); }
258
259 /*! @method GetSampleRate */
GetSampleRate()260 Float64 GetSampleRate()
261 {
262 return mAudioUnit->GetSampleRate();
263 }
264
265 /*! @method GetParameter */
GetParameter(AudioUnitParameterID paramID)266 AudioUnitParameterValue GetParameter (AudioUnitParameterID paramID)
267 {
268 return mAudioUnit->GetParameter(paramID);
269 }
270
SetChannelNum(UInt32 inChan)271 void SetChannelNum (UInt32 inChan) { mChannelNum = inChan; }
GetChannelNum()272 UInt32 GetChannelNum () { return mChannelNum; }
273
274 protected:
275 /*! @var mAudioUnit */
276 AUEffectBase * mAudioUnit;
277 UInt32 mChannelNum;
278
279 };
280
281 template <typename T>
ProcessBufferListsT(AudioUnitRenderActionFlags & ioActionFlags,const AudioBufferList & inBuffer,AudioBufferList & outBuffer,UInt32 inFramesToProcess)282 void AUEffectBase::ProcessBufferListsT(
283 AudioUnitRenderActionFlags & ioActionFlags,
284 const AudioBufferList & inBuffer,
285 AudioBufferList & outBuffer,
286 UInt32 inFramesToProcess )
287 {
288 bool ioSilence;
289
290 bool silentInput = IsInputSilent (ioActionFlags, inFramesToProcess);
291 ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence;
292
293 // call the kernels to handle either interleaved or deinterleaved
294 if (inBuffer.mNumberBuffers == 1) {
295 if (inBuffer.mBuffers[0].mNumberChannels == 0)
296 throw CAException(kAudio_ParamError);
297
298 for (UInt32 channel = 0; channel < mKernelList.size(); ++channel) {
299 AUKernelBase *kernel = mKernelList[channel];
300
301 if (kernel == NULL) continue;
302 ioSilence = silentInput;
303
304 // process each interleaved channel individually
305 kernel->Process(
306 (const T *)inBuffer.mBuffers[0].mData + channel,
307 (T *)outBuffer.mBuffers[0].mData + channel,
308 inFramesToProcess,
309 inBuffer.mBuffers[0].mNumberChannels,
310 ioSilence);
311
312 if (!ioSilence)
313 ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence;
314 }
315 } else {
316 for (UInt32 channel = 0; channel < mKernelList.size(); ++channel) {
317 AUKernelBase *kernel = mKernelList[channel];
318
319 if (kernel == NULL) continue;
320
321 ioSilence = silentInput;
322 const AudioBuffer *srcBuffer = &inBuffer.mBuffers[channel];
323 AudioBuffer *destBuffer = &outBuffer.mBuffers[channel];
324
325 kernel->Process(
326 (const T *)srcBuffer->mData,
327 (T *)destBuffer->mData,
328 inFramesToProcess,
329 1,
330 ioSilence);
331
332 if (!ioSilence)
333 ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence;
334 }
335 }
336 }
337
338
339 #endif // __AUEffectBase_h__
340