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