PublicUtility/CAAudioUnit.h

/*
     File: CAAudioUnit.h 
 Abstract:  Part of CoreAudio Utility Classes  
  Version: 1.01 
  
 Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple 
 Inc. ("Apple") in consideration of your agreement to the following 
 terms, and your use, installation, modification or redistribution of 
 this Apple software constitutes acceptance of these terms.  If you do 
 not agree with these terms, please do not use, install, modify or 
 redistribute this Apple software. 
  
 In consideration of your agreement to abide by the following terms, and 
 subject to these terms, Apple grants you a personal, non-exclusive 
 license, under Apple's copyrights in this original Apple software (the 
 "Apple Software"), to use, reproduce, modify and redistribute the Apple 
 Software, with or without modifications, in source and/or binary forms; 
 provided that if you redistribute the Apple Software in its entirety and 
 without modifications, you must retain this notice and the following 
 text and disclaimers in all such redistributions of the Apple Software. 
 Neither the name, trademarks, service marks or logos of Apple Inc. may 
 be used to endorse or promote products derived from the Apple Software 
 without specific prior written permission from Apple.  Except as 
 expressly stated in this notice, no other rights or licenses, express or 
 implied, are granted by Apple herein, including but not limited to any 
 patent rights that may be infringed by your derivative works or by other 
 works in which the Apple Software may be incorporated. 
  
 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE 
 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 
 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS 
 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 
 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 
  
 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 
 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 
 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 
 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 
 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 
 POSSIBILITY OF SUCH DAMAGE. 
  
 Copyright (C) 2012 Apple Inc. All Rights Reserved. 
  
*/
#ifndef __CAAudioUnit_h__
#define __CAAudioUnit_h__
 
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
    #include <CoreAudio/CoreAudioTypes.h>
    #include <AudioUnit/AudioUnit.h>
    #include <AudioToolbox/AUGraph.h>
    #include <AudioUnit/MusicDevice.h>
#else
    #include <ConditionalMacros.h>
    #include <CoreAudioTypes.h>
    #include <AudioUnit.h>
    #include <MusicDevice.h>
    #include <AUGraph.h>
    #include <MusicDevice.h>
#endif
 
#include <vector>
#include "CAStreamBasicDescription.h"
#include "CAComponent.h"
#include "CAAudioChannelLayout.h"
 
// defined below
class CAAUChanHelper;
 
// These constructors will NOT throw exceptions - so "check" after creation if AU IsValid()
// The destructor will NOT automatically close the AU down
// This state should be managed by the Caller
// once closed, the unit represented by this object is no longer valid
// it is up to the user of this object to ensure its validity is in sync 
// if it is removed from a graph
 
// methods that can significantly change the state of the AU (like its format) are
// NOT const whereas those that don't change the externally related state of the AU are not const
 
class CAAudioUnit {
    enum {
        paramErr = -50,
        badComponentSelector = (long)0x80008002
    };
public:
    typedef std::vector<AudioChannelLayoutTag>  ChannelTagVector;
    typedef ChannelTagVector::iterator          ChannelTagVectorIter;
 
public:
                            CAAudioUnit () 
                                : mDataPtr(0) {}
 
                            CAAudioUnit (const AudioUnit& inUnit);
 
                            CAAudioUnit (const AUNode &inNode, const AudioUnit& inUnit);
 
                            CAAudioUnit (const CAAudioUnit& y)
                                : mDataPtr(0) { *this = y; }
 
    static OSStatus         Open (const CAComponent& inComp, CAAudioUnit &outUnit);
 
                            ~CAAudioUnit ();
 
    void                    Close ();
 
    
    CAAudioUnit&            operator= (const CAAudioUnit& y);
 
    bool                    operator== (const CAAudioUnit& y) const;
 
    bool                    operator== (const AudioUnit& y) const;
 
#pragma mark __State Management 
    bool                    IsValid () const;
    
    AudioUnit               AU() const;
    operator AudioUnit () const { return AU(); }
 
    const CAComponent&      Comp() const { return mComp; }
    
    const CAComponentDescription& Desc() const { return mComp.Desc(); }
    
    bool                    FromAUGraph () const { return GetAUNode() != 0 && GetAUNode() != kCAAU_DoNotKnowIfAUNode; }
    
    AUNode                  GetAUNode () const;
    operator AUNode () const { return GetAUNode(); }
    
#pragma mark __API Wrapper
    OSStatus                Initialize() const {
                                return AudioUnitInitialize(AU());
                            }
    OSStatus                Uninitialize() const {
                                return AudioUnitUninitialize(AU());
                            }
    OSStatus                GetPropertyInfo(AudioUnitPropertyID propID, AudioUnitScope scope, AudioUnitElement element,
                                            UInt32 *outDataSize, Boolean *outWritable) const
                            {
                                return AudioUnitGetPropertyInfo(AU(), propID, scope, element, outDataSize, outWritable);
                            }
    OSStatus                GetProperty(AudioUnitPropertyID propID, AudioUnitScope scope, AudioUnitElement element,
                                            void *outData, UInt32 *ioDataSize) const
                            {
                                return AudioUnitGetProperty(AU(), propID, scope, element, outData, ioDataSize);
                            }
    OSStatus                SetProperty(AudioUnitPropertyID propID, AudioUnitScope scope, AudioUnitElement element,
                                            const void *inData, UInt32 inDataSize)
                            {
                                return AudioUnitSetProperty(AU(), propID, scope, element, inData, inDataSize);
                            }
    OSStatus                SetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
                                            Float32 value, UInt32 bufferOffsetFrames=0);
                            
    OSStatus                GetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
                                            Float32 &outValue) const;
 
    OSStatus                Render (AudioUnitRenderActionFlags              * ioActionFlags,
                                                const AudioTimeStamp        * inTimeStamp,
                                                UInt32                      inOutputBusNumber,
                                                UInt32                      inNumberFrames,
                                                AudioBufferList             * ioData);
 
    OSStatus                Process (AudioUnitRenderActionFlags             & ioActionFlags,
                                                const AudioTimeStamp        & inTimeStamp,
                                                UInt32                      inNumberFrames,
                                                AudioBufferList             & ioData);
    
    OSStatus                ProcessMultiple (AudioUnitRenderActionFlags     & ioActionFlags,
                                                const AudioTimeStamp        & inTimeStamp,
                                                UInt32                      inNumberFrames,
                                                UInt32                      inNumberInputBufferLists,
                                                const AudioBufferList **    inInputBufferLists,
                                                UInt32                      inNumberOutputBufferLists,
                                                AudioBufferList **          ioOutputBufferLists);
 
    
    OSStatus                Reset (AudioUnitScope scope, AudioUnitElement element)
                            {
                                return AudioUnitReset (AU(), scope, element);
                            }
    OSStatus                GlobalReset ()
                            {
                                return AudioUnitReset (AU(), kAudioUnitScope_Global, 0);
                            }
 
    OSStatus                AddRenderNotify (AURenderCallback   inProc, void *inProcRefCon)
                            {
                                return AudioUnitAddRenderNotify (AU(), inProc, inProcRefCon);
                            }
    
    OSStatus                RemoveRenderNotify (AURenderCallback   inProc, void *inProcRefCon)
                            {
                                return AudioUnitRemoveRenderNotify (AU(), inProc, inProcRefCon);
                            }
 
    OSStatus                AddPropertyListener (AudioUnitPropertyID                inID,
                                                    AudioUnitPropertyListenerProc   inProc,
                                                    void *                          inProcRefCon)
                            {
                                return AudioUnitAddPropertyListener (AU(), inID, inProc, inProcRefCon);
                            }
    
    OSStatus                RemovePropertyListener (AudioUnitPropertyID             inID,
                                                    AudioUnitPropertyListenerProc   inProc,
                                                    void *                          inProcUserData);
    
    OSStatus                MIDIEvent (UInt32                   inStatus,
                                        UInt32                  inData1,
                                        UInt32                  inData2,
                                        UInt32                  inOffsetSampleFrame);
                                
                                // uses the default VoiceForGroup value - this is the normal case
    OSStatus                StartNote (MusicDeviceGroupID       inGroupID,
                                    NoteInstanceID *            outNoteInstanceID,
                                    UInt32                      inOffsetSampleFrame,
                                    const MusicDeviceNoteParams * inParams)
                            {
                                return StartNote (kMusicNoteEvent_UseGroupInstrument, 
                                                    inGroupID, outNoteInstanceID, 
                                                    inOffsetSampleFrame, inParams);
                            }
 
    OSStatus                StartNote (MusicDeviceInstrumentID  inInstrument,
                                    MusicDeviceGroupID          inGroupID,
                                    NoteInstanceID *            outNoteInstanceID,
                                    UInt32                      inOffsetSampleFrame,
                                    const MusicDeviceNoteParams * inParams);
 
    OSStatus                StopNote (MusicDeviceGroupID        inGroupID,
                                    NoteInstanceID              inNoteInstanceID,
                                    UInt32                      inOffsetSampleFrame);
 
#pragma mark __Format Utilities
        // typically you ask this about an AU
        // These Questions are asking about Input and Output...
 
        // These ones just say whether an AU can do a single combination of channels
        // and is fine if the AU has a single output (and if an input, a single input)
    bool                    CanDo (int inChannelsInOut) const
                            {
                                return CanDo (inChannelsInOut, inChannelsInOut);
                            }
                            
    bool                    CanDo (     int                 inChannelsIn, 
                                        int                 inChannelsOut) const;
        
        // This version does a more thorough test for ANY AU with ANY ins/outs
        // you pass in the channel helper (for the current element count on that scope)
        
    bool                    CanDo (     const CAAUChanHelper        &input,
                                        const CAAUChanHelper        &output) const;
    
    bool                    SupportsNumChannels () const;
 
    bool                    HasChannelLayouts (AudioUnitScope       inScope, 
                                            AudioUnitElement        inEl) const;
        
    OSStatus                GetChannelLayoutTags (AudioUnitScope    inScope,
                                    AudioUnitElement                inEl,
                                    ChannelTagVector                &outChannelVector) const;
    
    bool                    HasChannelLayout (AudioUnitScope        inScope, 
                                            AudioUnitElement        inEl) const;
    
    OSStatus                GetChannelLayout (AudioUnitScope        inScope,
                                            AudioUnitElement        inEl,
                                            CAAudioChannelLayout    &outLayout) const;  
 
    OSStatus                SetChannelLayout (AudioUnitScope        inScope, 
                                            AudioUnitElement        inEl,
                                            const CAAudioChannelLayout  &inLayout);
 
    OSStatus                SetChannelLayout (AudioUnitScope        inScope, 
                                            AudioUnitElement        inEl,
                                            const AudioChannelLayout        &inLayout,
                                            UInt32                  inSize);
                                            
    OSStatus                ClearChannelLayout (AudioUnitScope      inScope,
                                            AudioUnitElement        inEl);
                                                
    OSStatus                GetFormat (AudioUnitScope                   inScope,
                                            AudioUnitElement            inEl,
                                            AudioStreamBasicDescription &outFormat) const;
    // if an AudioChannelLayout is either required or set, this call can fail
    // and the SetChannelLayout call should be used to set the format
    OSStatus                SetFormat (AudioUnitScope                           inScope,
                                            AudioUnitElement                    inEl,
                                            const AudioStreamBasicDescription   &inFormat);
 
    OSStatus                GetSampleRate (AudioUnitScope       inScope,
                                            AudioUnitElement    inEl,
                                            Float64             &outRate) const;
    OSStatus                SetSampleRate (AudioUnitScope       inScope,
                                            AudioUnitElement    inEl,
                                            Float64             inRate);
 
    // this sets the sample rate on all in/out buses of the AU
    OSStatus                SetSampleRate (Float64              inSampleRate);
    
    OSStatus                NumberChannels (AudioUnitScope      inScope,
                                            AudioUnitElement    inEl,
                                            UInt32              &outChans) const;
 
    OSStatus                GetNumberChannels (AudioUnitScope   inScope,
                                            AudioUnitElement    inEl,
                                            UInt32              &outChans) const 
                            { 
                                return NumberChannels (inScope, inEl, outChans); 
                            }
 
    OSStatus                SetNumberChannels (AudioUnitScope   inScope,
                                            AudioUnitElement    inEl,
                                            UInt32              inChans);
 
    OSStatus                IsElementCountWritable (AudioUnitScope inScope, bool &outWritable) const;
 
    OSStatus                GetElementCount (AudioUnitScope     inScope, UInt32 &outCount) const;
 
    OSStatus                SetElementCount (AudioUnitScope     inScope, UInt32 inCount);
        
        // value of -1 for outTotalNumChannels indicates no restriction on num channels
        // for ex. the Matrix Mixer satisfies this (its in/out element count is writable, and can be set to 
        // any number of channels.
        // outTotalNumChannels is only valid if method returns true...
    bool                    HasDynamicInputs (SInt32 &outTotalNumChannels) const
                            {
                                return HasDynamicScope (kAudioUnitScope_Input, outTotalNumChannels);
                            }
                            
    bool                    HasDynamicOutputs (SInt32 &outTotalNumChannels) const
                            {
                                return HasDynamicScope (kAudioUnitScope_Output, outTotalNumChannels);
                            }
    
        // here, if the in (or out) elements are dynamic, then you supply the number of elements
        // you want on in (or out) scope, and the number of channels on each consecutive element
    OSStatus                ConfigureDynamicInput (UInt32 inNumElements, UInt32 *inChannelsPerElement, Float64 inSampleRate)
                            {
                                return ConfigureDynamicScope (kAudioUnitScope_Input, inNumElements, inChannelsPerElement, inSampleRate);
                            }
                            
    OSStatus                ConfigureDynamicOutput (UInt32 inNumElements, UInt32 *inChannelsPerElement, Float64 inSampleRate)
                            {
                                return ConfigureDynamicScope (kAudioUnitScope_Output, inNumElements, inChannelsPerElement, inSampleRate);
                            }
 
    bool                    CanBypass       () const;
 
    bool                    GetBypass       () const;
 
    OSStatus                SetBypass       (bool               inBypass) const;
    
    OSStatus                GetMaxFramesPerSlice (UInt32& outMaxFrames) const;
    
    OSStatus                SetMaxFramesPerSlice (UInt32 inMaxFrames);
    
    Float64                 Latency () const;
    
        // these calls just deal with the global preset state
        // you could rescope them to deal with presets on the part scope
    OSStatus                GetAUPreset (CFPropertyListRef &outData) const;
 
    OSStatus                SetAUPreset (CFPropertyListRef &inData);
    
    OSStatus                SetAUPresetFromDocument (CFPropertyListRef &inData);
 
    OSStatus                GetPresentPreset (AUPreset &outData) const;
    
    OSStatus                SetPresentPreset (AUPreset &inData);
    
    bool                    HasCustomView () const;
    
#pragma mark __Print    
    void                    Print () const { Print (stdout); }
    void                    Print (FILE* file) const;
    
private:
    CAComponent             mComp;
    
    class AUState;
    AUState*        mDataPtr;
        
        // this can throw - so wrap this up in a static that returns a result code...
    CAAudioUnit (const CAComponent& inComp);
 
    bool                HasDynamicScope (AudioUnitScope inScope, SInt32 &outTotalNumChannels) const;
    OSStatus            ConfigureDynamicScope (AudioUnitScope   inScope, 
                                            UInt32              inNumElements, 
                                            UInt32              *inChannelsPerElement, 
                                            Float64             inSampleRate);
    bool                ValidateChannelPair (int                inChannelsIn, 
                                            int                 inChannelsOut,
                                            const AUChannelInfo * info,
                                            UInt32              numChanInfo) const;
                                            
    bool                ValidateDynamicScope (AudioUnitScope    inScope, 
                                            SInt32              &outTotalNumChannels, 
                                            const AUChannelInfo * info, 
                                            UInt32 numInfo) const;
    bool                CheckOneSide (const CAAUChanHelper      &inHelper, 
                                            bool                checkOutput, 
                                            const AUChannelInfo *info, 
                                            UInt32              numInfo) const;
    enum {
            kCAAU_DoNotKnowIfAUNode = -1
    };
};
 
class CAAUChanHelper {
public:
                CAAUChanHelper() 
                    : mChans(mStaticChans), mNumEls(0), mDidAllocate(false) 
                {
                    memset (mChans, 0, sizeof(UInt32) * kStaticElCount);
                }
                CAAUChanHelper(UInt32 inMaxElems);
                CAAUChanHelper(const CAAudioUnit &inAU, AudioUnitScope inScope);
                CAAUChanHelper (const CAAUChanHelper &c) 
                    : mChans(mStaticChans), mNumEls(0), mDidAllocate(false) 
                    { *this = c; }
                
                ~CAAUChanHelper();
 
    CAAUChanHelper& operator= (const CAAUChanHelper &c);
 
    UInt32      * mChans;
    UInt32      mNumEls;
    
private:
    enum {
        kStaticElCount = 8
    };
    UInt32 mStaticChans[kStaticElCount];
    bool mDidAllocate;
};
 
#endif