Jamoma API  0.6.0.a19
AUScopeElement.h
1 /* Copyright © 2007 Apple Inc. All Rights Reserved.
2 
3  Disclaimer: IMPORTANT: This Apple software is supplied to you by
4  Apple Inc. ("Apple") in consideration of your agreement to the
5  following terms, and your use, installation, modification or
6  redistribution of this Apple software constitutes acceptance of these
7  terms. If you do not agree with these terms, please do not use,
8  install, modify or redistribute this Apple software.
9 
10  In consideration of your agreement to abide by the following terms, and
11  subject to these terms, Apple grants you a personal, non-exclusive
12  license, under Apple's copyrights in this original Apple software (the
13  "Apple Software"), to use, reproduce, modify and redistribute the Apple
14  Software, with or without modifications, in source and/or binary forms;
15  provided that if you redistribute the Apple Software in its entirety and
16  without modifications, you must retain this notice and the following
17  text and disclaimers in all such redistributions of the Apple Software.
18  Neither the name, trademarks, service marks or logos of Apple Inc.
19  may be used to endorse or promote products derived from the Apple
20  Software without specific prior written permission from Apple. Except
21  as expressly stated in this notice, no other rights or licenses, express
22  or implied, are granted by Apple herein, including but not limited to
23  any patent rights that may be infringed by your derivative works or by
24  other works in which the Apple Software may be incorporated.
25 
26  The Apple Software is provided by Apple on an "AS IS" basis. APPLE
27  MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
28  THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
29  FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
30  OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
31 
32  IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
33  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
36  MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
37  AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
38  STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
39  POSSIBILITY OF SUCH DAMAGE.
40 */
41 #ifndef __AUScopeElement_h__
42 #define __AUScopeElement_h__
43 
44 #include <map>
45 #include <vector>
46 
47 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
48  #include <AudioUnit/AudioUnit.h>
49 #else
50  #include <AudioUnit.h>
51 #endif
52 #include "ComponentBase.h"
53 #include "AUBuffer.h"
54 
55 
56 class AUBase;
57 
58 // ____________________________________________________________________________
59 //
60 // represents a parameter's value (either constant or ramped)
61 /*! @class ParameterMapEvent */
62 class ParameterMapEvent
63 {
64 public:
65 /*! @ctor ParameterMapEvent */
66  ParameterMapEvent()
67  : mEventType(kParameterEvent_Immediate), mBufferOffset(0), mDurationInFrames(0), mValue1(0.0), mValue2(0.0), mSliceDurationFrames(0)
68  {}
69 
70 /*! @ctor ParameterMapEvent */
71  ParameterMapEvent(AudioUnitParameterValue inValue)
72  : mEventType(kParameterEvent_Immediate), mBufferOffset(0), mDurationInFrames(0), mValue1(inValue), mValue2(inValue), mSliceDurationFrames(0)
73  {}
74 
75  // constructor for scheduled event
76 /*! @ctor ParameterMapEvent */
77  ParameterMapEvent( const AudioUnitParameterEvent &inEvent,
78  UInt32 inSliceOffsetInBuffer,
79  UInt32 inSliceDurationFrames )
80  {
81  SetScheduledEvent(inEvent, inSliceOffsetInBuffer, inSliceDurationFrames );
82  };
83 
84 /*! @method SetScheduledEvent */
85  void SetScheduledEvent( const AudioUnitParameterEvent &inEvent,
86  UInt32 inSliceOffsetInBuffer,
87  UInt32 inSliceDurationFrames )
88  {
89  mEventType = inEvent.eventType;
90  mSliceDurationFrames = inSliceDurationFrames;
91 
92  if(mEventType == kParameterEvent_Immediate )
93  {
94  // constant immediate value for the whole slice
95  mValue1 = inEvent.eventValues.immediate.value;
96  mValue2 = mValue1;
97  mDurationInFrames = inSliceDurationFrames;
98  mBufferOffset = 0;
99  }
100  else
101  {
102  mDurationInFrames = inEvent.eventValues.ramp.durationInFrames;
103  mBufferOffset = inEvent.eventValues.ramp.startBufferOffset - inSliceOffsetInBuffer; // shift over for this slice
104  mValue1 = inEvent.eventValues.ramp.startValue;
105  mValue2 = inEvent.eventValues.ramp.endValue;
106  }
107  };
108 
109 
110 
111 /*! @method GetEventType */
112  AUParameterEventType GetEventType() const {return mEventType;};
113 
114 /*! @method GetValue */
115  AudioUnitParameterValue GetValue() const {return mValue1;}; // only valid if immediate event type
116 /*! @method GetEndValue */
117  AudioUnitParameterValue GetEndValue() const {return mValue2;}; // only valid if immediate event type
118 /*! @method SetValue */
119  void SetValue(AudioUnitParameterValue inValue)
120  {
121  mEventType = kParameterEvent_Immediate;
122  mValue1 = inValue;
123  mValue2 = inValue;
124  }
125 
126  // interpolates the start and end values corresponding to the current processing slice
127  // most ramp parameter implementations will want to use this method
128  // the start value will correspond to the start of the slice
129  // the end value will correspond to the end of the slice
130 /*! @method GetRampSliceStartEnd */
131  void GetRampSliceStartEnd( AudioUnitParameterValue & outStartValue,
132  AudioUnitParameterValue & outEndValue,
133  AudioUnitParameterValue & outValuePerFrameDelta )
134  {
135  if (mEventType == kParameterEvent_Ramped) {
136  outValuePerFrameDelta = (mValue2 - mValue1) / mDurationInFrames;
137 
138  outStartValue = mValue1 + outValuePerFrameDelta * (-mBufferOffset); // corresponds to frame 0 of this slice
139  outEndValue = outStartValue + outValuePerFrameDelta * mSliceDurationFrames;
140  } else {
141  outValuePerFrameDelta = 0;
142  outStartValue = outEndValue = mValue1;
143  }
144  };
145 
146  // Some ramp parameter implementations will want to interpret the ramp using their
147  // own interpolation method (perhaps non-linear)
148  // This method gives the raw ramp information, relative to this processing slice
149  // for the client to interpret as desired
150 /*! @method GetRampInfo */
151  void GetRampInfo( SInt32 & outBufferOffset,
152  UInt32 & outDurationInFrames,
153  AudioUnitParameterValue & outStartValue,
154  AudioUnitParameterValue & outEndValue )
155  {
156  outBufferOffset = mBufferOffset;
157  outDurationInFrames = mDurationInFrames;
158  outStartValue = mValue1;
159  outEndValue = mValue2;
160  };
161 
162 #if DEBUG
163  void Print()
164  {
165  printf("ParameterEvent @ %p\n", this);
166  printf(" mEventType = %d\n", (int)mEventType);
167  printf(" mBufferOffset = %d\n", (int)mBufferOffset);
168  printf(" mDurationInFrames = %d\n", (int)mDurationInFrames);
169  printf(" mSliceDurationFrames = %d\n", (int)mSliceDurationFrames);
170  printf(" mValue1 = %.5f\n", mValue1);
171  printf(" mValue2 = %.5f\n", mValue2);
172  }
173 #endif
174 
175 private:
176  AUParameterEventType mEventType;
177 
178  SInt32 mBufferOffset; // ramp start offset relative to start of this slice (may be negative)
179  UInt32 mDurationInFrames; // total duration of ramp parameter
180  AudioUnitParameterValue mValue1; // value if immediate : startValue if ramp
181  AudioUnitParameterValue mValue2; // endValue (only used for ramp)
182 
183  UInt32 mSliceDurationFrames; // duration of this processing slice
184 };
185 
186 
187 
188 // ____________________________________________________________________________
189 //
190 
191 /*! @class AUElement */
192 class AUElement {
193 public:
194 /*! @ctor AUElement */
195  AUElement(AUBase *audioUnit) : mAudioUnit(audioUnit),
196  mUseIndexedParameters(false), mElementName(0) { }
197 
198 /*! @dtor ~AUElement */
199  virtual ~AUElement() { if (mElementName) CFRelease (mElementName); }
200 
201 /*! @method GetNumberOfParameters */
202  UInt32 GetNumberOfParameters()
203  {
204  if(mUseIndexedParameters) return mIndexedParameters.size(); else return mParameters.size();
205  }
206 /*! @method GetParameterList */
207  void GetParameterList(AudioUnitParameterID *outList);
208 
209 /*! @method GetParameter */
210  AudioUnitParameterValue GetParameter(AudioUnitParameterID paramID);
211 /*! @method SetParameter */
212  void SetParameter(AudioUnitParameterID paramID, AudioUnitParameterValue value, bool okWhenInitialized = false);
213  // Only set okWhenInitialized to true when you know the outside world cannot access this element. Otherwise the parameter map could get corrupted.
214 
215  // interpolates the start and end values corresponding to the current processing slice
216  // most ramp parameter implementations will want to use this method
217 /*! @method GetRampSliceStartEnd */
218  void GetRampSliceStartEnd( AudioUnitParameterID paramID,
219  AudioUnitParameterValue & outStartValue,
220  AudioUnitParameterValue & outEndValue,
221  AudioUnitParameterValue & outValuePerFrameDelta );
222 
223 /*! @method GetEndValue */
224  AudioUnitParameterValue GetEndValue( AudioUnitParameterID paramID);
225 
226 /*! @method SetRampParameter */
227  void SetScheduledEvent( AudioUnitParameterID paramID,
228  const AudioUnitParameterEvent &inEvent,
229  UInt32 inSliceOffsetInBuffer,
230  UInt32 inSliceDurationFrames,
231  bool okWhenInitialized = false );
232  // Only set okWhenInitialized to true when you know the outside world cannot access this element. Otherwise the parameter map could get corrupted.
233 
234 
235 /*! @method GetAudioUnit */
236  AUBase * GetAudioUnit() const { return mAudioUnit; };
237 
238 /*! @method SaveState */
239  void SaveState(CFMutableDataRef data);
240 /*! @method RestoreState */
241  const UInt8 * RestoreState(const UInt8 *state);
242 /*! @method GetName */
243  CFStringRef GetName () const { return mElementName; }
244 /*! @method SetName */
245  void SetName (CFStringRef inName);
246 /*! @method HasName */
247  bool HasName () const { return mElementName != 0; }
248 /*! @method UseIndexedParameters */
249  virtual void UseIndexedParameters(int inNumberOfParameters);
250 
251 protected:
252  inline ParameterMapEvent& GetParamEvent(AudioUnitParameterID paramID);
253 
254 private:
255  typedef std::map<AudioUnitParameterID, ParameterMapEvent, std::less<AudioUnitParameterID> > ParameterMap;
256 
257 /*! @var mAudioUnit */
258  AUBase * mAudioUnit;
259 /*! @var mParameters */
260  ParameterMap mParameters;
261 
262 /*! @var mUseIndexedParameters */
263  bool mUseIndexedParameters;
264 /*! @var mIndexedParameters */
265  std::vector<ParameterMapEvent> mIndexedParameters;
266 
267 /*! @var mElementName */
268  CFStringRef mElementName;
269 };
270 
271 
272 
273 // ____________________________________________________________________________
274 //
275 /*! @class AUIOElement */
276 class AUIOElement : public AUElement {
277 public:
278 /*! @ctor AUIOElement */
279  AUIOElement(AUBase *audioUnit);
280 
281 /*! @method GetStreamFormat */
282  const CAStreamBasicDescription &GetStreamFormat() const { return mStreamFormat; }
283 
284 /*! @method SetStreamFormat */
285  virtual OSStatus SetStreamFormat(const CAStreamBasicDescription &desc);
286 
287 /*! @method AllocateBuffer */
288  virtual void AllocateBuffer(UInt32 inFramesToAllocate = 0);
289 /*! @method DeallocateBuffer */
290  void DeallocateBuffer();
291 /*! @method NeedsBufferSpace */
292  virtual bool NeedsBufferSpace() const = 0;
293 
294 /*! @method DeallocateBuffer */
295  void SetWillAllocateBuffer(bool inFlag) {
296  mWillAllocate = inFlag;
297  }
298 /*! @method DeallocateBuffer */
299  bool WillAllocateBuffer() const {
300  return mWillAllocate;
301  }
302 
303 /*! @method UseExternalBuffer */
304  void UseExternalBuffer(const AudioUnitExternalBuffer &buf) {
305  mIOBuffer.UseExternalBuffer(mStreamFormat, buf);
306  }
307 /*! @method PrepareBuffer */
308  AudioBufferList & PrepareBuffer(UInt32 nFrames) {
309  if (mWillAllocate)
310  return mIOBuffer.PrepareBuffer(mStreamFormat, nFrames);
311  throw OSStatus(kAudioUnitErr_InvalidPropertyValue);
312  }
313 /*! @method PrepareNullBuffer */
314  AudioBufferList & PrepareNullBuffer(UInt32 nFrames) {
315  return mIOBuffer.PrepareNullBuffer(mStreamFormat, nFrames);
316  }
317 /*! @method SetBufferList */
318  AudioBufferList & SetBufferList(AudioBufferList &abl) { return mIOBuffer.SetBufferList(abl); }
319 /*! @method SetBuffer */
320  void SetBuffer(UInt32 index, AudioBuffer &ab) { mIOBuffer.SetBuffer(index, ab); }
321 /*! @method InvalidateBufferList */
322  void InvalidateBufferList() { mIOBuffer.InvalidateBufferList(); }
323 
324 /*! @method GetBufferList */
325  AudioBufferList & GetBufferList() const { return mIOBuffer.GetBufferList(); }
326 
327 /*! @method GetChannelData */
328  AudioUnitSampleType * GetChannelData(int ch) const {
329  if (mStreamFormat.IsInterleaved())
330  return static_cast<AudioUnitSampleType *>(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch;
331  else
332  return static_cast<AudioUnitSampleType *>(mIOBuffer.GetBufferList().mBuffers[ch].mData);
333  }
334  SInt16 * GetInt16ChannelData(int ch) const {
335  if (mStreamFormat.IsInterleaved())
336  return static_cast<SInt16 *>(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch;
337  else
338  return static_cast<SInt16 *>(mIOBuffer.GetBufferList().mBuffers[ch].mData);
339  }
340 
341 /*! @method CopyBufferListTo */
342  void CopyBufferListTo(AudioBufferList &abl) const {
343  mIOBuffer.CopyBufferListTo(abl);
344  }
345 /*! @method CopyBufferContentsTo */
346  void CopyBufferContentsTo(AudioBufferList &abl) const {
347  mIOBuffer.CopyBufferContentsTo(abl);
348  }
349 
350 /* UInt32 BytesToFrames(UInt32 nBytes) { return nBytes / mStreamFormat.mBytesPerFrame; }
351  UInt32 BytesToFrames(AudioBufferList &abl) {
352  return BytesToFrames(abl.mBuffers[0].mDataByteSize);
353  }
354  UInt32 FramesToBytes(UInt32 nFrames) { return nFrames * mStreamFormat.mBytesPerFrame; }*/
355 
356 /*! @method IsInterleaved */
357  bool IsInterleaved() const { return mStreamFormat.IsInterleaved(); }
358 /*! @method NumberChannels */
359  UInt32 NumberChannels() const { return mStreamFormat.NumberChannels(); }
360 /*! @method NumberInterleavedChannels */
361  UInt32 NumberInterleavedChannels() const { return mStreamFormat.NumberInterleavedChannels(); }
362 
363 /*! @method GetChannelMapTags */
364  virtual UInt32 GetChannelLayoutTags (AudioChannelLayoutTag *outLayoutTagsPtr);
365 
366 /*! @method GetAudioChannelLayout */
367  virtual UInt32 GetAudioChannelLayout (AudioChannelLayout *outMapPtr, Boolean &outWritable);
368 
369 /*! @method SetAudioChannelLayout */
370  virtual OSStatus SetAudioChannelLayout (const AudioChannelLayout &inData);
371 
372 /*! @method RemoveAudioChannelLayout */
373  virtual OSStatus RemoveAudioChannelLayout ();
374 
375 protected:
376 /*! @var mStreamFormat */
377  CAStreamBasicDescription mStreamFormat;
378 /*! @var mIOBuffer */
379  AUBufferList mIOBuffer; // for input: input proc buffer, only allocated when needed
380  // for output: output cache, usually allocated early on
381 /*! @var mWillAllocate */
382  bool mWillAllocate;
383 };
384 
385 // ____________________________________________________________________________
386 //
387 /*! @class AUElementCreator */
388 class AUElementCreator {
389 public:
390 /*! @method CreateElement */
391  virtual AUElement * CreateElement(AudioUnitScope scope, AudioUnitElement element) = 0;
392  virtual ~AUElementCreator() { }
393 };
394 
395 // ____________________________________________________________________________
396 //
397 // AUScopeDelegates are a way to get virtual scopes.
398 /*! @class AUScopeDelegate */
399 class AUScopeDelegate {
400 public:
401 /*! @ctor AUScopeDelegate */
402  AUScopeDelegate() : mCreator(NULL), mScope(0) { }
403 /*! @dtor ~AUScopeDelegate */
404  virtual ~AUScopeDelegate() {}
405 
406 /*! @method Initialize */
407  virtual void Initialize( AUElementCreator *creator,
408  AudioUnitScope scope,
409  UInt32 numElements)
410  {
411  mCreator = creator;
412  mScope = scope;
413  SetNumberOfElements(numElements);
414  }
415 
416 /*! @method SetNumberOfElements */
417  virtual void SetNumberOfElements(UInt32 numElements) = 0;
418 
419 /*! @method GetNumberOfElements */
420  virtual UInt32 GetNumberOfElements() = 0;
421 
422 /*! @method GetElement */
423  virtual AUElement * GetElement(UInt32 elementIndex) = 0;
424 
425  AUElementCreator * GetCreator() const { return mCreator; }
426  AudioUnitScope GetScope() const { return mScope; }
427 
428 
429 private:
430 /*! @var mCreator */
431  AUElementCreator * mCreator;
432 /*! @var mScope */
433  AudioUnitScope mScope;
434 };
435 
436 
437 
438 // ____________________________________________________________________________
439 //
440 /*! @class AUScope */
441 class AUScope {
442 public:
443 /*! @ctor AUScope */
444  AUScope() : mCreator(NULL), mScope(0), mDelegate(0) { }
445 /*! @dtor ~AUScope */
446  ~AUScope();
447 
448 /*! @method Initialize */
449  void Initialize(AUElementCreator *creator,
450  AudioUnitScope scope,
451  UInt32 numElements)
452  {
453  if (mDelegate)
454  return mDelegate->Initialize(creator, scope, numElements);
455 
456  mCreator = creator;
457  mScope = scope;
458  SetNumberOfElements(numElements);
459  }
460 
461 /*! @method SetNumberOfElements */
462  void SetNumberOfElements(UInt32 numElements);
463 
464 /*! @method GetNumberOfElements */
465  UInt32 GetNumberOfElements() const
466  {
467  if (mDelegate)
468  return mDelegate->GetNumberOfElements();
469 
470  return mElements.size();
471  }
472 
473 /*! @method GetElement */
474  AUElement * GetElement(UInt32 elementIndex) const
475  {
476  if (mDelegate)
477  return mDelegate->GetElement(elementIndex);
478 
479  ElementVector::const_iterator i = mElements.begin() + elementIndex;
480  // catch passing -1 in as the elementIndex - causes a wrap around
481  return (i >= mElements.end() || i < mElements.begin()) ? NULL : *i;
482  }
483 
484 /*! @method SafeGetElement */
485  AUElement * SafeGetElement(UInt32 elementIndex)
486  {
487  AUElement *element = GetElement(elementIndex);
488  if (element == NULL)
489  COMPONENT_THROW(kAudioUnitErr_InvalidElement);
490  return element;
491  }
492 
493 /*! @method GetIOElement */
494  AUIOElement * GetIOElement(UInt32 elementIndex) const
495  {
496  AUElement *element = GetElement(elementIndex);
497  AUIOElement *ioel;
498  #if !CA_NO_RTTI
499  if (element == NULL || (ioel = dynamic_cast<AUIOElement *>(element)) == NULL)
500  COMPONENT_THROW (kAudioUnitErr_InvalidElement);
501  #else
502  if (element == NULL || (ioel = static_cast<AUIOElement *>(element)) == NULL)
503  COMPONENT_THROW (kAudioUnitErr_InvalidElement);
504  #endif
505  return ioel;
506  }
507 
508 /*! @method HasElementWithName */
509  bool HasElementWithName () const;
510 
511 /*! @method AddElementNamesToDict */
512  void AddElementNamesToDict (CFMutableDictionaryRef & inNameDict);
513 
514  bool RestoreElementNames (CFDictionaryRef& inNameDict);
515 
516  AUElementCreator * GetCreator() const { return mCreator; }
517  AudioUnitScope GetScope() const { return mScope; }
518 
519  void SetDelegate(AUScopeDelegate* inDelegate) { mDelegate = inDelegate; }
520 
521 private:
522  typedef std::vector<AUElement *> ElementVector;
523 /*! @var mCreator */
524  AUElementCreator * mCreator;
525 /*! @var mScope */
526  AudioUnitScope mScope;
527 /*! @var mElements */
528  ElementVector mElements;
529 /*! @var mDelegate */
530  AUScopeDelegate * mDelegate;
531 };
532 
533 
534 
535 #endif // __AUScopeElement_h__