Jamoma API  0.6.0.a19
PlugtasticAUEffect.cpp
1 #include "PlugtasticAUEffect.h"
2 
3 
4 COMPONENT_ENTRY(PlugtasticAUEffect)
5 
6 
7 PlugtasticAUEffect::PlugtasticAUEffect(AudioUnit component) :
8 AUEffectBase::AUEffectBase(component, false)
9 {
10  CreateElements();
11  Globals()->UseIndexedParameters(kNumberOfParameters);
12 
13 #ifdef PlugtasticAUEffect_HasSidechainInput
14  // defaults to 1 for PlugtasticAUEffect
15  OSStatus status = SetBusCount(kAudioUnitScope_Input, 2);
16  TT_ASSERT(setBusCount, status == noErr);
17 #endif
18 
19 #if AU_DEBUG_DISPATCHER
20  mDebugDispatcher = new AUDebugDispatcher (this);
21 #endif
22 
23  mGraph = new PlugtasticAUEffectGraph;
24  mParameters = new PlugtasticAUParameters;
25  mParameters->setDefaults(this);
26 }
27 
28 
29 OSStatus PlugtasticAUEffect::GetParameterValueStrings(AudioUnitScope inScope,
30  AudioUnitParameterID inParameterID,
31  CFArrayRef* outStrings)
32 {
33  return kAudioUnitErr_InvalidProperty;
34 }
35 
36 
37 OSStatus PlugtasticAUEffect::GetParameterInfo(AudioUnitScope inScope,
38  AudioUnitParameterID inParameterID,
39  AudioUnitParameterInfo &outParameterInfo )
40 {
41  return mParameters->getInfo(inScope, inParameterID, outParameterInfo);
42 }
43 
44 
45 OSStatus PlugtasticAUEffect::GetPropertyInfo(AudioUnitPropertyID inID,
46  AudioUnitScope inScope,
47  AudioUnitElement inElement,
48  UInt32& outDataSize,
49  Boolean& outWritable)
50 {
51  return AUEffectBase::GetPropertyInfo(inID, inScope, inElement, outDataSize, outWritable);
52 }
53 
54 
55 OSStatus PlugtasticAUEffect::GetProperty(AudioUnitPropertyID inID,
56  AudioUnitScope inScope,
57  AudioUnitElement inElement,
58  void* outData)
59 {
60  return AUEffectBase::GetProperty(inID, inScope, inElement, outData);
61 }
62 
63 
64 ComponentResult PlugtasticAUEffect::SetParameter(AudioUnitParameterID inID,
65  AudioUnitScope inScope,
66  AudioUnitElement inElement,
67  Float32 inValue,
68  UInt32 inBufferOffsetInFrames)
69 {
70  mParameters->setParameter(mGraph, inID,inValue);
71  return AUBase::SetParameter(inID, inScope, inElement, inValue, inBufferOffsetInFrames);
72 }
73 
74 
75 void PlugtasticAUEffect::SetParameter(AudioUnitParameterID inID, Float32 inValue)
76 {
77  mParameters->setParameter(mGraph, inID, inValue);
78  AUEffectBase::SetParameter(inID, inValue);
79 }
80 
81 
82 // Added for Plugtastic so we can do sidechains
83 // note that we use pointers for sidechains instead of references so that we can easily check for NULL
84 OSStatus PlugtasticAUEffect::ProcessBufferLists(AudioUnitRenderActionFlags& ioActionFlags,
85  const AudioBufferList& inBufferList,
86  AudioBufferList& outBufferList,
87  UInt32 nFrames,
88  const AudioBufferList* inSidechainBufferList,
89  AudioBufferList* outSidechainBufferList)
90 {
91  mGraph->mVectorSize = nFrames;
92  mGraph->process(&inBufferList, &outBufferList, inSidechainBufferList, outSidechainBufferList);
93 
94  // This flag can be set in a render input callback (or in the audio unit's render operation itself)
95  // and is used to indicate that the render buffer contains only silence. It can then be used by the
96  // caller as a hint to whether the buffer needs to be processed or not.
97  ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence;
98 
99  return noErr;
100 }
101 
102 
103 OSStatus PlugtasticAUEffect::ProcessBufferLists(AudioUnitRenderActionFlags& ioActionFlags,
104  const AudioBufferList& inBufferList,
105  AudioBufferList& outBufferList,
106  UInt32 nFrames)
107 {
108  return ProcessBufferLists(ioActionFlags, inBufferList, outBufferList, nFrames, NULL, NULL);
109 }
110 
111 
112 // ____________________________________________________________________________
113 //
114 // This method is called (potentially repeatedly) by ProcessForScheduledParams()
115 // in order to perform the actual DSP required for this portion of the entire buffer
116 // being processed. The entire buffer can be divided up into smaller "slices"
117 // according to the timestamps on the scheduled parameters...
118 //
119 OSStatus PlugtasticAUEffect::ProcessScheduledSlice( void *inUserData,
120  UInt32 inStartFrameInBuffer,
121  UInt32 inSliceFramesToProcess,
122  UInt32 inTotalBufferFrames )
123 {
124  PlugtasticScheduledProcessParams& sliceParams = *((PlugtasticScheduledProcessParams*)inUserData);
125  AudioUnitRenderActionFlags& actionFlags = *sliceParams.au.actionFlags;
126  AudioBufferList& inputBufferList = *sliceParams.au.inputBufferList;
127  AudioBufferList& outputBufferList = *sliceParams.au.outputBufferList;
128  AudioBufferList* sidechainInputBufferList = sliceParams.sidechainInputBufferList;
129  AudioBufferList* sidechainOutputBufferList = sliceParams.sidechainOutputBufferList;
130 
131  // fix the size of the buffer we're operating on before we render this slice of time
132  for (unsigned int i=0; i < inputBufferList.mNumberBuffers; i++) {
133  inputBufferList.mBuffers[i].mDataByteSize = (inputBufferList.mBuffers[i].mNumberChannels * inSliceFramesToProcess * sizeof(AudioUnitSampleType));
134  }
135 
136  for (unsigned int i = 0; i < outputBufferList.mNumberBuffers; i++) {
137  outputBufferList.mBuffers[i].mDataByteSize = (outputBufferList.mBuffers[i].mNumberChannels * inSliceFramesToProcess * sizeof(AudioUnitSampleType));
138  }
139 
140  // process the buffer
141  OSStatus result = ProcessBufferLists(actionFlags, inputBufferList, outputBufferList, inSliceFramesToProcess, sidechainInputBufferList, sidechainOutputBufferList);
142 
143  // we just partially processed the buffers, so increment the data pointers to the next part of the buffer to process
144  for (unsigned int i = 0; i < inputBufferList.mNumberBuffers; i++) {
145  inputBufferList.mBuffers[i].mData = (AudioUnitSampleType *)inputBufferList.mBuffers[i].mData + inputBufferList.mBuffers[i].mNumberChannels * inSliceFramesToProcess;
146  }
147 
148  for (unsigned int i = 0; i < outputBufferList.mNumberBuffers; i++) {
149  outputBufferList.mBuffers[i].mData = (AudioUnitSampleType *)outputBufferList.mBuffers[i].mData + outputBufferList.mBuffers[i].mNumberChannels * inSliceFramesToProcess;
150  }
151 
152  return result;
153 }
154 
155 
156 OSStatus PlugtasticAUEffect::Render(AudioUnitRenderActionFlags& ioActionFlags,
157  const AudioTimeStamp& inTimeStamp,
158  UInt32 nFrames)
159 {
160  if (!HasInput(0))
161  return kAudioUnitErr_NoConnection;
162 
163  OSStatus result = noErr;
164  AUOutputElement* theOutput = GetOutput(0); // throws if error
165  AUInputElement* theInput = GetInput(0);
166  AUOutputElement* theSidechainOutput = NULL;
167  AUInputElement* theSidechainInput = NULL;
168 
169 #ifdef PlugtasticAUEffect_HasSidechainOutput
170  theSidechainOutput = GetOutput(1); // throws if error
171 #endif
172 #ifdef PlugtasticAUEffect_HasSidechainInput
173  theSidechainInput = GetInput(1);
174 #endif
175 
176  result = theInput->PullInput(ioActionFlags, inTimeStamp, 0 /* element */, nFrames);
177  if (theSidechainInput && result == noErr)
178  result = theSidechainInput->PullInput(ioActionFlags, inTimeStamp, 0 /* element */, nFrames);
179 
180  if (result == noErr) {
181  if (ProcessesInPlace() && theOutput->WillAllocateBuffer()) {
182  theOutput->SetBufferList(theInput->GetBufferList() );
183  }
184 
185  if (ShouldBypassEffect()) {
186  // leave silence bit alone
187 
188  if (!ProcessesInPlace()) {
189  theInput->CopyBufferContentsTo (theOutput->GetBufferList());
190  }
191  }
192  else {
193  if (mParamList.size() == 0 ) {
194  // this will read/write silence bit
195 #ifdef PlugtasticAUEffect_HasSidechainInput
196  result = ProcessBufferLists(ioActionFlags, theInput->GetBufferList(), theOutput->GetBufferList(), nFrames, &theSidechainInput->GetBufferList(), NULL);
197 #else
198  result = ProcessBufferLists(ioActionFlags, theInput->GetBufferList(), theOutput->GetBufferList(), nFrames);
199 #endif
200  }
201  else {
202  // deal with scheduled parameters...
203 
204  AudioBufferList& inputBufferList = theInput->GetBufferList();
205  AudioBufferList& outputBufferList = theOutput->GetBufferList();
206  AudioBufferList* sidechainInputBufferList = NULL;
207  AudioBufferList* sidechainOutputBufferList = NULL;
208 
209 #ifdef PlugtasticAUEffect_HasSidechainOutput
210  sidechainOutputBufferList = &theSidechainOutput->GetBufferList();
211 #endif
212 #ifdef PlugtasticAUEffect_HasSidechainInput
213  sidechainInputBufferList = &theSidechainInput->GetBufferList();
214 #endif
215 
216  PlugtasticScheduledProcessParams processParams;
217  processParams.au.actionFlags = &ioActionFlags;
218  processParams.au.inputBufferList = &inputBufferList;
219  processParams.au.outputBufferList = &outputBufferList;
220  processParams.sidechainInputBufferList = sidechainInputBufferList;
221  processParams.sidechainOutputBufferList = sidechainOutputBufferList;
222 
223  // divide up the buffer into slices according to scheduled params then
224  // do the DSP for each slice (ProcessScheduledSlice() called for each slice)
225  result = ProcessForScheduledParams(mParamList, nFrames, &processParams);
226 
227  // fixup the buffer pointers to how they were before we started
228  for (unsigned int i=0; i < inputBufferList.mNumberBuffers; i++ ) {
229  inputBufferList.mBuffers[i].mData = (AudioUnitSampleType *)inputBufferList.mBuffers[i].mData - inputBufferList.mBuffers[i].mNumberChannels * nFrames;
230  inputBufferList.mBuffers[i].mDataByteSize = (inputBufferList.mBuffers[i].mNumberChannels * nFrames * sizeof(AudioUnitSampleType));
231  }
232 
233  for (unsigned int i=0; i < outputBufferList.mNumberBuffers; i++ ) {
234  outputBufferList.mBuffers[i].mData = (AudioUnitSampleType *)outputBufferList.mBuffers[i].mData - outputBufferList.mBuffers[i].mNumberChannels * nFrames;
235  outputBufferList.mBuffers[i].mDataByteSize = (outputBufferList.mBuffers[i].mNumberChannels * nFrames * sizeof(AudioUnitSampleType));
236  }
237  }
238  }
239 
240  if ((ioActionFlags & kAudioUnitRenderAction_OutputIsSilence) && !ProcessesInPlace()) {
241  AUBufferList::ZeroBuffer(theOutput->GetBufferList() );
242  }
243  }
244 
245  return result;
246 }
247