2015-10-17 20:46:58 -04:00
|
|
|
/*
|
|
|
|
File: CAAudioUnit.cpp
|
|
|
|
Abstract: CAAudioUnit.h
|
|
|
|
Version: 1.1
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
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.
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
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.
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
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.
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
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.
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
*/
|
|
|
|
#include "CAAudioUnit.h"
|
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
#if !TARGET_OS_IPHONE
|
2008-06-02 17:41:35 -04:00
|
|
|
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
2015-10-17 20:46:58 -04:00
|
|
|
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/Components.h>
|
|
|
|
#include <dlfcn.h>
|
2008-06-02 17:41:35 -04:00
|
|
|
#else
|
2015-10-17 20:46:58 -04:00
|
|
|
#include <Components.h>
|
|
|
|
#endif
|
2008-06-02 17:41:35 -04:00
|
|
|
#endif
|
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
#include "CAXException.h"
|
2008-06-02 17:41:35 -04:00
|
|
|
#include "CAReferenceCounted.h"
|
|
|
|
#include "AUOutputBL.h" //this is for the Preroll only
|
|
|
|
|
|
|
|
struct StackAUChannelInfo {
|
|
|
|
StackAUChannelInfo (UInt32 inSize) : mChanInfo ((AUChannelInfo*)malloc (inSize)) {}
|
|
|
|
~StackAUChannelInfo() { free (mChanInfo); }
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
AUChannelInfo* mChanInfo;
|
|
|
|
};
|
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
// is this symbol is not defined then we use the default setting which is that fast dispatch
|
|
|
|
// is supported on a desktop environment
|
|
|
|
#ifndef CA_AU_USE_FAST_DISPATCH
|
|
|
|
#define CA_AU_USE_FAST_DISPATCH !TARGET_OS_IPHONE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if CA_AU_USE_FAST_DISPATCH
|
|
|
|
static void *LoadGetComponentInstanceStorage (void *inst);
|
|
|
|
#endif
|
2008-06-02 17:41:35 -04:00
|
|
|
|
|
|
|
|
|
|
|
class CAAudioUnit::AUState : public CAReferenceCounted {
|
|
|
|
public:
|
2015-10-17 20:46:58 -04:00
|
|
|
AUState (AudioComponent inComp)
|
2008-06-02 17:41:35 -04:00
|
|
|
: mUnit(0), mNode (0)
|
2015-10-26 14:35:06 -04:00
|
|
|
{
|
|
|
|
OSStatus result = ::AudioComponentInstanceNew (inComp, &mUnit);
|
2008-06-02 17:41:35 -04:00
|
|
|
if (result)
|
|
|
|
throw result;
|
|
|
|
Init();
|
|
|
|
}
|
|
|
|
|
|
|
|
AUState (const AUNode &inNode, const AudioUnit& inUnit)
|
2015-10-26 14:35:06 -04:00
|
|
|
: mUnit (inUnit), mNode (inNode)
|
2008-06-02 17:41:35 -04:00
|
|
|
{
|
|
|
|
Init();
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
~AUState();
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
AudioUnit mUnit;
|
|
|
|
AUNode mNode;
|
|
|
|
|
|
|
|
OSStatus GetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
|
|
|
|
Float32 &outValue) const
|
|
|
|
{
|
2015-10-17 20:46:58 -04:00
|
|
|
#if CA_AU_USE_FAST_DISPATCH
|
2008-06-02 17:41:35 -04:00
|
|
|
if (mGetParamProc != NULL) {
|
2015-10-17 20:46:58 -04:00
|
|
|
return (mGetParamProc) (mConnInstanceStorage, inID, scope, element, &outValue);
|
2015-10-26 14:35:06 -04:00
|
|
|
}
|
2015-10-17 20:46:58 -04:00
|
|
|
#endif
|
2008-06-02 17:41:35 -04:00
|
|
|
return AudioUnitGetParameter(mUnit, inID, scope, element, &outValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus SetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
|
|
|
|
Float32 value, UInt32 bufferOffsetFrames)
|
|
|
|
{
|
2015-10-17 20:46:58 -04:00
|
|
|
#if CA_AU_USE_FAST_DISPATCH
|
2008-06-02 17:41:35 -04:00
|
|
|
if (mSetParamProc != NULL) {
|
2015-10-17 20:46:58 -04:00
|
|
|
return (mSetParamProc) (mConnInstanceStorage, inID, scope, element, value, bufferOffsetFrames);
|
2015-10-26 14:35:06 -04:00
|
|
|
}
|
2015-10-17 20:46:58 -04:00
|
|
|
#endif
|
2008-06-02 17:41:35 -04:00
|
|
|
return AudioUnitSetParameter(mUnit, inID, scope, element, value, bufferOffsetFrames);
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
OSStatus Render (AudioUnitRenderActionFlags * ioActionFlags,
|
|
|
|
const AudioTimeStamp * inTimeStamp,
|
|
|
|
UInt32 inOutputBusNumber,
|
|
|
|
UInt32 inNumberFrames,
|
|
|
|
AudioBufferList * ioData)
|
|
|
|
{
|
2015-10-17 20:46:58 -04:00
|
|
|
#if CA_AU_USE_FAST_DISPATCH
|
2008-06-02 17:41:35 -04:00
|
|
|
if (mRenderProc != NULL) {
|
2015-10-17 20:46:58 -04:00
|
|
|
return (mRenderProc) (mConnInstanceStorage, ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData);
|
2015-10-26 14:35:06 -04:00
|
|
|
}
|
2015-10-17 20:46:58 -04:00
|
|
|
#endif
|
2008-06-02 17:41:35 -04:00
|
|
|
return AudioUnitRender(mUnit, ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData);
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
OSStatus MIDIEvent (UInt32 inStatus,
|
|
|
|
UInt32 inData1,
|
|
|
|
UInt32 inData2,
|
|
|
|
UInt32 inOffsetSampleFrame)
|
|
|
|
{
|
|
|
|
#if !TARGET_OS_WIN32
|
2015-10-17 20:46:58 -04:00
|
|
|
#if CA_AU_USE_FAST_DISPATCH
|
2008-06-02 17:41:35 -04:00
|
|
|
if (mMIDIEventProc != NULL) {
|
2015-10-17 20:46:58 -04:00
|
|
|
return (mMIDIEventProc) (mConnInstanceStorage, inStatus, inData1, inData2, inOffsetSampleFrame);
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
2015-10-17 20:46:58 -04:00
|
|
|
#endif
|
2008-06-02 17:41:35 -04:00
|
|
|
return MusicDeviceMIDIEvent (mUnit, inStatus, inData1, inData2, inOffsetSampleFrame);
|
2015-10-17 20:46:58 -04:00
|
|
|
#else // ON WINDOWS _ NO MIDI EVENT dispatch
|
2008-06-02 17:41:35 -04:00
|
|
|
return paramErr;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus StartNote (MusicDeviceInstrumentID inInstrument,
|
|
|
|
MusicDeviceGroupID inGroupID,
|
|
|
|
NoteInstanceID * outNoteInstanceID,
|
|
|
|
UInt32 inOffsetSampleFrame,
|
|
|
|
const MusicDeviceNoteParams * inParams)
|
|
|
|
{
|
|
|
|
#if !TARGET_OS_WIN32
|
2015-10-17 20:46:58 -04:00
|
|
|
#if CA_AU_USE_FAST_DISPATCH
|
|
|
|
if (mStartNoteProc != NULL) {
|
|
|
|
return (mStartNoteProc) (mConnInstanceStorage, inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, inParams);
|
|
|
|
}
|
|
|
|
#endif
|
2008-06-02 17:41:35 -04:00
|
|
|
return MusicDeviceStartNote (mUnit, inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, inParams);
|
|
|
|
#else
|
|
|
|
return paramErr;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
OSStatus StopNote (MusicDeviceGroupID inGroupID,
|
|
|
|
NoteInstanceID inNoteInstanceID,
|
|
|
|
UInt32 inOffsetSampleFrame)
|
|
|
|
{
|
|
|
|
#if !TARGET_OS_WIN32
|
2015-10-17 20:46:58 -04:00
|
|
|
#if CA_AU_USE_FAST_DISPATCH
|
|
|
|
if (mStopNoteProc != NULL) {
|
|
|
|
return (mStopNoteProc) (mConnInstanceStorage, inGroupID, inNoteInstanceID, inOffsetSampleFrame);
|
|
|
|
}
|
|
|
|
#endif
|
2008-06-02 17:41:35 -04:00
|
|
|
return MusicDeviceStopNote (mUnit, inGroupID, inNoteInstanceID, inOffsetSampleFrame);
|
|
|
|
#else
|
|
|
|
return paramErr;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
// get the fast dispatch pointers
|
2015-10-26 14:35:06 -04:00
|
|
|
void Init()
|
2008-06-02 17:41:35 -04:00
|
|
|
{
|
2015-10-17 20:46:58 -04:00
|
|
|
#if CA_AU_USE_FAST_DISPATCH
|
2008-06-02 17:41:35 -04:00
|
|
|
UInt32 size = sizeof(AudioUnitRenderProc);
|
|
|
|
if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch,
|
|
|
|
kAudioUnitScope_Global, kAudioUnitRenderSelect,
|
|
|
|
&mRenderProc, &size) != noErr)
|
|
|
|
mRenderProc = NULL;
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
size = sizeof(AudioUnitGetParameterProc);
|
2008-06-02 17:41:35 -04:00
|
|
|
if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch,
|
|
|
|
kAudioUnitScope_Global, kAudioUnitGetParameterSelect,
|
|
|
|
&mGetParamProc, &size) != noErr)
|
|
|
|
mGetParamProc = NULL;
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
size = sizeof(AudioUnitSetParameterProc);
|
2008-06-02 17:41:35 -04:00
|
|
|
if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch,
|
|
|
|
kAudioUnitScope_Global, kAudioUnitSetParameterSelect,
|
|
|
|
&mSetParamProc, &size) != noErr)
|
|
|
|
mSetParamProc = NULL;
|
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
size = sizeof(MusicDeviceMIDIEventProc);
|
2008-06-02 17:41:35 -04:00
|
|
|
if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch,
|
|
|
|
kAudioUnitScope_Global, kMusicDeviceMIDIEventSelect,
|
|
|
|
&mMIDIEventProc, &size) != noErr)
|
|
|
|
mMIDIEventProc = NULL;
|
2015-10-05 10:17:49 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
size = sizeof(MusicDeviceStartNoteProc);
|
|
|
|
if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch,
|
|
|
|
kAudioUnitScope_Global, kMusicDeviceStartNoteSelect,
|
|
|
|
&mStartNoteProc, &size) != noErr)
|
|
|
|
mStartNoteProc = NULL;
|
|
|
|
|
|
|
|
size = sizeof(MusicDeviceStopNoteProc);
|
|
|
|
if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch,
|
|
|
|
kAudioUnitScope_Global, kMusicDeviceStopNoteSelect,
|
|
|
|
&mStopNoteProc, &size) != noErr)
|
|
|
|
mStopNoteProc = NULL;
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
if (mRenderProc || mGetParamProc || mSetParamProc || mMIDIEventProc || mStartNoteProc || mStopNoteProc) {
|
|
|
|
mConnInstanceStorage = LoadGetComponentInstanceStorage ( mUnit );
|
|
|
|
} else
|
2008-06-02 17:41:35 -04:00
|
|
|
mConnInstanceStorage = NULL;
|
2015-10-17 20:46:58 -04:00
|
|
|
#else
|
|
|
|
mConnInstanceStorage = NULL;
|
|
|
|
#endif
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
#if CA_AU_USE_FAST_DISPATCH
|
|
|
|
AudioUnitRenderProc mRenderProc;
|
2015-10-26 14:35:06 -04:00
|
|
|
AudioUnitGetParameterProc mGetParamProc;
|
2015-10-17 20:46:58 -04:00
|
|
|
AudioUnitSetParameterProc mSetParamProc;
|
|
|
|
MusicDeviceMIDIEventProc mMIDIEventProc;
|
|
|
|
MusicDeviceStartNoteProc mStartNoteProc;
|
|
|
|
MusicDeviceStopNoteProc mStopNoteProc;
|
|
|
|
#endif
|
2008-06-02 17:41:35 -04:00
|
|
|
|
|
|
|
void * mConnInstanceStorage;
|
|
|
|
|
|
|
|
private:
|
|
|
|
// get the compiler to tell us when we do a bad thing!!!
|
|
|
|
AUState () {}
|
2015-10-17 20:46:58 -04:00
|
|
|
AUState (const AUState&);
|
|
|
|
AUState& operator= (const AUState&);
|
2015-10-26 14:35:06 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
CAAudioUnit::AUState::~AUState ()
|
|
|
|
{
|
|
|
|
if (mUnit && (mNode == 0)) {
|
2015-10-17 20:46:58 -04:00
|
|
|
::AudioComponentInstanceDispose (mUnit);
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
mNode = 0;
|
|
|
|
mUnit = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::Open (const CAComponent& inComp, CAAudioUnit &outUnit)
|
|
|
|
{
|
|
|
|
try {
|
2015-10-26 14:35:06 -04:00
|
|
|
outUnit = inComp;
|
2008-06-02 17:41:35 -04:00
|
|
|
return noErr;
|
|
|
|
} catch (OSStatus res) {
|
|
|
|
return res;
|
|
|
|
} catch (...) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CAAudioUnit::CAAudioUnit (const AudioUnit& inUnit)
|
2015-10-17 20:46:58 -04:00
|
|
|
: mComp (inUnit), mDataPtr (new AUState (kCAAU_DoNotKnowIfAUNode, inUnit))
|
2008-06-02 17:41:35 -04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CAAudioUnit::CAAudioUnit (const CAComponent& inComp)
|
2015-10-17 20:46:58 -04:00
|
|
|
: mComp (inComp), mDataPtr (new AUState (mComp.Comp()))
|
2008-06-02 17:41:35 -04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CAAudioUnit::CAAudioUnit (const AUNode &inNode, const AudioUnit& inUnit)
|
2015-10-26 14:35:06 -04:00
|
|
|
: mComp (inUnit), mDataPtr(new AUState (inNode, inUnit))
|
2008-06-02 17:41:35 -04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CAAudioUnit::~CAAudioUnit ()
|
2015-10-17 20:46:58 -04:00
|
|
|
{
|
|
|
|
Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CAAudioUnit::Close()
|
2008-06-02 17:41:35 -04:00
|
|
|
{
|
|
|
|
if (mDataPtr) {
|
|
|
|
mDataPtr->release();
|
|
|
|
mDataPtr = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CAAudioUnit& CAAudioUnit::operator= (const CAAudioUnit &a)
|
|
|
|
{
|
|
|
|
if (mDataPtr != a.mDataPtr) {
|
|
|
|
if (mDataPtr)
|
|
|
|
mDataPtr->release();
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
if ((mDataPtr = a.mDataPtr) != NULL)
|
|
|
|
mDataPtr->retain();
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
mComp = a.mComp;
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CAAudioUnit::operator== (const CAAudioUnit& y) const
|
|
|
|
{
|
|
|
|
if (mDataPtr == y.mDataPtr) return true;
|
|
|
|
AudioUnit au1 = mDataPtr ? mDataPtr->mUnit : 0;
|
|
|
|
AudioUnit au2 = y.mDataPtr ? y.mDataPtr->mUnit : 0;
|
|
|
|
return au1 == au2;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CAAudioUnit::operator== (const AudioUnit& y) const
|
|
|
|
{
|
|
|
|
if (!mDataPtr) return false;
|
|
|
|
return mDataPtr->mUnit == y;
|
|
|
|
}
|
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
OSStatus CAAudioUnit::RemovePropertyListener (AudioUnitPropertyID inID,
|
|
|
|
AudioUnitPropertyListenerProc inProc,
|
|
|
|
void * inProcUserData)
|
2015-10-04 15:11:15 -04:00
|
|
|
{
|
2015-10-17 20:46:58 -04:00
|
|
|
// we call this first. If it fails we call the old API as the failure can
|
|
|
|
// mean that the AU doesn't implement that selector.
|
2015-10-26 14:35:06 -04:00
|
|
|
OSStatus result = AudioUnitRemovePropertyListenerWithUserData(AU(), inID,
|
2015-10-17 20:46:58 -04:00
|
|
|
inProc, inProcUserData);
|
|
|
|
#if !__LP64__ && !TARGET_OS_IPHONE
|
|
|
|
if (result) result = AudioUnitRemovePropertyListener (AU(), inID, inProc);
|
2015-10-26 14:35:06 -04:00
|
|
|
#endif
|
2015-10-17 20:46:58 -04:00
|
|
|
return result;
|
2015-10-26 14:35:06 -04:00
|
|
|
}
|
2015-10-05 10:17:49 -04:00
|
|
|
|
2015-10-26 14:35:06 -04:00
|
|
|
#pragma mark __State Management
|
2015-10-17 20:46:58 -04:00
|
|
|
|
2015-10-26 14:35:06 -04:00
|
|
|
bool CAAudioUnit::IsValid () const
|
|
|
|
{
|
|
|
|
return mDataPtr ? mDataPtr->mUnit != 0 : false;
|
2015-10-17 20:46:58 -04:00
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
|
|
|
AudioUnit CAAudioUnit::AU() const
|
|
|
|
{
|
|
|
|
return mDataPtr ? mDataPtr->mUnit : 0;
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
AUNode CAAudioUnit::GetAUNode () const
|
|
|
|
{
|
2015-10-26 14:35:06 -04:00
|
|
|
return mDataPtr ? mDataPtr->mNode : 0;
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark __Format Handling
|
2015-10-26 14:35:06 -04:00
|
|
|
|
|
|
|
bool CAAudioUnit::CanDo ( int inChannelsIn,
|
2008-06-02 17:41:35 -04:00
|
|
|
int inChannelsOut) const
|
2015-10-26 14:35:06 -04:00
|
|
|
{
|
2008-06-02 17:41:35 -04:00
|
|
|
// this is the default assumption of an audio effect unit
|
|
|
|
Boolean* isWritable = 0;
|
|
|
|
UInt32 dataSize = 0;
|
|
|
|
// lets see if the unit has any channel restrictions
|
|
|
|
OSStatus result = AudioUnitGetPropertyInfo (AU(),
|
|
|
|
kAudioUnitProperty_SupportedNumChannels,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
&dataSize, isWritable); //don't care if this is writable
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
// if this property is NOT implemented an FX unit
|
|
|
|
// is expected to deal with same channel valance in and out
|
2015-10-26 14:35:06 -04:00
|
|
|
if (result)
|
2008-06-02 17:41:35 -04:00
|
|
|
{
|
2015-10-17 20:46:58 -04:00
|
|
|
if ((Comp().Desc().IsEffect() && inChannelsIn == inChannelsOut)
|
|
|
|
|| (Comp().Desc().IsOffline() && inChannelsIn == inChannelsOut))
|
2008-06-02 17:41:35 -04:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
else
|
2008-06-02 17:41:35 -04:00
|
|
|
{
|
|
|
|
// the au should either really tell us about this
|
|
|
|
// or we will assume the worst
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
StackAUChannelInfo info (dataSize);
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
result = GetProperty (kAudioUnitProperty_SupportedNumChannels,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
info.mChanInfo, &dataSize);
|
|
|
|
if (result) { return false; }
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
return ValidateChannelPair (inChannelsIn, inChannelsOut, info.mChanInfo, (dataSize / sizeof (AUChannelInfo)));
|
|
|
|
}
|
|
|
|
|
2008-09-10 11:03:30 -04:00
|
|
|
int CAAudioUnit::GetChannelInfo (AUChannelInfo** chaninfo, UInt32& cnt)
|
|
|
|
{
|
2015-10-17 20:46:58 -04:00
|
|
|
// this is the default assumption of an audio effect unit
|
|
|
|
Boolean* isWritable = 0;
|
|
|
|
UInt32 dataSize = 0;
|
|
|
|
// lets see if the unit has any channel restrictions
|
|
|
|
OSStatus result = AudioUnitGetPropertyInfo (AU(),
|
|
|
|
kAudioUnitProperty_SupportedNumChannels,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
&dataSize, isWritable); //don't care if this is writable
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
// if this property is NOT implemented an FX unit
|
|
|
|
// is expected to deal with same channel valance in and out
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
if (result)
|
|
|
|
{
|
|
|
|
if (Comp().Desc().IsEffect())
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else if (Comp().Desc().IsGenerator() || Comp().Desc().IsMusicDevice()) {
|
|
|
|
// directly query Bus Formats
|
|
|
|
// Note that that these may refer to different subBusses
|
|
|
|
// (eg. Kick, Snare,.. on a Drummachine)
|
|
|
|
// eventually the Bus-Name for each configuration should be exposed
|
|
|
|
// for the User to select..
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
UInt32 elCountIn, elCountOut;
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
if (GetElementCount (kAudioUnitScope_Input, elCountIn)) return -1;
|
|
|
|
if (GetElementCount (kAudioUnitScope_Output, elCountOut)) return -1;
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
cnt = std::max(elCountIn, elCountOut);
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
*chaninfo = (AUChannelInfo*) malloc (sizeof (AUChannelInfo) * cnt);
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
for (unsigned int i = 0; i < elCountIn; ++i) {
|
|
|
|
UInt32 numChans;
|
|
|
|
if (NumberChannels (kAudioUnitScope_Input, i, numChans)) return -1;
|
|
|
|
(*chaninfo)[i].inChannels = numChans;
|
|
|
|
}
|
|
|
|
for (unsigned int i = elCountIn; i < cnt; ++i) {
|
|
|
|
(*chaninfo)[i].inChannels = 0;
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
for (unsigned int i = 0; i < elCountOut; ++i) {
|
|
|
|
UInt32 numChans;
|
|
|
|
if (NumberChannels (kAudioUnitScope_Output, i, numChans)) return -1;
|
|
|
|
(*chaninfo)[i].outChannels = numChans;
|
|
|
|
}
|
|
|
|
for (unsigned int i = elCountOut; i < cnt; ++i) {
|
|
|
|
(*chaninfo)[i].outChannels = 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
else
|
2015-10-17 20:46:58 -04:00
|
|
|
{
|
|
|
|
// the au should either really tell us about this
|
|
|
|
// or we will assume the worst
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
*chaninfo = (AUChannelInfo*) malloc (dataSize);
|
|
|
|
cnt = dataSize / sizeof (AUChannelInfo);
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
result = GetProperty (kAudioUnitProperty_SupportedNumChannels,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
*chaninfo, &dataSize);
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
if (result) { return -1; }
|
|
|
|
return 0;
|
2008-09-10 11:03:30 -04:00
|
|
|
}
|
|
|
|
|
2015-10-26 14:35:06 -04:00
|
|
|
bool CAAudioUnit::ValidateChannelPair (int inChannelsIn,
|
2008-06-02 17:41:35 -04:00
|
|
|
int inChannelsOut,
|
|
|
|
const AUChannelInfo * info,
|
|
|
|
UInt32 numChanInfo) const
|
|
|
|
{
|
|
|
|
// we've the following cases (some combinations) to test here:
|
|
|
|
/*
|
|
|
|
>0 An explicit number of channels on either side
|
|
|
|
0 that side (generally input!) has no elements
|
|
|
|
-1 wild card:
|
|
|
|
-1,-1 any num channels as long as same channels on in and out
|
|
|
|
-1,-2 any num channels channels on in and out - special meaning
|
2015-10-26 14:35:06 -04:00
|
|
|
-2+ indicates total num channs AU can handle
|
|
|
|
- elements configurable to any num channels,
|
2008-06-02 17:41:35 -04:00
|
|
|
- element count in scope must be writable
|
|
|
|
*/
|
|
|
|
|
|
|
|
//now chan layout can contain -1 for either scope (ie. doesn't care)
|
|
|
|
for (unsigned int i = 0; i < numChanInfo; ++i)
|
|
|
|
{
|
|
|
|
//less than zero on both sides - check for special attributes
|
|
|
|
if ((info[i].inChannels < 0) && (info[i].outChannels < 0))
|
|
|
|
{
|
|
|
|
// these are our wild card matches
|
|
|
|
if (info[i].inChannels == -1 && info[i].outChannels == -1) {
|
2015-10-17 20:46:58 -04:00
|
|
|
if (inChannelsIn && inChannelsOut) {
|
|
|
|
if (inChannelsOut == inChannelsIn)
|
|
|
|
return true;
|
|
|
|
} else
|
|
|
|
return true; // if one of these is zero, then a -1 means any
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
else if ((info[i].inChannels == -1 && info[i].outChannels == -2)
|
2015-10-26 14:35:06 -04:00
|
|
|
|| (info[i].inChannels == -2 && info[i].outChannels == -1))
|
2008-06-02 17:41:35 -04:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// these are our total num channels matches
|
|
|
|
// element count MUST be writable
|
|
|
|
else {
|
|
|
|
bool outWrite = false; bool inWrite = false;
|
|
|
|
IsElementCountWritable (kAudioUnitScope_Output, outWrite);
|
|
|
|
IsElementCountWritable (kAudioUnitScope_Input, inWrite);
|
|
|
|
if (inWrite && outWrite) {
|
|
|
|
if ((inChannelsOut <= abs(info[i].outChannels))
|
2015-10-26 14:35:06 -04:00
|
|
|
&& (inChannelsIn <= abs(info[i].inChannels)))
|
2008-06-02 17:41:35 -04:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
// special meaning on input, specific num on output
|
|
|
|
else if (info[i].inChannels < 0) {
|
2015-10-26 14:35:06 -04:00
|
|
|
if (info[i].outChannels == inChannelsOut)
|
2008-06-02 17:41:35 -04:00
|
|
|
{
|
|
|
|
// can do any in channels
|
|
|
|
if (info[i].inChannels == -1) {
|
|
|
|
return true;
|
2015-10-26 14:35:06 -04:00
|
|
|
}
|
2008-06-02 17:41:35 -04:00
|
|
|
// total chans on input
|
|
|
|
else {
|
|
|
|
bool inWrite = false;
|
|
|
|
IsElementCountWritable (kAudioUnitScope_Input, inWrite);
|
|
|
|
if (inWrite && (inChannelsIn <= abs(info[i].inChannels))) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
// special meaning on output, specific num on input
|
|
|
|
else if (info[i].outChannels < 0) {
|
2015-10-26 14:35:06 -04:00
|
|
|
if (info[i].inChannels == inChannelsIn)
|
2008-06-02 17:41:35 -04:00
|
|
|
{
|
|
|
|
// can do any out channels
|
|
|
|
if (info[i].outChannels == -1) {
|
|
|
|
return true;
|
2015-10-26 14:35:06 -04:00
|
|
|
}
|
2008-06-02 17:41:35 -04:00
|
|
|
// total chans on output
|
|
|
|
else {
|
|
|
|
bool outWrite = false;
|
|
|
|
IsElementCountWritable (kAudioUnitScope_Output, outWrite);
|
|
|
|
if (outWrite && (inChannelsOut <= abs(info[i].outChannels))) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// both chans in struct >= 0 - thus has to explicitly match
|
|
|
|
else if ((info[i].inChannels == inChannelsIn) && (info[i].outChannels == inChannelsOut)) {
|
|
|
|
return true;
|
2015-10-26 14:35:06 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// now check to see if a wild card on the args (inChannelsIn or inChannelsOut chans is zero) is found
|
2008-06-02 17:41:35 -04:00
|
|
|
// tells us to match just one side of the scopes
|
|
|
|
else if (inChannelsIn == 0) {
|
|
|
|
if (info[i].outChannels == inChannelsOut) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (inChannelsOut == 0) {
|
|
|
|
if (info[i].inChannels == inChannelsIn) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
static
|
2008-06-02 17:41:35 -04:00
|
|
|
bool CheckDynCount (SInt32 inTotalChans, const CAAUChanHelper &inHelper)
|
|
|
|
{
|
|
|
|
int totalChans = 0;
|
|
|
|
for (unsigned int i = 0; i < inHelper.mNumEls; ++i)
|
|
|
|
totalChans += inHelper.mChans[i];
|
|
|
|
return (totalChans <= inTotalChans);
|
|
|
|
}
|
|
|
|
|
2015-10-26 14:35:06 -04:00
|
|
|
bool CAAudioUnit::CheckOneSide (const CAAUChanHelper &inHelper,
|
|
|
|
bool checkOutput,
|
|
|
|
const AUChannelInfo *info,
|
2008-06-02 17:41:35 -04:00
|
|
|
UInt32 numInfo) const
|
|
|
|
{
|
|
|
|
// now we can use the wildcard option (see above impl) to see if this matches
|
|
|
|
for (unsigned int el = 0; el < inHelper.mNumEls; ++el) {
|
|
|
|
bool testAlready = false;
|
|
|
|
for (unsigned int i = 0; i < el; ++i) {
|
|
|
|
if (inHelper.mChans[i] == inHelper.mChans[el]) {
|
|
|
|
testAlready = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!testAlready) {
|
|
|
|
if (checkOutput) {
|
|
|
|
if (!ValidateChannelPair (0, inHelper.mChans[el], info, numInfo)) return false;
|
|
|
|
} else {
|
|
|
|
if (!ValidateChannelPair (inHelper.mChans[el], 0, info, numInfo)) return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-10-26 14:35:06 -04:00
|
|
|
bool CAAudioUnit::CanDo (const CAAUChanHelper &inputs,
|
2008-06-02 17:41:35 -04:00
|
|
|
const CAAUChanHelper &outputs) const
|
|
|
|
|
|
|
|
{
|
|
|
|
// first check our state
|
|
|
|
// huh!
|
|
|
|
if (inputs.mNumEls == 0 && outputs.mNumEls == 0) return false;
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
UInt32 elCount;
|
|
|
|
if (GetElementCount (kAudioUnitScope_Input, elCount)) { return false; }
|
|
|
|
if (elCount != inputs.mNumEls) return false;
|
|
|
|
|
|
|
|
if (GetElementCount (kAudioUnitScope_Output, elCount)) { return false; }
|
|
|
|
if (elCount != outputs.mNumEls) return false;
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
// (1) special cases (effects and sources (generators and instruments) only)
|
|
|
|
UInt32 dataSize = 0;
|
|
|
|
if (GetPropertyInfo (kAudioUnitProperty_SupportedNumChannels,
|
2015-10-26 14:35:06 -04:00
|
|
|
kAudioUnitScope_Global, 0, &dataSize, NULL) != noErr)
|
2008-06-02 17:41:35 -04:00
|
|
|
{
|
|
|
|
if (Comp().Desc().IsEffect() || Comp().Desc().IsOffline()) {
|
|
|
|
UInt32 numChan = outputs.mNumEls > 0 ? outputs.mChans[0] : inputs.mChans[0];
|
|
|
|
for (unsigned int in = 0; in < inputs.mNumEls; ++in)
|
|
|
|
if (numChan != inputs.mChans[in]) return false;
|
|
|
|
for (unsigned int out = 0; out < outputs.mNumEls; ++out)
|
|
|
|
if (numChan != outputs.mChans[out]) return false;
|
|
|
|
return true;
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
// in this case, all the channels have to match the current config
|
|
|
|
if (Comp().Desc().IsGenerator() || Comp().Desc().IsMusicDevice()) {
|
|
|
|
for (unsigned int in = 0; in < inputs.mNumEls; ++in) {
|
|
|
|
UInt32 chan;
|
|
|
|
if (NumberChannels (kAudioUnitScope_Input, in, chan)) return false;
|
|
|
|
if (chan != UInt32(inputs.mChans[in])) return false;
|
|
|
|
}
|
|
|
|
for (unsigned int out = 0; out < outputs.mNumEls; ++out) {
|
|
|
|
UInt32 chan;
|
|
|
|
if (NumberChannels (kAudioUnitScope_Output, out, chan)) return false;
|
|
|
|
if (chan != UInt32(outputs.mChans[out])) return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
// if we get here we can't determine anything about channel capabilities
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
StackAUChannelInfo info (dataSize);
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
if (GetProperty (kAudioUnitProperty_SupportedNumChannels,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
info.mChanInfo, &dataSize) != noErr)
|
2015-10-26 14:35:06 -04:00
|
|
|
{
|
|
|
|
return false;
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
int numInfo = dataSize / sizeof(AUChannelInfo);
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
// (2) Test for dynamic capability (or no elements on that scope)
|
|
|
|
SInt32 dynInChans = 0;
|
|
|
|
if (ValidateDynamicScope (kAudioUnitScope_Input, dynInChans, info.mChanInfo, numInfo)) {
|
|
|
|
if (CheckDynCount (dynInChans, inputs) == false) return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
SInt32 dynOutChans = 0;
|
|
|
|
if (ValidateDynamicScope (kAudioUnitScope_Output, dynOutChans, info.mChanInfo, numInfo)) {
|
|
|
|
if (CheckDynCount (dynOutChans, outputs) == false) return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dynOutChans && dynInChans) { return true; }
|
|
|
|
|
|
|
|
// (3) Just need to test one side
|
|
|
|
if (dynInChans || (inputs.mNumEls == 0)) {
|
|
|
|
return CheckOneSide (outputs, true, info.mChanInfo, numInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dynOutChans || (outputs.mNumEls == 0)) {
|
|
|
|
return CheckOneSide (inputs, false, info.mChanInfo, numInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
// (4) - not a dynamic AU, has ins and outs, and has channel constraints so we test every possible pairing
|
2015-10-26 14:35:06 -04:00
|
|
|
for (unsigned int in = 0; in < inputs.mNumEls; ++in)
|
2008-06-02 17:41:35 -04:00
|
|
|
{
|
|
|
|
bool testInAlready = false;
|
|
|
|
for (unsigned int i = 0; i < in; ++i) {
|
|
|
|
if (inputs.mChans[i] == inputs.mChans[in]) {
|
|
|
|
testInAlready = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!testInAlready) {
|
|
|
|
for (unsigned int out = 0; out < outputs.mNumEls; ++out) {
|
|
|
|
// try to save a little bit and not test the same pairing multiple times...
|
|
|
|
bool testOutAlready = false;
|
|
|
|
for (unsigned int i = 0; i < out; ++i) {
|
|
|
|
if (outputs.mChans[i] == outputs.mChans[out]) {
|
|
|
|
testOutAlready = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!testOutAlready) {
|
|
|
|
if (!ValidateChannelPair (inputs.mChans[in], outputs.mChans[out],info.mChanInfo, numInfo)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CAAudioUnit::SupportsNumChannels () const
|
|
|
|
{
|
|
|
|
// this is the default assumption of an audio effect unit
|
|
|
|
Boolean* isWritable = 0;
|
|
|
|
UInt32 dataSize = 0;
|
|
|
|
// lets see if the unit has any channel restrictions
|
|
|
|
OSStatus result = AudioUnitGetPropertyInfo (AU(),
|
|
|
|
kAudioUnitProperty_SupportedNumChannels,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
&dataSize, isWritable); //don't care if this is writable
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
// if this property is NOT implemented an FX unit
|
|
|
|
// is expected to deal with same channel valance in and out
|
|
|
|
if (result) {
|
|
|
|
if (Comp().Desc().IsEffect() || Comp().Desc().IsOffline())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return result == noErr;
|
|
|
|
}
|
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
OSStatus CAAudioUnit::GetChannelLayoutTags (AudioUnitScope inScope,
|
2008-06-02 17:41:35 -04:00
|
|
|
AudioUnitElement inEl,
|
|
|
|
ChannelTagVector &outChannelVector) const
|
|
|
|
{
|
2015-10-26 14:35:06 -04:00
|
|
|
if (HasChannelLayouts (inScope, inEl) == false) return kAudioUnitErr_InvalidProperty;
|
2008-06-02 17:41:35 -04:00
|
|
|
|
|
|
|
UInt32 dataSize;
|
|
|
|
OSStatus result = AudioUnitGetPropertyInfo (AU(),
|
|
|
|
kAudioUnitProperty_SupportedChannelLayoutTags,
|
|
|
|
inScope, inEl,
|
|
|
|
&dataSize, NULL);
|
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
if (result) return result;
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
// OK lets get our channel layouts and see if the one we want is present
|
|
|
|
AudioChannelLayoutTag* info = (AudioChannelLayoutTag*)malloc (dataSize);
|
|
|
|
result = AudioUnitGetProperty (AU(),
|
|
|
|
kAudioUnitProperty_SupportedChannelLayoutTags,
|
|
|
|
inScope, inEl,
|
|
|
|
info, &dataSize);
|
|
|
|
if (result) goto home;
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
outChannelVector.erase (outChannelVector.begin(), outChannelVector.end());
|
|
|
|
for (unsigned int i = 0; i < (dataSize / sizeof (AudioChannelLayoutTag)); ++i)
|
|
|
|
outChannelVector.push_back (info[i]);
|
|
|
|
|
|
|
|
home:
|
|
|
|
free (info);
|
2015-10-17 20:46:58 -04:00
|
|
|
return result;
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
|
2015-10-26 14:35:06 -04:00
|
|
|
bool CAAudioUnit::HasChannelLayouts (AudioUnitScope inScope,
|
2008-06-02 17:41:35 -04:00
|
|
|
AudioUnitElement inEl) const
|
|
|
|
{
|
|
|
|
OSStatus result = AudioUnitGetPropertyInfo (AU(),
|
|
|
|
kAudioUnitProperty_SupportedChannelLayoutTags,
|
|
|
|
inScope, inEl,
|
|
|
|
NULL, NULL);
|
|
|
|
return !result;
|
|
|
|
}
|
|
|
|
|
2015-10-26 14:35:06 -04:00
|
|
|
bool CAAudioUnit::HasChannelLayout (AudioUnitScope inScope,
|
2015-10-17 20:46:58 -04:00
|
|
|
AudioUnitElement inEl) const
|
|
|
|
{
|
|
|
|
Boolean writable;
|
|
|
|
UInt32 size;
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
return AudioUnitGetPropertyInfo (AU(),
|
|
|
|
kAudioUnitProperty_AudioChannelLayout,
|
|
|
|
inScope, inEl,
|
|
|
|
&size, &writable) == noErr;
|
2015-10-26 14:35:06 -04:00
|
|
|
}
|
2015-10-17 20:46:58 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
OSStatus CAAudioUnit::GetChannelLayout (AudioUnitScope inScope,
|
|
|
|
AudioUnitElement inEl,
|
|
|
|
CAAudioChannelLayout &outLayout) const
|
|
|
|
{
|
|
|
|
UInt32 size;
|
|
|
|
OSStatus result = AudioUnitGetPropertyInfo (AU(), kAudioUnitProperty_AudioChannelLayout,
|
|
|
|
inScope, inEl, &size, NULL);
|
|
|
|
if (result) return result;
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
AudioChannelLayout *layout = (AudioChannelLayout*)malloc (size);
|
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
ca_require_noerr (result = AudioUnitGetProperty (AU(), kAudioUnitProperty_AudioChannelLayout,
|
2008-06-02 17:41:35 -04:00
|
|
|
inScope, inEl, layout, &size), home);
|
|
|
|
|
|
|
|
outLayout = CAAudioChannelLayout (layout);
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
home:
|
|
|
|
free (layout);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::SetChannelLayout (AudioUnitScope inScope,
|
|
|
|
AudioUnitElement inEl,
|
2015-10-17 20:46:58 -04:00
|
|
|
const CAAudioChannelLayout &inLayout)
|
2008-06-02 17:41:35 -04:00
|
|
|
{
|
|
|
|
OSStatus result = AudioUnitSetProperty (AU(),
|
|
|
|
kAudioUnitProperty_AudioChannelLayout,
|
|
|
|
inScope, inEl,
|
|
|
|
inLayout, inLayout.Size());
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-10-26 14:35:06 -04:00
|
|
|
OSStatus CAAudioUnit::SetChannelLayout (AudioUnitScope inScope,
|
2008-06-02 17:41:35 -04:00
|
|
|
AudioUnitElement inEl,
|
2015-10-17 20:46:58 -04:00
|
|
|
const AudioChannelLayout &inLayout,
|
2008-06-02 17:41:35 -04:00
|
|
|
UInt32 inSize)
|
|
|
|
{
|
|
|
|
OSStatus result = AudioUnitSetProperty (AU(),
|
|
|
|
kAudioUnitProperty_AudioChannelLayout,
|
|
|
|
inScope, inEl,
|
|
|
|
&inLayout, inSize);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::ClearChannelLayout (AudioUnitScope inScope,
|
|
|
|
AudioUnitElement inEl)
|
|
|
|
{
|
|
|
|
return AudioUnitSetProperty (AU(),
|
|
|
|
kAudioUnitProperty_AudioChannelLayout,
|
|
|
|
inScope, inEl, NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::GetFormat (AudioUnitScope inScope,
|
|
|
|
AudioUnitElement inEl,
|
|
|
|
AudioStreamBasicDescription &outFormat) const
|
|
|
|
{
|
|
|
|
UInt32 dataSize = sizeof (AudioStreamBasicDescription);
|
|
|
|
return AudioUnitGetProperty (AU(), kAudioUnitProperty_StreamFormat,
|
2015-10-26 14:35:06 -04:00
|
|
|
inScope, inEl,
|
2008-06-02 17:41:35 -04:00
|
|
|
&outFormat, &dataSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::SetFormat (AudioUnitScope inScope,
|
|
|
|
AudioUnitElement inEl,
|
|
|
|
const AudioStreamBasicDescription &inFormat)
|
|
|
|
{
|
|
|
|
return AudioUnitSetProperty (AU(), kAudioUnitProperty_StreamFormat,
|
|
|
|
inScope, inEl,
|
2015-10-26 14:35:06 -04:00
|
|
|
const_cast<AudioStreamBasicDescription*>(&inFormat),
|
2008-06-02 17:41:35 -04:00
|
|
|
sizeof (AudioStreamBasicDescription));
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::GetSampleRate (AudioUnitScope inScope,
|
|
|
|
AudioUnitElement inEl,
|
|
|
|
Float64 &outRate) const
|
|
|
|
{
|
|
|
|
UInt32 dataSize = sizeof (Float64);
|
|
|
|
return AudioUnitGetProperty (AU(), kAudioUnitProperty_SampleRate,
|
2015-10-26 14:35:06 -04:00
|
|
|
inScope, inEl,
|
2008-06-02 17:41:35 -04:00
|
|
|
&outRate, &dataSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::SetSampleRate (AudioUnitScope inScope,
|
|
|
|
AudioUnitElement inEl,
|
|
|
|
Float64 inRate)
|
|
|
|
{
|
|
|
|
AudioStreamBasicDescription desc;
|
|
|
|
OSStatus result = GetFormat (inScope, inEl, desc);
|
|
|
|
if (result) return result;
|
|
|
|
desc.mSampleRate = inRate;
|
|
|
|
return SetFormat (inScope, inEl, desc);
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::SetSampleRate (Float64 inSampleRate)
|
|
|
|
{
|
|
|
|
OSStatus result;
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
UInt32 elCount;
|
2015-10-17 20:46:58 -04:00
|
|
|
ca_require_noerr (result = GetElementCount(kAudioUnitScope_Input, elCount), home);
|
2008-06-02 17:41:35 -04:00
|
|
|
if (elCount) {
|
|
|
|
for (unsigned int i = 0; i < elCount; ++i) {
|
2015-10-17 20:46:58 -04:00
|
|
|
ca_require_noerr (result = SetSampleRate (kAudioUnitScope_Input, i, inSampleRate), home);
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
ca_require_noerr (result = GetElementCount(kAudioUnitScope_Output, elCount), home);
|
2008-06-02 17:41:35 -04:00
|
|
|
if (elCount) {
|
|
|
|
for (unsigned int i = 0; i < elCount; ++i) {
|
2015-10-17 20:46:58 -04:00
|
|
|
ca_require_noerr (result = SetSampleRate (kAudioUnitScope_Output, i, inSampleRate), home);
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
home:
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::NumberChannels (AudioUnitScope inScope,
|
|
|
|
AudioUnitElement inEl,
|
|
|
|
UInt32 &outChans) const
|
|
|
|
{
|
|
|
|
AudioStreamBasicDescription desc;
|
|
|
|
OSStatus result = GetFormat (inScope, inEl, desc);
|
|
|
|
if (!result)
|
|
|
|
outChans = desc.mChannelsPerFrame;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::SetNumberChannels (AudioUnitScope inScope,
|
|
|
|
AudioUnitElement inEl,
|
|
|
|
UInt32 inChans)
|
|
|
|
{
|
|
|
|
// set this as the output of the AU
|
|
|
|
CAStreamBasicDescription desc;
|
|
|
|
OSStatus result = GetFormat (inScope, inEl, desc);
|
|
|
|
if (result) return result;
|
2015-10-17 20:46:58 -04:00
|
|
|
desc.ChangeNumberChannels (inChans, desc.IsInterleaved());
|
2008-06-02 17:41:35 -04:00
|
|
|
result = SetFormat (inScope, inEl, desc);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::IsElementCountWritable (AudioUnitScope inScope, bool &outWritable) const
|
|
|
|
{
|
|
|
|
Boolean isWritable;
|
|
|
|
UInt32 outDataSize;
|
|
|
|
OSStatus result = GetPropertyInfo (kAudioUnitProperty_ElementCount, inScope, 0, &outDataSize, &isWritable);
|
|
|
|
if (result)
|
|
|
|
return result;
|
|
|
|
outWritable = isWritable ? true : false;
|
2015-10-26 14:35:06 -04:00
|
|
|
return noErr;
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::GetElementCount (AudioUnitScope inScope, UInt32 &outCount) const
|
|
|
|
{
|
|
|
|
UInt32 propSize = sizeof(outCount);
|
|
|
|
return GetProperty (kAudioUnitProperty_ElementCount, inScope, 0, &outCount, &propSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::SetElementCount (AudioUnitScope inScope, UInt32 inCount)
|
|
|
|
{
|
|
|
|
return SetProperty (kAudioUnitProperty_ElementCount, inScope, 0, &inCount, sizeof(inCount));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CAAudioUnit::HasDynamicScope (AudioUnitScope inScope, SInt32 &outTotalNumChannels) const
|
|
|
|
{
|
|
|
|
// ok - now we need to check the AU's capability here.
|
|
|
|
// this is the default assumption of an audio effect unit
|
|
|
|
Boolean* isWritable = 0;
|
|
|
|
UInt32 dataSize = 0;
|
|
|
|
OSStatus result = GetPropertyInfo (kAudioUnitProperty_SupportedNumChannels,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
&dataSize, isWritable); //don't care if this is writable
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
// AU has to explicitly tell us about this.
|
|
|
|
if (result) return false;
|
|
|
|
|
|
|
|
StackAUChannelInfo info (dataSize);
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
result = GetProperty (kAudioUnitProperty_SupportedNumChannels,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
info.mChanInfo, &dataSize);
|
|
|
|
if (result) return false;
|
|
|
|
|
|
|
|
return ValidateDynamicScope (inScope, outTotalNumChannels, info.mChanInfo, (dataSize / sizeof(AUChannelInfo)));
|
|
|
|
}
|
|
|
|
|
|
|
|
// as we've already checked that the element count is writable
|
|
|
|
// the following conditions will match this..
|
|
|
|
/*
|
|
|
|
-1, -2 -> signifies no restrictions
|
|
|
|
-2, -1 -> signifies no restrictions -> in this case outTotalNumChannels == -1 (any num channels)
|
|
|
|
|
|
|
|
-N (where N is less than -2), signifies the total channel count on the scope side (in or out)
|
|
|
|
*/
|
2015-10-26 14:35:06 -04:00
|
|
|
bool CAAudioUnit::ValidateDynamicScope (AudioUnitScope inScope,
|
|
|
|
SInt32 &outTotalNumChannels,
|
|
|
|
const AUChannelInfo *info,
|
2008-06-02 17:41:35 -04:00
|
|
|
UInt32 numInfo) const
|
|
|
|
{
|
|
|
|
bool writable = false;
|
|
|
|
OSStatus result = IsElementCountWritable (inScope, writable);
|
|
|
|
if (result || (writable == false))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
//now chan layout can contain -1 for either scope (ie. doesn't care)
|
|
|
|
for (unsigned int i = 0; i < numInfo; ++i)
|
|
|
|
{
|
|
|
|
// lets test the special wild card case first...
|
|
|
|
// this says the AU can do any num channels on input or output - for eg. Matrix Mixer
|
|
|
|
if (((info[i].inChannels == -1) && (info[i].outChannels == -2))
|
|
|
|
|| ((info[i].inChannels == -2) && (info[i].outChannels == -1)))
|
|
|
|
{
|
|
|
|
outTotalNumChannels = -1;
|
|
|
|
return true;
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
// ok lets now test our special case....
|
|
|
|
if (inScope == kAudioUnitScope_Input) {
|
|
|
|
// isn't dynamic on this side at least
|
|
|
|
if (info[i].inChannels >= 0)
|
|
|
|
continue;
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
if (info[i].inChannels < -2) {
|
|
|
|
outTotalNumChannels = abs (info[i].inChannels);
|
|
|
|
return true;
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
}
|
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
else if (inScope == kAudioUnitScope_Output) {
|
|
|
|
// isn't dynamic on this side at least
|
|
|
|
if (info[i].outChannels >= 0)
|
|
|
|
continue;
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
if (info[i].outChannels < -2) {
|
|
|
|
outTotalNumChannels = abs (info[i].outChannels);
|
|
|
|
return true;
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
}
|
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
else {
|
|
|
|
break; // wrong scope was specified
|
|
|
|
}
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
|
|
|
return false;
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
|
2015-10-26 14:35:06 -04:00
|
|
|
OSStatus CAAudioUnit::ConfigureDynamicScope (AudioUnitScope inScope,
|
|
|
|
UInt32 inNumElements,
|
|
|
|
UInt32 *inChannelsPerElement,
|
2008-06-02 17:41:35 -04:00
|
|
|
Float64 inSampleRate)
|
|
|
|
{
|
|
|
|
SInt32 numChannels = 0;
|
|
|
|
bool isDyamic = HasDynamicScope (inScope, numChannels);
|
|
|
|
if (isDyamic == false)
|
|
|
|
return kAudioUnitErr_InvalidProperty;
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
//lets to a sanity check...
|
|
|
|
// if numChannels == -1, then it can do "any"...
|
|
|
|
if (numChannels > 0) {
|
|
|
|
SInt32 count = 0;
|
|
|
|
for (unsigned int i = 0; i < inNumElements; ++i)
|
|
|
|
count += inChannelsPerElement[i];
|
|
|
|
if (count > numChannels)
|
|
|
|
return kAudioUnitErr_InvalidPropertyValue;
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
OSStatus result = SetElementCount (inScope, inNumElements);
|
|
|
|
if (result)
|
|
|
|
return result;
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
for (unsigned int i = 0; i < inNumElements; ++i) {
|
2015-10-17 20:46:58 -04:00
|
|
|
CAStreamBasicDescription desc;
|
|
|
|
result = GetFormat (inScope, i, desc);
|
|
|
|
if (result) return result;
|
|
|
|
desc.ChangeNumberChannels (inChannelsPerElement[i], desc.IsInterleaved());
|
|
|
|
desc.mSampleRate = inSampleRate;
|
2008-06-02 17:41:35 -04:00
|
|
|
result = SetFormat (inScope, i, desc);
|
|
|
|
if (result)
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
return noErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark __Properties
|
|
|
|
|
|
|
|
bool CAAudioUnit::CanBypass () const
|
|
|
|
{
|
|
|
|
Boolean outWritable;
|
|
|
|
OSStatus result = AudioUnitGetPropertyInfo (AU(), kAudioUnitProperty_BypassEffect,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
NULL, &outWritable);
|
|
|
|
return (!result && outWritable);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CAAudioUnit::GetBypass () const
|
|
|
|
{
|
|
|
|
UInt32 dataSize = sizeof (UInt32);
|
|
|
|
UInt32 outBypass;
|
|
|
|
OSStatus result = AudioUnitGetProperty (AU(), kAudioUnitProperty_BypassEffect,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
&outBypass, &dataSize);
|
|
|
|
return (result ? false : outBypass);
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::SetBypass (bool inBypass) const
|
2015-10-26 14:35:06 -04:00
|
|
|
{
|
2008-06-02 17:41:35 -04:00
|
|
|
UInt32 bypass = inBypass ? 1 : 0;
|
|
|
|
return AudioUnitSetProperty (AU(), kAudioUnitProperty_BypassEffect,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
&bypass, sizeof (UInt32));
|
|
|
|
}
|
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
OSStatus CAAudioUnit::GetMaxFramesPerSlice (UInt32& outMaxFrames) const
|
|
|
|
{
|
|
|
|
UInt32 dataSize = sizeof(outMaxFrames);
|
|
|
|
return AudioUnitGetProperty (AU(), kAudioUnitProperty_MaximumFramesPerSlice,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
&outMaxFrames, &dataSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::SetMaxFramesPerSlice (UInt32 inMaxFrames)
|
|
|
|
{
|
|
|
|
return AudioUnitSetProperty (AU(), kAudioUnitProperty_MaximumFramesPerSlice,
|
|
|
|
kAudioUnitScope_Global, 0,
|
2015-10-26 14:35:06 -04:00
|
|
|
&inMaxFrames, sizeof (UInt32));
|
2015-10-17 20:46:58 -04:00
|
|
|
}
|
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
Float64 CAAudioUnit::Latency () const
|
|
|
|
{
|
|
|
|
Float64 secs;
|
|
|
|
UInt32 size = sizeof(secs);
|
|
|
|
if (GetProperty (kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0, &secs, &size))
|
|
|
|
return 0;
|
|
|
|
return secs;
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::GetAUPreset (CFPropertyListRef &outData) const
|
|
|
|
{
|
|
|
|
UInt32 dataSize = sizeof(outData);
|
|
|
|
return AudioUnitGetProperty (AU(), kAudioUnitProperty_ClassInfo,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
&outData, &dataSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::SetAUPreset (CFPropertyListRef &inData)
|
|
|
|
{
|
|
|
|
return AudioUnitSetProperty (AU(), kAudioUnitProperty_ClassInfo,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
&inData, sizeof (CFPropertyListRef));
|
|
|
|
}
|
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
#if !TARGET_OS_IPHONE
|
|
|
|
OSStatus CAAudioUnit::SetAUPresetFromDocument (CFPropertyListRef &inData)
|
|
|
|
{
|
|
|
|
return AudioUnitSetProperty (AU(), kAudioUnitProperty_ClassInfoFromDocument,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
&inData, sizeof (CFPropertyListRef));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
OSStatus CAAudioUnit::GetPresentPreset (AUPreset &outData) const
|
|
|
|
{
|
|
|
|
UInt32 dataSize = sizeof(outData);
|
|
|
|
OSStatus result = AudioUnitGetProperty (AU(), kAudioUnitProperty_PresentPreset,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
&outData, &dataSize);
|
2015-10-17 20:46:58 -04:00
|
|
|
#if !TARGET_OS_IPHONE
|
2015-10-26 14:35:06 -04:00
|
|
|
#ifndef __LP64__
|
2008-06-02 17:41:35 -04:00
|
|
|
if (result == kAudioUnitErr_InvalidProperty) {
|
|
|
|
dataSize = sizeof(outData);
|
|
|
|
result = AudioUnitGetProperty (AU(), kAudioUnitProperty_CurrentPreset,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
&outData, &dataSize);
|
|
|
|
if (result == noErr) {
|
|
|
|
// we now retain the CFString in the preset so for the client of this API
|
|
|
|
// it is consistent (ie. the string should be released when done)
|
|
|
|
if (outData.presetName)
|
|
|
|
CFRetain (outData.presetName);
|
|
|
|
}
|
|
|
|
}
|
2015-10-17 20:46:58 -04:00
|
|
|
#endif
|
|
|
|
#endif
|
2008-06-02 17:41:35 -04:00
|
|
|
return result;
|
|
|
|
}
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
OSStatus CAAudioUnit::SetPresentPreset (AUPreset &inData)
|
|
|
|
{
|
|
|
|
OSStatus result = AudioUnitSetProperty (AU(), kAudioUnitProperty_PresentPreset,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
&inData, sizeof (AUPreset));
|
2015-10-17 20:46:58 -04:00
|
|
|
#if !TARGET_OS_IPHONE
|
|
|
|
#ifndef __LP64__
|
2008-06-02 17:41:35 -04:00
|
|
|
if (result == kAudioUnitErr_InvalidProperty) {
|
|
|
|
result = AudioUnitSetProperty (AU(), kAudioUnitProperty_CurrentPreset,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
&inData, sizeof (AUPreset));
|
|
|
|
}
|
2015-10-17 20:46:58 -04:00
|
|
|
#endif
|
|
|
|
#endif
|
2008-06-02 17:41:35 -04:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CAAudioUnit::HasCustomView () const
|
|
|
|
{
|
2015-10-17 20:46:58 -04:00
|
|
|
#if !TARGET_OS_IPHONE
|
2008-06-02 17:41:35 -04:00
|
|
|
UInt32 dataSize = 0;
|
2015-10-17 20:46:58 -04:00
|
|
|
OSStatus result = -4/*unimpErr*/;
|
|
|
|
#ifndef __LP64__
|
|
|
|
result = GetPropertyInfo(kAudioUnitProperty_GetUIComponentList,
|
2008-06-02 17:41:35 -04:00
|
|
|
kAudioUnitScope_Global, 0,
|
2015-10-26 14:35:06 -04:00
|
|
|
&dataSize, NULL);
|
2015-10-17 20:46:58 -04:00
|
|
|
#endif
|
2008-06-02 17:41:35 -04:00
|
|
|
if (result || !dataSize) {
|
|
|
|
dataSize = 0;
|
|
|
|
result = GetPropertyInfo(kAudioUnitProperty_CocoaUI,
|
|
|
|
kAudioUnitScope_Global, 0,
|
|
|
|
&dataSize, NULL);
|
|
|
|
if (result || !dataSize)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2015-10-17 20:46:58 -04:00
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::GetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
|
|
|
|
Float32 &outValue) const
|
|
|
|
{
|
2015-10-17 20:46:58 -04:00
|
|
|
return mDataPtr ? mDataPtr->GetParameter (inID, scope, element, outValue) : static_cast<OSStatus>(paramErr);
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::SetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
|
|
|
|
Float32 value, UInt32 bufferOffsetFrames)
|
|
|
|
{
|
2015-10-17 20:46:58 -04:00
|
|
|
return mDataPtr ? mDataPtr->SetParameter (inID, scope, element, value, bufferOffsetFrames) : static_cast<OSStatus>(paramErr);
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::MIDIEvent (UInt32 inStatus,
|
|
|
|
UInt32 inData1,
|
|
|
|
UInt32 inData2,
|
|
|
|
UInt32 inOffsetSampleFrame)
|
|
|
|
{
|
2015-10-17 20:46:58 -04:00
|
|
|
return mDataPtr ? mDataPtr->MIDIEvent (inStatus, inData1, inData2, inOffsetSampleFrame) : paramErr;
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::StartNote (MusicDeviceInstrumentID inInstrument,
|
|
|
|
MusicDeviceGroupID inGroupID,
|
|
|
|
NoteInstanceID * outNoteInstanceID,
|
|
|
|
UInt32 inOffsetSampleFrame,
|
|
|
|
const MusicDeviceNoteParams * inParams)
|
|
|
|
{
|
2015-10-26 14:35:06 -04:00
|
|
|
return mDataPtr ? mDataPtr->StartNote (inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, inParams)
|
2015-10-17 20:46:58 -04:00
|
|
|
: paramErr;
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::StopNote (MusicDeviceGroupID inGroupID,
|
|
|
|
NoteInstanceID inNoteInstanceID,
|
|
|
|
UInt32 inOffsetSampleFrame)
|
|
|
|
{
|
2015-10-17 20:46:58 -04:00
|
|
|
return mDataPtr ? mDataPtr->StopNote (inGroupID, inNoteInstanceID, inOffsetSampleFrame) : paramErr;
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
#pragma mark __Render
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::Render (AudioUnitRenderActionFlags * ioActionFlags,
|
|
|
|
const AudioTimeStamp * inTimeStamp,
|
|
|
|
UInt32 inOutputBusNumber,
|
|
|
|
UInt32 inNumberFrames,
|
|
|
|
AudioBufferList * ioData)
|
|
|
|
{
|
2015-10-17 20:46:58 -04:00
|
|
|
return mDataPtr ? mDataPtr->Render (ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData) : static_cast<OSStatus>(paramErr);
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
extern "C" OSStatus
|
2015-10-26 14:35:06 -04:00
|
|
|
AudioUnitProcess ( AudioUnit inUnit,
|
|
|
|
AudioUnitRenderActionFlags * ioActionFlags,
|
|
|
|
const AudioTimeStamp * inTimeStamp,
|
|
|
|
UInt32 inNumberFrames,
|
2015-10-17 20:46:58 -04:00
|
|
|
AudioBufferList * ioData);
|
2008-06-02 17:41:35 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
OSStatus CAAudioUnit::Process (AudioUnitRenderActionFlags & ioActionFlags,
|
|
|
|
const AudioTimeStamp & inTimeStamp,
|
|
|
|
UInt32 inNumberFrames,
|
|
|
|
AudioBufferList & ioData)
|
|
|
|
{
|
|
|
|
#if defined(__MAC_10_7) || defined(__IPHONE_4_0)
|
|
|
|
return AudioUnitProcess (AU(), &ioActionFlags, &inTimeStamp, inNumberFrames, &ioData);
|
|
|
|
#else
|
|
|
|
return -4/*unimpErr*/;
|
|
|
|
#endif
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
extern "C" OSStatus
|
2015-10-26 14:35:06 -04:00
|
|
|
AudioUnitProcessMultiple ( AudioUnit inUnit,
|
|
|
|
AudioUnitRenderActionFlags * ioActionFlags,
|
|
|
|
const AudioTimeStamp * inTimeStamp,
|
2015-10-17 20:46:58 -04:00
|
|
|
UInt32 inNumberFrames,
|
|
|
|
UInt32 inNumberInputBufferLists,
|
|
|
|
const AudioBufferList ** inInputBufferLists,
|
|
|
|
UInt32 inNumberOutputBufferLists,
|
|
|
|
AudioBufferList ** ioOutputBufferLists);
|
|
|
|
|
|
|
|
OSStatus CAAudioUnit::ProcessMultiple (AudioUnitRenderActionFlags & ioActionFlags,
|
|
|
|
const AudioTimeStamp & inTimeStamp,
|
|
|
|
UInt32 inNumberFrames,
|
|
|
|
UInt32 inNumberInputBufferLists,
|
|
|
|
const AudioBufferList ** inInputBufferLists,
|
|
|
|
UInt32 inNumberOutputBufferLists,
|
|
|
|
AudioBufferList ** ioOutputBufferLists)
|
2008-06-02 17:41:35 -04:00
|
|
|
{
|
2015-10-17 20:46:58 -04:00
|
|
|
#if defined(__MAC_10_7) || defined(__IPHONE_4_0)
|
2015-10-26 14:35:06 -04:00
|
|
|
return AudioUnitProcessMultiple (AU(), &ioActionFlags, &inTimeStamp, inNumberFrames,
|
2015-10-17 20:46:58 -04:00
|
|
|
inNumberInputBufferLists, inInputBufferLists, inNumberOutputBufferLists, ioOutputBufferLists);
|
|
|
|
#else
|
|
|
|
return -4/*unimpErr*/;
|
|
|
|
#endif
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark __CAAUChanHelper
|
|
|
|
|
|
|
|
CAAUChanHelper::CAAUChanHelper(const CAAudioUnit &inAU, AudioUnitScope inScope)
|
|
|
|
:mChans(NULL), mNumEls(0), mDidAllocate(false)
|
|
|
|
{
|
|
|
|
UInt32 elCount;
|
|
|
|
if (inAU.GetElementCount (inScope, elCount)) return;
|
2015-10-17 20:46:58 -04:00
|
|
|
if (elCount > kStaticElCount) {
|
2008-06-02 17:41:35 -04:00
|
|
|
mChans = new UInt32[elCount];
|
|
|
|
mDidAllocate = true;
|
|
|
|
memset (mChans, 0, sizeof(int) * elCount);
|
|
|
|
} else {
|
|
|
|
mChans = mStaticChans;
|
2015-10-17 20:46:58 -04:00
|
|
|
memset (mChans, 0, sizeof(int) * kStaticElCount);
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
for (unsigned int i = 0; i < elCount; ++i) {
|
|
|
|
UInt32 numChans;
|
|
|
|
if (inAU.NumberChannels (inScope, i, numChans)) return;
|
|
|
|
mChans[i] = numChans;
|
|
|
|
}
|
|
|
|
mNumEls = elCount;
|
|
|
|
}
|
|
|
|
|
2015-10-26 14:35:06 -04:00
|
|
|
CAAUChanHelper::CAAUChanHelper(UInt32 inMaxElems)
|
|
|
|
: mNumEls(inMaxElems), mDidAllocate(false)
|
2015-10-17 20:46:58 -04:00
|
|
|
{
|
|
|
|
if (inMaxElems > kStaticElCount) {
|
|
|
|
mChans = new UInt32[inMaxElems];
|
|
|
|
mDidAllocate = true;
|
|
|
|
memset (mChans, 0, sizeof(int) * inMaxElems);
|
|
|
|
} else {
|
|
|
|
mChans = mStaticChans;
|
|
|
|
memset (mChans, 0, sizeof(int) * kStaticElCount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
CAAUChanHelper::~CAAUChanHelper()
|
|
|
|
{
|
|
|
|
if (mDidAllocate) delete [] mChans;
|
|
|
|
}
|
|
|
|
|
2015-10-26 14:35:06 -04:00
|
|
|
CAAUChanHelper& CAAUChanHelper::operator= (const CAAUChanHelper &c)
|
|
|
|
{
|
2008-06-02 17:41:35 -04:00
|
|
|
if (mDidAllocate) delete [] mChans;
|
|
|
|
if (c.mDidAllocate) {
|
|
|
|
mChans = new UInt32[c.mNumEls];
|
|
|
|
mDidAllocate = true;
|
|
|
|
} else {
|
|
|
|
mDidAllocate = false;
|
|
|
|
mChans = mStaticChans;
|
|
|
|
}
|
|
|
|
memcpy (mChans, c.mChans, c.mNumEls * sizeof(int));
|
2015-10-26 14:35:06 -04:00
|
|
|
|
|
|
|
return *this;
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
#pragma mark __Print Utilities
|
|
|
|
|
|
|
|
void CAAudioUnit::Print (FILE* file) const
|
|
|
|
{
|
|
|
|
fprintf (file, "AudioUnit:%p\n", AU());
|
2015-10-26 14:35:06 -04:00
|
|
|
if (IsValid()) {
|
2008-06-02 17:41:35 -04:00
|
|
|
fprintf (file, "\tnode=%ld\t", (long)GetAUNode()); Comp().Print (file);
|
|
|
|
}
|
|
|
|
}
|
2015-10-17 20:46:58 -04:00
|
|
|
|
|
|
|
#if CA_AU_USE_FAST_DISPATCH
|
|
|
|
// Handle GetComponentInstanceStorage(ComponentInstance aComponentInstance)
|
|
|
|
static void *LoadGetComponentInstanceStorage (void *inst)
|
|
|
|
{
|
|
|
|
typedef void* (*GetComponentInstanceStorageProc)(void* aComponentInstance);
|
|
|
|
static GetComponentInstanceStorageProc sGetComponentInstanceStorageProc = NULL;
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
static int sDoCSLoad = 1;
|
|
|
|
if (sDoCSLoad) {
|
|
|
|
sDoCSLoad = 0;
|
|
|
|
void *theImage = dlopen("/System/Library/Frameworks/CoreServices.framework/CoreServices", RTLD_LAZY);
|
|
|
|
if (!theImage) return NULL;
|
2015-10-26 14:35:06 -04:00
|
|
|
|
2015-10-17 20:46:58 -04:00
|
|
|
sGetComponentInstanceStorageProc = (GetComponentInstanceStorageProc) dlsym(theImage, "GetComponentInstanceStorage");
|
|
|
|
}
|
|
|
|
if (sGetComponentInstanceStorageProc)
|
|
|
|
return (*sGetComponentInstanceStorageProc)(inst);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|